dwavesystems / dimod

A shared API for QUBO/Ising samplers.
https://docs.ocean.dwavesys.com/en/stable/docs_dimod/
Apache License 2.0
121 stars 80 forks source link

Equality of CQM objects #1165

Open rlmstargithub opened 2 years ago

rlmstargithub commented 2 years ago

Intuitively one would expect the CQM.is_equal() and CQM.is_almost_equal() to mean that the models are logically/mathematically equal. For example, the constraints b1+b2-1<=0 and b1+b2<=1 are equal (although not identical - in form).

But the methods will return false.

` qm = QM() qm.add_variable('BINARY', 'b1') qm.add_variable('BINARY', 'b2') qm.add_linear('b1', 1) qm.add_linear('b2', 1)

cqm1 = CQM() cqm1.add_constraint(qm <= 1, label='constraint')

cqm2 = CQM() cqm2.add_constraint(qm - 1 <= 0, label='constraint')

b = cqm1.is_almost_equal(cqm2) print(f'models are equal: {cqm1.is_almost_equal(cqm2)}') print(f'models are equal: {cqm1.is_equal(cqm2)}') `

Assuming that I am using the SDK correctly, the results are not what one would expect. The Python doc stings also support the notion that the methods are testing for logical/mathematical equivalence.

I would suggest to update the code or the docs to make it clear what the methods do. My preference would be to alter the code to return the intuitively expected result. In the case when the documentation is updated/changed, it would be important to have a new equality method that checks for math equality/equivalence. That is the functionality that the user cares about.

As a user I rely on the is_equal() and is_almost_equal() methods when I construct two CQM objects for the same problem using different styles to make sure that the two models are mathematically the same.

arcondello commented 2 years ago

Hi @rlmstargithub, thanks for the request!

We can, and will, update the docs.

For the more general request, the main barrier I see is that "mathematically equivalence" is pretty general. I think there are three different areas one could check: 1) The example you give, the offset: i - 1 <= 0 is equivalent to i <= 1 2) Label ordering: e.g. i + j == 0 is equivalent to j + i == 0, this is actually already the behavior 3) Scale: 2*i <= 4 is equivalent to i <= 2

I gather that you would consider (1) and (2) intuitive, but what about (3)?

rlmstargithub commented 2 years ago

In (3) the two inequalities are also equal/equivalent, but I see your predicament. The full implementation of is_equal() requires a definition of a "normalized [minimal] form" of the model. This form can be defined but is perhaps a bit painful to implement (need to pick a variable and normalize its coefficient to 1 and then compare the remaining coefficients; it will have to behave like is_almost_equal, it will have to have some tolerance). This is unfortunate.

OK, updating the documentation to make it clear what to expect is good. :-)

But I think it would be useful to have a new method that would implement this normalized form. I'll let you decide to do it or not.

I mean the full implementation requires [alphabetical] variable sorting, moving constants to the right hand side, and then do the normalization of the coefficients by the leading var.

A simpler solution is to just state in the docs that the user should adopt a convention and follow it in all models (say put constants always on the right hand side of the relations) and avoid scaling. Then he could expect the current methods to work as expected.