Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature expansion and bug-fix #537

Merged
merged 43 commits into from
Oct 15, 2024
Merged

Conversation

AndyZzzZzzZzz
Copy link
Contributor

@AndyZzzZzzZzz AndyZzzZzzZzz commented Sep 19, 2024

Feature Expansion:

  • Added an option to specify which sampler to use for MockDWaveSampler in testing.py.
  • If no sampler is specified, the script defaults to using SteepestDescentSampler.
  • Introduced an additional option to specify mocking_sampler_params if the user decides to use a different sampler.

Tests:

  • Added two new tests in test_mock_sampler.py:
    1. 'test_custom_mock_sampler' to verify that the script successfully switches between samplers.
    2. 'test_mocking_sampler_params' to ensure that the script correctly accepts and processes substitute mocking sampler parameters.

Bug Fixes:

  • Fixed the calculation of the number of qubits for Pegasus topology (missing property that triggers an error when running tests locally).
  • Changed mock_parameters, substitute_sampler, and substitute_kwargs from class attributes to instance attributes to ensure instance independence.
  • Created a local variable for substitute_kwarg in the sample function to ensure that each sample gets its own copy.

@arcondello
Copy link
Member

Hi @AndyZzzZzzZzz looks like you accidentally included some extra files, including your whole virtual environment, in the commit.

Copy link

codecov bot commented Sep 19, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 86.83%. Comparing base (60a4e4b) to head (a064358).
Report is 4 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #537      +/-   ##
==========================================
- Coverage   89.66%   86.83%   -2.84%     
==========================================
  Files          24       24              
  Lines        1761     1777      +16     
==========================================
- Hits         1579     1543      -36     
- Misses        182      234      +52     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@kevinchern
Copy link
Contributor

please add me and @jackraymond to reviewer

Copy link
Contributor

@kevinchern kevinchern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.gitignore Show resolved Hide resolved
dwave/system/testing.py Outdated Show resolved Hide resolved
dwave/system/testing.py Outdated Show resolved Hide resolved
dwave/system/testing.py Outdated Show resolved Hide resolved
dwave/system/testing.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Outdated Show resolved Hide resolved
custom_sampler = CustomSampler()

# Create a simple BQM
bqm = dimod.BQM({'a': -1, 'b': -1}, {('a', 'b'): -1}, 0.0, vartype='SPIN')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this problem size, the exact solver would be triggered. should override the default exact_solver_cutoff

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option is to return two samples (num_reads=2) and check the second sample. This might be simpler.

# Check that the sample returned is as expected from the custom sampler
expected_sample = {'a': 1, 'b': 1}
self.assertEqual(ss.first.sample, expected_sample)
self.assertEqual(ss.first.energy, bqm.energy(expected_sample))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these assertions will pass because they coincide with exact solver's solution

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be useful if the bqm is defined so that the unique solution to the bqm is a ground state. I am not sure this is true for your Hamiltonian. If greedy initial state is (-1,-1) then flipping either spin yields energy zero and steepest descent will return the answer, but it is not a ground state.
Furthermore, define your constant sampler to return an excited state, that way it is guaranteed to conflict with both ExactSolver and SteepestDescentSolver defaults.
I've recommended code changes to achieve these things.

self.assertEqual(ss.first.sample, expected_sample)
self.assertEqual(ss.first.energy, bqm.energy(expected_sample))

def test_mocking_sampler_params(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will review after the comment on whether sample should consume kwargs for the substitute sampler has been addressed

dwave/.DS_Store Outdated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😛

.gitignore Outdated Show resolved Hide resolved
@@ -366,7 +397,7 @@ def sample(self, bqm, **kwargs):
if pair[1]!=3],dtype=float),
[pair[0] for pair in initial_state if pair[1]!=3])

