···11-%----------------------------------------------------------------------------%
22-%----------------------------------------------------------------------------%
33-%
44-% We have n trains moving along a single track with m stations. There is a
55-% non-zero constant flow of passengers arriving at all but the first and last
66-% station who wish to travel to the final station. Trains are originally
77-% scheduled so that they collect the passengers and drop them at the final
88-% station. To this original schedule a disruption is introduced whereby a train
99-% is delayed. Each of the trains (at the time of the delay) has knowledge of the
1010-% duration of the delay. The objective is to reschedule the trains to minimize
1111-% the average travel time of the passengers. Trains are not able to overtake
1212-% preceding trains, however they do have the option to
1313-% skip a station and wait longer at a station to collect more passengers.
1414-1515-%----------------------------------------------------------------------------%
1616-%----------------------------------------------------------------------------%
1717-1818-%include "globals.mzn";
1919-2020-int : n;
2121-int : m;
2222-2323-int : maxTime;
2424-2525-0..maxTime : delayTime;
2626-1..n : delayTrain;
2727-0..maxTime : delayDuration;
2828-2929-array [1..m-1] of 0..maxTime : distance;
3030-3131-array [1..n, 1..m] of 0..maxTime : scheduledArrival;
3232-array [1..n, 1..m] of 0..maxTime : scheduledDeparture;
3333-3434-array [1..m] of 0..maxTime : passengerStart;
3535-array [1..m] of 0..maxTime : passengerStop = [scheduledDeparture[n,j] | j in 1..m];
3636-array [1..m] of int : passengerFlow;
3737-3838-array [1..n, 1..m] of var 0..maxTime : departure;
3939-array [1..n, 1..m] of var 0..maxTime : arrival;
4040-4141-array [1..n] of var 0..maxTime : finalArrival = [ arrival[i,m] | i in 1..n ];
4242-4343-array [1..n, 1..m] of var 0..maxTime : sigmaLower;
4444-array [1..n, 1..m] of var 0..maxTime : sigmaUpper;
4545-4646-int : capacity;
4747-4848-array [1..n, 1..m] of var 0..capacity : collect;
4949-array [1..n, 1..m] of var 0..capacity : load;
5050-5151-% All trains "arrive" at the first station at time 0.
5252-constraint forall (i in 1..n)
5353- (arrival[i,1] = 0);
5454-% ... and "depart" from the last station as soon as they arrive there.
5555-constraint forall (i in 1..n)
5656- (departure[i,m] = arrival[i,m]);
5757-5858-% Before the delay, everything runs to schedule.
5959-constraint forall (i in 1..n, j in 1..m-1)
6060- (if scheduledDeparture[i,j] <= delayTime
6161- then departure[i,j] = scheduledDeparture[i,j]
6262- else true
6363- endif);
6464-6565-% If the train is in motion, then the arrival of the
6666-% delayed train is at least the departure time at the previous station
6767-% plus the ordinary travel time plus the duration of the delay.
6868-int : destinationWhenDelayed = min([j | j in 1..m where scheduledDeparture[delayTrain,j] > delayTime]);
6969-constraint if destinationWhenDelayed > 1
7070- then if delayTime < scheduledDeparture[delayTrain,destinationWhenDelayed-1] + distance[destinationWhenDelayed-1]
7171- then arrival[delayTrain,destinationWhenDelayed] >=
7272- departure[delayTrain,destinationWhenDelayed-1] + delayDuration + distance[destinationWhenDelayed-1]
7373- else true
7474- endif
7575- else true
7676- endif;
7777-% The train's next departure is at least the delay time plus the delay
7878-% duration.
7979-constraint departure[delayTrain, destinationWhenDelayed] >= delayTime + delayDuration;
8080-8181-% Trains depart after they arrive.
8282-constraint forall (i in 1..n, j in 1..m)
8383- (departure[i,j] >= arrival[i,j]);
8484-8585-% Trains never leave earlier than scheduled.
8686-constraint forall (i in 1..n, j in 1..m-1)
8787- (departure[i,j] >= scheduledDeparture[i,j]);
8888-8989-% There is a minimum travel time between stations.
9090-constraint forall (i in 1..n, j in 1..m-1)
9191- (arrival[i,j+1] >= departure[i,j] + distance[j]);
9292-9393-% At station 1, trains leave in order.
9494-constraint forall (i in 1..n-1)
9595- (departure[i,1] < departure[i+1,1]);
9696-% At most one train dwelling at a station at a given time.
9797-constraint forall (i in 1..n-1, j in 2..m-1)
9898- (departure[i,j] <= arrival[i+1,j]-2);
9999-100100-% The sigma values partition time at each station.
101101-constraint forall (i in 1..n, j in 1..m)
102102- (sigmaLower[i,j] <= sigmaUpper[i,j]);
103103-104104-% For the first and last trains, the sigma values are equal to the
105105-% extreme times of passenger arrivals.
106106-constraint forall (j in 2..m-1)
107107- ((sigmaLower[1,j] = passengerStart[j])
108108- /\ (sigmaUpper[n,j] = scheduledDeparture[n,j]));
109109-% The sigma values join together.
110110-constraint forall (i in 1..n-1, j in 1..m)
111111- (sigmaUpper[i,j] = sigmaLower[i+1,j]);
112112-113113-% You can't pick up people after you leave.
114114-constraint forall (i in 1..n-1, j in 1..m-1)
115115- (sigmaUpper[i,j] <= departure[i,j]);
116116-constraint forall (j in 1..m-1)
117117- (sigmaUpper[n,j] <= departure[n,j]);
118118-119119-% Defines collect and load variables.
120120-constraint forall (i in 1..n, j in 1..m)
121121- (collect[i,j] = (sigmaUpper[i,j]-sigmaLower[i,j])*passengerFlow[j]);
122122-123123-constraint forall (i in 1..n) (load[i,1] = collect[i,1]);
124124-constraint forall (i in 1..n, j in 2..m)
125125- (load[i,j] = load[i,j-1] + collect[i,j]);
126126-127127-% If a train picks anyone up, then it must pick
128128-% everyone up (until it gets full).
129129-constraint forall (i in 1..n, j in 1..m-1)
130130- (sigmaUpper[i,j] > sigmaLower[i,j] ->
131131- ((sigmaUpper[i,j] = departure[i,j]) \/
132132- (sigmaUpper[i,j] = scheduledDeparture[n,j]) \/
133133- (load[i,j] + bool2int(sigmaUpper[i,j] < scheduledDeparture[n,j])*passengerFlow[j] > capacity)));
134134-135135-% Boarding time.
136136-constraint forall (i in 1..n, j in 2..m)
137137- (((capacity-load[i,j-1] < 100) -> (collect[i,j] <= dwell[i,j]*20)) /\
138138- ((capacity-load[i,j-1] >= 100) -> (collect[i,j] <= dwell[i,j]*50)));
139139-% (Redundant for j>=2 (but necessary for j=1))
140140-constraint forall (i in 1..n, j in 1..m)
141141- (collect[i,j] <= (departure[i,j]-arrival[i,j])*50);
142142-143143-array [1..n, 1..m] of var 0..maxTime : dwell;
144144-constraint forall (i in 1..n, j in 1..m) (dwell[i,j] = departure[i,j] - arrival[i,j]);
145145-146146-int: objective_min = lb(sum(i in 1..n)(load[i,m]*arrival[i,m]));
147147-int: objective_max = ub(sum(i in 1..n)(load[i,m]*arrival[i,m]));
148148-var objective_min..objective_max: objective = sum(i in 1..n)(load[i,m]*arrival[i,m]);
149149-150150-solve
151151- :: seq_search([
152152- int_search(
153153- [arrival[i,m-j+1] | j in 1..m, i in 1..n] ++
154154- [departure[i,m-j+1] | j in 1..m, i in 1..n] ++
155155- [sigmaUpper[i,m-j+1] | j in 1..m, i in 1..n] ++
156156- [sigmaLower[i,m-j+1] | j in 1..m, i in 1..n],
157157- input_order, indomain_min, complete
158158- ),
159159- int_search(
160160- array1d(1..n*m, collect) ++ array1d(1..n*m, load) ++ array1d(1..n*m, dwell),
161161- first_fail, indomain_min, complete
162162- )
163163- ])
164164- minimize objective;
165165-166166-output [
167167- "arrival = array2d(1..", show(n), ", 1..", show(m), ", ", show(arrival), ");\n",
168168- "departure = array2d(1..", show(n), ", 1..", show(m), ", ", show(departure), ");\n",
169169- "sigmaLower = array2d(1..", show(n), ", 1..", show(m), ", ", show(sigmaLower), ");\n",
170170- "sigmaUpper = array2d(1..", show(n), ", 1..", show(m), ", ", show(sigmaUpper), ");\n",
171171- "collect = array2d(1..", show(n), ", 1..", show(m), ", ", show(collect), ");\n",
172172- "load = array2d(1..", show(n), ", 1..", show(m), ", ", show(load), ");\n",
173173- "dwell = array2d(1..", show(n), ", 1..", show(m), ", ", show(dwell), ");\n",
174174- "constraint objective = ", show(objective), ";\n"
175175-];
176176-
···11-% Copyright (c) 2016, Jacopo Mauro. All rights reserved.
22-% This file is licensed under the terms of the ISC License.
33-44-55-% Please note that you will need to set the MiniZinc standard library
66-% environment variable $MZN_STDLIB_PATH to share/minizinc to include
77-% the MiniSearch builtins
88-99-include "lex_greatereq.mzn";
1010-include "lex_less.mzn";
1111-1212-int: MAX_INT = 4096;
1313-%%%%%%%%%%%%%%%%
1414-% Input parameters
1515-%%%%%%%%%%%%%%%%
1616-1717-% components
1818-set of int: comps;
1919-% ports
2020-set of int: ports;
2121-% multiple provide port
2222-set of int: multi_provide_ports;
2323-2424-% locations
2525-set of int: locations;
2626-% resources
2727-set of int: resources;
2828-2929-% map of components with their requirements number
3030-array[ comps, ports] of int: requirement_port_nums;
3131-% map of components with their provided multi-ports
3232-% -1 means infinite multi-port provider
3333-array[ comps, multi_provide_ports] of int: provide_port_nums;
3434-% map of components with their conflicts
3535-array[ comps, ports] of bool: conflicts;
3636-% map of multi-ports with their ports
3737-array[ multi_provide_ports, ports] of bool: multi_provides;
3838-3939-% map of location with their costs
4040-array[ locations ] of int: costs;
4141-% map of locations with the resouces they provide
4242-array[ locations, resources ] of int: resource_provisions;
4343-% map of components with the resources they consume
4444-array[ comps, resources ] of int: resource_consumptions;
4545-4646-%%%%%%%%%%%%%%%%
4747-% variables
4848-%%%%%%%%%%%%%%%%
4949-% bindings number
5050-array[ multi_provide_ports, ports, comps, comps] of var 0..MAX_INT: bindings;
5151-% components number
5252-array[ comps ] of var 0..MAX_INT: comps_num;
5353-% location to number of component map
5454-array[ locations, comps] of var 0..MAX_INT: comp_locations;
5555-5656-% total number of components
5757-var 0..MAX_INT: sum_comp;
5858-5959-%%%%%%%%%%%%%%%%
6060-% constraints (no location)
6161-%%%%%%%%%%%%%%%%
6262-6363-% bind the total number of components
6464-constraint sum_comp = sum( i in comps)(comps_num[i]);
6565-6666-% bindings 0 if the multiprovide does not provide port
6767-constraint forall(mport in multi_provide_ports, port in ports) (
6868- if multi_provides[mport,port]
6969- then true
7070- else forall(i in comps, j in comps) ( bindings[mport,port,i,j] = 0)
7171- endif
7272-);
7373-7474-% provides must be greater or equal to bindings & infinite provide port constraints
7575-constraint forall(mport in multi_provide_ports, pcomp in comps) (
7676- if provide_port_nums[pcomp,mport]=0
7777- then forall(port in ports, rcomp in comps) (
7878- bindings[mport,port,pcomp,rcomp] = 0
7979- )
8080- else
8181- if (provide_port_nums[pcomp,mport] = -1)
8282- then forall(port in ports, rcomp in comps) (
8383- (comps_num[pcomp] = 0) -> (bindings[mport,port,pcomp,rcomp]=0))
8484- else sum( port in ports, rcomp in comps)(
8585- bindings[mport,port,pcomp,rcomp] ) <= comps_num[pcomp] * provide_port_nums[pcomp,mport]
8686- endif
8787- endif
8888-);
8989-9090-% requires must be equal to bindings
9191-% note: here is possible to require also smaller than or equal
9292-constraint forall(port in ports, rcomp in comps) (
9393- sum( mport in multi_provide_ports, pcomp in comps)(
9494- bindings[mport,port,pcomp,rcomp] ) = comps_num[rcomp] * requirement_port_nums[rcomp,port]
9595-);
9696-9797-9898-% conflict constraints if component provide same port
9999-constraint forall(port in ports, pcomp in comps) (
100100- if (conflicts[pcomp,port] /\ exists(mport in multi_provide_ports) (
101101- (multi_provides[mport,port]) /\ provide_port_nums[pcomp,mport] != 0))
102102- then comps_num[pcomp] <= 1
103103- else true
104104- endif
105105-);
106106-107107-% conflict constraints
108108-constraint forall(port in ports, pcomp in comps, rcomp in comps) (
109109- if (conflicts[rcomp,port] /\ exists(mport in multi_provide_ports) (
110110- (multi_provides[mport,port]) /\ provide_port_nums[pcomp,mport] != 0))
111111- then comps_num[pcomp] > 0 -> comps_num[rcomp] = 0
112112- else true
113113- endif
114114-);
115115-116116-% unicity constraint
117117-% note that we require that a component does not
118118-% require more than one port provided by a
119119-% multiple provide port
120120-constraint forall(mport in multi_provide_ports, pcomp in comps, rcomp in comps) (
121121- let
122122- { int: max_req = sum(port in ports) (
123123- if multi_provides[mport,port]
124124- then requirement_port_nums[rcomp,port]
125125- else 0
126126- endif
127127- )
128128- } in
129129- if pcomp = rcomp
130130- then
131131- ( comps_num[pcomp] >= max_req ->
132132- sum(port in ports)(bindings[mport,port,pcomp,rcomp])
133133- <= max_req * (comps_num[rcomp] - 1))
134134- /\
135135- ( comps_num[pcomp] < max_req ->
136136- forall (i in 1..max_req)( comps_num[pcomp] = i ->
137137- sum(port in ports)(bindings[mport,port,pcomp,rcomp]) <= i * (i-1) ))
138138- else
139139- ( comps_num[pcomp] >= max_req ->
140140- sum(port in ports)(bindings[mport,port,pcomp,rcomp])
141141- <= max_req * comps_num[rcomp] )
142142- /\
143143- ( comps_num[pcomp] < max_req ->
144144- forall (i in 0..max_req)( comps_num[pcomp] = i ->
145145- sum(port in ports)(bindings[mport,port,pcomp,rcomp]) <= i * comps_num[rcomp] ) )
146146- endif
147147-);
148148-149149-%%%%%%%%%%%%%%%%
150150-% constraints for deciding locations
151151-%%%%%%%%%%%%%%%%
152152-153153-% map location used or not used
154154-array[ locations ] of var 0..1: used_locations;
155155-constraint forall( l in locations)(
156156- sum(c in comps)(comp_locations[l,c]) = 0 <-> used_locations[l] = 0
157157-);
158158-159159-constraint forall( c in comps) (
160160- sum( l in locations) ( comp_locations[l,c]) = comps_num[c]
161161-);
162162-163163-164164-constraint forall( res in resources, loc in locations) (
165165- sum( comp in comps)( comp_locations[loc,comp] * resource_consumptions[comp,res] )
166166- <= resource_provisions[loc,res]
167167-);
168168-169169-% the number of locations can not be greater than the number of components
170170-% i.e, one component per location in the worst case
171171-constraint sum(i in locations) (used_locations[i]) <= sum_comp;
172172-173173-%------------------------------------------------------------------------------%
174174-% symmetry constraints (wrap in a unique predicate following minizinc specs
175175-176176-177177-constraint symmetry_breaking_constraint(
178178- %if location are equal then first location has more comps than the second
179179- %in lexicographically order (based on the cost)
180180- forall( l1 in locations, l2 in locations)(
181181- if l1 < l2 /\ forall ( r in resources)(resource_provisions[l1,r] = resource_provisions[l2,r] )
182182- then
183183- if costs[l1] > costs[l2]
184184- then lex_greatereq(
185185- [comp_locations[l2,c] | c in comps],
186186- [comp_locations[l1,c] | c in comps])
187187- /\
188188- (used_locations[l1] = 1 -> used_locations[l2] = 1)
189189- else
190190- lex_greatereq(
191191- [comp_locations[l1,c] | c in comps],
192192- [comp_locations[l2,c] | c in comps])
193193- /\
194194- (used_locations[l2] = 1 -> used_locations[l1] = 1)
195195- endif
196196- else
197197- true
198198- endif
199199- ));
200200-201201-202202-%------------------------------------------------------------------------------%
203203-% Redundant constraints
204204-205205-%constraint redundant_constraint(
206206-% % Ralf constraints
207207-% forall (rcomp in comps, port in ports)(
208208-% if requirement_port_nums[rcomp,port]!=0
209209-% then
210210-% comps_num[rcomp] > 0 -> sum( mport in multi_provide_ports, pcomp in comps)(
211211-% if provide_port_nums[pcomp,mport] != 0 /\ multi_provides[mport,port]
212212-% then comps_num[pcomp]
213213-% else 0
214214-% endif ) >= requirement_port_nums[rcomp,port]
215215-% else
216216-% true
217217-% endif
218218-% ));
219219-220220-%------------------------------------------------------------------------------%
221221-% Constraints
222222-constraint
223223- ( sum(l in locations)(comp_locations[l,1]) > 0
224224- \/ sum(l in locations)(comp_locations[l,2]) > 0
225225- )
226226-/\ forall(x in locations)(comp_locations[x,3] < 2)
227227-/\ forall(x in locations)(comp_locations[x,4] < 2)
228228-;
229229-230230-int: obj_min = sum(l in locations)(if costs[l] < 0 then costs[l] else 0 endif);
231231-int: obj_max = sum(l in locations)(if costs[l] > 0 then costs[l] else 0 endif);
232232-var obj_min..obj_max: objective;
233233-234234-constraint objective = sum(l in locations)(used_locations[l] * costs[l]);
235235-236236-%------------------------------------------------------------------------------%
237237-% Solve item
238238-239239-array [locations] of locations: costs_asc = arg_sort(costs);
240240-array [locations] of locations: costs_desc = reverse(costs_asc);
241241-242242-solve
243243- :: seq_search([
244244- int_search([used_locations[costs_desc[i]] | i in locations],
245245- input_order, indomain_min, complete),
246246- int_search([comp_locations[l, i] | l in locations, i in comps],
247247- first_fail, indomain_max, complete),
248248- int_search(comps_num, first_fail, indomain_max, complete),
249249- int_search([bindings[m,p,i,j] | m in multi_provide_ports, p in ports, i,j in comps],
250250- first_fail, indomain_max, complete)
251251- ])
252252- minimize objective;
253253-254254-%------------------------------------------------------------------------------%
255255-% Output item
256256-257257-output [
258258- "bindings = array4d(\(multi_provide_ports), \(ports), \(comps), \(comps), \(bindings));\n",
259259- "comps_num = \(comps_num);\n",
260260- "comp_locations = array2d(\(locations), \(comps), \(comp_locations));\n",
261261- "used_locations = \(used_locations);\n",
262262- "objective = \(objective);\n",
263263- "% [\(objective), \(sum(x in locations)(sum(y in comps)(comp_locations[x,y])))]\n"
264264-];
265265-266266-