Skip to content

Commit

Permalink
Merge pull request #39 from arcondello/projection
Browse files Browse the repository at this point in the history
Add projection method to Constraint
  • Loading branch information
arcondello committed May 15, 2018
2 parents 98d2e36 + 19068bd commit 2cac84d
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
5 changes: 3 additions & 2 deletions docs/reference/constraint.rst
Expand Up @@ -42,10 +42,11 @@ Transformations
Constraint.fix_variable
Constraint.flip_variable

Copy
----
Copies and projections
----------------------

.. autosummary::
:toctree: generated/

Constraint.copy
Constraint.projection
39 changes: 38 additions & 1 deletion dwavebinarycsp/core/constraint.py
Expand Up @@ -470,7 +470,7 @@ def func(*args):
self.name = '{} ({} flipped)'.format(self.name, v)

#
# copy
# copies and projections
#

def copy(self):
Expand All @@ -493,3 +493,40 @@ def copy(self):
"""
# each object is itself immutable (except the function)
return self.__class__(self.func, self.configurations, self.variables, self.vartype, name=self.name)

def projection(self, variables):
"""Create a new constraint that is the projection onto a subset of the variables.
Args:
variables (iterable):
Subset of the constraint's variables.
Returns:
:obj:`.Constraint`: A new constraint over a subset of the variables.
Examples:
>>> import dwavebinarycsp
...
>>> const = dwavebinarycsp.Constraint.from_configurations([(0, 0), (0, 1)],
... ['a', 'b'],
... dwavebinarycsp.BINARY)
>>> proj = const.projection(['a'])
>>> proj.variables
['a']
>>> proj.configurations
{(0,)}
"""
# resolve iterables or mutability problems by casting the variables to a set
variables = set(variables)

if not variables.issubset(self.variables):
raise ValueError("Cannot project to variables not in the constraint.")

idxs = [i for i, v in enumerate(self.variables) if v in variables]

configurations = frozenset(tuple(config[i] for i in idxs) for config in self.configurations)
variables = tuple(self.variables[i] for i in idxs)

return self.from_configurations(configurations, variables, self.vartype)
24 changes: 24 additions & 0 deletions tests/test_constraint.py
Expand Up @@ -198,3 +198,27 @@ def test_copy(self):
new_const = const.copy()

self.assertEqual(const, new_const)
self.assertIsNot(const, new_const)

def test_projection_identity(self):
const = dwavebinarycsp.Constraint.from_func(operator.eq, ['a', 'b'], dwavebinarycsp.SPIN)

proj = const.projection(['a', 'b'])

self.assertEqual(const, proj)
self.assertIsNot(const, proj)

def test_projection_unknown_variables(self):
const = dwavebinarycsp.Constraint.from_func(operator.eq, ['a', 'b'], dwavebinarycsp.SPIN)

with self.assertRaises(ValueError):
proj = const.projection(['a', 'c'])

def test_projection_reducible(self):
const = dwavebinarycsp.Constraint.from_configurations([(0, 0), (0, 1)], ['a', 'b'], dwavebinarycsp.BINARY)

a = dwavebinarycsp.Constraint.from_configurations([(0,)], ['a'], dwavebinarycsp.BINARY)
b = dwavebinarycsp.Constraint.from_configurations([(0,), (1,)], ['b'], dwavebinarycsp.BINARY)

self.assertEqual(const.projection(['b']), b)
self.assertEqual(const.projection(['a']), a)

0 comments on commit 2cac84d

Please sign in to comment.