/**
*
*/
package vroom.common.modeling.vrprep;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.HashSet;
import vroom.common.modeling.dataModel.Depot;
import vroom.common.modeling.dataModel.INodeVisit;
import vroom.common.modeling.dataModel.IVRPInstance;
import vroom.common.modeling.dataModel.IVRPRequest;
import vroom.common.modeling.dataModel.attributes.DeterministicDemand;
import vroom.common.modeling.dataModel.attributes.Duration;
import vroom.common.modeling.dataModel.attributes.IDemand;
import vroom.common.modeling.dataModel.attributes.ILocation;
import vroom.common.modeling.dataModel.attributes.ITimeWindow;
import vroom.common.modeling.dataModel.attributes.RequestAttributeKey;
import vroom.common.modeling.dataModel.attributes.VehicleAttributeKey;
import vroom.common.modeling.vrprep.Instance.Fleet;
import vroom.common.modeling.vrprep.Instance.Fleet.Vehicle;
import vroom.common.modeling.vrprep.Instance.Info;
import vroom.common.modeling.vrprep.Instance.Info.Contributor;
import vroom.common.modeling.vrprep.Instance.Network;
import vroom.common.modeling.vrprep.Instance.Network.Descriptor;
import vroom.common.modeling.vrprep.Instance.Network.Links;
import vroom.common.modeling.vrprep.Instance.Network.Links.Link;
import vroom.common.modeling.vrprep.Instance.Network.Nodes;
import vroom.common.modeling.vrprep.Instance.Network.Nodes.Node;
import vroom.common.modeling.vrprep.Instance.Requests;
import vroom.common.modeling.vrprep.Instance.Requests.Request;
import vroom.common.modeling.vrprep.Location.Euclidean;
import vroom.common.modeling.vrprep.Tw.End;
import vroom.common.modeling.vrprep.Tw.Start;
import vroom.common.utilities.Utilities;
/**
* The class <code>VRPRepFactory</code> provides factory methods to convert objects between the VroomModeling data model
* and the VRPRep JAXB data model
* <p>
* Creation date: Jun 22, 2012 - 11:35:46 AM
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a
* href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a>
* @version 1.0
*/
public class VRPRepFactory extends ObjectFactory {
public Vehicle convertSingleVehicle(vroom.common.modeling.dataModel.Vehicle vehicle) {
Vehicle v = createInstanceFleetVehicle();
v.setNumber(BigInteger.valueOf(1));
v.setType(BigInteger.valueOf(vehicle.getID()));
Depot d = vehicle.getAttribute(VehicleAttributeKey.DEPOT);
if (d != null) {
v.setDepartureNode(BigInteger.valueOf(d.getID()));
v.setArrivalNode(BigInteger.valueOf(d.getID()));
}
for (int i = 0; i < vehicle.getCompartmentCount(); i++) {
v.getCapacity().add(vehicle.getCapacity(i));
}
return v;
}
public Fleet convertFleet(vroom.common.modeling.dataModel.Fleet<?> fleet) {
Fleet f = createInstanceFleet();
if (fleet.isHomogeneous()) {
Vehicle v = convertSingleVehicle(fleet.getVehicle());
if (fleet.isUnlimited())
v.setNumber(BigInteger.valueOf(-1));
else
v.setNumber(BigInteger.valueOf(fleet.size()));
f.getVehicle().add(v);
} else {
for (vroom.common.modeling.dataModel.Vehicle v : fleet) {
f.getVehicle().add(convertSingleVehicle(v));
}
}
return f;
}
public Location convertLocation(ILocation location) {
if (Double.isNaN(location.getX()))
return null;
// FIXME check coordinate type
Location loc = createLocation();
Euclidean coords = createLocationEuclidean();
loc.setEuclidean(coords);
coords.setCx(location.getX());
coords.setCy(location.getY());
return loc;
}
public Node convertNode(vroom.common.modeling.dataModel.Node node) {
Node n = createInstanceNetworkNodesNode();
n.setId(BigInteger.valueOf(node.getID()));
Location loc = convertLocation(node.getLocation());
if (loc != null)
n.setLocation(loc);
if (Depot.class.isAssignableFrom(node.getClass()))
n.setType(BigInteger.valueOf(0));
else
n.setType(BigInteger.valueOf(1));
return n;
}
/**
* Convert a simple request (supported: single node, multiple deterministic demands, tw)
*
* @param request
* @return the converted request
*/
public Request convertRequest(IVRPRequest request) {
Request r = createInstanceRequestsRequest();
r.setId(BigInteger.valueOf(request.getID()));
// Node
r.setNode(BigInteger.valueOf(request.getNode().getID()));
// Demands
IDemand dem = request.getDemandAttribute();
if (dem != null) {
for (int p = 0; p < dem.getProductCount(); p++) {
Demand d = createDemand();
r.getDemand().add(d);
if (DeterministicDemand.class.isAssignableFrom(dem.getClass()))
d.getContent().add(Utilities.format(dem.getDemand(p)));
else
throw new UnsupportedOperationException("Unsupported demand " + dem);
d.setType(BigInteger.valueOf(p));
}
}
// Time window
ITimeWindow rtw = request.getAttribute(RequestAttributeKey.TIME_WINDOW);
if (rtw != null)
r.getTw().add(convertTimeWindow(rtw));
// Service time
Duration rst = request.getAttribute(RequestAttributeKey.SERVICE_TIME);
if (rst != null && rst.getDuration() > 0) {
Time st = createTime();
st.getContent().add(rst.toString());
r.setServiceTime(st);
}
return r;
}
public Tw convertTimeWindow(ITimeWindow rtw) {
Tw tw = createTw();
Start twstart = createTwStart();
twstart.setIsHard(!rtw.isSoftStart());
twstart.setContent(Utilities.format(rtw.startAsDouble()));
tw.setStart(twstart);
End twend = createTwEnd();
twend.setIsHard(!rtw.isSoftEnd());
twend.setContent(Utilities.format(rtw.endAsDouble()));
tw.setEnd(twend);
return tw;
}
/**
* Factory method to create the information related to an instance
*
* @param contribName
* @param contribEmail
* @param instanceName
* @param problemName
* @param reference
* @return
*/
public Info createInstanceInfo(String contribName, String contribEmail, String instanceName,
String problemName, String reference) {
Info info = createInstanceInfo();
Contributor contrib = createInstanceInfoContributor();
contrib.setName(contribName);
contrib.setEmail(contribEmail);
info.setContributor(contrib);
info.setName(instanceName);
info.setProblem(problemName);
info.setReference(reference);
return info;
}
/**
* Convert a {@link IVRPInstance} into an {@link Instance}
*
* @param instance
* @return the converted instance
*/
public Instance convertInstance(IVRPInstance instance) {
Instance i = createInstance();
// Network
// ------------------------
Network net = createInstanceNetwork();
i.setNetwork(net);
Nodes nodes = createInstanceNetworkNodes();
net.setNodes(nodes);
// - Nodes
HashSet<INodeVisit> addedNodes = new HashSet<>();
for (Depot d : instance.getDepots()) {
nodes.getNode().add(convertNode(d));
}
for (INodeVisit n : instance.getNodeVisits()) {
if (!addedNodes.contains(n.getNode())) {
Node node = convertNode(n.getNode());
nodes.getNode().add(node);
addedNodes.add(n);
}
}
// - Descriptor
Descriptor desc = createInstanceNetworkDescriptor();
net.setDescriptor(desc);
// Euclidean distance
desc.setDistanceType(instance.getCostDelegate().getDistanceType());
desc.setIsComplete(true);
if (instance.getCostDelegate().getPrecision() != Double.MAX_VALUE
&& instance.getCostDelegate().getRoundingMethod() != RoundingMode.UNNECESSARY)
desc.setRoundingRule(String.format("%s[%s]", instance.getCostDelegate()
.getRoundingMethod().toString(), instance.getCostDelegate().getPrecision()));
// -----------------------------------------------------
// Fleet
// -----------------------------------------------------
Fleet fleet = convertFleet(instance.getFleet());
i.setFleet(fleet);
// -----------------------------------------------------
// Requests
// -----------------------------------------------------
Requests reqs = createInstanceRequests();
i.setRequests(reqs);
for (IVRPRequest r : instance.getRequests()) {
reqs.getRequest().add(convertRequest(r));
}
// -----------------------------------------------------
if (instance.getCostDelegate().getDistanceType().contains("EXPLICIT")) {
Links links = createInstanceNetworkLinks();
i.getNetwork().setLinks(links);
for (INodeVisit m : instance.getNodeVisits()) {
for (INodeVisit n : instance.getNodeVisits()) {
if (m == n)
continue;
double distance = instance.getCostDelegate().getDistance(m, n);
if (!Double.isInfinite(distance) && !Double.isNaN(distance)) {
Link edge = createInstanceNetworkLinksLink();
edge.setTail(BigInteger.valueOf(m.getID()));
edge.setHead(BigInteger.valueOf(n.getID()));
edge.setDirected(false);
edge.setCost(distance);
links.getLink().add(edge);
}
}
}
}
return i;
}
}