SystemAnalysisDpt-CMC-MSU / ellipsoids

Ellipsoidal Toolbox for MATLAB is a standalone set of easy-to-use configurable MATLAB routines and classes to perform operations with ellipsoids and hyperplanes of arbitrary dimensions
http://systemanalysisdpt-cmc-msu.github.io/ellipsoids
Other
19 stars 7 forks source link

Make matrix function classes derived from gras.mat.AMatrixFunctionComparable comparable #40

Open pgagarinov opened 8 years ago

pgagarinov commented 8 years ago

Deadline: end of the semester

The goal of this task is to make all subclasses of gras.mat.AMatrixFunctionComparable class comparable. This is needed for issue #39 so that ellipsoidal tubes with built-in Dormand-Prince interpolation can be compared with any given precision.

1) Please read a description for issue #39 and make sure you fully understand it. 2) Investigate gras.mat.AMatrixFunctionComparable class. Current implementation of this class needs to be slightly changed by a) inheriting it from modgen.common.obj.HandleObjectCloner (which automatically adds isEqual and re-defines isequal,isequaln, eq,ge,le etc). b) Re-defining isEqualScalarInternal method of HandleObjectCloner using the current code from AMatrixFunctionComparable.isEqual method (with a few simplifications - after all isEqualScalarInternal is only for comparing scalar objects). This way any vectorial object (isEqual inherited from HandleObjectCloner as well as other comparison methods inherited from this class can handle vectorial objects by comparing them element-wise and using isEqualScalarInternal method that can be re-defined in derived classes) inherited AMatrixFunctionComparable can be comparable as long as it implements an abstract AMatrixFunctionComparable.toStructInternal.

3) Study all functions from gras.mat and gras.mat.fcnlib packages. Then implement toStructInternal for each of them in a way that makes possible an adequate comparison. By adequate comparison I mean that comparing structures should be equivalent to comparing functions themselves. For instace comparing objects of ConstMatrixFunction class is easy - you just compare constant matrices because the function is not time-dependent. However for the most functions (except for a few functions that are very simple or/and similar to ConstMatrixFunction) it is not that easy because all you have is "evaluate" method and no analytical formula. Given a comparison precision absTol and two matrix functions M_1(t) and M2(t) the problem you need to solve then is finding t^{} such that ||M_1(t) - M2(t)||>absTol. If no such t^{} if found M_1 and M2 are considered equal and not equal otherwise. Of course this is not that simple for a least two reasons: a) in addition to absTol and also have relTol - relative precision and comparison should be performed using both precision levels. The rough idea behind comparing a and b with both relative and absolute precision is as follows: if ||a-b|| <absTol - cosider a and b as equal, otherwise check if 2||a-b||/(||a||+||b||)< relTol. If positive - a and b are still equal and not equal otherwise. But in reality this is a bit more complex than this - see modgen.common.absrelcompare for an exact algorithm. b) in practice it is often impossible to find an exact value of t^{_} or prove that it doesn't exist because neither M_1 nor M_2 is not specified in an analytical form.

Assuming you investigated AMatrixFunctionComparable.isEqual method it should be clear that this method uses modgen.struct.structcomparevec to compare structures. structcomparevec in its turn uses absrelcompare function. For simple functions like ConstMatrixFunction for instance AMatrixFunctionComparable.toStructInternal should generate a single structure with something that is equivalent to comparing the function itself. For ConstMatrixFunction representing a function M=M(t) it would be a structure like struct ('ConstantMatrix',M). However for "complex| functions this approach might not work well. Why might? Because I suggest we try it as the first step and generate a vector of M(t) values for a certain time grid and put this vector into the resulting structure generated by toStructInternal method. This way we will at least have something to compare with later in term of both performance and precision. Thus the next step 4) Implement toStructInternal for simple functions based on their internal structure and for "complex" functions - by putting 3d-array of M(t) values into the structure with a single field and then letting isEqualScalarInternal compare these structures with single-field 3d arrays via structcompare. Time grids for which M(t) is calculated should be specified in isEqual as an additional property "timeGridVec". For this purpose you need to override isEqual in AMatrixFunctionApxComparable class using the same approach as the one used in \products+gras+ellapx+smartdb+rels\ATypifiedAdjustedRel.isEqual method. AMatrixFunctionApxComparable should be inherited from AMatrixFunctionComparable and should be used as base class for comparing all "complex" functions. "timeGridVec" property should be obligatory for now. "Simple" functions should be inherited from AMatrixFunctionComparable directly. Also please make sure that your implementation of isEqualScalarInternal just calls "isEqualScalarAsBlobInternal" when both absTol=0 and relTol=0 (when we need to do comparison with absolute precision we can just compare a BLOB representation of an object) 5) Write tests that show that a) "simple" functions are compared correctly and that both absTol and relTol precisions are treated adequatly. b) "complex" functions can be compared correctly for sufficiently dense time grids (specified as additional properties to isEqual).

All tests should be written in a "parameterized way" - a few test case that are parameterized with a factory generating instances of different matrix funciton classes. See how this is done in elltool.reach.test.run_cont_tests.

Note: you should work in a branch derived from "issue_10" and merge back to issue_10 as it were master. This is because you will work in parallel with Nikitua Zuyanov who also uses issue_10 as "master" branch. Once you both finish your work "issue_10" will be merged to master.

ghost commented 8 years ago

What I need to do in 2.b? Do I have to do isEqualScalarInternal to work with scalar objects and in isEqual method just call first one for all elements in vector or I don't need to touch isEqual and need to make only isEqualScalarInternal?

pgagarinov commented 8 years ago

isEqualScalarInternal is a protected method of HandleObjectCloner. Once you override it you will automatically get implementations of isEqual and isEqualElem, eq, isequal and some other methods inherited from HandleObjectCloner. The only thing you need to implement is isEqualScalarInternal, all other public methods in HandleObjectCloner with use isEqualScalarInternal internally.

Externally you will want to use isEqual most of the time (compares arrays) but you can also use isEqualElem which performs element-wise comparison. Please read help headers for these methods in HandleObjectCloner class.

ghost commented 8 years ago

Understand, so I've done isEqualScalarInternal mostly like an isEqual, but only for scalar values otherwise I throw an error that input arguments are non scalar values. Also a question about next part: AMatrixFunctionComparable is a superclass for 9 other matrix classes(by one way or another) where I need to rerwrite or just write toScalarInternal method(to improove adequate comparison), am I understand everything correctly?

pgagarinov commented 8 years ago

It is toStructInternal, not toScalarInternal but the rest is correct.