def test_serialzie_proto_problem(self): problem = Problem(name="test_proto", problem_type=ProblemType.ising, content_type=ContentType.protobuf) problem.terms = [ Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), ] problem_msgs = problem.serialize() self.assertEqual(len(problem_msgs), 1) proto_problem = ProtoProblem() proto_problem.ParseFromString(problem_msgs[0]) self.assertEqual(proto_problem.cost_function.type, ProtoProblem.ProblemType.ISING) self.assertEqual(len(proto_problem.cost_function.terms), 12)
def test_submit_proto_problem(testprotosolver): problem = Problem(name="proto_test", content_type=ContentType.protobuf) problem.terms = [Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0])] with patch("azure.quantum.job.base_job.upload_blob") as mock_upload: job = testprotosolver.submit(problem) mock_upload.assert_called_once() testprotosolver.workspace.submit_job.assert_called_once()
def create_problem(init: bool = False) -> Problem: """Create optimization problem with some default terms :param init: Set initial configuration :type init: bool :return: Optimization problem :rtype: Problem """ terms = [ Term(w=-3, indices=[1,0]), Term(w=5, indices=[2,0]), Term(w=9, indices=[2,1]), Term(w=2, indices=[3,0]), Term(w=-4, indices=[3,1]), Term(w=4, indices=[3,2]) ] if init is True: initial_config = { "1": -1, "0": 1, "2": -1, "3": 1 } return Problem(name="initial_condition_demo", terms = terms, init_config=initial_config) else: return Problem(name = "first-demo", terms=terms)
def test_serialization_init_config(self): count = 2 terms = [] for i in range(count): terms.append(Term(c=i, indices=[i, i + 1])) init_config = {"0": -1, "1": 1, "2": -1} problem = Problem(name="test", terms=terms, init_config=init_config) expected = json.dumps({ "cost_function": { "version": "1.1", "type": "ising", "terms": [{ 'c': 0, 'ids': [0, 1] }, { 'c': 1, 'ids': [1, 2] }], "initial_configuration": { "0": -1, "1": 1, "2": -1 }, } }) actual = problem.serialize() self.assertEqual(expected, actual)
def test_job_get_results(self): ws = self.create_workspace() problem = Problem(name="test") count = 4 for i in range(count): problem.add_term(c=i, indices=[i, i + 1]) with unittest.mock.patch.object(Job, self.mock_create_job_id_name, return_value=self.get_dummy_job_id()): solver = SimulatedAnnealing(ws) job = solver.submit(problem) actual = job.get_results() expected = { 'version': '1.0', 'configuration': { '0': 1, '1': 1, '2': -1, '3': 1, '4': -1 }, 'cost': -6.0, 'parameters': { 'beta_start': 0.2, 'beta_stop': 1.9307236000000003, 'restarts': 360, 'sweeps': 50 } } self.assertEqual(expected, actual)
def test_throw_exception_proto_problem(testprotosolver): testprotosolver.name = "SimulatedAnnealing" problem = Problem(name="proto_test_exception", content_type=ContentType.protobuf) problem.terms = [Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0])] with patch("azure.quantum.job.base_job.upload_blob") as mock_upload: pytest.raises(ValueError, testprotosolver.submit, problem)
def setUp(self): self.mock_ws = Mock() self.mock_ws.get_container_uri = Mock( return_value="mock_container_uri/foo/bar") self.mock_ws._get_linked_storage_sas_uri = Mock( return_value="mock_linked_storage_sas_uri/foo/bar") ## QUBO problem self.problem = Problem(name="test") self.problem.terms = [ Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), ] self.problem.uploaded_blob_uri = "mock_blob_uri" # Create equivalent NPZ file for translation self.problem.row = numpy.array([1, 2]) self.problem.col = numpy.array([0, 0]) self.problem.data = numpy.array([3, 5]) # If arguments are passed to savez with no keywords # then default names are used (e.g. "arr_0", "arr_1", etc) # otherwise it uses those supplied by user (e.g. "row", "col", etc) self.default_qubo_filename = "default_qubo.npz" numpy.savez(self.default_qubo_filename, self.problem.row, self.problem.col, self.problem.data) self.with_keywords_qubo_filename = "with_keywords_qubo.npz" numpy.savez(self.with_keywords_qubo_filename, row=self.problem.row, col=self.problem.col, data=self.problem.data) ## PUBO problem self.pubo_problem = Problem(name="test") self.pubo_problem.terms = [ Term(c=3, indices=[1, 0, 1]), Term(c=5, indices=[2, 0, 0]), Term(c=-1, indices=[1, 0, 0]), Term(c=4, indices=[0, 2, 1]) ] # Create equivalent NPZ file for translation self.pubo_problem.i = numpy.array([1, 2, 1, 0]) self.pubo_problem.j = numpy.array([0, 0, 0, 2]) self.pubo_problem.k = numpy.array([1, 0, 0, 1]) self.pubo_problem.c = numpy.array([3, 5, -1, 4]) self.default_pubo_filename = "default_pubo.npz" numpy.savez(self.default_pubo_filename, self.pubo_problem.i, self.pubo_problem.j, self.pubo_problem.k, self.pubo_problem.c) self.with_keywords_pubo_filename = "with_keywords_pubo.npz" numpy.savez(self.with_keywords_pubo_filename, i=self.pubo_problem.i, j=self.pubo_problem.j, k=self.pubo_problem.k, c=self.pubo_problem.c)
def __test_upload_problem( self, count: int, terms_thresh: int, size_thresh: int, compress: bool, problem_type: ProblemType = ProblemType.ising, initial_terms: List[Term] = [], **kwargs ): if not (self.in_recording or self.is_live): # Temporarily disabling this test in playback mode # due to multiple calls to the storage API # that need to have a request id to distinguish # them while playing back print("Skipping this test in playback mode") return ws = self.create_workspace() sProblem = StreamingProblem( ws, name="test", problem_type=problem_type, terms=initial_terms ) rProblem = Problem( "test", problem_type=problem_type, terms=initial_terms ) sProblem.upload_terms_threshold = terms_thresh sProblem.upload_size_threshold = size_thresh sProblem.compress = compress for i in range(count): sProblem.add_term(c=i, indices=[i, i + 1]) rProblem.add_term(c=i, indices=[i, i + 1]) self.assertEqual(problem_type, sProblem.problem_type) self.assertEqual(problem_type.name, sProblem.stats["type"]) self.assertEqual( count + len(initial_terms), sProblem.stats["num_terms"] ) self.assertEqual( self.__kwarg_or_value(kwargs, "avg_coupling", 2), sProblem.stats["avg_coupling"], ) self.assertEqual( self.__kwarg_or_value(kwargs, "max_coupling", 2), sProblem.stats["max_coupling"], ) self.assertEqual( self.__kwarg_or_value(kwargs, "min_coupling", 2), sProblem.stats["min_coupling"], ) uri = sProblem.upload(ws) uploaded = json.loads(sProblem.download().serialize()) local = json.loads(rProblem.serialize()) self.assertEqual(uploaded, local)
def test_submit_large_proto_problem(testprotosolver): problem = Problem(name="proto_test", content_type=ContentType.protobuf) terms = [] for i in range(0, 3000): terms.append(Term(c=i, indices=[i, i + 1])) problem.terms = terms with patch("azure.quantum.job.base_job.upload_blob") as mock_upload: job = testprotosolver.submit(problem) mock_upload.assert_called_once() testprotosolver.workspace.submit_job.assert_called_once()
def test_grouped_type(self): problem = Problem(name="test_pubo_grouped", problem_type=ProblemType.pubo) problem.terms = [ Term(c=3, indices=[1, 0, 1]), Term(c=5, indices=[2, 0, 0]), Term(c=-1, indices=[1, 0, 0]), Term(c=4, indices=[0, 2, 1]) ] assert problem.problem_type is ProblemType.pubo problem.add_slc_term([(3, 0), (2, 1), (-1, None)]) assert problem.problem_type is ProblemType.pubo_grouped
def test_deserialize(self): count = 2 terms = [] for i in range(count): terms.append(Term(c=i, indices=[i, i + 1])) problem = Problem(name="test", terms=terms) deserialized = Problem.deserialize(problem.serialize(), problem.name) self.assertEqual(problem.name, deserialized.name) self.assertEqual(problem.problem_type, deserialized.problem_type) self.assertEqual(count, len(deserialized.terms)) self.assertEqual(problem.init_config, deserialized.init_config) self.assertEqual(Term(c=0, indices=[0, 1]), problem.terms[0]) self.assertEqual(Term(c=1, indices=[1, 2]), problem.terms[1])
def test_job_refresh(self): ws = self.create_workspace() problem = Problem(name="test") count = 4 for i in range(count): problem.add_term(c=i, indices=[i, i + 1]) with unittest.mock.patch.object(Job, self.mock_create_job_id_name, return_value=self.get_dummy_job_id()): solver = SimulatedAnnealing(ws) job = solver.submit(problem) job.refresh()
def test_serialization_cterms(self): count = 2 terms = [] for i in range(count): terms.append(Term(c=i, indices=[i, i + 1])) terms.append( SlcTerm([ Term(c=0, indices=[0]), Term(c=1, indices=[1]), Term(c=-5, indices=[]) ], c=1)) problem = Problem(name="test", terms=terms) expected = json.dumps({ "metadata": { "name": "test" }, "cost_function": { "version": "1.0", "type": "ising_grouped", "terms": [{ "c": 0, "ids": [0, 1] }, { "c": 1, "ids": [1, 2] }], "terms_slc": [{ "c": 1, "terms": [{ "c": 0, "ids": [0] }, { "c": 1, "ids": [1] }, { "c": -5, "ids": [] }] }] } }) actual = problem.serialize() self.assertEqual(expected, actual)
def create_problem(cost_function, nb_binary_variables) -> Problem: ### the cost_function is given as a list of polynomial coefficients. problem_type = ProblemType.ising indices = range(nb_binary_variables) random_weights = np.array([rd.random() for _ in indices]) # random_weights = np.array([np.random.exponential(scale=100) for _ in indices]) random_weights = random_weights / sum( random_weights) ### Normalize random_weights to sum to 1. reduced_variable_subset_list = [] weight_list = [] for degree, coefficient in enumerate(cost_function): for variable_subset_of_size_degree in itertools.product(indices, repeat=degree): weight = coefficient * product(variable_subset_of_size_degree, random_weights) reduced_variable_subset = reduce_subset( variable_subset_of_size_degree, problem_type) if reduced_variable_subset not in reduced_variable_subset_list: reduced_variable_subset_list.append(reduced_variable_subset) weight_list.append(weight) else: i = reduced_variable_subset_list.index(reduced_variable_subset) weight_list[i] += weight terms = [] for weight, reduced_variable_subset in zip(weight_list, reduced_variable_subset_list): terms.append(Term(c=weight, indices=list(reduced_variable_subset))) return random_weights, Problem(name="Continuous cost function", problem_type=problem_type, terms=terms)
def create_problem( self, name: str, init: bool = False, problem_type: ProblemType = ProblemType.pubo, test_grouped: bool = False, content_type: ContentType = None, ) -> Problem: """Create optimization problem with some default terms :param init: Set initial configuration :type init: bool :return: Optimization problem :rtype: Problem """ terms = [ Term(w=-3, indices=[1, 0]), Term(w=5, indices=[2, 0]), Term(w=9, indices=[2, 1]), Term(w=2, indices=[3, 0]), Term(w=-4, indices=[3, 1]), Term(w=4, indices=[3, 2]), ] if test_grouped: terms.append( SlcTerm(c=1, terms=[Term(c=i + 2, indices=[i]) for i in range(3)])) initial_config = {"1": 0, "0": 1, "2": 0, "3": 1} if init \ else None return Problem(name=name, terms=terms, init_config=initial_config, problem_type=problem_type, content_type=content_type or ContentType.json)
def check_submission_warnings(self, problem: Problem): # print a warning if we suspect the job # may take long based on its configured properties. is_large_problem = problem.is_large() if is_large_problem: if self.nested_params and "sweeps" in self.params["params"]: sweeps = int(self.params["params"]["sweeps"]) # if problem is large and sweeps is large, warn. if sweeps >= Solver.SWEEPS_WARNING: logger.warning( f"There is a large problem submitted and \ a large number of sweeps ({sweeps}) configured. \ This submission could result in a long runtime." ) # do a timeout check if param-free, to warn # new users who accidentally set high timeout values. if self.nested_params and "timeout" in self.params["params"]: timeout = int(self.params["params"]["timeout"]) if timeout >= Solver.TIMEOUT_WARNING: logger.warning( f"A large timeout has been set for this submission \ ({timeout}). \ If this is intended, disregard this warning. \ Otherwise, consider cancelling the job \ and resubmitting with a lower timeout." )
def create_problem( self, name: str, init: bool = False, problem_type: ProblemType = ProblemType.pubo, ) -> Problem: """Create optimization problem with some default terms :param init: Set initial configuration :type init: bool :return: Optimization problem :rtype: Problem """ terms = [ Term(w=-3, indices=[1, 0]), Term(w=5, indices=[2, 0]), Term(w=9, indices=[2, 1]), Term(w=2, indices=[3, 0]), Term(w=-4, indices=[3, 1]), Term(w=4, indices=[3, 2]), ] initial_config = {"1": 0, "0": 1, "2": 0, "3": 1} if init \ else None return Problem( name=name, terms=terms, init_config=initial_config, problem_type=problem_type, )
def test_job_wait_unit_completed(self): ws = self.create_workspace() problem = Problem(name="test") count = 4 for i in range(count): problem.add_term(c=i, indices=[i, i + 1]) with unittest.mock.patch.object(Job, self.mock_create_job_id_name, return_value=self.get_dummy_job_id()): solver = SimulatedAnnealing(ws) job = solver.submit(problem) job.wait_until_completed() self.assertEqual(True, job.has_completed())
def test_serialization_cterms(self): count = 2 terms = [] for i in range(count): terms.append(Term(c=i, indices=[i, i+1])) problem = Problem(name="test", terms=terms) expected = json.dumps({ "cost_function": { "version": "1.0", "type": "ising", "terms": [ { 'c':0, 'ids':[0, 1] }, {'c':1, 'ids':[1, 2]} ], } }) print(problem.serialize()) actual = problem.serialize() self.assertEqual(expected, actual)
def test_provide_cterms(self): count = 4 terms = [] for i in range(count): terms.append(Term(c=i, indices=[i, i+1])) problem = Problem(name="test", terms=terms, problem_type=ProblemType.pubo) self.assertEqual(ProblemType.pubo, problem.problem_type) self.assertEqual(count, len(problem.terms)) self.assertEqual(Term(c=1, indices=[1, 2]), problem.terms[1])
def download(self): """Downloads the uploaded problem as an instance of `Problem`""" if not self.uploaded_uri: raise Exception( 'StreamingProblem may not be downloaded before it is uploaded') coords = self._get_upload_coords() blob = coords['container_client'].get_blob_client(coords['blob_name']) contents = download_blob(blob.url) return Problem.deserialize(contents, self.name)
def createFBP_expanded(weights: List[int]) -> Problem: # Expand the squared summation terms = [] for i in range(len(weights)): for j in range(i + 1, len(weights)): terms.append(Term(c=2 * weights[i] * weights[j], indices=[i, j])) # Return an Ising-type problem return Problem(name="Freight Balancing Problem", problem_type=ProblemType.ising, terms=terms)
def test_problem_name_serialization(self): problem_names = ["test", "my_problem"] for problem_name in problem_names: problem = Problem(name=problem_name) problem.terms = [ Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), ] serialized_problem = problem.serialize() # name is in the serialized string assert re.search(f'"name"\\s*:\\s*"{problem_name}"', serialized_problem, flags=re.RegexFlag.MULTILINE) # name is in the correct place in the json structure problem_json = json.loads(serialized_problem) assert problem_json["metadata"]["name"] == problem_name # deserializes name deserialized_problem = Problem.deserialize( input_problem=serialized_problem) assert problem_name == deserialized_problem.name new_problem_name = "new_problem_name" # use the name passed in the parameter deserialized_problem = Problem.deserialize( input_problem=serialized_problem, name=new_problem_name) assert new_problem_name == deserialized_problem.name # test deserializing a problem that does not have a name in the json # and leaving the name as None serialized_problem_without_name = '{"cost_function": {"version": "1.0", "type": "ising", "terms": [{"c": 3, "ids": [1, 0]}, {"c": 5, "ids": [2, 0]}]}}' deserialized_problem = Problem.deserialize( input_problem=serialized_problem_without_name) assert deserialized_problem.name == "Optimization problem" # test deserializing a problem that does not have a name in the json # and using the name parameter new_problem_name = "new_problem_name" deserialized_problem = Problem.deserialize( input_problem=serialized_problem_without_name, name=new_problem_name) assert new_problem_name == deserialized_problem.name # test deserializing a problem that does not have a name but have a metadata in the json # and leaving the name as None serialized_problem_without_name = '{"metadata":{"somemetadata":123}, "cost_function": {"version": "1.0", "type": "ising", "terms": [{"c": 3, "ids": [1, 0]}, {"c": 5, "ids": [2, 0]}]}}' deserialized_problem = Problem.deserialize( input_problem=serialized_problem_without_name) assert deserialized_problem.name == "Optimization problem"
def test_deserialize_proto_problem(self): problem = Problem(name="test_proto", problem_type=ProblemType.pubo, content_type=ContentType.protobuf) problem.terms = [ Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), Term(c=3, indices=[1, 0]), Term(c=5, indices=[2, 0]), ] problem_msgs = problem.serialize() deserialized_problem = Problem.deserialize(problem_msgs) self.assertEqual(len(deserialized_problem.terms), 12) self.assertEqual(deserialized_problem.problem_type, ProblemType.pubo) self.assertEqual(deserialized_problem.name, problem.name)
def createFBP_factored(weights: List[int]) -> Problem: # Construct the factored form terms = [ SlcTerm(c=1, terms=[ Term(c=weights[i], indices=[i]) for i in range(len(weights)) ]) ] # Return an Ising-type problem return Problem(name="Freight Balancing Problem", problem_type=ProblemType.ising, terms=terms)
def __test_upload_problem( self, count: int, terms_thresh: int, size_thresh: int, compress: bool, problem_type: ProblemType = ProblemType.ising, initial_terms: List[Term] = [], **kwargs ): ws = create_workspace() sProblem = StreamingProblem( ws, name="test", problem_type=problem_type, terms=initial_terms ) rProblem = Problem('test', problem_type=problem_type, terms=initial_terms) sProblem.upload_terms_threshold = terms_thresh sProblem.upload_size_threshold = size_thresh sProblem.compress = compress for i in range(count): sProblem.add_term(c = i, indices = [i, i+1]) rProblem.add_term(c = i, indices = [i, i+1]) self.assertEqual(problem_type, sProblem.problem_type) self.assertEqual(problem_type.name, sProblem.stats['type']) self.assertEqual(count + len(initial_terms), sProblem.stats['num_terms']) self.assertEqual(self.__kwarg_or_value(kwargs, 'avg_coupling', 2), sProblem.stats['avg_coupling']) self.assertEqual(self.__kwarg_or_value(kwargs, 'max_coupling', 2), sProblem.stats['max_coupling']) self.assertEqual(self.__kwarg_or_value(kwargs, 'min_coupling', 2), sProblem.stats['min_coupling']) uri = sProblem.upload(ws) uploaded = json.loads(sProblem.download().serialize()) local = json.loads(rProblem.serialize()) self.assertEqual(uploaded, local)
def createProblem(self): terms: List[Term] = [] for i in range(len(self.mineralWeights)): for j in range(len(self.mineralWeights)): if i == j: # Skip the terms where i == j as they form constant terms in an Ising problem and can be disregarded. continue terms.append( Term(c=self.mineralWeights[i] * self.mineralWeights[j], indices=[i, j])) self.problem = Problem(name="Balancing Problem", problem_type=ProblemType.ising, terms=terms)
def create_simplified_problem_for_container_weights( container_weights: List[int]) -> Problem: terms: List[Term] = [] # Expand the squared summation for i in range(len(container_weights) - 1): for j in range(i + 1, len(container_weights)): terms.append( Term(c=container_weights[i] * container_weights[j], indices=[i, j])) # Return an Ising-type problem return Problem(name="Ship Sample Problem (Simplified)", problem_type=ProblemType.ising, terms=terms)
def test_provide_cterms(self): count = 4 terms = [] for i in range(count): terms.append(Term(c=i, indices=[i, i + 1])) terms.append( SlcTerm([Term(c=i / 2, indices=[i + 2]) for i in range(count)] + [Term(c=5, indices=[])], c=1)) problem = Problem(name="test", terms=terms, problem_type=ProblemType.pubo) self.assertEqual(ProblemType.pubo_grouped, problem.problem_type) self.assertEqual(count, len(problem.terms)) self.assertEqual(1, len(problem.terms_slc)) self.assertEqual(Term(c=1, indices=[1, 2]), problem.terms[1])
def create_problem_for_container_weights( container_weights: List[int]) -> Problem: terms: List[Term] = [] # Expand the squared summation for i in range(len(container_weights)): for j in range(len(container_weights)): if i == j: # Skip the terms where i == j as they form constant terms in an Ising problem and can be disregarded: # w_i∗w_j∗x_i∗x_j = w_i*w_j∗(x_i)^2 = w_i∗w_j # for x_i = x_j, x_i ∈ {1, -1} continue terms.append( Term(c=container_weights[i] * container_weights[j], indices=[i, j])) # Return an Ising-type problem return Problem(name="Ship Sample Problem", problem_type=ProblemType.ising, terms=terms)