Skip to content

Commit

Permalink
Fix the checking of solutions containing MiniZinc defined enums
Browse files Browse the repository at this point in the history
  • Loading branch information
Dekker1 committed Nov 11, 2020
1 parent 931b6b5 commit ac1ea56
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@ Changed
^^^^^^^
- The MiniZinc Python repository moved from GitLab to GitHub, replacing GitLab
CI for GitHub Actions for the continuous testing.
- Values of an enumerated type defined in MiniZinc will now appear in solutions
as a member of a singular anonymous ``enum.Enum`` class.

Fixed
^^^^^
- Handle the cancellation of asynchronous solving and correctly dispose of the
process
- Correct the JSON representation of sets of with ``IntEnum`` members. (Lists
are still not correctly represented).
- ``check_solution`` will now correctly handle solution values of an enumerated
type defined in MiniZinc.

0.4.0_ - 2020-10-06
------------
Expand Down
14 changes: 12 additions & 2 deletions src/minizinc/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ def __init__(self, enum_map=None, *args, **kwargs):
self.enum_map = enum_map
JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs)

def _lookup_enum(self, name: str):
if name in self.enum_map:
return self.enum_map[name]
else:
# TODO: mypy seems to believe name the elements should be literals,
# but I cannot find this anywhere in the documentation
anon_enum = Enum("AnonymousEnum", name) # type: ignore
self.enum_map[name] = anon_enum(1)
return anon_enum(1)

def object_hook(self, obj):
if len(obj) == 1 and "set" in obj:
if len(obj["set"]) == 1 and isinstance(obj["set"][0], list):
Expand All @@ -36,11 +46,11 @@ def object_hook(self, obj):
assert len(item) == 2
li.extend([i for i in range(item[0], item[1] + 1)])
elif len(obj) == 1 and "e" in obj:
li.append(self.enum_map.get(obj["e"], obj["e"]))
li.append(self._lookup_enum(obj["e"]))
else:
li.append(item)
return set(li)
elif len(obj) == 1 and "e" in obj:
return self.enum_map.get(obj["e"], obj["e"])
return self._lookup_enum(obj["e"])
else:
return obj
5 changes: 5 additions & 0 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,8 @@ def test_dict(self):
assert check_solution(
self.instance, {"x": [5, 6]}, Status.SATISFIED, self.other_solver
)

def test_enum(self):
self.instance.add_string("""enum Foo = {A, B};var Foo: f;""")
result = self.instance.solve()
assert check_result(self.instance, result, self.other_solver)
17 changes: 8 additions & 9 deletions tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class TestEnum(InstanceTestCase):
def test_value(self):
self.instance.add_string("constraint d == Mo;")
result = self.instance.solve()
assert isinstance(result["d"], str)
assert result["d"] == "Mo"
assert isinstance(result["d"], enum.Enum)
assert result["d"].name == "Mo"

def test_cmp_in_instance(self):
self.instance.add_string("var DAY: d2;")
self.instance.add_string("constraint d < d2;")
result = self.instance.solve()
assert isinstance(result["d"], str)
assert isinstance(result["d2"], str)
assert isinstance(result["d"], enum.Enum)
assert isinstance(result["d2"], enum.Enum)
# TODO: assert result["d"] < result["d2"]

def test_cmp_between_instances(self):
Expand All @@ -36,9 +36,9 @@ def test_cmp_between_instances(self):
inst = Instance(self.solver)
inst.add_string(self.code + append)
result2 = inst.solve()
assert isinstance(result["d"], str)
assert isinstance(result2["d"], str)
assert result["d"] == result2["d"]
assert isinstance(result["d"], enum.Enum)
assert isinstance(result2["d"], enum.Enum)
assert result["d"].name == result2["d"].name

inst = Instance(self.solver)
inst.add_string(
Expand All @@ -49,8 +49,7 @@ def test_cmp_between_instances(self):
+ append
)
result2 = inst.solve()
# TODO: assert type(result["d"]) != type(result2["d"])
# TODO: assert result["d"] == result2["d"]
assert result["d"].name == result2["d"].name

def test_assign(self):
self.instance = Instance(self.solver)
Expand Down

0 comments on commit ac1ea56

Please sign in to comment.