Forbid creation of sparse matrix with sparse(hm)
[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  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 #include <algorithm>
14
15 #include "sparse_gw.hxx"
16 #include "function.hxx"
17 #include "sparse.hxx"
18
19 extern "C"
20 {
21 #include "charEncoding.h"
22 #include "Scierror.h"
23 #include "localization.h"
24 }
25
26 types::Function::ReturnValue sci_sparse(types::typed_list &in, int _piRetCount, types::typed_list &out)
27 {
28     bool isValid = true;
29     types::GenericType* pRetVal = NULL;
30
31     // per the scilab manual sparse will take upto 3 arguments but no less than one
32     if (in.size() < 1 || in.size() > 3)
33     {
34         Scierror(999, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "sparse", 1, 3);
35         return types::Function::Error;
36     }
37
38     for (int i = 0 ; isValid && i < in.size() ; i++)
39     {
40         // Valid input arguments are of Bool and Double types (dense or sparse)
41         switch (in[i]->getType())
42         {
43             case types::InternalType::ScilabBool :
44             case types::InternalType::ScilabSparseBool :
45             {
46                 isValid = (i == (in.size() > 1) ? 1 : 0);
47             }
48             case types::InternalType::ScilabDouble :
49             case types::InternalType::ScilabSparse :
50             {
51                 break;
52             }
53             default :
54             {
55                 isValid = false;
56             }
57         }
58
59         if (!isValid)
60         {
61             Scierror(999, _("%s: Wrong type for input argument #%d: Matrix expected.\n"), "sparse", i + 1);
62             return types::Function::Error;
63         }
64
65         // Valid input arguments are matrices and not hypermatrices
66         if ( in[i]->getAs<types::GenericType>()->getDims() > 2 )
67         {
68             Scierror(999, _("%s: Wrong size for input argument #%d: A m-by-n matrix expected.\n"), "sparse", i + 1);
69             return types::Function::Error;
70         }
71
72     }
73     // if one argument is given, it will be a matrix of constant or sparse type, which will be converted into a sparse matrix
74     if (in.size() == 1)
75     {
76         switch (in[0]->getType())
77         {
78             case types::InternalType::ScilabSparse :
79             {
80                 pRetVal = new types::Sparse(*in[0]->getAs<types::Sparse>());
81                 break;
82             }
83             case types::InternalType::ScilabDouble :
84             {
85                 if (in[0]->getAs<types::Double>()->isEmpty())
86                 {
87                     out.push_back(types::Double::Empty());
88                     return types::Function::OK;
89                 }
90
91                 if (in[0]->getAs<types::Double>()->isIdentity())
92                 {
93                     out.push_back(in[0]);
94                     return types::Function::OK;
95                 }
96
97                 pRetVal = new types::Sparse(*in[0]->getAs<types::Double>());
98                 break;
99             }
100             case types::InternalType::ScilabBool :
101             {
102                 pRetVal = new types::SparseBool(*in[0]->getAs<types::Bool>());
103                 break;
104             }
105             case types::InternalType::ScilabSparseBool :
106             {
107                 pRetVal = new types::SparseBool(*in[0]->getAs<types::SparseBool>());
108                 break;
109             }
110             default :
111             {
112                 pRetVal = NULL;
113             }
114         }
115     }
116     else if (in.size() == 2 || in.size() == 3)
117     {
118         // if two arguments are given the first is a 'n x 2' matrix of the non zero indices and the second is a 'n x 1' vector of the values
119         for (int i = 0 ; i < in.size() ; i++)
120         {
121             if (in[i]->isDouble() == false && !(in[i]->isBool() && i == 1))
122             {
123                 Scierror(999, _("%s: Wrong type for input argument #%d: Real or Complex matrix expected.\n"), "sparse", i + 1);
124                 return types::Function::Error;
125             }
126         }
127
128         //Double* pDims( (in.size()==3) ? in[2]->getAs<Double>() : 0);
129         types::Double* pDims = NULL;
130         if (in.size() == 3)
131         {
132             pDims = in[2]->getAs<types::Double>();
133             if (pDims->getRows() != 1 || pDims->getCols() != 2)
134             {
135                 Scierror(999, _("%s: Wrong size for input argument #%d: A matrix of size %d x %d expected.\n"), "sparse", 3, 1, 2);
136                 return types::Function::Error;
137             }
138
139             if (pDims->get(0) * pDims->get(1) == 0)
140             {
141                 out.push_back(types::Double::Empty());
142                 return types::Function::OK;
143             }
144         }
145
146         types::Double* ij = in[0]->getAs<types::Double>();
147         types::GenericType* pGT2 = in[1]->getAs<types::GenericType>();
148
149         if (pGT2->getSize() != ij->getRows())
150         {
151             Scierror(999, _("%s: Wrong size for input argument #%d: A matrix of size %d expected.\n"), "sparse", 2, ij->getRows());
152             return types::Function::Error;
153         }
154
155         bool alloc = false;
156         if (pDims == nullptr)
157         {
158             int size = ij->getRows();
159             double* i = ij->get();
160             double* j = i + ij->getRows();
161             pDims = new types::Double(1, 2, false);
162             pDims->set(0, *std::max_element(i, i + size));
163             pDims->set(1, *std::max_element(j, j + size));
164             alloc = true;
165         }
166
167         if (in[1]->isDouble())
168         {
169             types::Double* dbl = pGT2->getAs<types::Double>();
170             pRetVal = new types::Sparse(*dbl, *ij, *pDims);
171         }
172         else
173         {
174             types::Bool* b = pGT2->getAs<types::Bool>();
175             pRetVal = new types::SparseBool(*b, *ij, *pDims);
176         }
177
178         if (alloc)
179         {
180             delete pDims;
181         }
182     }
183
184     if (pRetVal == NULL)
185     {
186         return types::Function::Error;
187     }
188
189     out.push_back(pRetVal);
190     return types::Function::OK;
191 }