def _update_variables_type(self): vartype = self._modeltype_to_vartype(self._mtype) for name, variable in self._variables.items(): self._variables[name] = pyqubo.Array.create(name, shape=variable.shape, vartype=vartype) df = self.select_interaction(query="removed == False") for index, interaction in df.iterrows(): interacts = interaction["interacts"] if self._mtype == constants.MODEL_ISING: if isinstance(interacts, tuple): self._interactions_array["interacts"][index] = ( pyqubo.Spin(interaction["interacts"][0].label), pyqubo.Spin(interaction["interacts"][1].label), ) else: self._interactions_array["interacts"][index] = pyqubo.Spin( interaction["interacts"].label) elif self._mtype == constants.MODEL_QUBO: if isinstance(interacts, tuple): self._interactions_array["interacts"][index] = ( pyqubo.Binary(interaction["interacts"][0].label), pyqubo.Binary(interaction["interacts"][1].label), ) else: self._interactions_array["interacts"][ index] = pyqubo.Binary(interaction["interacts"].label)
def test_zero_or_one_hot_constraint(): c = ZeroOrOneHotConstraint() assert c.get_constraint_class() == "ZeroOrOneHotConstraint" assert c.get_variables() == set() assert c.get_label() == "Default Zero-or-One-hot Constraint" assert c.get_strength() == 1.0 x0 = pyqubo.Spin("x0") x1 = pyqubo.Spin("x1") x2 = pyqubo.Binary("x2") c.add_variable(x0) assert c.get_variables() == set([x0]) assert len(c.get_variables()) == 1 c.add_variable([x1, x2]) assert c.get_variables() == set([x0, x1, x2]) assert len(c.get_variables()) == 3 c.add_variable(set([x0])) assert c.get_variables() == set([x0, x1, x2]) assert len(c.get_variables()) == 3 c.add_variable(variables=[x0, x1]) assert c.get_variables() == set([x0, x1, x2]) assert len(c.get_variables()) == 3 c.remove_variable(variables=[x0]) assert c.get_variables() == set([x1, x2]) assert len(c.get_variables()) == 2 with pytest.raises(ValueError): c.remove_variable(variables=[x0])
def test_n_hot_constraint(): c = NHotConstraint() assert c.get_constraint_class() == "NHotConstraint" assert c.get_variables() == set() assert c.get_n() == 1 assert c.get_label() == "Default N-hot Constraint" assert c.get_strength() == 1.0 x0 = pyqubo.Spin("x0") x1 = pyqubo.Spin("x1") x2 = pyqubo.Binary("x2") c.add_variable(x0) assert c.get_variables() == {x0} assert len(c.get_variables()) == 1 c.add_variable([x1, x2]) assert c.get_variables() == {x0, x1, x2} assert len(c.get_variables()) == 3 c.add_variable({x0}) assert c.get_variables() == {x0, x1, x2} assert len(c.get_variables()) == 3 c.add_variable(variables=[x0, x1]) assert c.get_variables() == {x0, x1, x2} assert len(c.get_variables()) == 3 c.remove_variable(variables=[x0]) assert c.get_variables() == {x1, x2} assert len(c.get_variables()) == 2 with pytest.raises(ValueError): c.remove_variable(variables=[x0])
def Constrain_NumberOfFermions(n_so, n_ferm): # see https://buildmedia.readthedocs.org/media/pdf/pyqubo/stable/pyqubo.pdf qubits = [pyqubo.Binary(str(i)) for i in range(n_so)] H = sum(qubits) - n_ferm H = H * H model = H.compile() qubo, offset = model.to_qubo() return qubo
def create_bin_vars(self): bin_vars = {} for job, ops in self.time_vars.items(): bin_vars[job] = {} for op_num, op_times in enumerate(ops, start=1): bin_vars[job][op_num] = {} for op_time in op_times: bin_vars[job][op_num][op_time] = pyqubo.Binary( "x_{}_o{}_t{}".format(job, op_num, op_time)) return bin_vars
def test_equality_constraint(): c = EqualityConstraint() assert c.get_constraint_class() == "EqualityConstraint" assert c.get_variables_1() == set() assert c.get_variables_2() == set() assert c.get_label() == "Default Equality Constraint" assert c.get_strength() == 1.0 x0 = pyqubo.Spin("x0") x1 = pyqubo.Spin("x1") y0 = pyqubo.Binary("y0") y1 = pyqubo.Binary("y1") c.add_variable_to_1(x0) assert c.get_variables_1() == {x0} assert c.get_variables_2() == set() c.add_variable_to_1([x1]) assert c.get_variables_1() == {x0, x1} assert c.get_variables_2() == set() c.add_variable_to_2({y0}) assert c.get_variables_1() == {x0, x1} assert c.get_variables_2() == {y0} c.add_variable_to_2(variables=[y0, y1]) assert c.get_variables_1() == {x0, x1} assert c.get_variables_2() == {y0, y1} c.remove_variable_from_1(variables=x0) assert c.get_variables_1() == {x1} assert c.get_variables_2() == {y0, y1} c.remove_variable_from_2(variables=y1) assert c.get_variables_1() == {x1} assert c.get_variables_2() == {y0} with pytest.raises(ValueError): c.remove_variable_from_1(variables=[x0]) with pytest.raises(ValueError): c.remove_variable_from_2(variables=[y1])
def test_n_hot_constraint_eq(): assert NHotConstraint() == NHotConstraint() a = pyqubo.Spin("a") b = pyqubo.Binary("b") c1 = NHotConstraint(variables={a, b}, n=2, label="my label", strength=20) c2 = NHotConstraint(variables=[a, b], n=2, label="my label", strength=2 * 10) assert c1 == c2
def test_zero_or_one_hot_constraint_eq(): assert ZeroOrOneHotConstraint() == ZeroOrOneHotConstraint() a = pyqubo.Spin("a") b = pyqubo.Binary("b") c1 = ZeroOrOneHotConstraint(variables=set([a, b]), label="my label", strength=20) c2 = ZeroOrOneHotConstraint(variables=[a, b], label="my label", strength=2 * 10) assert c1 == c2
def test_equality_constraint_eq(): assert EqualityConstraint() == EqualityConstraint() a = pyqubo.Spin("a") b = pyqubo.Binary("b") c1 = EqualityConstraint(variables_1={a}, variables_2=b, label="my label", strength=20) c2 = EqualityConstraint(variables_1=[a], variables_2=b, label="my label", strength=2 * 10) assert c1 == c2
def test_zero_or_one_hot_constraint_ne(): a = pyqubo.Spin("a") b = pyqubo.Binary("b") c = [] c.append(ZeroOrOneHotConstraint()) c.append( ZeroOrOneHotConstraint(variables=[a, b], label="my label", strength=20)) c.append(ZeroOrOneHotConstraint(variables=set([a, b]))) c.append(ZeroOrOneHotConstraint(variables=a)) c.append(ZeroOrOneHotConstraint(label="my label")) c.append(ZeroOrOneHotConstraint(strength=20)) c.append("another type") for i in range(len(c) - 1): for j in range(i + 1, len(c)): assert c[i] != c[j]
def test_n_hot_constraint_ne(): a = pyqubo.Spin("a") b = pyqubo.Binary("b") c = [] c.append(NHotConstraint()) c.append( NHotConstraint(variables=[a, b], n=2, label="my label", strength=20)) c.append(NHotConstraint(variables={a, b})) c.append(NHotConstraint(variables=a)) c.append(NHotConstraint(n=2)) c.append(NHotConstraint(label="my label")) c.append(NHotConstraint(strength=20)) c.append("another type") for i in range(len(c) - 1): for j in range(i + 1, len(c)): assert c[i] != c[j]
def test_equality_constraint_ne(): a = pyqubo.Spin("a") b = pyqubo.Binary("b") c = [] c.append(EqualityConstraint()) c.append( EqualityConstraint(variables_1=[a], variables_2=[b], label="my label", strength=20)) c.append(EqualityConstraint(variables_1=[a], variables_2=[b])) c.append(EqualityConstraint(variables_1={a, b})) c.append(EqualityConstraint(variables_2={a, b})) c.append(EqualityConstraint(variables_1=a)) c.append(EqualityConstraint(variables_2=a)) c.append(EqualityConstraint(variables_1=b)) c.append(EqualityConstraint(variables_2=b)) c.append(EqualityConstraint(label="my label")) c.append(EqualityConstraint(strength=20)) c.append("another type") for i in range(len(c) - 1): for j in range(i + 1, len(c)): assert c[i] != c[j]
def to_physical(self, placeholder={}): physical = PhysicalModel(mtype=self._mtype) linear, quadratic = {}, {} will_remove = [] # Save the model before merging constraints to restore it later # original_variables = copy.deepcopy(self._variables) # Variables will not be changed original_offset = self._offset original_deleted = copy.deepcopy(self._deleted) original_fixed = copy.deepcopy(self._fixed) # original_constraints = copy.deepcopy(self._constraints) # Constraints will not be changed original_interactions_array = copy.deepcopy(self._interactions_array) original_interactions_attrs = copy.deepcopy(self._interactions_attrs) original_interactions_length = self._interactions_length # Resolve constraints, and convert them to the interactions for label, constraint in self._constraints.items(): constraint_model = constraint.to_model() self.merge(constraint_model) # group by key for i in range(self._interactions_length): if self._interactions_array["removed"][i]: will_remove.append(self._interactions_array["name"][i]) continue # Resolve placeholders for coefficients and scales, using PyQUBO. # Firstly resolve placeholders if the coefficient is already Coefficient type coeff_i = self._interactions_array["coefficient"][i] scale_i = self._interactions_array["scale"][i] if isinstance(coeff_i, pyqubo.core.Coefficient): coeff_i = coeff_i.evaluate(feed_dict=placeholder) # Calculate coefficient with the placeholder coeff_with_ph = coeff_i * scale_i coeff_model = ( coeff_with_ph + pyqubo.Binary("sawatabi-fake-variable") ).compile() # We need a variable for a valid model for pyqubo coeff_ph_resolved = coeff_model.to_qubo(feed_dict=placeholder) coeff = coeff_ph_resolved[ 1] # We don't need the variable just prepared, extracting only offset if self._interactions_array["body"][ i] == constants.INTERACTION_LINEAR: if self._interactions_array["key"][i] in linear: linear[self._interactions_array["key"][i]] += coeff else: linear[self._interactions_array["key"][i]] = coeff elif self._interactions_array["body"][ i] == constants.INTERACTION_QUADRATIC: if self._interactions_array["key"][i] in quadratic: quadratic[self._interactions_array["key"][i]] += coeff else: quadratic[self._interactions_array["key"][i]] = coeff # For offset as well offset = self._offset if isinstance(self._offset, pyqubo.core.Coefficient): offset = self._offset.evaluate(feed_dict=placeholder) # Calculate coefficient with the placeholder offset_model = ( offset + pyqubo.Binary("sawatabi-fake-variable") ).compile() # We need a variable for a valid model for pyqubo offset_ph_resolved = offset_model.to_qubo(feed_dict=placeholder) offset = offset_ph_resolved[ 1] # We don't need the variable just prepared, extracting only offset # set to physical for k, v in linear.items(): if v != 0.0: physical.add_interaction(k, body=constants.INTERACTION_LINEAR, coefficient=v) physical._variables_set.add(k) for k, v in quadratic.items(): if v != 0.0: physical.add_interaction(k, body=constants.INTERACTION_QUADRATIC, coefficient=v) physical._variables_set.add(k[0]) physical._variables_set.add(k[1]) physical._offset = offset # label_to_index / index_to_label current_index = 0 for val in self._variables.values(): flattened = list(Functions._flatten(val.bit_list)) for v in flattened: if (v.label not in self._deleted) and (v.label in physical._variables_set): physical._label_to_index[v.label] = current_index physical._index_to_label[current_index] = v.label current_index += 1 # save the last physical model self._previous_physical_model = physical # Restore the model before adding constraints # self._variables = original_variables # Variables were not changed self._offset = original_offset self._deleted = original_deleted self._fixed = original_fixed # self._constraints = original_constraints # Constraints were not changed self._interactions_array = original_interactions_array self._interactions_attrs = original_interactions_attrs self._interactions_length = original_interactions_length # Remove interactions # TODO: Physically remove the logically removed interactions for rm in will_remove: idx = self._interactions_array["name"].index(rm) for k in self._interactions_array.keys(): self._interactions_array[k].pop(idx) self._interactions_length -= 1 # Set dirty flag for i in range(self._interactions_length): # TODO: Calc difference from previous physical model by referencing dirty flags. if self._interactions_array["dirty"][i]: self._interactions_array["dirty"][i] = False return physical
def _create_model(self, job_num, machine_num, job_ids, r_times, d_times, p_intervals, assign, prev_start_time): """ Set I' is set of jobs assigned to machines, their assign variable equal to 1""" print("assignment:", assign) print("previous start time:", prev_start_time) # set_I_apos = set S' = {i,j | x_im = x_jm = 1} set_I_apos = [ i_id for i_id in range(job_num) for m_id in range(machine_num) if assign[(i_id, m_id)].x == 1 ] # print("set I apos:", set_I_apos) z_apos = { i_id: m_id for i_id in range(job_num) for m_id in range(machine_num) if assign[(i_id, m_id)].x == 1 } print(z_apos) """ Prepare the index for decision variables """ # start time of process jobs = tuple(job_ids) # print("inside:", jobs) # sequence of processing jobs: tuple list job_pairs_apos = [(i, j) for i in set_I_apos for j in set_I_apos if i != j and z_apos[i] == z_apos[j]] # print(job_pairs_apos) # # assignment of jobs on machines # job_machine_pairs = [(i, m) for i in jobs for m in machines] # print(job_machine_pairs) """ Parameters model (dictionary) """ # 1. release time release_time = dict(zip(jobs, tuple(r_times))) # print("release time:", release_time) # 2. due time due_time = dict(zip(jobs, tuple(d_times))) # print("due time:", due_time) # 3. processing time process_time = dict(zip(jobs, tuple(p_intervals))) print("process time:", process_time) U = sum([max(p_intervals[i]) for i in range(job_num)]) print("test U:", U) # for (i,j) in job_pairs_apos: # print("job apos:", i,j) # print(process_time[i][z_apos[i]] - max(due_time.values())) """ Create decision variables """ # # 1. Sequence (Order) of executing jobs # y = model.addVars(job_pairs_apos, vtype=grb.GRB.BINARY, name="sequence") # # 2. Start time of executing each job (ts = time_start) # ts = model.addVars(set_I_apos, lb=0, name="start_time") y = { item: pyqubo.Binary("y_(%d,%d)" % item) for item in job_pairs_apos } print("y is: {}".format(y)) """ Create the objective function """ # model.setObjective(0, sense=grb.GRB.MINIMIZE) H = 0 for (i, j) in job_pairs_apos: H += (1 - y[(i, j)] - y[(j, i)] + 2 * y[(i, j)] * y[(j, i)] + y[(i, j)] * (U * (prev_start_time[i].x - prev_start_time[j].x) + sum(process_time[i][m] * assign[(i, m)].x for m in range(machine_num) if assign[(i, m)].x == 1))) print("H is {}".format(H)) # """ Create constraints """ # # 1. job release time constraint # model.addConstrs((ts[i] >= release_time[i] for i in set_I_apos), name="assigned job release constraint") # # 2. job due time constraint # model.addConstrs((ts[i] <= due_time[i] - process_time[i][z_apos[i]] for i in set_I_apos), # name="assigned job due constraint") # # 3. when assigned, either job 'i' is processed before job 'j' or vice versa # model.addConstrs((y[(i,j)] + y[(j,i)] == 1 for (i,j) in job_pairs_apos if i > j and # assign[(i,z_apos[i])].x == assign[(j,z_apos[j])].x), name="sequence of assigned jobs") # # 4. valid cut, starting times, using latest due date as big-M parameter # model.addConstrs((ts[j] >= ts[i] + process_time[i][z_apos[i]] - max(due_time.values())*(1 - y[(i,j)]) # for (i,j) in job_pairs_apos if z_apos[j] == z_apos[i]), name="valid cut by big-M") # return model, y, ts """ Create model """ model = H.compile() ts = prev_start_time return model, y, ts, job_pairs_apos, z_apos, U