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

instantiate solvers without setting a system matrix? #22

Open
lheagy opened this issue Feb 21, 2018 · 1 comment
Open

instantiate solvers without setting a system matrix? #22

lheagy opened this issue Feb 21, 2018 · 1 comment

Comments

@lheagy
Copy link
Member

lheagy commented Feb 21, 2018

Motivation

In developing a Simulation class in SimPEG (simpeg/simpeg#672), I want to be able to readily serialize and deserialize an instance of a Simulation, so we are injecting properties throughout, which gives us serialization, deserialization and validation (thanks @fwkoch!!). Right now, the solvers are attached as the simulation as a class, and the solver_opts are attached to the simulation as a dict. We then instantiate a solver as needed in SimPEG.

State the problem

There are a couple potential snags with this approach

  • if your solver_opts are not valid, we won't find out until we try and use the solver
  • It is not readily clear how to serialize the solver class (a Class property is one option New Class property seequent/properties#163, we could also think about serializing / deserializing the name of the class as a string)

Another approach?

We could instantiate the solver with its options and then call it to create Ainv. This would solve the serialization problem and also allow immediate validation of the solver options on its creation.

import pymatsolver
solver = pymatsolver.Pardiso(**opts)
Ainv = solver(A)

so the base class might look like:

class Base(properties.HasProperties):

    check_accuracy = properties.Bool(
        "check the accuracy of the solve?",
        default = False
    )

    accuracy_tol = properties.Float(
        "tolerance on the accuracy of the solver",
        default=1e-6
    )

    def __init__(self, **kwargs):
        super(Base, self).__init__(**kwargs)

    def __call__(self, A):
        self.A = A.tocsr()

There are a couple impacts of this within SimPEG. The one that comes to mind is:

  • right now in the inversion, if a solver is not set for the data misfit, we use the same one as on the simulation, here we would likely want to make a copy of the instance, rather than re-use the same instance (so that factors are not cleared)
@rowanc1
Copy link
Member

rowanc1 commented Mar 8, 2018

I think the generic serialization of a class is going to be tough. But inside of pymatsolver, this should be easy.

This snippet might help on the SimPEG side of things?

import properties
import pymatsolver
import inspect

class SolverClass(properties.Property):

    def validate(self, instance, value):
        if not inspect.isclass(value):
            self.error(
                instance, value,
                extra="The Solver must be a class."
            )
        if not hasattr(value, "__mul__"):
            self.error(
                instance, value,
                extra="The Solver must have a `__mul__` method."
            )
        return value
    
    def to_json(self, value, **kwargs):
        cls_name = value.__name__
        if hasattr(pymatsolver, cls_name):
            return {
                "module": "pymatsolver",
                "version": pymatsolver.__version__,
                "class": cls_name
            }
        return value
            
    def from_json(self, value, **kwargs):
        assert isinstance(value, dict)
        assert "module" in value and value["module"] == "pymatsolver"
        assert "version" in value and value["version"] == pymatsolver.__version__
        if hasattr(pymatsolver, value["class"]):
            return getattr(pymatsolver, value["class"])
        raise ValueError('pymatsolver has no class "{}"'.format(value))
        

class Simulation(properties.HasProperties):
    Solver = SolverClass("pymatsolver Solver Class")
test = pymatsolver.Pardiso
sim = Simulation(Solver=test)
data = sim.serialize()
print(data)
assert Simulation.deserialize(data).Solver is test
{
    "Solver": {
        "version": "0.1.2",
        "module": "pymatsolver",
        "class": "Pardiso"
    },
    "__class__": "Simulation"
}

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

No branches or pull requests

2 participants