[sparse] now sparse([]) is sparse
[scilab.git] / scilab / modules / sparse / sci_gateway / cpp / sci_sparse.cpp
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 #include <algorithm>
17
18 #include "sparse_gw.hxx"
19 #include "function.hxx"
20 #include "sparse.hxx"
21 #include "double.hxx"
22
23 extern "C"
24 {
25 #include "charEncoding.h"
26 #include "Scierror.h"
27 #include "localization.h"
28 }
29
30 types::Function::ReturnValue sci_sparse(types::typed_list &in, int _piRetCount, types::typed_list &out)
31 {
32     bool isValid = true;
33     types::GenericType* pRetVal = NULL;
34
35     // per the scilab manual sparse will take upto 3 arguments but no less than one
36     if (in.size() < 1 || in.size() > 3)
37     {
38         Scierror(999, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "sparse", 1, 3);
39         return types::Function::Error;
40     }
41
42     for (int i = 0 ; isValid && i < in.size() ; i++)
43     {
44         // Valid input arguments are of Bool and Double types (dense or sparse)
45         switch (in[i]->getType())
46         {
47             case types::InternalType::ScilabBool :
48             case types::InternalType::ScilabSparseBool :
49             {
50                 isValid = (i == (in.size() > 1) ? 1 : 0);
51             }
52             case types::InternalType::ScilabDouble :
53             case types::InternalType::ScilabSparse :
54             {
55                 break;
56             }
57             default :
58             {
59                 isValid = false;
60             }
61         }
62
63         if (!isValid)
64         {
65             Scierror(999, _("%s: Wrong type for input argument #%d: Matrix expected.\n"), "sparse", i + 1);
66             return types::Function::Error;
67         }
68
69         // Valid input arguments are matrices and not hypermatrices
70         if ( in[i]->getAs<types::GenericType>()->getDims() > 2 )
71         {
72             Scierror(999, _("%s: Wrong size for input argument #%d: A m-by-n matrix expected.\n"), "sparse", i + 1);
73             return types::Function::Error;
74         }
75
76     }
77     // if one argument is given, it will be a matrix of constant or sparse type, which will be converted into a sparse matrix
78     if (in.size() == 1)
79     {
80         switch (in[0]->getType())
81         {
82             case types::InternalType::ScilabSparse :
83             {
84                 pRetVal = new types::Sparse(*in[0]->getAs<types::Sparse>());
85                 break;
86             }
87             case types::InternalType::ScilabDouble :
88             {
89                 if (in[0]->getAs<types::Double>()->isEmpty())
90                 {
91                     pRetVal = new types::Sparse(0,0,false);
92                     break;
93                 }
94
95                 if (in[0]->getAs<types::Double>()->isIdentity())
96                 {
97                     out.push_back(in[0]);
98                     return types::Function::OK;
99                 }
100
101                 pRetVal = new types::Sparse(*in[0]->getAs<types::Double>());
102                 break;
103             }
104             case types::InternalType::ScilabBool :
105             {
106                 pRetVal = new types::SparseBool(*in[0]->getAs<types::Bool>());
107                 break;
108             }
109             case types::InternalType::ScilabSparseBool :
110             {
111                 pRetVal = new types::SparseBool(*in[0]->getAs<types::SparseBool>());
112                 break;
113             }
114             default :
115             {
116                 pRetVal = NULL;
117             }
118         }
119     }
120     else // 2 or 3 arguments
121     {
122         types::Double* pDij = in[0]->getAs<types::Double>(); // arg 2 necessarily *Double
123         types::GenericType* pGT2 = in[1]->getAs<types::GenericType>();
124         int size = pGT2->getSize();
125
126         if ( ((size !=0) || (pDij->getSize() != 0)) && ((pDij->getCols() != 2) || (pDij->getRows() != size)))
127         {
128             if (size > 0)
129             {
130                 Scierror(999, _("%s: Wrong size for input argument #%d: A matrix of size %d x %d expected.\n"), "sparse", 1, size, 2);
131             }
132             else
133             {
134                 Scierror(999, _("%s: Wrong size for input argument #%d: An empty matrix expected.\n"), "sparse", 1);
135             }
136             return types::Function::Error;
137         }
138
139         //Double* pDdims( (in.size()==3) ? in[2]->getAs<Double>() : 0);
140         types::Double* pDdims = NULL;
141         if (in.size() == 3)
142         {
143             pDdims = in[2]->getAs<types::Double>();
144             if (pDdims->getSize() != 2)
145             {
146                 Scierror(999, _("%s: Wrong size for input argument #%d: A matrix of size %d x %d expected.\n"), "sparse", 3, 1, 2);
147                 return types::Function::Error;
148             }
149
150             if (pDdims->get(0) != (double) ( (unsigned int) pDdims->get(0) ) || pDdims->get(1) != (double) ( (unsigned int) pDdims->get(1) ))
151             {
152                 Scierror(999, _("%s: Wrong values for input argument #%d: Positive integers expected.\n"), "sparse", 3);
153                 return types::Function::Error;
154             }
155         }
156
157         bool alloc = false;
158         double* pdbli = pDij->get();
159         double* pdblj = pdbli + size;
160
161         for (int i = 0; i < 2*size; i++)
162         {
163             pdbli[i] = trunc(pdbli[i]);
164         }
165
166         if ( (size > 0) && ((*std::min_element(pdbli, pdbli + size) <= 0) || (*std::min_element(pdblj, pdblj + size) <= 0)) )
167         {
168             Scierror(999, _("%s: Invalid index.\n"), "sparse");
169             return types::Function::Error;
170         }
171         
172         if (pDdims == nullptr)
173         {
174             pDdims = new types::Double(1, 2, false);
175             pDdims->setZeros();
176             if (size > 0)
177             {
178                 pDdims->set(0, *std::max_element(pdbli, pdbli + size));
179                 pDdims->set(1, *std::max_element(pdblj, pdblj + size));
180             }
181             alloc = true;
182         }
183         else if ( (size > 0) && ((pDdims->get(0) < *std::max_element(pdbli, pdbli + size)) 
184                   || (pDdims->get(1) < *std::max_element(pdblj, pdblj + size))) )
185         {
186             Scierror(999, _("%s: Invalid index.\n"),"sparse");
187             return types::Function::Error;
188         }
189
190         if ((pDdims->get(0) == 0) || (pDdims->get(1) == 0))
191         {
192             pRetVal = new types::Sparse(0,0,false);
193         }
194         else if (in[1]->isDouble())
195         {
196             types::Double* pDbl = pGT2->getAs<types::Double>();
197             pRetVal = new types::Sparse(*pDbl, *pDij, *pDdims);
198         }
199         else
200         {
201             types::Bool* pBb = pGT2->getAs<types::Bool>();
202             pRetVal = new types::SparseBool(*pBb, *pDij, *pDdims);
203         }
204
205         if (alloc)
206         {
207             delete pDdims;
208         }
209     }
210
211     if (pRetVal == NULL)
212     {
213         return types::Function::Error;
214     }
215
216     out.push_back(pRetVal);
217     return types::Function::OK;
218 }