On Fri, May 08, 2009 at 09:36:26AM +0200, Martin Sandve Alnæs wrote: > On Fri, May 8, 2009 at 9:17 AM, Anders Logg <[email protected]> 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.
I mostly agree. I'll keep this in memory and see what comes out of it. Once we have the first iteration in place, it will be easier to discuss the details. -- Anders
signature.asc
Description: Digital signature
_______________________________________________ DOLFIN-dev mailing list [email protected] http://www.fenics.org/mailman/listinfo/dolfin-dev
