def test_submit_continue_then_ok_reply(self):
        """Handle polling for a complete problem."""

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda a, _: choose_reply(
                a, {'problems/': [self.sapi.continue_reply(id='123')]})
            session.get = lambda a: choose_reply(
                a, {
                    'problems/?id=123':
                    [self.sapi.complete_no_answer_reply(id='123')],
                    'problems/123/':
                    self.sapi.complete_reply(id='123')
                })
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem
                params = dict(num_reads=100)
                results = solver.sample_ising(linear, quadratic, **params)

                self._check(results, linear, quadratic, **params)
    def test_submit_immediate_error_reply(self):
        """Handle an (obvious) error on problem submission."""

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda a, _: choose_reply(
                a, {
                    'problems/': [
                        self.sapi.immediate_error_reply(
                            code=400,
                            msg="Missing parameter 'num_reads' in problem JSON"
                        )
                    ]
                })
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem
                results = solver.sample_ising(linear, quadratic)

                with self.assertRaises(SolverFailureError):
                    results.samples
    def test_submit_offset_answer_does_not_include_it(self):
        """Handle a normal query with offset and response that doesn't include it."""

        # ising problem energy offset
        offset = 3

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda a, _: choose_reply(a, {
                'problems/': [self.sapi.complete_no_answer_reply(id='123')]
            })
            session.get = lambda a: choose_reply(
                a, {'problems/123/': self.sapi.complete_reply(id='123')})
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem
                params = dict(num_reads=100)
                results = solver.sample_ising(linear, quadratic, offset,
                                              **params)

                # although SAPI response doesn't include offset, Future should patch it on-the-fly
                self._check(results,
                            linear,
                            quadratic,
                            offset=offset,
                            **params)
    def test_immediate_polling_with_local_clock_unsynced(self):
        """First poll happens with minimal delay if local clock is way off from
        the remote/server clock."""

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            badnow = utcrel(100)
            session = mock.Mock()
            session.post = lambda path, _: choose_reply(
                path, {'problems/': [self.sapi.continue_reply(id='1')]},
                date=badnow)
            session.get = lambda path: choose_reply(path, {
                'problems/?id=1': [self.sapi.complete_no_answer_reply(id='1')],
                'problems/1/':
                self.sapi.complete_reply(id='1')
            },
                                                    date=badnow)
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                def assert_no_delay(s):
                    s and self.assertTrue(
                        abs(s - client.poll_backoff_min) <
                        client.DEFAULTS['poll_backoff_min'])

                with mock.patch('time.sleep', assert_no_delay):
                    future = solver.sample_qubo({})
                    future.result()
    def test_immediate_polling(self):
        "First poll happens with minimal delay"

        # each thread can have its instance of a session because
        # responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda path, _: choose_reply(
                path, {'problems/': [self.sapi.continue_reply(id='1')]})
            session.get = lambda path: choose_reply(
                path, {
                    'problems/?id=1':
                    [self.sapi.complete_no_answer_reply(id='1')],
                    'problems/1/': self.sapi.complete_reply(id='1')
                })
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client(endpoint='endpoint', token='token') as client:
                solver = Solver(client, self.sapi.solver.data)

                def assert_no_delay(s):
                    s and self.assertTrue(
                        abs(s - client.poll_backoff_min) <
                        client.DEFAULTS['poll_backoff_min'])

                with mock.patch('time.sleep', assert_no_delay):
                    future = solver.sample_qubo({})
                    future.result()
    def test_deprecations(self):
        """Proper deprecation warnings are raised."""
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda a, _: choose_reply(a, {
                'problems/': [self.sapi.complete_no_answer_reply(id='123')]
            })
            session.get = lambda a: choose_reply(
                a, {'problems/123/': self.sapi.complete_reply(id='123')})
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem
                params = dict(num_reads=100)
                results = solver.sample_ising(linear, quadratic, **params)

                # aliased keys are deprecated in 0.8.0
                with self.assertWarns(DeprecationWarning):
                    results['samples']
                with self.assertWarns(DeprecationWarning):
                    results['occurrences']

                # .error is deprecated in 0.7.x, scheduled for removal in 0.9.0
                with self.assertWarns(DeprecationWarning):
                    results.error

                # .occurrences is deprecated in 0.8.0, scheduled for removal in 0.10.0+
                with self.assertWarns(DeprecationWarning):
                    results.occurrences