ss = SteepestDescentSampler().sample(bqm, **substitute_kwargs)
ss = self.substitute_sampler.sample(bqm, **substitute_kwargs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to document that for the first sample the substitution is ignored unless self.exact_solver_cutoff=0; i.e. for small problems the first sample is always a ground state. See comment in tests.

Copy link
Contributor

@jackraymond jackraymond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. One issue in the tests to address.

custom_sampler = CustomSampler()

# Create a simple BQM
bqm = dimod.BQM({'a': -1, 'b': -1}, {('a', 'b'): -1}, 0.0, vartype='SPIN')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option is to return two samples (num_reads=2) and check the second sample. This might be simpler.

# Check that the sample returned is as expected from the custom sampler
expected_sample = {'a': 1, 'b': 1}
self.assertEqual(ss.first.sample, expected_sample)
self.assertEqual(ss.first.energy, bqm.energy(expected_sample))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be useful if the bqm is defined so that the unique solution to the bqm is a ground state. I am not sure this is true for your Hamiltonian. If greedy initial state is (-1,-1) then flipping either spin yields energy zero and steepest descent will return the answer, but it is not a ground state.
Furthermore, define your constant sampler to return an excited state, that way it is guaranteed to conflict with both ExactSolver and SteepestDescentSolver defaults.
I've recommended code changes to achieve these things.

tests/test_mock_sampler.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Outdated Show resolved Hide resolved
dwave/system/testing.py Outdated Show resolved Hide resolved
`sample` method. This allows users to configure the substitute sampler
with specific parameters like `num_reads`, `initial_state`, or other
sampler-specific options. If not provided, an empty dictionary is used
by default.

exact_solver_cutoff (int, optional, default=:attr:`EXACT_SOLVER_CUTOFF_DEFAULT`):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, it would make sense that if substitute_sampler is provided then this setting is ignored and the substitute sampler is applied for all samples. We can add this clarification (afer code modification).

EXACT_SOLVER_CUTOFF_DEFAULT = 16

def __init__(self,
nodelist=None, edgelist=None, properties=None,
broken_nodes=None, broken_edges=None,
topology_type=None, topology_shape=None,
parameter_warnings=True,
substitute_sampler=None,
substitute_kwargs=None,
exact_solver_cutoff=EXACT_SOLVER_CUTOFF_DEFAULT,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this to None. See also comment on docstrings

if substitute_sampler is None:
          substitute_sampler = SteepestDescentSampler()
          if exact_solver_cutoff is None:
              exact_solver_cutoff = EXACT_SOLVER_CUTOFF_DEFAULT
  elif exact_solver_cutoff is None:
     exact_solver_cutoff = 0  # Always use substitute_sampler, never ExactSolver()

Copy link
Contributor

@jackraymond jackraymond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.
Someone @kevin should check my minor changes to test_mock_sampler.py just pushed.

Copy link
Contributor

@kevinchern kevinchern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- Add a release note, see dimod readme example. not used

  • Squash commits

LGTM otherwise

# use SteepestDescentSampler()
ss = sampler.sample(bqm, num_reads=2)
self.assertEqual(sampler.exact_solver_cutoff, 0)
self.assertEqual(ss.record.sample.shape, (1,2), 'Unique sample expected')
Copy link
Contributor

@kevinchern kevinchern Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.assertEqual(ss.record.sample.shape, (1,2), 'Unique sample expected')
self.assertEqual(ss.aggregate().record.sample.shape, (1,2), 'Unique sample expected')
Suggested change
self.assertEqual(ss.record.sample.shape, (1,2), 'Unique sample expected')

covered by other test cases

tests/test_mock_sampler.py Show resolved Hide resolved
Copy link
Contributor

@kevinchern kevinchern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@randomir could you take another look? This should be the draft_final_final; @jackraymond and I approve.

Copy link
Member

@randomir randomir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kwargs overwrite order should be fixed, but generally the code looks good (minus a few nits below).


P.S. since this PR organically extends the idea of exact solver fallback, that's fine, but the switching logic is becoming to look ugly and inelegant, so I think we should generalize it (in a follow-up PR; I'll make an issue).

dwave/system/testing.py Outdated Show resolved Hide resolved
dwave/system/testing.py Outdated Show resolved Hide resolved
dwave/system/testing.py Outdated Show resolved Hide resolved
dwave/system/testing.py Outdated Show resolved Hide resolved
dwave/system/testing.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Outdated Show resolved Hide resolved
tests/test_mock_sampler.py Show resolved Hide resolved
@randomir
Copy link
Member

I'm happy to merge this; would you like to take a final look, @arcondello?

Copy link
Member

@arcondello arcondello left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable to me

@randomir randomir merged commit 17b142a into dwavesystems:master Oct 15, 2024
21 checks passed
pau557 pushed a commit to pau557/dwave-system that referenced this pull request Nov 29, 2024
* WIP - added the option to switch sampler and relevant testing codes

* removed the flux biases code

* changed the initialization of mocking sampler from init to body

* simplified substitude_kwargs

* Fix num_qubits bug; raise mocked_parameters and dimod_sampler to class variable status

* Add missing property. Make substitute_kwargs a class variable.

* Minor corrections

* Revert change to support virtual graph composite

* num_qubits for pegasus fixed

* moved class attributes to instance attributes

* updated tests for mock dwave sampler

* Revert "updated tests for mock dwave sampler"

This reverts commit 89ade5f.

* created a local dictionary substitue_kwargs to ensure each instance of mock sampler has its own copies

* updated gitignore

* Update BQM definition to simplify variable weights

Co-authored-by: Jack Raymond <[email protected]>

* Replace single-read sample with num_reads=2 in MockDWaveSampler test

Co-authored-by: Jack Raymond <[email protected]>

* Update test to validate second sample state in MockDWaveSampler

Co-authored-by: Jack Raymond <[email protected]>

* Remove redundant energy check in MockDWaveSampler test

Co-authored-by: Jack Raymond <[email protected]>

* Removed redundant comments

* Polished formatting and removed changes in .gitignore

* Renamed CustomSampler to ConstantSampler in test cases

* Updated documentation of MockDWaveSampler

* Bugfix: substitute sampler not working as expected

* Removed files

* Changed shortcircuit to None identity check

* Modified None identity check slightly

* Add ss.info.update

* Added documentation for new parameters

* Move comments to documentation

* Update exact_solver_cutoff along with its documentation

* Correct errors related to misnaming subtitute_* as mock_*

* Delete duplicate file accidentally pushed

* Add note on return of ascent sampler

* Update dwave/system/testing.py

Co-authored-by: Radomir Stevanovic <[email protected]>

* Update dwave/system/testing.py

Change plain text to Sphinx style for documentation

Co-authored-by: Radomir Stevanovic <[email protected]>

* Update dwave/system/testing.py

Co-authored-by: Radomir Stevanovic <[email protected]>

* Fixed indentation

* Updated comment

* Added subtests in TestMockSampler

* Modified comments

* Minor adjustment for assert statement

* Added test for kwargs overwrite in TestMockDWaveSampler

---------

Co-authored-by: Andy Zhang <[email protected]>
Co-authored-by: Jack Raymond <[email protected]>
Co-authored-by: Kevin Chern <[email protected]>
Co-authored-by: Radomir Stevanovic <[email protected]>
@randomir randomir mentioned this pull request Dec 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants