Skip to content

Commit

Permalink
fix: make model.Clone use json as default (#44)
Browse files Browse the repository at this point in the history
* fix: make model.Clone use json as default

Using LP format as intermediate has problems on cross-solver clones.

* chore: add warning to clone with use_lp

* test: change clone test to use json

* fix: import warnings

* test: assert that cloned optimal value is the same
  • Loading branch information
KristianJensen authored Nov 15, 2016
1 parent 9b80766 commit 1196387
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 5 deletions.
12 changes: 10 additions & 2 deletions optlang/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import logging
import sys
import uuid
import warnings

import six

Expand Down Expand Up @@ -1041,7 +1042,7 @@ class Model(object):
"""

@classmethod
def clone(cls, model, use_lp=True):
def clone(cls, model, use_json=True, use_lp=False):
"""
Make a copy of a model. The model being copied can be of the same type or belong to
a different solver interface. This is the preferred way of copying models.
Expand All @@ -1052,11 +1053,18 @@ def clone(cls, model, use_lp=True):
"""
model.update()
interface = sys.modules[cls.__module__]
if use_lp and hasattr(cls, "from_lp") and hasattr(model, "to_lp"):

if use_lp:
warnings.warn("Cloning with LP formats can change variable and constraint ID's.")
new_model = cls.from_lp(model.to_lp())
new_model.configuration = interface.Configuration.clone(model.configuration, problem=new_model)
return new_model

if use_json:
new_model = cls.from_json(model.to_json())
new_model.configuration = interface.Configuration.clone(model.configuration, problem=new_model)
return new_model

new_model = cls()
for variable in model.variables:
new_variable = interface.Variable.clone(variable)
Expand Down
26 changes: 23 additions & 3 deletions optlang/tests/abstract_test_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,21 +518,41 @@ def test_change_objective_can_handle_removed_vars(self):
self.model.update()
self.model.objective = self.interface.Objective(self.model.variables[1] * 2)

def test_clone_model_with_lp(self):
def test_clone_model_with_json(self):
self.assertEquals(self.model.configuration.verbosity, 0)
self.model.configuration.verbosity = 3
self.model.optimize()
opt = self.model.objective.value
cloned_model = self.interface.Model.clone(self.model)
self.assertEquals(cloned_model.configuration.verbosity, 3)
self.assertEquals(len(cloned_model.variables), len(self.model.variables))
self.assertEquals(len(cloned_model.constraints), len(self.model.constraints))
cloned_model.optimize()
self.assertAlmostEqual(cloned_model.objective.value, opt)

def test_clone_model_without_lp(self):
def test_clone_model_with_lp(self):
self.assertEquals(self.model.configuration.verbosity, 0)
self.model.configuration.verbosity = 3
cloned_model = self.interface.Model.clone(self.model, use_lp=False)
self.model.optimize()
opt = self.model.objective.value
cloned_model = self.interface.Model.clone(self.model, use_lp=True)
self.assertEquals(cloned_model.configuration.verbosity, 3)
self.assertEquals(len(cloned_model.variables), len(self.model.variables))
self.assertEquals(len(cloned_model.constraints), len(self.model.constraints))
cloned_model.optimize()
self.assertAlmostEqual(cloned_model.objective.value, opt)

def test_clone_model_without_json(self):
self.assertEquals(self.model.configuration.verbosity, 0)
self.model.configuration.verbosity = 3
self.model.optimize()
opt = self.model.objective.value
cloned_model = self.interface.Model.clone(self.model, use_json=False)
self.assertEquals(cloned_model.configuration.verbosity, 3)
self.assertEquals(len(cloned_model.variables), len(self.model.variables))
self.assertEquals(len(cloned_model.constraints), len(self.model.constraints))
cloned_model.optimize()
self.assertAlmostEqual(cloned_model.objective.value, opt)


@six.add_metaclass(abc.ABCMeta)
Expand Down

0 comments on commit 1196387

Please sign in to comment.