External Solvers

From ASCEND
Jump to: navigation, search

All ASCEND NLA and NLP Solvers are loaded dynamically at runtime. This helps us to keep a tidy architecture in which solver code is kept by itself, and the 'core' part of ASCEND contains none of the numerical algorithms other than automatic differentiation, direct solution and a few other small things.

By default, QRSlv, CONOPT (if available), LRSlv, and CMSlv (if available) are loaded at launch. If you create your own external solver, you can load it my adding an IMPORT statement into your model file. We also plan to add import functionality via the scripting interface but this is not implemented yet. We currently don't support linear solvers via this mechanism: our API for those still needs a little work.

The API is similar to that used for External Integrators and still requires some more changes to the way that problem/system/solver APIs are connected together. The Python test-suite contains a large number of tests that provide a fair coverage of these functions, so we are fairly confident that the API changes can be made without too much inconvenience.

Using an external solver

Some solvers are loaded by default, including QRSlv and the others listed above. If you have a solver that is not loaded by default, you can add a command at the start of your model file:

IMPORT "path/to/yoursolver";

This should cause the solver to be added to the list of available solvers. We still need to test this, however.

How to write your own external solver for ASCEND

There are several examples currently in the solvers/ directories.

To create your own external solver for ASCEND, you need to compile a DLL or shared object that can be loaded with the LoadArchiveLibrary("pathname/to/yourpackage") function from compiler/packages.h. This means that your DLL must contain a exported function called yourpackage_register. That function will be called when your DLL is first loaded, and it must 'tell ASCEND about' your solver. This means that you prepare a SlvFunctionsT structure containing the hook functions provided by your solver, and then call the solver_register(slvfunctions) function. You can return a non-zero value from yourpackage_register if there is anything that stops the solver from registering correctly, for example if other sub-solvers are not found, or a secondary DLL can't be loaded, etc.

The contents of the SlvFunctionsT structure are described in the header file ascend/solver/solver.h and in a minimal solver, this will header may be the only one you need to include. However, most solvers make callbacks to other functions in 'libascend' so you will probably include ascend/system/slv_client.h and possibly others too.

Currently the solver functionality is pretty much tied to the mtx sparse-matrix data storage format. We do intend to de-couple this from libascend so that solvers can use arbitrary data storage. This is already possible in the Integrator API, but not yet with the Solver API. Part of fixing this requires boiling down the Linear API, which is yet to be tackled.

Here is the snippet of code that does the registration of the QRSlv solver. Note that the optional hook function dump_internals is not provided by this solver. Not all hook functions are required for all solvers.

static const SlvFunctionsT qrslv_internals = {
	SOLVER_QRSLV_EXT
	,"QRSlv"
	,qrslv_create
  	,qrslv_destroy
	,qrslv_eligible_solver
	,qrslv_get_default_parameters
	,qrslv_get_parameters
	,qrslv_set_parameters
	,qrslv_get_status
	,qrslv_solve
	,qrslv_presolve
	,qrslv_iterate
	,qrslv_resolve
	,qrslv_get_linsolqr_sys
	,qrslv_get_jacobian
	,NULL /* dump_internals not defined for QRSlv */
};

ASC_EXPORT int qrslv_register(void){
	return solver_register(&qrslv_internals);
}

Further documentation of these methods is available in ascend/solver/solver.h.

See also External Integrators.