Beispiel #7
0
    def setUp(self):
        # mock client
        self.client = Client(token='token', solver={'qpu': True})
        self.client._fetch_solvers = lambda **kw: self.solvers
        self.client._submit = lambda *pa, **kw: None

        # mock solvers
        self.solver = Solver(client=self.client,
                             data={
                                 "properties": {
                                     "supported_problem_types":
                                     ["qubo", "ising"],
                                     "qubits": [0, 1, 2],
                                     "couplers": [[0, 1], [0, 2], [1, 2]],
                                     "num_qubits": 3,
                                     "num_reads_range": [0, 100],
                                     "parameters": {
                                         "num_reads":
                                         "Number of samples to return.",
                                         "postprocess":
                                         "either 'sampling' or 'optimization'"
                                     },
                                     "topology": {
                                         "type": "chimera",
                                         "shape": [16, 16, 4]
                                     },
                                     "category": "qpu",
                                     "tags": ["lower_noise"]
                                 },
                                 "id": "solver1",
                                 "description": "A test solver 1",
                                 "status": "online"
                             })
        self.solvers = [self.solver]
    def test_submit_bqm_ising_ok_reply(self):
        """Handle a normal query and response."""

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda a, _: choose_reply(a, {
                'problems/': [self.sapi.complete_no_answer_reply(id='123')]
            })
            session.get = lambda a: choose_reply(
                a, {'problems/123/': self.sapi.complete_reply(id='123')})
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                h, J = self.sapi.problem
                bqm = dimod.BinaryQuadraticModel.from_ising(h, J)

                params = dict(num_reads=100)
                results = solver.sample_bqm(bqm, **params)

                self._check(results, h, J, **params)
    def test_answer_load_error(self):
        """Answer load error is propagated as exception."""

        error_code = 404
        error_message = 'Problem not found'

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda path, _: choose_reply(
                path,
                {'problems/': [self.sapi.complete_no_answer_reply(id='123')]})
            session.get = lambda path: choose_reply(
                path,
                replies={'problems/123/': error_message},
                statuses={'problems/123/': iter([error_code])})
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem
                future = solver.sample_ising(linear, quadratic)

                with self.assertRaises(SolverError) as exc:
                    future.result()

                self.assertEqual(str(exc.exception), error_message)
Beispiel #10
0
    def setUp(self):
        # mock solvers
        self.solver1 = Solver(client=None, data={
            "properties": {
                "supported_problem_types": ["qubo", "ising"],
                "qubits": [0, 1, 2],
                "couplers": [[0, 1], [0, 2], [1, 2]],
                "num_qubits": 3,
                "num_reads_range": [0, 100],
                "parameters": {
                    "num_reads": "Number of samples to return.",
                    "postprocess": "either 'sampling' or 'optimization'"
                }
            },
            "id": "solver1",
            "description": "A test solver 1",
            "status": "online"
        })
        self.solver2 = Solver(client=None, data={
            "properties": {
                "supported_problem_types": ["qubo", "ising"],
                "qubits": [0, 1, 2, 3, 4],
                "couplers": [[0, 1], [0, 2], [1, 2], [2, 3], [3, 4]],
                "num_qubits": 5,
                "num_reads_range": [0, 200],
                "parameters": {
                    "num_reads": "Number of samples to return.",
                    "flux_biases": "Supported ...",
                    "anneal_schedule": "Supported ..."
                },
                "vfyc": True
            },
            "id": "solver2",
            "description": "A test solver 2"
        })
        self.solver3 = Solver(client=None, data={
            "properties": {
                "supported_problem_types": ["qubo", "ising"],
                "qubits": [0, 1],
                "couplers": [[0, 1]],
                "num_qubits": 7,
                "num_reads_range": [0, 1000],
                "parameters": {"num_reads": "Number of samples to return."},
                "vfyc": False,
                # the following are only present in this solver
                "some_set": [1, 2],
                "some_range": [1, 2],
                "some_string": "x"
            },
            "id": "c4-sw_solver3",
            "description": "A test of software solver",
            "avg_load": 0.7
        })
        self.solvers = [self.solver1, self.solver2, self.solver3]

        # mock client
        self.client = Client('endpoint', 'token')
        self.client._fetch_solvers = lambda **kw: self.solvers
    def test_polling_recovery_after_5xx(self):
        "Polling shouldn't be aborted on 5xx responses."

        # we need a "global session", because mocked responses are stateful
        def global_mock_session():
            session = mock.Mock()

            # on submit, return status pending
            session.post = lambda path, _: choose_reply(
                path, {'problems/': [self.sapi.continue_reply(id='123')]})

            # on first and second status poll, fail with 503 and 504
            # on third status poll, return completed
            statuses = iter([503, 504])

            def continue_then_complete(path, state={'count': 0}):
                state['count'] += 1
                if state['count'] < 3:
                    return choose_reply(
                        path,
                        replies={
                            'problems/?id=123':
                            [self.sapi.continue_reply(id='123')],
                            'problems/123/':
                            self.sapi.continue_reply(id='123')
                        },
                        statuses={
                            'problems/?id=123': statuses,
                            'problems/123/': statuses
                        })
                else:
                    return choose_reply(
                        path, {
                            'problems/?id=123':
                            [self.sapi.complete_no_answer_reply(id='123')],
                            'problems/123/':
                            self.sapi.complete_reply(id='123')
                        })

            session.get = continue_then_complete

            return session

        session = global_mock_session()

        with mock.patch.object(Client, 'create_session', lambda self: session):
            with Client(endpoint='endpoint', token='token') as client:
                solver = Solver(client, self.sapi.solver.data)

                future = solver.sample_qubo({})
                future.result()

                # after third poll, back-off interval should be 4 x initial back-off
                self.assertAlmostEqual(
                    future._poll_backoff,
                    client.poll_backoff_min * client.poll_backoff_base**2)
