Remove Instant dependency

Issue #859 wontfix
Prof Garth Wells created an issue

With the use of dijitso for much of the JIT in DOLFIN, Instant is used only in a small set of cases. Instant is showing its age and is a heavy weight approach to something that could be simplified if made DOLFIN-specific.

Proposal is to add the JIT functionality presently provided by Instant into DOLFIN.

Comments (15)

  1. Martin Sandve Alnæs

    I promised a sketch of a solution for jit-compiled Expressions in dolfin without jitting swig wrappers. This solution covers most use cases, but not the all-out user defined class code. (That use case could arguably be better solved by writing a use module anyway, maybe someone can make a cookiecutter project to set up dolfin extensions with cmake and swig.)

    In python, users write

    e = Expression("c * f * x[0]", c=1.23, f=myfunction, ...)
    

    and then can do

    e.c = 5.3
    e.f = myotherfunction
    

    The challenges are thus to construct an instance of Expression from generated code, instantiate it with proper inherited classes in the python layer, and connect e.c = 5.3 with setting a C++ member variable double c of the generated code. Currently swig deals with this by wrapping the class we generate.

    1. Add an Expression subclassExpressionWithAttributes
      • that has get/set functions (see draft below) to dolfin
      • let dolfin swig build step wrap it once and for all
      • all python access to jit-generated Expression subclasses must go through this predefined interface!
    2. Change code generation to subclass ExpressionWithAttributes.
      • make the generated data members private
      • implement the relevant get/set functions to read/modify custom data members
      • add __getattr__, __setattr__ implementations in the python layer to delegate e.c = 3 to e.set("c", 3)
      • now the custom attributes shouldn't require any jit-time defined C wrapper code
    3. Generate a factory function CLS * create_expression_CLS() { return new CLS(); } where CLS is the classname of the generated subclass (e.g. expression_${jitsignature})
      • use factory function to instantiate an object of the generated subclass from python
      • there might be some tricky parts to adding python subclasses to the newly generated class, or maybe not because only the regular Expression(WithAttributes) needs to subclass ufl.Coefficient?
      • now the construction shouldn't require any jit-time defined C wrapper code
    4. Once no jit-time generated code is no longer needed, drop instant/swig and use dijitso to compile the generated code and get the factory function via ctypes as ffc.jit does.

    Draft of ExpressionWithAttributes:

    // This can be a separate subclass or just added to Expression
    class ExpressionWithAttributes: public Expression
    {
    public:
       virtual bool has(string name) const { return false; }
    
       virtual double get(string name) const { missing_get(name); }
       virtual void set(string name, double value) { missing_set(name); }
    
       virtual shared_ptr<Function> get(string name) const { missing_get(name); }
       virtual void set(string name, shared_ptr<Function> value) { missing_set(name); }
    
       // ... more of the same:
    
       virtual shared_ptr<Expression> get(string name) const { missing_get(name); }
       virtual void set(string name, shared_ptr<Expression> value) { missing_set(name); }
    
       virtual shared_ptr<MeshFunction<size_t>> get(string name) const { missing_get(name); }
       virtual void set(string name, shared_ptr<MeshFunction<size_t>> value) { missing_set(name); }
    
       virtual shared_ptr<MeshFunction<double>> get(string name) const { missing_get(name); }
       virtual void set(string name, shared_ptr<MeshFunction<double>> value) { missing_set(name); }
    
       // ... get/set for each allowed value type ...
    
    protected:
       // Could be warnings, errors, do-nothing:
       virtual void missing_get(string name) const { dolfin_error(...); }
       virtual void missing_set(string name) const { dolfin_error(...); }
    };
    

    If this is a separate subclass of Expression it doesn't have to be exposed to dolfin in C++ for this to work.

  2. Martin Sandve Alnæs
  3. Prof Garth Wells reporter

    @martinal Could you give some more detail on what the ExpressionWithAttributes::set would do? Who would implement them? They would need set private data. Would the class that implements set be generated as part of the JIT?

  4. Martin Sandve Alnæs

    It would be implemented in the class generated by dolfin (in compilemodules/compile_expression.py or one of those files):

    class JitExpr_019561923812934 : public dolfin::ExpressionWithAttributes
    {
    public:
        void set(string name, double value) {
          if (name == "f") throw wrong_type();
          else if (name == "c") c = value;
          else throw unknown_name();
        }
    
        void set(string name, shared_ptr<Function> value) {
          if (name == "f") f = value;
          else if (name == "c") throw wrong_type();
          else throw unknown_name();
        }
    private:
        // These are already generated as public members:
        double c;
        shared_ptr<Function> f;
    };
    
  5. Martin Sandve Alnæs

    You could also as a first step just add generation of get/set functions like above without the base class and without making the member variables private.

  6. Prof Garth Wells reporter

    Bumping priority because the way Instant is using the DOLFIN CMake files has introduced some major JIT overhead.

  7. Prof Garth Wells reporter

    The approach described above has been implemented in the pybind11 branch and is working well. It's fast!

  8. Log in to comment