1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2010-2010 - DIGITEO - Bernard Hugueney
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15 
16 #ifndef __SPARSE_HH__
17 #define __SPARSE_HH__
18 
19 //#include <Eigen/Sparse>
20 #include <complex>
21 #include "double.hxx"
22 #include "bool.hxx"
23 #include "keepForSparse.hxx"
24 
25 #define SPARSE_CONST
26 
27 namespace Eigen
28 {
29 template<typename _Scalar, int _Flags, typename _Index>  class SparseMatrix;
30 }
31 
32 namespace types
33 {
34 /* Utility function to create a new var on the heap from another type
35  */
36 template<typename Dest, typename Arg>
37 Dest* create_new(Arg const&);
38 
39 struct SparseBool;
40 
41 /**
42    Sparse is a wrapper over Eigen sparse matrices templates for either double or std::complex<double> values.
43  */
44 struct EXTERN_AST Sparse : GenericType
45 {
46     virtual ~Sparse();
47     /* @param src: Double matrix to copy into a new sparse matrix
48     **/
49     Sparse(Double SPARSE_CONST& src);
50     /* @param src : Double matrix to copy into a new sparse matrix
51        @param idx : Double matrix to use as indexes to get values from the src
52     **/
53     Sparse(Double SPARSE_CONST& src, Double SPARSE_CONST& idx);
54     /* @param src : Double matrix to copy into a new sparse matrix
55        @param idx : Double matrix to use as indexes to get values from the src
56        @param dims : Double matrix containing the dimensions of the new matrix
57     **/
58     Sparse(Double SPARSE_CONST& src, Double SPARSE_CONST& idx, Double SPARSE_CONST& dims);
59     /*
60       @param rows : nb of rows of the new matrix
61       @param rows : nb of columns of the new matrix
62       @param cplx : if the new matrix contains complex numbers
63     **/
64     Sparse(int rows, int cols, bool cplx = false);
65     Sparse(Sparse const& o);
66     /* cf. adj2sp()
67       @param xadj : adjacency matrix for the new matrix
68       @param adjncy : adjacency matrix (row indexes) for the new matrix
69       @param src : data for the new matrix
70       @param r : nb of rows for the new matrix
71       @param c : nb of columns for the new matrix
72     **/
73     Sparse(Double SPARSE_CONST& xadj, Double SPARSE_CONST& adjncy, Double SPARSE_CONST& src, std::size_t r, std::size_t c);
74 
75     //constructor to create a sparse from value extract to another ( save / load operation typically)
76     Sparse(int rows, int cols, int nonzeros, int* inner, int* outer, double* real, double* img);
77 
isSparsetypes::Sparse78     bool isSparse()
79     {
80         return true;
81     }
82     void finalize();
83 
84     bool getMemory(long long *_piSize, long long* _piSizePlusType);
85 
86     /*data management member function defined for compatibility with the Double API*/
87     Sparse* set(int _iRows, int _iCols, double _dblReal, bool _bFinalize = true);
settypes::Sparse88     Sparse* set(int _iIndex, double _dblReal, bool _bFinalize = true)
89     {
90         return set(_iIndex % m_iRows, _iIndex / m_iRows, _dblReal, _bFinalize);
91     }
92 
93     Sparse* set(int _iRows, int _iCols, std::complex<double> v, bool _bFinalize = true);
settypes::Sparse94     Sparse* set(int _iIndex, std::complex<double> v, bool _bFinalize = true)
95     {
96         return set(_iIndex % m_iRows, _iIndex / m_iRows, v, _bFinalize);
97     }
98     /*
99       set non zero values to 1.
100     **/
101     bool one_set();
102     /* get real value at coords (r,c)
103     **/
104     double getReal(int r, int c) const;
getRealtypes::Sparse105     double getReal(int _iIndex) const
106     {
107         return getReal(_iIndex % m_iRows, _iIndex / m_iRows);
108     }
109 
110     double* get();
111     double get(int r, int c) const;
gettypes::Sparse112     double get(int _iIndex) const
113     {
114         return get(_iIndex % m_iRows, _iIndex / m_iRows);
115     }
116 
117     std::complex<double>* getImg();
118     std::complex<double> getImg(int r, int c) const;
getImgtypes::Sparse119     std::complex<double> getImg(int _iIndex) const
120     {
121         return getImg(_iIndex % m_iRows, _iIndex / m_iRows);
122     }
123 
124     /* return true if matrix contains complex numbers, false otherwise.
125     **/
126     bool isComplex() const;
127     // overload of GenericType methode.
isComplextypes::Sparse128     bool isComplex()
129     {
130         // force const to call isComplex const method.
131         const Sparse* sp = this;
132         return sp->isComplex();
133     }
134 
isScalartypes::Sparse135     inline bool isScalar()
136     {
137         return (getRows() == 1 && getCols() == 1);
138     }
139     /* clear all the values of the matrix to 0. (or 0.+0.i if complex)
140     **/
141     bool zero_set();
142 
143     /*
144       Config management and GenericType methods overrides
145     */
146     void whoAmI() SPARSE_CONST;
147     bool isExtract() const;
148     Sparse* clone(void);
149     bool toString(std::wostringstream& ostr);
150 
151     /* post condition: dimensions are at least _iNewRows, _iNewCols
152        preserving existing data.
153        If dimensions where already >=, this is a no-op.
154 
155        @param _iNewRows new minimum nb of rows
156        @param _iNewCols new minimum nb of cols
157        @return true upon succes, false otherwise.
158      */
159     Sparse* resize(int _iNewRows, int _iNewCols);
160     /* post condition: new total size must be equal to the old size.
161                        Two dimensions maximum.
162 
163        @param _iNewRows new nb of rows
164        @param _iNewCols new nb of cols
165        @param _piNewDims new nb of dimension
166        @param _iNewDims new size for each dimension
167        @return true upon succes, false otherwise.
168     */
169     Sparse* reshape(int* _piNewDims, int _iNewDims);
170     Sparse* reshape(int _iNewRows, int _iNewCols);
171     /*
172       insert _iSeqCount elements from _poSource at coords given by _piSeqCoord (max in _piMaxDim).
173       coords are considered 1D if _bAsVector, 2D otherwise.
174       @param _iSeqCount nb of elts to insert
175       @param _piSeqCoord dest coords
176       @param _poSource src
177       @param  _bAsVector if _piSeqCoord contains 1D coords.
178      */
179     Sparse* insert(typed_list* _pArgs, InternalType* _pSource);
180 
181     GenericType* remove(typed_list* _pArgs);
182 
183     GenericType* insertNew(typed_list* _pArgs);
184 
185     /* append _poSource from coords _iRows, _iCols
186        @param _iRows row to append from
187        @param _iCols col to append from
188        @param _poSource src data to append
189      */
190     Sparse* append(int r, int c, types::Sparse SPARSE_CONST* src);
191 
192     /*
193       extract a submatrix
194       @param _iSeqCount nb of elts to extract
195       @param _piSeqCoord src coords
196       @param _piMaxDim max coords
197       @param _piDimSize size of the extracted matrix
198       @param  _bAsVector if _piSeqCoord contains 1D coords.
199 
200      */
201     GenericType* extract(typed_list* _pArgs);
202     Sparse* extract(int _iSeqCount, int* _piSeqCoord, int* _piMaxDim, int* _piDimSize, bool _bAsVector) SPARSE_CONST;
203     virtual bool invoke(typed_list & in, optional_list & /*opt*/, int /*_iRetCount*/, typed_list & out, const ast::Exp & e);
204     virtual bool isInvokable() const;
205     virtual bool hasInvokeOption() const;
206     virtual int getInvokeNbIn();
207     virtual int getInvokeNbOut();
208 
209     /*
210        change the sign (inplace).
211      */
212     void opposite();
213 
214     /*
215       compares with another value for equality (same nb of elts, with same values)
216       TODO: should it handle other types ?
217      */
218     bool operator==(const InternalType& it) SPARSE_CONST;
219     /*
220       compares with another value for inequality (same nb of elts, with same values)
221       TODO: should it handle other types ?
222      */
operator !=types::Sparse223     bool operator!=(const InternalType& it) SPARSE_CONST
224     {
225         return !(*this == it);
226     }
227 
228 
229     /* return type as string ( double, int, cell, list, ... )*/
getTypeStrtypes::Sparse230     virtual std::wstring         getTypeStr() const
231     {
232         return std::wstring(L"sparse");
233     }
234 
235     /* return type as short string ( s, i, ce, l, ... ), as in overloading macros*/
getShortTypeStrtypes::Sparse236     virtual std::wstring         getShortTypeStr() const
237     {
238         return std::wstring(L"sp");
239     }
240 
241     /* create a new sparse matrix containing the result of an addition
242        @param o other matrix to add
243        @return ptr to the new matrix, 0 in case of failure
244      */
245     Sparse* add(Sparse const& o) const;
246 
247     /* create a new sparse matrix containing the result of an addition
248        @param d scalar to add
249        @return ptr to the new matrix, 0 in case of failure
250      */
251     Double* add(double d) const;
252 
253     /* create a new sparse matrix containing the result of an addition
254        @param c complex  to add
255        @return ptr to the new matrix, 0 in case of failure
256      */
257     Double* add(std::complex<double> c) const;
258 
259 
260 
261 
262     /* create a new sparse matrix containing the result of a substraction
263        @param o other matrix to substract
264        @return ptr to the new matrix, 0 in case of failure
265      */
266     Sparse* substract(Sparse const& o) const;
267 
268     /* create a new sparse matrix containing the result of an subtraction
269        @param d scalar to subtract
270        @return ptr to the new matrix, 0 in case of failure
271      */
272     Double* substract(double d) const;
273 
274     /* create a new sparse matrix containing the result of an subtraction
275        @param c scalar to subtract
276        @return ptr to the new matrix, 0 in case of failure
277      */
278     Double* substract(std::complex<double> c) const;
279 
280 
281     /* create a new sparse matrix containing the result of a multiplication
282        @param o other matrix to substract
283        @return ptr to the new matrix, 0 in case of failure
284      */
285     Sparse* multiply(Sparse const& o) const;
286 
287     /* create a new sparse matrix containing the result of an multiplication
288        @param s scalar to multiply by
289        @return ptr to the new matrix, 0 in case of failure
290      */
291     Sparse* multiply(double s) const;
292 
293     /* create a new sparse matrix containing the result of an multiplication
294        @param c scalar to subtract
295        @return ptr to the new matrix, 0 in case of failure
296      */
297     Sparse* multiply(std::complex<double> c) const;
298 
299     /* create a new matrix containing the result of an .*
300        @param o sparse matrix to .*
301        @return ptr to the new matrix, 0 in case of failure
302      */
303     Sparse* dotMultiply(Sparse SPARSE_CONST& o) const;
304 
305     /* create a new matrix containing the result of an ./
306       @param o sparse matrix to ./
307       @return ptr to the new matrix, 0 in case of failure
308     */
309     Sparse* dotDivide(Sparse SPARSE_CONST& o) const;
310 
311     bool neg(InternalType *& out);
312 
313     bool transpose(InternalType *& out);
314     bool adjoint(InternalType *& out);
315     int newCholLLT(Sparse** permut, Sparse** factor) const;
316 
317     /** create a new sparse matrix containing the non zero values set to 1.
318        equivalent but faster than calling one_set() on a new copy of the
319        current matrix.
320        @return ptr to the new matrix, 0 in case of failure
321      */
322     Sparse* newOnes() const;
323 
324     Sparse* newReal() const;
325     /** @return the nb of non zero values.
326      */
327     std::size_t nonZeros() const;
328 
329     /* @param i row of the current sparse matrix
330        @return the nb of non zero values in row i
331      */
332     std::size_t nonZeros(std::size_t i) const;
333 
334     int* getNbItemByRow(int* _piNbItemByRows);
335     int* getColPos(int* _piColPos);
336     int* getInnerPtr(int* count);
337     int* getOuterPtr(int* count);
338 
339 
340     /**
341        "in-place" cast into a sparse matrix of comlpex values
342      */
343     void toComplex();
344 
345     /* coefficient wise relational operator < between *this sparse matrix and another.
346        Matrices must have the same dimensions except if one of them is of size (1,1)
347        (i.e. a scalar) : it is then treated as a constant matrix of thre required dimensions.
348 
349        @param o other sparse matrix
350 
351        @return ptr to a new Sparse matrix where each element is the result of the logical operator
352         '<' between the elements of *this and those of o.
353      */
354     SparseBool* newLessThan(Sparse &o);
355 
356     /* coefficient wise relational operator != between *this sparse matrix and another.
357        Matrices must have the same dimensions except if one of them is of size (1,1)
358        (i.e. a scalar) : it is then treated as a constant matrix of thre required dimensions.
359 
360        @param o other sparse matrix
361 
362        @return ptr to a new Sparse matrix where each element is the result of the logical operator
363         '!=' between the elements of *this and those of o.
364      */
365     SparseBool* newNotEqualTo(Sparse const&o) const;
366 
367     /* coefficient wise relational operator <= between *this sparse matrix and another.
368        Matrices must have the same dimensions except if one of them is of size (1,1)
369        (i.e. a scalar) : it is then treated as a constant matrix of thre required dimensions.
370 
371        Do not use this function is possible as the result will be dense because
372        0. <= 0. is true, hence the result matrix will hold a non default value (i.e. true)
373        for each pair of default values (0.) of the sparse arguments !
374 
375        @param o other sparse matrix
376 
377        @return ptr to a new Sparse matrix where each element is the result of the logical operator
378         '<=' between the elements of *this and those of o.
379      */
380     SparseBool* newLessOrEqual(Sparse &o);
381 
382     /* coefficient wise relational operator == between *this sparse matrix and another.
383        Matrices must have the same dimensions except if one of them is of size (1,1)
384        (i.e. a scalar) : it is then treated as a constant matrix of thre required dimensions.
385 
386        Do not use this function is possible as the result will be dense because
387        0. == 0. is true, hence the result matrix will hold a non default value (i.e. true)
388        for each pair of default values (0.) of the sparse arguments !
389 
390        @param o other sparse matrix
391 
392        @return ptr to a new Sparse matrix where each element is the result of the logical operator
393         '==' between the elements of *this and those of o.
394      */
395     SparseBool* newEqualTo(Sparse &o);
396 
397     /**
398        output 1-base column numbers of the non zero elements
399        @param out : ptr used as an output iterator over double values
400        @return past-the-end output iterator after ouput is done
401      */
402     double* outputCols(double* out) const;
403 
404     /**
405        output real and imaginary values of the non zero elements
406        @param outReal : ptr used as an output iterator over double values for real values
407        @param outImag : ptr used as an output iterator over double values for imaginary values if any
408        @return pair of past-the-end output iterators after ouput is done
409      */
410     std::pair<double*, double*> outputValues(double* outReal, double* outImag)const;
411 
412     /**
413        ouput rows and afterwards columns of the non zero elements
414        @param out : ptr used as an output iterator over double values
415        @return past-the-end output iterators after ouput is done
416      */
417     int* outputRowCol(int* out)const;
418 
419     /**
420        @param dest Double to be filled with values from the current sparse matrix.
421      */
422     void fill(Double& dest, int r = 0, int c = 0) SPARSE_CONST;
423 
424 
getTypetypes::Sparse425     inline ScilabType  getType(void) SPARSE_CONST
426     {
427         return ScilabSparse;
428     }
429 
getIdtypes::Sparse430     inline ScilabId    getId(void) SPARSE_CONST
431     {
432         if (isComplex())
433         {
434             return IdSparseComplex;
435         }
436         return IdSparse;
437     }
438 
439 
440 
441     SparseBool* newLesserThan(Sparse const&o);
442 
443     typedef Eigen::SparseMatrix<double, 0x1, int>                   RealSparse_t;
444     typedef Eigen::SparseMatrix<std::complex<double>, 0x1, int>     CplxSparse_t;
445     /**
446        One and only one of the args should be 0.
447        @param realSp ptr to an Eigen sparse matrix of double values
448        @param cplxSp ptr to an Eigen sparse matrix of std::complex<double> elements
449      */
450     Sparse(RealSparse_t* realSp, CplxSparse_t* cplxSp);
451 
452     RealSparse_t* matrixReal;
453     CplxSparse_t* matrixCplx;
454 
455 protected :
456 private :
457 
458     /** utility function used by constructors
459         @param rows : nb of rows
460         @param cols : nb of columns
461         @param src : Double matrix data source
462         @param : iterator (cf MatrixIterator.hxx) with indices
463         @param n : nb of elements to copy from data source.
464      */
465     template<typename DestIter>
466     void create(int rows, int cols, Double SPARSE_CONST& src, DestIter o, std::size_t n);
467     void create2(int rows, int cols, Double SPARSE_CONST& src, Double SPARSE_CONST& idx);
468 
469     /** utility function used by insert functions conceptually : sp[destTrav]= src[srcTrav]
470         @param src : data source
471         @param SrcTrav : iterator over the data source
472         @param n : nb of elements to copy
473         @param sp : sparse destination matrix
474         @param destTrav : iterator over the data sink (i.e. sp)
475      */
476     template<typename Src, typename SrcTraversal, typename Sz, typename DestTraversal>
477     static bool copyToSparse(Src SPARSE_CONST& src, SrcTraversal srcTrav, Sz n, Sparse& sp, DestTraversal destTrav);
478 
479     Sparse* insert(typed_list* _pArgs, Sparse* _pSource);
480 };
481 
482 template<typename T>
483 void neg(const int r, const int c, const T * const in, Eigen::SparseMatrix<bool, 1, int> * const out);
484 
485 
486 /*
487   Implement sparse boolean matrix
488  */
489 struct EXTERN_AST SparseBool : GenericType
490 {
491     virtual ~SparseBool();
492     /* @param src: Bool matrix to copy into a new sparse matrix
493     **/
494     SparseBool(Bool SPARSE_CONST& src);
495     /* @param src : Bool matrix to copy into a new sparse matrix
496        @param idx : Double matrix to use as indexes to get values from the src
497     **/
498     SparseBool(Bool SPARSE_CONST& src, Double SPARSE_CONST& idx);
499     /* @param src : Bool matrix to copy into a new sparse matrix
500        @param idx : Double matrix to use as indexes to get values from the src
501        @param dims : Double matrix containing the dimensions of the new matrix
502     **/
503     SparseBool(Bool SPARSE_CONST& src, Double SPARSE_CONST& idx, Double SPARSE_CONST& dims);
504     /*
505        @param rows : nb of rows of the new matrix
506        @param rows : nb of columns of the new matrix
507     */
508     SparseBool(int rows, int cols);
509 
510     SparseBool(SparseBool const& o);
511 
512     //constructor to create a sparse from value extract to another ( save / load operation typically)
513     SparseBool(int rows, int cols, int trues, int* inner, int* outer);
514 
isSparseBooltypes::SparseBool515     bool isSparseBool()
516     {
517         return true;
518     }
519     void finalize();
520 
521     bool getMemory(long long *_piSize, long long* _piSizePlusType);
522 
523     bool toString(std::wostringstream& ostr);
524 
525     /* Config management and GenericType methods overrides */
526     SparseBool* clone(void);
527 
528     SparseBool* resize(int _iNewRows, int _iNewCols);
529     SparseBool* reshape(int* _piNewDims, int _iNewDims);
530     SparseBool* reshape(int _iNewRows, int _iNewCols);
531     SparseBool* insert(typed_list* _pArgs, InternalType* _pSource);
532     SparseBool* append(int _iRows, int _iCols, SparseBool SPARSE_CONST* _poSource);
533 
534     GenericType* remove(typed_list* _pArgs);
535     GenericType* insertNew(typed_list* _pArgs);
536     GenericType* extract(typed_list* _pArgs);
537 
538     SparseBool* extract(int _iSeqCount, int* _piSeqCoord, int* _piMaxDim, int* _piDimSize, bool _bAsVector) SPARSE_CONST;
539 
540     virtual bool invoke(typed_list & in, optional_list &/*opt*/, int /*_iRetCount*/, typed_list & out, const ast::Exp & e);
541     virtual bool isInvokable() const;
542     virtual bool hasInvokeOption() const;
543     virtual int getInvokeNbIn();
544     virtual int getInvokeNbOut();
545 
546     bool transpose(InternalType *& out);
547 
548     /** @return the nb of non zero values.
549      */
550     std::size_t nbTrue() const;
551     /* @param i row of the current sparse matrix
552        @return the nb of non zero values in row i
553      */
554     std::size_t nbTrue(std::size_t i) const;
555 
556     void setTrue(bool finalize = true);
557     void setFalse(bool finalize = true);
558 
559     int* getNbItemByRow(int* _piNbItemByRows);
560     int* getColPos(int* _piColPos);
561     int* getInnerPtr(int* count);
562     int* getOuterPtr(int* count);
563     /**
564        output 1-base column numbers of the non zero elements
565        @param out : ptr used as an output iterator over double values
566        @return past-the-end output iterator after ouput is done
567      */
568 
569     int* outputRowCol(int* out)const;
570 
571     bool operator==(const InternalType& it) SPARSE_CONST;
572     bool operator!=(const InternalType& it) SPARSE_CONST;
573 
574     /* return type as string ( double, int, cell, list, ... )*/
getTypeStrtypes::SparseBool575     virtual std::wstring getTypeStr() const
576     {
577         return std::wstring(L"boolean sparse");
578     }
579     /* return type as short string ( s, i, ce, l, ... )*/
getShortTypeStrtypes::SparseBool580     virtual std::wstring getShortTypeStr() const
581     {
582         return std::wstring(L"spb");
583     }
584 
getTypetypes::SparseBool585     inline ScilabType getType(void) SPARSE_CONST
586     {
587         return ScilabSparseBool;
588     }
589 
getIdtypes::SparseBool590     inline ScilabId getId(void) SPARSE_CONST
591     {
592         return IdSparseBool;
593     }
594 
isScalartypes::SparseBool595     inline bool isScalar()
596     {
597         return (getRows() == 1 && getCols() == 1);
598     }
599 
isTruetypes::SparseBool600     bool isTrue()
601     {
602         if (m_iSize > 0 && static_cast<int>(nbTrue()) == m_iSize)
603         {
604             return true;
605         }
606         return false;
607     }
608 
negtypes::SparseBool609     bool neg(InternalType *& out)
610     {
611         SparseBool * _out = new SparseBool(getRows(), getCols());
612         types::neg(getRows(), getCols(), matrixBool, _out->matrixBool);
613         _out->finalize();
614         out = _out;
615         return true;
616     }
617 
618     void whoAmI() SPARSE_CONST;
619 
620     bool* get();
621     bool get(int r, int c) SPARSE_CONST;
gettypes::SparseBool622     bool get(int _iIndex) SPARSE_CONST
623     {
624         return get(_iIndex % m_iRows, _iIndex / m_iRows);
625     }
626 
627     SparseBool* set(int r, int c, bool b, bool _bFinalize = true) SPARSE_CONST;
settypes::SparseBool628     SparseBool* set(int _iIndex, bool b, bool _bFinalize = true) SPARSE_CONST
629     {
630         return set(_iIndex % m_iRows, _iIndex / m_iRows, b, _bFinalize);
631     }
632 
633     void fill(Bool& dest, int r = 0, int c = 0) SPARSE_CONST;
634 
635     Sparse* newOnes() const;
636     SparseBool* newNotEqualTo(SparseBool const&o) const;
637     SparseBool* newEqualTo(SparseBool& o);
638 
639     SparseBool* newLogicalOr(SparseBool const&o) const;
640     SparseBool* newLogicalAnd(SparseBool const&o) const;
641 
642     typedef Eigen::SparseMatrix<bool, 0x1, int> BoolSparse_t;
643     SparseBool(BoolSparse_t* o);
644     BoolSparse_t* matrixBool;
645 
646 private:
647     void create2(int rows, int cols, Bool SPARSE_CONST& src, Double SPARSE_CONST& idx);
648     SparseBool* insert(typed_list* _pArgs, SparseBool* _pSource);
649 };
650 
651 template<typename T>
652 struct SparseTraits
653 {
654     typedef types::Sparse type;
655 };
656 template<>
657 struct SparseTraits<types::Bool>
658 {
659     typedef types::SparseBool type;
660 };
661 template<>
662 struct SparseTraits<types::SparseBool>
663 {
664     typedef types::SparseBool type;
665 };
666 
667 }
668 
669 #endif /* !__SPARSE_HH__ */
670