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