← Back to team overview

dolfin team mailing list archive

Re: Parameter system

 

On Fri, May 8, 2009 at 9:17 AM, Anders Logg <logg@xxxxxxxxx> wrote:
> On Fri, May 08, 2009 at 09:06:16AM +0200, Johan Hake wrote:
>> On Friday 08 May 2009 08:49:59 Garth N. Wells wrote:
>> > Anders Logg wrote:
>> > > On Fri, May 08, 2009 at 08:12:35AM +0200, Johan Hake wrote:
>> > >> On Thursday 07 May 2009 23:16:54 Anders Logg wrote:
>> > >>> On Thu, May 07, 2009 at 11:05:49PM +0200, Johan Hake wrote:
>> > >>>> On Thursday 07 May 2009 18:54:04 Anders Logg wrote:
>> > >>>>> I've added some of the requested features to the parameter system,
>> > >>>>> some pushed and some sitting here in a local repository. But the
>> > >>>>> current design makes it a pain to add new features. A single change
>> > >>>>> will make it necessary to add a function in at least 5 different
>> > >>>>> classes.
>> > >>>>>
>> > >>>>> So I'm thinking of reimplementing and simplifying the parameter
>> > >>>>> system. I think I know how to make it simpler.
>> > >>>>>
>> > >>>>> But before I do that, does anyone have opinions on the
>> > >>>>> design/implementation? Is there any third-party library that we
>> > >>>>> could/should use (maybe something in boost)?
>> > >>>>
>> > >>>> It would be nice to have something that easely could be transferable
>> > >>>> to Python.
>> > >>>>
>> > >>>> Having a base class let say Parameterized and then let all inherit
>> > >>>> this to be able to define parameters will not work well for the
>> > >>>> shared_ptr interface we have. We have problems with the Variable
>> > >>>> class, which does not work for the derived shared_ptr classes e.g.
>> > >>>> Function. I would rather have classes that have a parameter rather
>> > >>>> than beeing.
>> > >>>
>> > >>> How would that work? Inheritance now provides get/set functions for
>> > >>> subclasses making it possible to do
>> > >>>
>> > >>>   solver.set("tolerance", 0.1);
>> > >>
>> > >> Not sure what you ask for here. I know of Parametrized and I agree that
>> > >> the above syntax is nice. But I prefer to keep the parameters in its own
>> > >> object and just operate on that. These can then be collected into one
>> > >> "dict/map" and then form the parameters of an application. This is also
>> > >> easier to wrap to python.
>> > >>
>> > >> The shared_ptr argument might not be so relevant as the potential
>> > >> parametrized classes may not be declared as shared_ptr classes in the
>> > >> swig interface anyway. However if that will be the case we must declare
>> > >> Parametrized as a shared_ptr class in swig and then we must declare all
>> > >> Parametrized sub classes as shared_ptr...
>> > >>
>> > >>>> Also by defining a parameter(list/dict) class which can be accessed as
>> > >>>> a dict let us make the transition to python smoother.
>> > >>>>
>> > >>>>    ParameterDict p = solver.default_params();
>> > >>>>    p["abs_tol"] = 1e-9;
>> > >>>
>> > >>> It would need to be
>> > >>>
>> > >>>     ParameterDict& p = solver.default_params();
>> > >>
>> > >> Sure :P
>> > >>
>> > >>> and I'd suggest naming it Parameters:
>> > >>>
>> > >>>     Parameters& p = solver.parameters();
>> > >>
>> > >> Fine.
>> > >>
>> > >>>> By defining some templated check classes we could controll the
>> > >>>> assignment. In the Solver:
>> > >>>>    ...
>> > >>>>    ParameterDict& default_params(){
>> > >>>>       if (!_par)
>> > >>>>       {
>> > >>>>          _par = new ParameterDict();
>> > >>>>          _par->add_param("abs_tol",new RangeCheck<double>(1e-15,0,1));
>> > >>>>          vector<string> * allowed_prec = new Vector<string>();
>> > >>>>          allowed_prec->push_back("ilu");
>> > >>>>          allowed_prec->push_back("amg");
>> > >>>>          allowed_prec->push_back("jacobi");
>> > >>>>          _par->add_param("prec",new
>> > >>>> OptionCheck<string>("ilu"),allowed_prec));
>> > >>>> _par->add_param("nonsense","jada"); // No checks
>> > >>>>       }
>> > >>>>    }
>> > >>>>
>> > >>>> Well, I admit that the above code is not beautiful, and others can
>> > >>>> probably make it cleaner and spot errors. The point is that RangeCheck
>> > >>>> and OptionCheck can be derived from a ParCheck class that overloads
>> > >>>> the operator=(). This will just call a private set function which is
>> > >>>> defined in the derived classes, and which do the check.
>> > >>>
>> > >>> I think we can also solve this without excessive templating... ;-)
>> > >>
>> > >> Good!
>> > >>
>> > >>>> The to and from file can be implemented in the ParameterDict body. The
>> > >>>> checks do not have to be written or read, as a ParameterDict can only
>> > >>>> read in allready predefined parameters, and the check will be done
>> > >>>> when the file is read.
>> > >>>>
>> > >>>> The option parser ability can also be implemented in ParameterDict
>> > >>>> using boost or other libraries, based on the registered parameters.
>> > >>>>
>> > >>>> I have implemented something like this in Python, and the above is a
>> > >>>> try to scetch something similare in c++.
>> > >>>
>> > >>> What exactly is needed from the Python side? I think I can make a
>> > >>> fairly simple implementation of this in C++ using a minimal amount of
>> > >>> templates with simple syntax.
>> > >>
>> > >> Using operator[] to get and set parameters can straightforwardly be
>> > >> mapped to python, and we can then also implement the map/dict protocol
>> > >> on top of that. Other get and set methods can also be used, however set
>> > >> is a built in type in Python and not a good alternative.
>> > >>
>> > >>> Is the main difference that instead of inheriting Parametrized, a
>> > >>> subclass needs to implement a method named parameters() which returns
>> > >>> the parameter "dictionary"?
>> > >>
>> > >> Yes.
>> > >
>> > > ok, I'll try this. I'll add a sketch of a new class using as much of
>> > > po as seems reasonable and then you could have a look before I proceed.
>> >
>> > Will there be just one parameter dictionary, or will objects have their
>> > own? I'm thinking of cases like when a program uses two Krylov solvers
>> > but may use different tolerances for each one.
>>
>> You mean one parameter dictionary per class or one per instance? I have the
>> same distinction in a Python application. Some places I need one per instance
>> and other places it is more convinient to have one per class.
>
> One per instance. But there could be a default Parameter database for
> "Krylov solver" which is used if an option is not set for a specific
> instance.


Suggestions:

const Parameters & a = FooBarType::default_parameters();
Parameters & b = foobar.parameters();

Parameters p = b.diff(a); // parameters in b that differs from a

p.disp();
file << p.format();

Parameters par;
par["beta"] = 1.0;
foobar.set_parameters(par);


I prefer the global/class defaults to be immutable.
(Global state is _always_ evil!)
Otherwise combining applications becomes a real mess.
Application-wide defaults can still be handled manually
using set_parameters.

Martin


Follow ups

References