Beispiel #12
0
    def setUp(self):
        # mock solvers
        self.solver1 = Solver(client=None,
                              data={
                                  "properties": {
                                      "supported_problem_types":
                                      ["qubo", "ising"],
                                      "qubits": [0, 1, 2],
                                      "couplers": [[0, 1], [0, 2], [1, 2]],
                                      "num_qubits": 3,
                                      "parameters": {
                                          "num_reads":
                                          "Number of samples to return."
                                      }
                                  },
                                  "id": "solver1",
                                  "description": "A test solver 1",
                                  "status": "online"
                              })
        self.solver2 = Solver(client=None,
                              data={
                                  "properties": {
                                      "supported_problem_types":
                                      ["qubo", "ising"],
                                      "qubits": [0, 1, 2, 3, 4],
                                      "couplers": [[0, 1], [0, 2], [1, 2],
                                                   [2, 3], [3, 4]],
                                      "num_qubits":
                                      5,
                                      "parameters": {
                                          "num_reads":
                                          "Number of samples to return.",
                                          "flux_biases": "Supported ..."
                                      },
                                      "vfyc":
                                      True
                                  },
                                  "id": "solver2",
                                  "description": "A test solver 2"
                              })
        self.solvers = [self.solver1, self.solver2]

        # mock client
        self.client = Client('endpoint', 'token')
        self.client._solvers = {
            self.solver1.id: self.solver1,
            self.solver2.id: self.solver2
        }
        self.client._all_solvers_ready = True
    def test_exponential_backoff_polling(self):
        "After each poll, back-off should double"

        # we need a "global session", because mocked responses are stateful
        def global_mock_session():
            session = mock.Mock()

            # on submit, return status pending
            session.post = lambda path, _: choose_reply(
                path, {'problems/': [self.sapi.continue_reply(id='123')]})

            # on first and second status poll, return pending
            # on third status poll, return completed
            def continue_then_complete(path, state={'count': 0}):
                state['count'] += 1
                if state['count'] < 3:
                    return choose_reply(
                        path, {
                            'problems/?id=123':
                            [self.sapi.continue_reply(id='123')],
                            'problems/123/':
                            self.sapi.continue_reply(id='123')
                        })
                else:
                    return choose_reply(
                        path, {
                            'problems/?id=123':
                            [self.sapi.complete_no_answer_reply(id='123')],
                            'problems/123/':
                            self.sapi.complete_reply(id='123')
                        })

            session.get = continue_then_complete

            return session

        session = global_mock_session()

        with mock.patch.object(Client, 'create_session', lambda self: session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                future = solver.sample_qubo({})
                future.result()

                # after third poll, back-off interval should be 4 x initial back-off
                self.assertEqual(future._poll_backoff,
                                 client.poll_backoff_min * 2**2)
    def test_cancel_without_id(self):
        """Make sure the cancel method submits to the right endpoint.

        When cancel is called before the submission has returned the problem id.
        """
        submission_id = 'test-id'
        release_reply = threading.Event()

        # each thread can have its instance of a session because
        # we use a global lock (event) in the mocked responses
        def create_mock_session(client):
            reply_body = [self.sapi.continue_reply(id=submission_id)]

            session = mock.Mock()
            session.get = lambda a: choose_reply(
                a, {'problems/?id={}'.format(submission_id): reply_body})

            def post(a, _):
                release_reply.wait()
                return choose_reply(a, {'problems/': reply_body})

            session.post = post
            session.delete = DeleteEvent.handle

            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem

                future = solver.sample_ising(linear, quadratic)
                future.cancel()

                try:
                    release_reply.set()
                    future.samples
                    self.fail()
                except DeleteEvent as event:
                    if event.url == 'problems/':
                        self.assertEqual(event.body,
                                         '["{}"]'.format(submission_id))
                    else:
                        self.assertEqual(event.url,
                                         'problems/{}/'.format(submission_id))
    def test_submit_null_reply(self):
        """Get an error when the server's response is incomplete."""

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda a, _: choose_reply(a, {'problems/': ''})
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem
                results = solver.sample_ising(linear, quadratic)

                with self.assertRaises(InvalidAPIResponseError):
                    results.samples
    def test_solver_feature_properties(self):
        self.assertTrue(solver_object('solver', 'qpu').qpu)
        self.assertTrue(solver_object('solver', 'QPU').qpu)
        self.assertFalse(solver_object('solver', 'qpu').software)
        self.assertFalse(solver_object('solver', 'qpu').hybrid)
        self.assertFalse(solver_object('solver', 'software').qpu)
        self.assertTrue(solver_object('solver', 'software').software)
        self.assertFalse(solver_object('solver', 'software').hybrid)
        self.assertTrue(solver_object('solver', 'hybrid').hybrid)
        self.assertFalse(solver_object('solver', 'hybrid').qpu)
        self.assertFalse(solver_object('solver', 'hybrid').software)

        self.assertFalse(solver_object('solver').is_vfyc)
        self.assertEqual(solver_object('solver').num_qubits, 3)
        self.assertFalse(solver_object('solver').has_flux_biases)

        # test .num_qubits vs .num_actual_qubits
        data = structured_solver_data('test')
        data['properties']['num_qubits'] = 7
        solver = Solver(None, data)
        self.assertEqual(solver.num_qubits, 7)
        self.assertEqual(solver.num_active_qubits, 3)

        # test .is_vfyc
        data = structured_solver_data('test')
        data['properties']['vfyc'] = 'error'
        self.assertFalse(Solver(None, data).is_vfyc)
        data['properties']['vfyc'] = True
        self.assertTrue(Solver(None, data).is_vfyc)

        # test .has_flux_biases
        self.assertFalse(Solver(None, data).has_flux_biases)
        data['properties']['parameters']['flux_biases'] = '...'
        self.assertTrue(Solver(None, data).has_flux_biases)

        # test .has_anneal_schedule
        self.assertFalse(Solver(None, data).has_anneal_schedule)
        data['properties']['parameters']['anneal_schedule'] = '...'
        self.assertTrue(Solver(None, data).has_anneal_schedule)

        # test `.online` property
        self.assertTrue(solver_object('solver').online)
        data = structured_solver_data('test')
        data['status'] = 'offline'
        self.assertFalse(Solver(None, data).online)
        del data['status']
        self.assertTrue(Solver(None, data).online)
    def test_submit_cancel_reply(self):
        """Handle a response for a canceled job."""

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda a, _: choose_reply(
                a, {'problems/': [self.sapi.cancel_reply()]})
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem
                results = solver.sample_ising(linear, quadratic)

                with self.assertRaises(CanceledFutureError):
                    results.samples
    def test_submit_bqm_qubo_ok_reply(self):
        """Handle a normal query and response."""

        qubo_msg_diff = dict(type="qubo")
        qubo_answer_diff = {
            'energies': 'AAAAAAAAAAA=',
            'solutions': 'AA==',
            'active_variables': 'AAAAAAQAAAA='
        }

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda a, _: choose_reply(a, {
                'problems/': [self.sapi.complete_no_answer_reply(id='123')]
            })
            session.get = lambda a: choose_reply(
                a, {
                    'problems/123/':
                    self.sapi.complete_reply(id='123',
                                             answer_patch=qubo_answer_diff,
                                             **qubo_msg_diff)
                })
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                qubo = {(0, 0): 4.0, (0, 4): -4, (4, 4): 4.0}
                offset = -2.0
                params = dict(num_reads=100)

                results = solver.sample_qubo(qubo, offset, **params)

                # make sure energies are correct in raw results
                for energy, sample in zip(results.energies, results.samples):
                    self.assertEqual(
                        energy, evaluate_ising({}, qubo, sample,
                                               offset=offset))
    def test_id_integration(self):
        """Problem ID getter blocks correctly when ID set by the client."""

        submission_id = 'test-id'
        solver_name = 'solver-id'
        release_reply = threading.Event()

        # each thread can have its instance of a session because
        # we use a global lock (event) in the mocked responses
        def create_mock_session(client):
            session = mock.Mock()

            # delayed submit; emulates waiting in queue
            def post(path, _):
                release_reply.wait()
                reply_body = self.sapi.complete_reply(id=submission_id,
                                                      solver=solver_name)
                return choose_reply(path, {'problems/': [reply_body]})

            session.post = post

            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem

                future = solver.sample_ising(linear, quadratic)

                # initially, the id is not available
                with self.assertRaises(TimeoutError):
                    future.wait_id(timeout=1)

                # release the mocked sapi reply with the id
                release_reply.set()

                # verify the id is now available
                self.assertEqual(future.wait_id(), submission_id)
Beispiel #20
0
    def get_solvers(self, refresh=False):
        """List all the solvers this client can provide, and load the data
        about the solvers.

        This is a blocking web call to `{endpoint}/solvers/remote/`` that
        caches the result and populates a list of available solvers described
        through :class:`.Solver` instances.

        To submit a sampling problem to the D-Wave API, filter the list returned
        and execute a ``sampling_*`` method on the solver of interest.
        Alternatively, if you know the solver name (or it's defined in config),
        use the :meth:`.get_solver` method.

        Args:
            refresh (bool, default=False):
                By default, ``get_solvers`` caches the list of solvers it
                receives from the API. Use this parameter to force refresh.

        Returns:
            dict[id, solver]: a mapping of solver name/id to :class:`.Solver`
        """
        with self._solvers_lock:
            if self._all_solvers_ready and not refresh:
                return self._solvers

            _LOGGER.debug("Requesting list of all solver data.")
            response = self.session.get(
                posixpath.join(self.endpoint, 'solvers/remote/'))

            if response.status_code == 401:
                raise SolverAuthenticationError
            response.raise_for_status()

            _LOGGER.debug("Received list of all solver data.")
            data = response.json()

            for solver_desc in data:
                try:
                    solver = Solver(self, solver_desc)
                    if self.is_solver_handled(solver):
                        self._solvers[solver.id] = solver
                        _LOGGER.debug("Adding solver %r", solver)
                    else:
                        _LOGGER.debug(
                            "Skipping solver %r inappropriate for client",
                            solver)

                except UnsupportedSolverError as e:
                    _LOGGER.debug("Skipping solver due to %r", e)

            self._all_solvers_ready = True
            return self._solvers
    def test_submit_offset_wrong_offset_in_answer(self):
        """Energy levels don't match because offset in answer is respected, even if wrong"""

        # ising problem energy offset
        offset = 3
        answer_offset = 2 * offset  # make it wrong

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            session.post = lambda a, _: choose_reply(a, {
                'problems/': [self.sapi.complete_no_answer_reply(id='123')]
            })
            session.get = lambda a: choose_reply(
                a, {
                    'problems/123/':
                    self.sapi.complete_reply(
                        id='123', answer_patch=dict(offset=answer_offset))
                })
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem
                params = dict(num_reads=100)
                results = solver.sample_ising(linear, quadratic, offset,
                                              **params)

                # since SAPI response includes offset, Future shouldn't patch it;
                # but because the offset in answer is wrong, energies are off
                with self.assertRaises(AssertionError):
                    self._check(results,
                                linear,
                                quadratic,
                                offset=offset,
                                **params)
Beispiel #22
0
    def get_solver(self, name=None, refresh=False):
        """Load the configuration for a single solver, as publicized by the API
        on ``{endpoint}/solvers/remote/{solver_name}/``.

        This is a blocking web call that returns a :class:`.Solver` instance,
        which in turn can be used to submit sampling problems to the D-Wave API
        and fetch the results.

        Args:
            name (str):
                Id of the requested solver. ``None`` will return the default solver.

            refresh (bool):
                Return solver from cache (if cached with ``get_solvers()``),
                unless set to ``True``.

        Returns:
            :class:`.Solver`
        """
        _LOGGER.debug("Looking for solver: %s", name)
        if name is None:
            if self.default_solver:
                name = self.default_solver
            else:
                raise ValueError(
                    "No name or default name provided when loading solver.")

        with self._solvers_lock:
            if refresh or name not in self._solvers:
                response = self.session.get(
                    posixpath.join(self.endpoint,
                                   'solvers/remote/{}/'.format(name)))

                if response.status_code == 401:
                    raise SolverAuthenticationError

                if response.status_code == 404:
                    raise KeyError(
                        "No solver with the name {} was available".format(
                            name))

                response.raise_for_status()

                solver = Solver(self, data=response.json())
                if solver.id != name:
                    raise InvalidAPIResponseError(
                        "Asked for solver named {!r}, got {!r}".format(
                            name, solver.id))
                self._solvers[name] = solver

            return self._solvers[name]
    def test_cancel_with_id(self):
        """Make sure the cancel method submits to the right endpoint.

        When cancel is called after the submission is finished.
        """
        submission_id = 'test-id'

        # each thread can have its instance of a session because
        # the mocked responses are stateless
        def create_mock_session(client):
            session = mock.Mock()
            reply_body = [
                self.sapi.continue_reply(id=submission_id, solver='solver')
            ]
            session.get = lambda a: choose_reply(
                a, {'problems/?id={}'.format(submission_id): reply_body})
            session.delete = DeleteEvent.handle
            return session

        with mock.patch.object(Client, 'create_session', create_mock_session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)
                future = solver._retrieve_problem(submission_id)
                future.cancel()

                try:
                    self.assertTrue(future.id is not None)
                    future.samples
                    self.fail()
                except DeleteEvent as event:
                    if event.url == 'problems/':
                        self.assertEqual(event.body,
                                         '["{}"]'.format(submission_id))
                    else:
                        self.assertEqual(event.url,
                                         'problems/{}/'.format(submission_id))
Beispiel #24
0
    def get_solver(self, name=None, refresh=False):
        """Load the configuration for a single solver.

        To get specific solver data: ``GET /solvers/remote/{solver_name}/``

        Args:
            name (str):
                Id of the requested solver. `None` will return the default solver.

            refresh (bool):
                Return solver from cache (if cached with ``get_solvers()``),
                unless set to `True`.

        Returns:
            :class:`.Solver`
        """
        _LOGGER.debug("Looking for solver: %s", name)
        if name is None:
            if self.default_solver is not None:
                name = self.default_solver
            else:
                raise ValueError(
                    "No name or default name provided when loading solver.")

        with self._solvers_lock:
            if refresh or name not in self._solvers:
                response = self.session.get(
                    posixpath.join(self.endpoint,
                                   'solvers/remote/{}/'.format(name)))

                if response.status_code == 401:
                    raise SolverAuthenticationError

                if response.status_code == 404:
                    raise KeyError(
                        "No solver with the name {} was available".format(
                            name))

                response.raise_for_status()

                solver = Solver(self, data=response.json())
                if solver.id != name:
                    raise InvalidAPIResponseError(
                        "Asked for solver named {!r}, got {!r}".format(
                            name, solver.id))
                self._solvers[name] = solver

            return self._solvers[name]
    def test_label_is_sent(self, name, label):
        """Problem label is set on problem submit."""

        with Client('endpoint', 'token') as client:
            solver = Solver(client, self.sapi.solver.data)
            problems = self.generate_sample_problems(solver)

            for method_name, problem_args in problems:
                with self.subTest(method_name=method_name):
                    sample = getattr(solver, method_name)

                    with mock.patch.object(
                            Client, '_submit',
                            self.on_submit_label_verifier(label)):

                        with self.assertRaises(self.PrimaryAssertionSatisfied):
                            sample(*problem_args, label=label).result()
Beispiel #26
0
    def get_solvers(self, refresh=False):
        """List all the solvers this connection can provide,
        and load the data about the solvers.

        To get all solver data: ``GET /solvers/remote/``

        Args:
            refresh (bool, default=False):
                By default, ``get_solvers`` caches the list of solvers it
                receives from the API. Use this parameter to force refresh.

        Returns:
            dict[id, solver]: a mapping of solver name/id to :class:`.Solver`
        """
        with self._solvers_lock:
            if self._all_solvers_ready and not refresh:
                return self._solvers

            _LOGGER.debug("Requesting list of all solver data.")
            response = self.session.get(
                posixpath.join(self.endpoint, 'solvers/remote/'))

            if response.status_code == 401:
                raise SolverAuthenticationError
            response.raise_for_status()

            _LOGGER.debug("Received list of all solver data.")
            data = response.json()

            for solver_desc in data:
                try:
                    solver = Solver(self, solver_desc)
                    if self.is_solver_handled(solver):
                        self._solvers[solver.id] = solver
                        _LOGGER.debug("Adding solver %r", solver)
                    else:
                        _LOGGER.debug(
                            "Skipping solver %r inappropriate for client",
                            solver)

                except UnsupportedSolverError as e:
                    _LOGGER.debug("Skipping solver due to %r", e)

            self._all_solvers_ready = True
            return self._solvers
    def test_label_is_received(self, name, label):
        """Problem label is set from response in result/sampleset."""
        def make_session_generator(label):
            def create_mock_session(client):
                session = mock.Mock()
                session.post = lambda a, _: choose_reply(
                    a, {
                        'problems/': [
                            self.sapi.complete_no_answer_reply(id='123',
                                                               label=None)
                        ]
                    })
                session.get = lambda a: choose_reply(
                    a, {
                        'problems/123/':
                        self.sapi.complete_reply(id='123', label=label)
                    })
                return session

            return create_mock_session

        with mock.patch.object(Client, 'create_session',
                               make_session_generator(label)):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)
                problems = self.generate_sample_problems(solver)

                for method_name, problem_args in problems:
                    with self.subTest(method_name=method_name):
                        sample = getattr(solver, method_name)

                        future = sample(*problem_args, label=label)
                        future.result()  # ensure future is resolved

                        self.assertEqual(future.label, label)

                        # sampleset will only be available if dimod is installed
                        if dimod:
                            info = future.sampleset.info
                            self.assertEqual(info.get('problem_label'), label)
