def test_checkkey(): with assert_raises(KeyError): QUSOMatrix({('a', ): -1}) with assert_raises(KeyError): QUSOMatrix({0: -1}) with assert_raises(KeyError): QUSOMatrix({(0, 1, 2): -1})
def test_symbols(): a, b = Symbol('a'), Symbol('b') d = QUSOMatrix() d[(0, )] -= a d[(0, 1)] += 2 d[(1, )] += b assert d == {(0, ): -a, (0, 1): 2, (1, ): b} assert d.subs(a, 2) == {(0, ): -2, (0, 1): 2, (1, ): b} assert d.subs(b, 1) == {(0, ): -a, (0, 1): 2, (1, ): 1} assert d.subs({a: -3, b: 4}) == {(0, ): 3, (0, 1): 2, (1, ): 4}
def test_create_var(): d = QUSOMatrix.create_var(0) assert d == {(0, ): 1} assert d.name == 0 assert type(d) == QUSOMatrix d = QUSOMatrix.create_var(1) assert d == {(1, ): 1} assert d.name == 1 assert type(d) == QUSOMatrix
def test_quso_remove_value_when_zero(): d = QUSOMatrix() d[(0, )] += 1 d[(0, )] -= 1 assert d == {} d.refresh() assert d.degree == 0 assert d.num_binary_variables == 0 assert d.variables == set()
def test_qusosimulation_reset(): ising = sum(-spin_var(i) * spin_var(i + 1) for i in range(3)) initial_state = {0: 1, 1: 1, 2: -1, 3: 1} sim = QUSOSimulation(ising, initial_state) sim.schedule_update([(2, 100)]) sim.update(2, 2000) sim.reset() assert sim.state == initial_state == sim.initial_state # test the same thing but with matrix ising = QUSOMatrix(sum(-spin_var(i) * spin_var(i + 1) for i in range(3))) initial_state = {0: 1, 1: 1, 2: -1, 3: 1} sim = QUSOSimulation(ising, initial_state) sim.schedule_update([(2, 100)]) sim.update(2, 2000) sim.reset() assert sim.state == initial_state == sim.initial_state # test the same thing but with QUSO ising = QUSO(sum(-spin_var(i) * spin_var(i + 1) for i in range(3))) initial_state = {0: 1, 1: 1, 2: -1, 3: 1} sim = QUSOSimulation(ising, initial_state) sim.schedule_update([(2, 100)]) sim.update(2, 2000) sim.reset() assert sim.state == initial_state == sim.initial_state
def to_quso(self, A=1): r"""to_quso. Create and return the number partitioning problem in QUSO form following section 2.1 of [Lucas]. It is the value such that the solution to the QUSO formulation is 0 if a valid number partitioning exists. Parameters ---------- A: positive float (optional, defaults to 1). Factor in front of objective function. See section 2.1 of [Lucas]. Return ------ L : qubovert.utils.QUSOMatrix object. For most practical purposes, you can use QUSOMatrix in the same way as an ordinary dictionary. For more information, see ``help(qubovert.utils.QUSOMatrix)``. Example ------- >>> problem = NumberPartitioning([1, 2, 3, 4]) >>> L = problem.to_quso() """ L = QUSOMatrix({(i, ): self._S[i] for i in range(self._N)}) return A * L * L
def test_qusosimulation_bigrun(): # test that it runs on a big problem model = QUSOMatrix({(i, j): 1 for i in range(2, 200, 3) for j in range(2, 200, 2)}) sim = QUSOSimulation(model) sim.update(3, 1000) sim.update(3, 1000, in_order=True)
def test_round(): d = QUSOMatrix({(0, ): 3.456, (1, ): -1.53456}) assert round(d) == {(0, ): 3, (1, ): -2} assert round(d, 1) == {(0, ): 3.5, (1, ): -1.5} assert round(d, 2) == {(0, ): 3.46, (1, ): -1.53} assert round(d, 3) == {(0, ): 3.456, (1, ): -1.535}
def test_properties(): L = QUSOMatrix() L[(0, )] -= 1 L[(0, 1)] += 1 L += 2 assert L.offset == 2 assert L.h == {0: -1} assert L.J == {(0, 1): 1}
def test_normalize(): temp = {(0, ): 4, (1, ): -2} d = QUSOMatrix(temp) d.normalize() assert d == {k: v / 4 for k, v in temp.items()} temp = {(0, ): -4, (1, ): 2} d = QUSOMatrix(temp) d.normalize() assert d == {k: v / 4 for k, v in temp.items()}
def test_qusomatrix_solve_bruteforce(): L = QUSOMatrix({(0, 1): 1, (1, 2): 1, (1, ): -1, (2, ): -2}) sol = L.solve_bruteforce() assert sol in ({0: -1, 1: 1, 2: 1}, {0: 1, 1: -1, 2: 1}) assert allclose(L.value(sol), -3) L = QUSOMatrix({(0, ): 0.25, (1, ): -0.25, (0, 1): -0.25, (): 1.25}) sols = L.solve_bruteforce(True) assert sols == [{0: 1, 1: 1}, {0: -1, 1: 1}, {0: -1, 1: -1}] assert all(allclose(L.value(s), 1) for s in sols)
def test_quso_degree(): d = QUSOMatrix() assert d.degree == 0 d[(0, )] += 2 assert d.degree == 1 d[(1, )] -= 3 assert d.degree == 1 d[(1, 2)] -= 2 assert d.degree == 2
def to_quso(self, A=None, B=1): r"""to_quso. Create and return the graph partitioning problem in QUSO form following section 2.2 of [Lucas]. A and B are parameters to enforce constraints. It is formatted such that the solution to the QUSO formulation is equal to the the total number of edges connecting the two partitions (or the total weight if we are solving weighted partitioning). Parameters ---------- A: positive float (optional, defaults to None). A enforces the constraints. If it is None, then A will be chosen to enforce hard constraints (equation 10 in [Lucas]). Note that this may not be optimal for a solver, often hard constraints result in unsmooth energy landscapes that are difficult to minimize. Thus it may be useful to play around with the magnitude of this value. B: positive float (optional, defaults to 1). Constant in front of the objective function to minimize. See section 2.2 of [Lucas]. Return ------ L : qubovert.utils.QUSOMatrix object. For most practical purposes, you can use QUSOMatrix in the same way as an ordinary dictionary. For more information, see ``help(qubovert.utils.QUSOMatrix)``. Example ------- >>> problem = GraphPartitioning({(0, 1), (1, 2), (0, 3)}) >>> L = problem.to_quso() """ # all naming conventions follow the paper listed in the docstring if A is None: A = min(2 * self._degree, self._N) * B / 8 L = QUSOMatrix() # encode H_A (equation 8) L += PCSO().add_constraint_eq_zero({(i, ): 1 for i in range(self._N)}, lam=A) # encode H_B (equation 9) L += B * sum(self._edges.values()) / 2 for (u, v), w in self._edges.items(): L[(self._vertex_to_index[u], self._vertex_to_index[v])] -= w * B / 2 return L
def test_quso_addition(): temp = QUSOMatrix({(0, ): 1, (0, 1): 2}) temp1 = {(0, ): -1, (1, 0): 3} temp2 = {(0, 1): 5} temp3 = {(0, ): 2, (0, 1): -1} # add constant d = temp.copy() d += 5 d[()] -= 2 d == {(0, ): 1, (0, 1): 2, (): 3} # __add__ d = temp.copy() g = d + temp1 assert g == temp2 # __iadd__ d = temp.copy() d += temp1 assert d == temp2 # __radd__ d = temp.copy() g = temp1 + d assert g == temp2 # __sub__ d = temp.copy() g = d - temp1 assert g == temp3 # __isub__ d = temp.copy() d -= temp1 assert d == temp3 # __rsub__ d = temp.copy() g = temp1 - d assert g == QUSOMatrix(temp3) * -1
def test_quso_to_qubo_to_quso(): quso = {(0, 1): -4, (0, 2): 3, (): -2, (0, ): 1, (2, ): -2} assert quso == qubo_to_quso(quso_to_qubo(quso)) # type asserting assert type(quso_to_qubo(quso)) == QUBO assert type(quso_to_qubo(QUSOMatrix(quso))) == QUBOMatrix assert type(quso_to_qubo(QUSO(quso))) == QUBO quso = {('0', 1): -4, ('0', '2'): 3, (): -2, ('0', ): 1, ('2', '2'): -2} # need to reformat quso so it is sorted with the same hash and squashed key assert QUSO(quso) == qubo_to_quso(quso_to_qubo(quso)) # type asserting assert type(quso_to_qubo(quso)) == QUBO assert type(quso_to_qubo(QUSO(quso))) == QUBO
def to_quso(self, pbc=False): r"""to_quso. Create and return the alternating Sectors chain problem in QUSO form The J coupling matrix for the QUSO will be returned as an uppertriangular dictionary. Thus, the problem becomes minimizing :math:`\sum_{i <= j} z_i z_j J_{ij} + \sum_{i} z_i h_i + offset`. Parameters ---------- pbc: bool (optional, defaults to False). Whether or not to use periodic boundary conditions. Return ------ L : qubovert.utils.QUSOMatrix object. For most practical purposes, you can use QUSOMatrix in the same way as an ordinary dictionary. For more information, see ``help(qubovert.utils.QUSOMatrix)``. Example ------- >>> args = n, l, min_s, max_s = 6, 3, 1, 5 >>> problem = AlternatingSectorsChain(*args) >>> L = problem.to_quso(pbc=True) >>> L {(0, 1): 5, (1, 2): 5, (2, 3): 5, (3, 4): 1, (4, 5): 1, (5, 0): 1} >>> L = problem.to_quso(pbc=False) >>> L {(0, 1): 5, (1, 2): 5, (2, 3): 5, (3, 4): 1, (4, 5): 1} """ L = QUSOMatrix() for q in range(self._N - 1): L[(q, q + 1)] = (self._min_strength if (q // self._chain_length) % 2 else self._max_strength) if pbc: L[(self._N - 1, 0)] = (self._min_strength if ((self._N - 1) // self._chain_length) % 2 else self._max_strength) return L
def test_pretty_str(): def equal(expression, string): assert expression.pretty_str() == string z = [QUSOMatrix() + {(i, ): 1} for i in range(3)] a, b = Symbol('a'), Symbol('b') equal(z[0], "z(0)") equal(-z[0], "-z(0)") equal(z[0] * 0, "0") equal(2 * z[0] * z[1] - 3 * z[2], "2 z(0) z(1) - 3 z(2)") equal(0 * z[0] + 1, "1") equal(0 * z[0] - 1, "-1") equal(0 * z[0] + a, "(a)") equal(0 * z[0] + a * b, "(a*b)") equal((a + b) * (z[0] * z[1] - z[2]), "(a + b) z(0) z(1) + (-a - b) z(2)") equal(2 * z[0] * z[1] - z[2], "2 z(0) z(1) - z(2)") equal(-z[2] + z[0] * z[1], "-z(2) + z(0) z(1)") equal(-2 * z[2] + 2 * z[0] * z[1], "-2 z(2) + 2 z(0) z(1)")
def test_quso_reinitialize_dictionary(): d = QUSOMatrix({(0, ): 1, (1, 0): 2, (2, 0): 0, (0, 1): 1}) assert d == {(0, ): 1, (0, 1): 3}
def test_quso_default_valid(): d = QUSOMatrix() assert d[(0, )] == 0 d[(0, )] += 1 assert d == {(0, ): 1}
def test_quso_num_binary_variables(): d = QUSOMatrix({(0, ): 1, (0, 3): 2}) assert d.num_binary_variables == 2
def test_num_terms(): d = QUSOMatrix({(0, ): 1, (0, 3): 2, (0, 2): -1}) assert d.num_terms == len(d)
def test_quso_max_index(): d = QUSOMatrix({(0, ): 1, (0, 3): 2}) assert d.max_index == 3
def test_qusosimulation_set_state(): ising = sum(-spin_var(i) * spin_var(i + 1) for i in range(9)) sim = QUSOSimulation(ising) assert sim.state == {i: 1 for i in ising.variables} sim = QUSOSimulation(ising, {i: -1 for i in ising.variables}) assert sim.state == {i: -1 for i in ising.variables} with assert_raises(ValueError): sim.set_state({i: 3 for i in ising.variables}) with assert_raises(ValueError): QUSOSimulation(ising, {i: 0 for i in ising.variables}) sim = QUSOSimulation({(0, ): 1}) with assert_raises(ValueError): sim.set_state([0]) sim.set_state([-1]) assert sim.state == {0: -1} # test the same but with matrix ising = QUSOMatrix(sum(-spin_var(i) * spin_var(i + 1) for i in range(9))) sim = QUSOSimulation(ising) assert sim.state == {i: 1 for i in ising.variables} sim = QUSOSimulation(ising, {i: -1 for i in ising.variables}) assert sim.state == {i: -1 for i in ising.variables} with assert_raises(ValueError): sim.set_state({i: 3 for i in ising.variables}) with assert_raises(ValueError): QUSOSimulation(ising, {i: 0 for i in ising.variables}) sim = QUSOSimulation({(0, ): 1}) with assert_raises(ValueError): sim.set_state([0]) sim.set_state([-1]) assert sim.state == {0: -1} # test the same for QUSO ising = QUSO(sum(-spin_var(i) * spin_var(i + 1) for i in range(9))) sim = QUSOSimulation(ising) assert sim.state == {i: 1 for i in ising.variables} sim = QUSOSimulation(ising, {i: -1 for i in ising.variables}) assert sim.state == {i: -1 for i in ising.variables} with assert_raises(ValueError): sim.set_state({i: 3 for i in ising.variables}) with assert_raises(ValueError): QUSOSimulation(ising, {i: 0 for i in ising.variables}) sim = QUSOSimulation({(0, ): 1}) with assert_raises(ValueError): sim.set_state([0]) sim.set_state([-1]) assert sim.state == {0: -1}
def test_quso_update(): d = QUSOMatrix({(0, ): 1, (0, 1): 2}) d.update({(0, ): 0, (1, 0): 1, (1, ): -1}) assert d == {(0, 1): 1, (1, ): -1}
def test_qubosimulation_set_state(): ising = quso_to_qubo(sum(-spin_var(i) * spin_var(i + 1) for i in range(9))) sim = QUBOSimulation(ising) assert sim.state == {i: 0 for i in ising.variables} sim = QUBOSimulation(ising, {i: 1 for i in ising.variables}) assert sim.state == {i: 1 for i in ising.variables} with assert_raises(ValueError): sim.set_state({i: 3 for i in ising.variables}) with assert_raises(ValueError): QUBOSimulation(ising, {i: -1 for i in ising.variables}) sim = QUBOSimulation({(0, ): 1}) with assert_raises(ValueError): sim.set_state([-1]) sim.set_state([1]) assert sim.state == {0: 1} # test the same thing but wiht matrix ising = quso_to_qubo( QUSOMatrix(sum(-spin_var(i) * spin_var(i + 1) for i in range(9)))) sim = QUBOSimulation(ising) assert sim.state == {i: 0 for i in ising.variables} sim = QUBOSimulation(ising, {i: 1 for i in ising.variables}) assert sim.state == {i: 1 for i in ising.variables} with assert_raises(ValueError): sim.set_state({i: 3 for i in ising.variables}) with assert_raises(ValueError): QUBOSimulation(ising, {i: -1 for i in ising.variables}) sim = QUBOSimulation({(0, ): 1}) with assert_raises(ValueError): sim.set_state([-1]) sim.set_state([1]) assert sim.state == {0: 1} # test the same thing but wiht QUBO ising = quso_to_qubo( QUBO(sum(-spin_var(i) * spin_var(i + 1) for i in range(9)))) sim = QUBOSimulation(ising) assert sim.state == {i: 0 for i in ising.variables} sim = QUBOSimulation(ising, {i: 1 for i in ising.variables}) assert sim.state == {i: 1 for i in ising.variables} with assert_raises(ValueError): sim.set_state({i: 3 for i in ising.variables}) with assert_raises(ValueError): QUBOSimulation(ising, {i: -1 for i in ising.variables}) sim = QUBOSimulation({(0, ): 1}) with assert_raises(ValueError): sim.set_state([-1]) sim.set_state([1]) assert sim.state == {0: 1}
def test_quso_multiplication(): temp = QUSOMatrix({(0, ): 1, (0, 1): 2}) temp += 2 # __mul__ d = temp.copy() g = d * 3 assert g == {(0, ): 3, (0, 1): 6, (): 6} d = temp.copy() g = d * 0 assert g == {} # __imul__ d = temp.copy() d *= 3 assert d == {(0, ): 3, (0, 1): 6, (): 6} d = temp.copy() d *= 0 assert d == {} # __rmul__ d = temp.copy() g = 3 * d assert g == {(0, ): 3, (0, 1): 6, (): 6} d = temp.copy() g = 0 * d assert g == {} # __truediv__ d = temp.copy() g = d / 2 assert g == {(0, ): .5, (0, 1): 1, (): 1} # __itruediv__ d = temp.copy() d /= 2 assert d == {(0, ): .5, (0, 1): 1, (): 1} # __floordiv__ d = temp.copy() g = d // 2 assert g == {(0, 1): 1, (): 1} # __ifloordiv__ d = temp.copy() d //= 2 assert d == {(0, 1): 1, (): 1} # __mul__ but with dict d = temp.copy() d *= {(1, ): 2, (0, ): -1} assert d == {(): -1, (0, ): 2, (1, ): 2, (0, 1): 2} # __pow__ d = temp.copy() d **= 2 assert d == {(): 9, (0, ): 4, (1, ): 4, (0, 1): 8} temp = d.copy() assert d**3 == d * d * d # should raise a KeyError since can't fit this into QUSO. with assert_raises(KeyError): QUSOMatrix({(0, 1): 1, (2, 3): -1})**2