def __init__(self, quantite_objectif, liste_gallons): # Create a MiniZinc model self.model = mnz.Model() self.model.add_file("ProjSceau.mzn") # Transform Model into a instance gecode = mnz.Solver.lookup("gecode") self.inst = mnz.Instance(gecode, self.model) self.gallons = liste_gallons self.quantite_objectif = quantite_objectif self.inst["nbr_sceau"] = len(liste_gallons) self.inst["remplissage_final"] = quantite_objectif list_taille_sceau = [] list_remplissage_init = [] for g in self.gallons: list_taille_sceau.append(g.taille) list_remplissage_init.append(g.remplissage) self.inst["taille_sceau"] = list_taille_sceau self.inst["remplissage_initial"] = list_remplissage_init print("CONFIGURATION d'ORIGINE:") print("\tnombre sceaux : ", self.inst["nbr_sceau"]) print("\tremplissage_final : ", self.inst["remplissage_final"]) print("\ttaille_sceau : ", self.inst["taille_sceau"]) print("\tremplissage_initial : ", self.inst["remplissage_initial"])
async def run_instance(problem, model, data, config, timeout, stat_base, sol_file, stats_file): statistics = stat_base.copy() try: driver = minizinc.default_driver if config.minizinc is not None: driver = minizinc.CLI.CLIDriver(config.minizinc) instance = minizinc.Instance(config.solver, minizinc.Model(model), driver) if data is not None: instance.add_file(data, parse_data=False) is_satisfaction = instance.method == minizinc.Method.SATISFY for key, value in config.extra_data.items(): instance[key] = value start = time.perf_counter() with sol_file.open(mode="w") as file: async for result in instance.solutions( timeout=timeout, processes=config.processes, random_seed=config.random_seed, intermediate_solutions=True, free_search=config.free_search, optimisation_level=config.optimisation_level, **config.other_flags, ): solution = stat_base.copy() solution["status"] = str(result.status) if "time" in result.statistics: solution["time"] = result.statistics.pop( "time").total_seconds() if result.solution is not None: solution["solution"] = asdict(result.solution) solution["solution"].pop("_output_item", None) solution["solution"].pop("_checker", None) file.write(ruamel.yaml.dump([solution])) statistics.update(result.statistics) statistics["status"] = str(result.status) if result.solution is not None and not is_satisfaction: statistics["objective"] = result.solution.objective total_time = time.perf_counter() - start statistics["time"] = total_time except minizinc.MiniZincError as err: statistics["status"] = str(minizinc.result.Status.ERROR) statistics["error"] = str(err) for key, val in statistics.items(): if isinstance(val, timedelta): statistics[key] = val.total_seconds() ruamel.yaml.dump( statistics, stats_file.open(mode="w"), default_flow_style=False, )
def minizinc_model(): src = "float: a;\n" \ "var float: x;\n" \ "constraint x == a + 1;\n" \ "solve satisfy" model = minizinc.Model() model.add_string(src) solver = minizinc.Solver.lookup("cbc") inst = minizinc.Instance(solver, model) inst["a"] = 2 result = inst.solve() return result
def minizinc_model(): src = "int: a;\n" \ "int: b;\n" \ "var -100..100: x;\n" \ "constraint a < x;\n" \ "constraint x < b;\n" \ "solve satisfy" model = minizinc.Model() model.add_string(src) gecode = minizinc.Solver.lookup("gecode") inst = minizinc.Instance(gecode, model) inst["a"] = 1 inst["b"] = 4 result = inst.solve(all_solutions=True) return result
def __init__(self, nombre_moutons): # Create a MiniZinc model self.model = mnz.Model() self.model.add_file("ProjSauteMouton.mzn") # Transform Model into a instance gecode = mnz.Solver.lookup("gecode") self.inst = mnz.Instance(gecode, self.model) self.nb_moutons = nombre_moutons self.inst["nbr_m"] = nombre_moutons self.moutons = [] '''
def solver_exists(self, solver): solver_exists = pytest.solver_cache.get(solver, None) if solver_exists is None: try: s = mzn.Solver.lookup(solver) empty_model = mzn.Model() empty_model.add_string("solve satisfy;") instance = mzn.Instance(s, empty_model) instance.solve() solver_exists = True except (mzn.MiniZincError, LookupError) as error: solver_exists = False finally: pytest.solver_cache[solver] = solver_exists return solver_exists
def run(self, mzn_file, solver, default_options={}): """ Runs this test case given an mzn file path, a solver name and some default options. Any options specified in this test case directly will override those provided in default options. Returns a tuple containing: - the model produced - the result of running the solver - a list of expected results - the actual obtained result Pass the actual obtained result to passed() to determine if the test case passed. """ options = {k: v for k, v in default_options.items()} options.update(self.options) file = pathlib.Path(mzn_file) extra_files = [ file.parent.joinpath(other) for other in self.extra_files ] try: model = mzn.Model([file] + extra_files) solver = mzn.Solver.lookup(solver) instance = mzn.Instance(solver, model) if self.type == "solve": instance.output_type = Solution result = instance.solve(**options) obtained = Result.from_mzn(result) elif self.type == "compile": with instance.flat(**options) as (fzn, ozn, stats): obtained = FlatZinc.from_mzn(fzn, file.parent) result = obtained elif self.type == "output-model": with instance.flat(**options) as (fzn, ozn, stats): obtained = OutputModel.from_mzn(ozn, file.parent) result = obtained else: raise NotImplementedError("Unknown test case type") except mzn.MiniZincError as error: result = error obtained = Error.from_mzn(result) required = self.expected if isinstance(self.expected, list) else [self.expected] return model, result, required, obtained
def minizinc_model(): src = "int: a;\n" \ "int: b;\n" \ "int: c;\n" \ "var -100..100: x;\n" \ "constraint ((((a * pow(x, 2)) + (b * x)) + c) = 0);\n" \ "solve satisfy" model = minizinc.Model() model.add_string(src) gecode = minizinc.Solver.lookup("gecode") inst = minizinc.Instance(gecode, model) inst["a"] = 1 inst["b"] = 4 inst["c"] = 0 result = inst.solve(all_solutions=True) return result
def _solve(self, *how_to_solve, all_solutions, result_as, verbose, solver): solver = minizinc.Solver.lookup(solver) model = minizinc.Model() src = self.compile(how_to_solve) if verbose: print(src) model.add_string(src) inst = minizinc.Instance(solver, model) for name, param in self._ir.pars.items(): inst[name] = param.value for e in self._ir.enums: inst[e.__name__] = e result: minizinc.Result = inst.solve(all_solutions=all_solutions) if result_as is None: return Result(result) else: return result_as(result)
def _model(self, model, solvername=None): import minizinc if solvername is None: # default solver solvername = "gecode" # from superclass mzn_txt = self.convert(model) # minizinc-python API # Create a MiniZinc model mznmodel = minizinc.Model() mznmodel.add_string(mzn_txt) # Transform Model into a instance slv = minizinc.Solver.lookup(solvername) return minizinc.Instance(slv, mznmodel)
def schedule_evs(num_days, num_periods_day, peak_periods, off_peak_periods, num_evs, max_charge, total_energy, prices_2d, loads_2d, network_tariff_peak, network_tariff_off_peak, model_file="scripts/ev-scheduling.mzn"): off_peak_periods2 = {i + 1 for i in off_peak_periods}.copy() if network_tariff_peak == network_tariff_off_peak: peak_periods2 = {i + 1 for i in range(num_periods_day)}.copy() network_tariff_off_peak = 0 else: # minizinc index starts from 1 peak_periods2 = {i + 1 for i in peak_periods}.copy() # build a MiniZinc model model = mzn.Model(model_file) solver = mzn.Solver.lookup("mip") ins = mzn.Instance(solver, model) ins["num_days"] = num_days ins["num_periods_day"] = num_periods_day ins["PEAK_PERIODS"] = peak_periods2 ins["OFF_PEAK_PERIODS"] = off_peak_periods2 ins["num_evs"] = num_evs ins["max_charge"] = max_charge ins["total_energy"] = total_energy ins["wholesale_prices"] = prices_2d ins["network_tariff_peak"] = network_tariff_peak ins["network_tariff_off_peak"] = network_tariff_off_peak ins["existing_loads"] = loads_2d result = ins.solve() # organise results charge_ev_day_period = result.solution.charge_strategy minizinc_outputs = ast.literal_eval(result.solution._output_item) minizinc_outputs["time (ms)"] = [ result.statistics['solveTime'].microseconds * 0.001 ] return charge_ev_day_period, minizinc_outputs
def calcular(self, siCondicionesA): self.crearVarRegiones() self.kitsPorUnidad() self.Unidades() self.costosAdecuacion() if(siCondicionesA): self.condicionesAdicionales() self.poblacion() self.noNegatividad() self.funcionObjetivo() # desde aca se resilve el codigo en minizinc, en alguna parte desde aca iria la funcion de parar en X minutos # Create a MiniZinc model model = mz.Model() model.add_string(self.stringFinal) # Transform Model into a instance gecode = mz.Solver.lookup("gecode") inst = mz.Instance(gecode, model) # Solve the instance result = inst.solve() print("************************* RESULTADOS MINIZINC *************************") for regionX in self.listaDeRegiones: nombreRegionX = str(regionX.get_nombreCorto()) + " = " resultadoX = result[str(regionX.get_nombreCorto())] print(resultadoX) print(nombreRegionX, end = "") print(resultadoX) self.stringResultado = self.stringResultado + nombreRegionX + str(resultadoX) + "\n" self.stringResultado = self.stringResultado + "Beneficio = " + str(result["Beneficio"]) + "\n" print("Beneficio", end = " = ") print(result["Beneficio"]) print("\n************************* FIN DE PROGRAMA *************************")
def schedule_evs(num_days, prices_2d, loads_2d, network_tariff_peak, network_tariff_off_peak): # build a MiniZinc model model = mzn.Model(model_file) solver = mzn.Solver.lookup("coin-bc") ins = mzn.Instance(solver, model) ins["num_days"] = num_days ins["num_periods_day"] = num_periods_day ins["num_evs"] = num_evs ins["max_charge"] = max_charge ins["total_energy"] = total_energy ins["wholesale_prices"] = prices_2d ins["network_tariff_peak"] = network_tariff_peak ins["network_tariff_off_peak"] = network_tariff_off_peak ins["existing_loads"] = loads_2d result = ins.solve() return result
def from_feature_model( cls, feature_model: FeatureModel, solver: minizinc.Solver = minizinc.Solver.lookup("gecode"), ) -> MZFMSolver: mini_zinc_vars = "" mini_zinc_const = "" optional_features = [] for feature in feature_model.features: mini_zinc_vars = "".join([mini_zinc_vars, gen_variable(feature)]) if feature.constraints: for constraint in feature.constraints: mini_zinc_const = "".join( [ mini_zinc_const, gen_constraint(constraint, feature.id), ] ) if type(constraint) == Optional: optional_features.append(f"feature_{constraint.destination}") feature_names = [f"feature_{feature.id}" for feature in feature_model.features] mini_zinc_str = "\n".join([mini_zinc_vars, mini_zinc_const, "solve satisfy;"]) model = minizinc.Model() model.add_string(mini_zinc_str) return cls( model=model, feature_names=feature_names, optional_features=optional_features, solver=solver, )
def __init__(self, params={}): self.model = mz.Model() self.params = params self.frozen = False
for a in range(len(positions)): if positions[a][i] < positions[a][j]: agent_prefs += 1 else: agent_prefs -= 1 if agent_prefs > 0: n_wins += 1 copeland.append(n_wins) votes = [(w, solutions[i]) for i, w in enumerate(copeland)] return sorted(votes, key=lambda v: v[0], reverse=True) if __name__ == "__main__": args = argparser.parse_args() m = minizinc.Model() m.add_file(args.model) m.add_file(args.data) agents = [Agent(a, m) for a in range(len(m["Passenger"]))] n_steps = args.iterations n_agents = len(agents) n_sol_per_agent = args.sol_per_agent d = Diversifier(m) s = d.next_k(n_agents * n_sol_per_agent, []) voting = None if args.voting_method == "borda": voting = Borda() elif args.voting_method == "copeland":
def csp(blocks, sheets, matches): print('numblocks', len(blocks)) blocks = blocks[:] model = minizinc.Model() model.add_string(""" include "globals.mzn"; int: num_blocks; int: num_rows; int: num_cols; set of int: b=1..num_blocks; set of int: rows=1..num_rows; set of int: cols=1..num_cols; array[b] of cols: x1; array[b] of cols: x2; array[b] of rows: y1; array[b] of rows: y2; array[b] of int: w; array[b] of int: h; array[rows] of var int: rowsa; array[cols] of var int: colsa; int: num_left; int: num_above; set of int: l=1..num_left; set of int: t=1..num_above; array[l] of cols: left1; array[l] of cols: left2; array[t] of rows: above1; array[t] of rows: above2; int: num_left_equal; int: num_above_equal; set of int: le=1..num_left_equal; set of int: te=1..num_above_equal; array[le] of cols: left_equal1; array[le] of cols: left_equal2; array[te] of rows: above_equal1; array[te] of rows: above_equal2; int: max_col = sum(w) + 1; int: max_row = sum(h) + 1; array[b] of var bool: use_block; array[b] of var int: wf; array[b] of var int: hf; constraint forall(bl in b) ((use_block[bl] -> wf[bl] = w[bl]) /\ (not use_block[bl] -> wf[bl] = 0)); constraint forall(bl in b) ((use_block[bl] -> hf[bl] = h[bl]) /\ (not use_block[bl] -> hf[bl] = 0)); array[l] of var bool: use_left; array[t] of var bool: use_above; array[le] of var bool: use_left_equal; array[te] of var bool: use_above_equal; constraint forall(c in cols) (colsa[c] > 0 /\ colsa[c] <= max_col); constraint forall(r in rows) (rowsa[r] > 0 /\ rowsa[r] <= max_row); constraint diffn([colsa[x1[bl]] | bl in b], [rowsa[y1[bl]] | bl in b], [wf[bl] | bl in b], [hf[bl] | bl in b]); constraint forall(i in b) (colsa[x1[i]] + w[i] -1= colsa[x2[i]]); constraint forall(i in b) (rowsa[y1[i]] + h[i] -1= rowsa[y2[i]]); constraint forall(i in l) (use_left[i] <-> (colsa[left1[i]] < colsa[left2[i]])); constraint forall(i in t) (use_above[i] <-> (rowsa[above1[i]] < rowsa[above2[i]])); constraint forall(i in le) (use_left_equal[i] <-> (colsa[left_equal1[i]] = colsa[left_equal2[i]])); constraint forall(i in te) (use_above_equal[i] <-> (rowsa[above_equal1[i]] = rowsa[above_equal2[i]])); %solve satisfy; %solve minimize sum(rowsa) + sum(colsa); solve maximize sum(use_left) + sum(use_above) + sum(use_block) + sum(use_left_equal) + sum(use_above_equal); """) cols = sorted( list( set(block.x1 for block in blocks).union(set(block.x2 for block in blocks)))) rows = sorted( list( set(block.y1 for block in blocks).union(set(block.y2 for block in blocks)))) relative_left, relative_left_equals = _parse_indices(cols, matches) relative_above, relative_above_equals = _parse_indices(rows, matches) colsi = {col: i + 1 for i, col in enumerate(cols)} rowsi = {row: i + 1 for i, row in enumerate(rows)} left, above = _location_constraints(cols, rows, sheets, matches) left = [(l1, l2) for l1, l2 in left if l1 in cols and l2 in cols] + relative_left above = [(a1, a2) for a1, a2 in above if a1 in rows and a2 in rows] + relative_above print('blocks', blocks) ProjectedBlock = collections.namedtuple('ProjectedBlock', 'x1 y1 x2 y2 width height') pblocks = list( set( ProjectedBlock(block.x1, block.y1, block.x2, block.y2, block.width, block.height) for block in blocks)) for b in blocks: print(' ', b) print(len(blocks), len(pblocks)) for b in pblocks: print(' ', b) print('pblocks', len(pblocks), pblocks) print('colsi', colsi) print('rowsi', rowsi) gecode = minizinc.Solver.lookup("chuffed") minst = minizinc.Instance(gecode, model) inst = {} inst['num_blocks'] = len(pblocks) inst['num_rows'] = len(rows) inst['num_cols'] = len(cols) inst['x1'] = [colsi[block.x1] for block in pblocks] inst['x2'] = [colsi[block.x2] for block in pblocks] inst['y1'] = [rowsi[block.y1] for block in pblocks] inst['y2'] = [rowsi[block.y2] for block in pblocks] inst['w'] = [block.width for block in pblocks] inst['h'] = [block.height for block in pblocks] inst['num_left'] = len(left) inst['num_above'] = len(above) inst['left1'] = [colsi[l1] for l1, _ in left] inst['left2'] = [colsi[l2] for _, l2 in left] inst['above1'] = [rowsi[a1] for a1, _ in above] inst['above2'] = [rowsi[a2] for _, a2 in above] inst['num_left_equal'] = len(relative_left_equals) inst['num_above_equal'] = len(relative_above_equals) inst['left_equal1'] = [colsi[l1] for l1, _ in relative_left_equals] inst['left_equal2'] = [colsi[l2] for _, l2 in relative_left_equals] inst['above_equal1'] = [rowsi[a1] for a1, _ in relative_above_equals] inst['above_equal2'] = [rowsi[a2] for _, a2 in relative_above_equals] print(inst) for k, v in inst.items(): minst[k] = v # Solve the instance print('CSP') result = minst.solve(all_solutions=False) print('res', result) print(result['rowsa']) print(result['colsa']) assignment = {col: r for col, r in zip(cols, result['colsa'])} assignment.update(**{row: r for row, r in zip(rows, result['rowsa'])}) used_blocks = {} for block, used in zip(pblocks, result['use_block']): used_blocks[block] = used print(used) if not used: print('Warning not used:', block) for oblock in blocks: if oblock.x1 == block.x1 and oblock.y1 == block.y1 and oblock.x2 == block.x2 and oblock.y2 == block.y2: print('Original block:', oblock) print('assignment', assignment) return assignment
def run_minizinc_model(params): mdl_name, instance_name, timeout = params instance_path = os.path.join(INSTANCE_FOLDER, instance_name) if not os.path.isfile(mdl_name): raise Exception("ERROR: mdl_name not found: ", mdl_name) if not os.path.isfile(instance_path): raise Exception("ERROR: instance_name not found: ", instance_name) print("*** Processing model {} with instance {}".format(mdl_name, instance_name)) model = minizinc.Model([mdl_name]) instance = minizinc.Instance(SOLVER, model) with open(instance_path, 'r') as f: input_data = json.load(f) scenesLength, actorsToScenes, actorsCosts = input_data['scenesLength'],input_data['actorsToScenes'], input_data['actorsCosts'] num_scenes = len(scenesLength) num_actors = len(actorsCosts) if "1" in mdl_name: actorsToScenes_new = np.zeros((len(actorsCosts), len(scenesLength))) for actor, scenes in enumerate(actorsToScenes): actorsToScenes_new[actor, scenes] = 1 data = { "num_scenes": len(scenesLength), "num_actors": len(actorsCosts), "max_cost": max(actorsCosts), "duration": scenesLength, "actor_cost": actorsCosts, "actorsToScenes": actorsToScenes_new.astype(int).tolist() } else: actorsToScenes_new = [set([i + 1 for i in scenes]) for scenes in actorsToScenes] data = { "num_scenes": len(scenesLength), "num_actors": len(actorsCosts), "max_cost": max(actorsCosts), "max_SceneDuration": max(scenesLength), "max_ActorCost":max(actorsCosts), "duration": scenesLength, "cost": actorsCosts, "actorsToScenes": actorsToScenes_new } for key, val in data.items(): instance[key] = val msol = instance.solve(verbose=True, timeout=datetime.timedelta(seconds=timeout)) # output= { # # } if msol: results = [ msol.status.name, msol.solution.objective, msol.statistics['initTime'].total_seconds(), msol.statistics['solveTime'].total_seconds(), msol.statistics['variables']] if "1" in mdl_name: scene_order = msol['scene_order'] else: scene_order = msol['order'] success = True else: results = [msol.status.name if msol else "NOTFOUND"] success = False scene_order = None return success, mdl_name, instance_name, timeout, num_actors, num_scenes, scene_order, results
def partial_schedule(volunteers, vehicle_request): # create an array of preferredHours preferred_hours = [] for volunteer in volunteers: preferred_hours.append(volunteer["prefHours"]) # generates a list of shift lengths corresponding to each vehicle request shift_lengths = generate_shift_lengths(vehicle_request) # generates a 2d array of booleans for the model # each entry denotes the compatability of 1 volunteer to 1 request compatible = generate_compatibility(volunteers, vehicle_request) # generates a 2d array of booleans for the model # each entry denotes whether there is a clash (true) between the corresponding vehicle requests clashing = generate_clashes(vehicle_request) # the following codeblock generates 3 lists of booleans # if is_heavy(index) = true then vehicle_request(index) is a heavy tanker # if is_medium(index) = true then vehicle_request(index) is a medium tanker # if is_light(index) = true then vehicle_request(index) is a light unit is_heavy = [] is_medium = [] is_light = [] for request in vehicle_request: if request["assetClass"] == "heavyTanker": is_heavy.append(True) is_medium.append(False) is_light.append(False) if request["assetClass"] == "mediumTanker": is_heavy.append(False) is_medium.append(True) is_light.append(False) if request["assetClass"] == "lightUnit": is_heavy.append(False) is_medium.append(False) is_light.append(True) # the following codeblock generates 4 lists of booleans # if is_driver(index) = true then volunteer(index) is a driver # if is_crew_leader(index) = true then volunteer(index) is a crewleader # if is_advanced(index) = true then volunteer(index) is advanced # if is_basic(index) = true then volunteer(index) is basic is_driver = [] is_crew_leader = [] is_advanced = [] is_basic = [] for volunteer in volunteers: basic = False advanced = False crewLeader = False driver = False for qualification in volunteer["possibleRoles"]: if qualification == "basic": basic = True if qualification == "advanced": advanced = True if qualification == "crewLeader": crewLeader = True if qualification == "driver": driver = True is_basic.append(basic) is_advanced.append(advanced) is_crew_leader.append(crewLeader) is_driver.append(driver) # we are using the gecode optimiser gecode = minizinc.Solver.lookup("gecode") # create the model model = minizinc.Model() # the following string generates the minizinc model for a full solve model.add_string(""" int: V; int: S; set of int: volunteers = 1..V; set of int: Shifts = 1..S; array[Shifts,volunteers] of bool: compatible; array[Shifts,Shifts] of bool: clashing; array[Shifts,volunteers] of var bool: assignments; array[volunteers] of int: preferredHours; array[Shifts] of int: shiftLength; array[Shifts] of bool: is_heavy; array[Shifts] of bool: is_medium; array[Shifts] of bool: is_light; array[volunteers] of bool: is_basic; array[volunteers] of bool: is_advanced; array[volunteers] of bool: is_crew_leader; array[volunteers] of bool: is_driver; array[Shifts] of var 0..V: seat1; array[Shifts] of var 0..V: seat2; array[Shifts] of var 0..V: seat3; array[Shifts] of var 0..V: seat4; array[Shifts] of var 0..V: seat5; array[volunteers,Shifts] of var int: hoursOnAssignment; array[volunteers] of var int: totalHours; %volunteer availability check constraint forall(s in Shifts)(forall(v in volunteers)(if compatible[s,v] == false then assignments[s,v] == false endif)); %volunteers cannot be assigned to 2 shifts at once constraint forall(s1 in Shifts)(forall(s2 in Shifts)(forall(v in volunteers)(if clashing[s1,s2] /\ assignments[s1,v] then assignments[s2,v] == false endif))); %all vehicles are (at most) filled. This allows for partial fills constraint forall(s in Shifts)(if is_heavy[s] then sum(v in volunteers)(assignments[s,v]) <= 5 endif); constraint forall(s in Shifts)(if is_medium[s] then sum(v in volunteers)(assignments[s,v]) <= 3 endif); constraint forall(s in Shifts)(if is_light[s] then sum(v in volunteers)(assignments[s,v]) <= 2 endif); %Seat1 Requirements constraint forall(s in Shifts)(forall(v in volunteers) (if seat1[s] == v then assignments[s,v] = true endif)); constraint forall(s in Shifts)(forall(v in volunteers)(if seat1[s] == v then is_driver[v] = true endif)); constraint forall(s in Shifts)(if is_light[s] then forall(v in volunteers)(if seat1[s] == v then is_crew_leader[v] = true endif) endif); %seat2 Requirements constraint forall(s in Shifts)(forall(v in volunteers) (if seat2[s] == v then assignments[s,v] = true endif)); constraint forall(s in Shifts)(if is_light[s] then forall(v in volunteers)(if seat2[s] == v then is_advanced[v] = true endif) endif); constraint forall(s in Shifts)(if is_medium[s] then forall(v in volunteers)(if seat2[s] == v then is_crew_leader[v] = true endif) endif); constraint forall(s in Shifts)(if is_heavy[s] then forall(v in volunteers)(if seat2[s] == v then is_crew_leader[v] = true endif) endif); %seat3 Requirements constraint forall(s in Shifts)(forall(v in volunteers) (if seat3[s] == v then assignments[s,v] = true endif)); constraint forall(s in Shifts)(if is_light[s] then seat3[s] == seat2[s] endif); constraint forall(s in Shifts)(if is_medium[s] then forall(v in volunteers)(if seat3[s] == v then is_basic[v] = true endif) endif); constraint forall(s in Shifts)(if is_heavy[s] then forall(v in volunteers)(if seat3[s] == v then is_advanced[v] = true endif) endif); %seat4 Requirements constraint forall(s in Shifts)(forall(v in volunteers) (if seat4[s] == v then assignments[s,v] = true endif)); constraint forall(s in Shifts)(if is_light[s] then seat4[s] == seat2[s] endif); constraint forall(s in Shifts)(if is_medium[s] then seat4[s] == seat3[s] endif); constraint forall(s in Shifts)(if is_heavy[s] then forall(v in volunteers)(if seat4[s] == v then is_advanced[v] = true endif) endif); %seat5 Requirements constraint forall(s in Shifts)(forall(v in volunteers) (if seat5[s] == v then assignments[s,v] = true endif)); constraint forall(s in Shifts)(if is_light[s] then seat5[s] == seat2[s] endif); constraint forall(s in Shifts)(if is_medium[s] then seat5[s] == seat3[s] endif); constraint forall(s in Shifts)(if is_heavy[s] then forall(v in volunteers)(if seat5[s] == v then is_basic[v] = true endif) endif); %if a volunteer is not on any seats of a shift, they are not on the shift constraint forall(s in Shifts)(forall(v in volunteers) (if seat5[s] != v /\ seat4[s] != v /\ seat3[s] != v /\ seat2[s] != v /\ seat1[s] != v then assignments[s,v] = false endif)); %maps shifts to hours worked constraint forall(v in volunteers)(forall(s in Shifts)(if assignments[s,v] then hoursOnAssignment[v,s] = shiftLength[s] else hoursOnAssignment[v,s] = 0 endif)); %defines total hours for each volunteer constraint forall(v in volunteers)(totalHours[v] == sum(s in Shifts)(hoursOnAssignment[v,s])); %ensures no one is overworked constraint forall(v in volunteers)(totalHours[v] <= preferredHours[v]); %maximise for number of volunteers assigned solve maximize sum(s in Shifts)(sum(v in volunteers)(assignments[s,v])) """) # initialise all the variables in the minizinc model from the variables we previously created instance = minizinc.Instance(gecode, model) instance["V"] = len(volunteers) instance["S"] = len(vehicle_request) instance["preferredHours"] = preferred_hours instance["shiftLength"] = shift_lengths instance["compatible"] = compatible instance["clashing"] = clashing instance["is_heavy"] = is_heavy instance["is_medium"] = is_medium instance["is_light"] = is_light instance["is_basic"] = is_basic instance["is_advanced"] = is_advanced instance["is_crew_leader"] = is_crew_leader instance["is_driver"] = is_driver # solve the model result = instance.solve() # if there is a valid solution, format it and output if result.solution: output = [] for i in range(len(vehicle_request)): vehicle_dict = {} vehicle_dict["shiftID"] = vehicle_request[i]["shiftID"] vehicle_dict["assetClass"] = vehicle_request[i]["assetClass"] vehicle_dict["timeframe"] = vehicle_request[i]["timeframe"] seats = [] seats.append(result["seat1"]) seats.append(result["seat2"]) seats.append(result["seat3"]) seats.append(result["seat4"]) seats.append(result["seat5"]) if vehicle_dict["assetClass"] == "lightUnit": volunteers = add_light_unit_to_output(seats, i, volunteers) if vehicle_dict["assetClass"] == "mediumTanker": volunteers = add_medium_tanker_to_output(seats, i, volunteers) if vehicle_dict["assetClass"] == "heavyTanker": volunteers = add_heavy_tanker_to_output(seats, i, volunteers) vehicle_dict["volunteers"] = volunteers output.append(vehicle_dict) # if there is no valid model, output an empty list else: print("No partial fill possible") output = [] return output