Beispiel #28
0
class TestEventDispatch(unittest.TestCase):
    def setUp(self):
        # mock client
        self.client = Client(token='token', solver={'qpu': True})
        self.client._fetch_solvers = lambda **kw: self.solvers
        self.client._submit = lambda *pa, **kw: None

        # mock solvers
        self.solver = Solver(client=self.client,
                             data={
                                 "properties": {
                                     "supported_problem_types":
                                     ["qubo", "ising"],
                                     "qubits": [0, 1, 2],
                                     "couplers": [[0, 1], [0, 2], [1, 2]],
                                     "num_qubits": 3,
                                     "num_reads_range": [0, 100],
                                     "parameters": {
                                         "num_reads":
                                         "Number of samples to return.",
                                         "postprocess":
                                         "either 'sampling' or 'optimization'"
                                     },
                                     "topology": {
                                         "type": "chimera",
                                         "shape": [16, 16, 4]
                                     },
                                     "category": "qpu",
                                     "tags": ["lower_noise"]
                                 },
                                 "id": "solver1",
                                 "description": "A test solver 1",
                                 "status": "online"
                             })
        self.solvers = [self.solver]

    def test_validation(self):
        """Event name and handler are validated."""

        with self.assertRaises(ValueError):
            add_handler('invalid_event_name', lambda: None)
        with self.assertRaises(TypeError):
            add_handler('before_client_init', None)

    def test_client_init(self):
        """Before/After client init events are dispatched with correct signatures."""

        # setup event handlers
        memo = {}

        def handler(event, **data):
            memo[event] = data

        add_handler('before_client_init', handler)
        add_handler('after_client_init', handler)

        # client init
        client = Client(token='token', unknown='unknown')

        # test entry values
        before = memo['before_client_init']
        self.assertEqual(before['obj'], client)
        self.assertEqual(before['args']['endpoint'], None)
        self.assertEqual(before['args']['token'], 'token')
        self.assertEqual(before['args']['kwargs']['unknown'], 'unknown')

        # test exit values
        after = memo['after_client_init']
        self.assertEqual(after['obj'], client)
        self.assertEqual(after['args']['token'], 'token')
        self.assertEqual(after['args']['kwargs']['unknown'], 'unknown')
        self.assertEqual(after['return_value'], None)

    def test_get_solvers(self):
        """Before/After get_solvers events are dispatched with correct signatures."""

        # setup event handlers
        memo = {}

        def handler(event, **data):
            memo[event] = data

        add_handler('before_get_solvers', handler)
        add_handler('after_get_solvers', handler)

        # get solver(s)
        self.client.get_solver()

        # test entry values
        before = memo['before_get_solvers']
        self.assertEqual(before['obj'], self.client)
        self.assertIn('refresh', before['args'])
        self.assertIn('filters', before['args'])
        self.assertIn('qpu', before['args']['filters'])

        # test exit values
        after = memo['after_get_solvers']
        self.assertEqual(after['obj'], self.client)
        self.assertIn('qpu', after['args']['filters'])
        self.assertEqual(after['return_value'], self.solvers)

    def test_sample(self):
        """Before/After solver sample events are dispatched with correct signatures."""

        # setup event handlers
        memo = {}

        def handler(event, **data):
            memo[event] = data

        add_handler('before_sample', handler)
        add_handler('after_sample', handler)

        # sample
        lin = {0: 1}
        quad = {(0, 1): 1}
        offset = 2
        params = dict(num_reads=100)
        future = self.solver.sample_ising(lin, quad, offset, **params)

        # test entry values
        before = memo['before_sample']
        args = dict(type_='ising',
                    linear=lin,
                    quadratic=quad,
                    offset=offset,
                    params=params,
                    undirected_biases=False)
        self.assertEqual(before['obj'], self.solver)
        self.assertDictEqual(before['args'], args)

        # test exit values
        after = memo['after_sample']
        self.assertEqual(after['obj'], self.solver)
        self.assertDictEqual(after['args'], args)
        self.assertEqual(after['return_value'], future)
