6c14bb61b220932bd7037033dad12d8c43c1381c
[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         switch (in[i]->getType())
41         {
42             case types::InternalType::ScilabBool :
43             case types::InternalType::ScilabSparseBool :
44             {
45                 isValid = (i == (in.size() > 1) ? 1 : 0);
46             }
47             case types::InternalType::ScilabDouble :
48             case types::InternalType::ScilabSparse :
49             {
50                 break;
51             }
52             default :
53             {
54                 isValid = false;
55             }
56         }
57
58         if (!isValid)
59         {
60             Scierror(999, _("%s: Wrong type for input argument #%d: Matrix expected.\n"), "sparse", i + 1);
61             return types::Function::Error;
62         }
63     }
64     // if one argument is given, it will be a matrix of constant or sparse type, which will be converted into a sparse matrix
65     if (in.size() == 1)
66     {
67         switch (in[0]->getType())
68         {
69             case types::InternalType::ScilabSparse :
70             {
71                 pRetVal = new types::Sparse(*in[0]->getAs<types::Sparse>());
72                 break;
73             }
74             case types::InternalType::ScilabDouble :
75             {
76                 if (in[0]->getAs<types::Double>()->isEmpty())
77                 {
78                     out.push_back(types::Double::Empty());
79                     return types::Function::OK;
80                 }
81
82                 if (in[0]->getAs<types::Double>()->isIdentity())
83                 {
84                     out.push_back(in[0]);
85                     return types::Function::OK;
86                 }
87
88                 pRetVal = new types::Sparse(*in[0]->getAs<types::Double>());
89                 break;
90             }
91             case types::InternalType::ScilabBool :
92             {
93                 pRetVal = new types::SparseBool(*in[0]->getAs<types::Bool>());
94                 break;
95             }
96             case types::InternalType::ScilabSparseBool :
97             {
98                 pRetVal = new types::SparseBool(*in[0]->getAs<types::SparseBool>());
99                 break;
100             }
101             default :
102             {
103                 pRetVal = NULL;
104             }
105         }
106     }
107     else if (in.size() == 2 || in.size() == 3)
108     {
109         // 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
110         for (int i = 0 ; i < in.size() ; i++)
111         {
112             if (in[i]->isDouble() == false && !(in[i]->isBool() && i == 1))
113             {
114                 Scierror(999, _("%s: Wrong type for input argument #%d: Real or Complex matrix expected.\n"), "sparse", i + 1);
115                 return types::Function::Error;
116             }
117         }
118
119         //Double* pDims( (in.size()==3) ? in[2]->getAs<Double>() : 0);
120         types::Double* pDims = NULL;
121         if (in.size() == 3)
122         {
123             pDims = in[2]->getAs<types::Double>();
124             if (pDims->getRows() != 1 || pDims->getCols() != 2)
125             {
126                 Scierror(999, _("%s: Wrong size for input argument #%d: A matrix of size %d x %d expected.\n"), "sparse", 3, 1, 2);
127                 return types::Function::Error;
128             }
129
130             if (pDims->get(0) * pDims->get(1) == 0)
131             {
132                 out.push_back(types::Double::Empty());
133                 return types::Function::OK;
134             }
135         }
136
137         types::Double* ij = in[0]->getAs<types::Double>();
138         types::GenericType* pGT2 = in[1]->getAs<types::GenericType>();
139
140         if (pGT2->getSize() != ij->getRows())
141         {
142             Scierror(999, _("%s: Wrong size for input argument #%d: A matrix of size %d expected.\n"), "sparse", 2, ij->getRows());
143             return types::Function::Error;
144         }
145
146         bool alloc = false;
147         if (pDims == nullptr)
148         {
149             int size = ij->getRows();
150             double* i = ij->get();
151             double* j = i + ij->getRows();
152             pDims = new types::Double(1, 2, false);
153             pDims->set(0, *std::max_element(i, i + size));
154             pDims->set(1, *std::max_element(j, j + size));
155             alloc = true;
156         }
157
158         if (in[1]->isDouble())
159         {
160             types::Double* dbl = pGT2->getAs<types::Double>();
161             pRetVal = new types::Sparse(*dbl, *ij, *pDims);
162         }
163         else
164         {
165             types::Bool* b = pGT2->getAs<types::Bool>();
166             pRetVal = new types::SparseBool(*b, *ij, *pDims);
167         }
168
169         if (alloc)
170         {
171             delete pDims;
172         }
173     }
174
175     if (pRetVal == NULL)
176     {
177         return types::Function::Error;
178     }
179
180     out.push_back(pRetVal);
181     return types::Function::OK;
182 }