def solver_object(id_, cat='qpu', incomplete=False):
    return Solver(client=None,
                  data=structured_solver_data(id_, cat, incomplete))
    def test_submit_continue_then_ok_and_error_reply(self):
        """Handle polling for the status of multiple problems."""

        # we need a "global session", because mocked responses are stateful
        def global_mock_session():
            session = mock.Mock()

            # on first status poll, return pending for both problems
            # on second status poll, return error for first problem and complete for second
            def continue_then_complete(path, state={'count': 0}):
                state['count'] += 1
                if state['count'] < 2:
                    return choose_reply(
                        path, {
                            'problems/?id=1':
                            [self.sapi.continue_reply(id='1')],
                            'problems/?id=2':
                            [self.sapi.continue_reply(id='2')],
                            'problems/1/':
                            self.sapi.continue_reply(id='1'),
                            'problems/2/':
                            self.sapi.continue_reply(id='2'),
                            'problems/?id=1,2': [
                                self.sapi.continue_reply(id='1'),
                                self.sapi.continue_reply(id='2')
                            ],
                            'problems/?id=2,1': [
                                self.sapi.continue_reply(id='2'),
                                self.sapi.continue_reply(id='1')
                            ]
                        })
                else:
                    return choose_reply(
                        path, {
                            'problems/?id=1': [self.sapi.error_reply(id='1')],
                            'problems/?id=2':
                            [self.sapi.complete_no_answer_reply(id='2')],
                            'problems/1/':
                            self.sapi.error_reply(id='1'),
                            'problems/2/':
                            self.sapi.complete_reply(id='2'),
                            'problems/?id=1,2': [
                                self.sapi.error_reply(id='1'),
                                self.sapi.complete_no_answer_reply(id='2')
                            ],
                            'problems/?id=2,1': [
                                self.sapi.complete_no_answer_reply(id='2'),
                                self.sapi.error_reply(id='1')
                            ]
                        })

            def accept_problems_with_continue_reply(path, body,
                                                    ids=iter('12')):
                problems = json.loads(body)
                return choose_reply(
                    path, {
                        'problems/': [
                            self.sapi.continue_reply(id=next(ids))
                            for _ in problems
                        ]
                    })

            session.get = continue_then_complete
            session.post = accept_problems_with_continue_reply

            return session

        session = global_mock_session()

        with mock.patch.object(Client, 'create_session', lambda self: session):
            with Client('endpoint', 'token') as client:
                solver = Solver(client, self.sapi.solver.data)

                linear, quadratic = self.sapi.problem
                params = dict(num_reads=100)

                results1 = solver.sample_ising(linear, quadratic, **params)
                results2 = solver.sample_ising(linear, quadratic, **params)

                with self.assertRaises(SolverFailureError):
                    self._check(results1, linear, quadratic, **params)
                self._check(results2, linear, quadratic, **params)