/* * Copyright (c) 2002-2006 Samit Basu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "Array.hpp" #include "Math.hpp" #include "Exception.hpp" #include #include #include "Core.hpp" #include "Malloc.hpp" #include //! //@Module RESHAPE Reshape An Array //@@Section ARRAY //@@Usage //Reshapes an array from one size to another. Two seperate //syntaxes are possible. The first syntax specifies the array //dimensions as a sequence of scalar dimensions: //@[ // y = reshape(x,d1,d2,...,dn). //@] //The resulting array has the given dimensions, and is filled with //the contents of @|x|. The type of @|y| is the same as @|x|. //The second syntax specifies the array dimensions as a vector, //where each element in the vector specifies a dimension length: //@[ // y = reshape(x,[d1,d2,...,dn]). //@] //This syntax is more convenient for calling @|reshape| using a //variable for the argument. The //@|reshape| function requires that the length of @|x| equal the product //of the @|di| values. //Note that arrays are stored in column format, //which means that elements in @|x| are transferred to the new array //@|y| starting with the first column first element, then proceeding to //the last element of the first column, then the first element of the //second column, etc. //@@Example //Here are several examples of the use of @|reshape| applied to //various arrays. The first example reshapes a row vector into a //matrix. //@< //a = uint8(1:6) //reshape(a,2,3) //@> //The second example reshapes a longer row vector into a volume with //two planes. //@< //a = uint8(1:12) //reshape(a,[2,3,2]) //@> //The third example reshapes a matrix into another matrix. //@< //a = [1,6,7;3,4,2] //reshape(a,3,2) //@> //! ArrayVector ReshapeFunction(int nargout, const ArrayVector& arg) { Array t, s; Dimensions dims; int32 *dp; int i; if (arg.size() == 0) throw Exception("reshape function requires at least one argument"); Array x(arg[0]); if (arg.size() == 1) { ArrayVector retval; retval.push_back(x); return retval; } // Case 1 - all of the entries are scalar bool allScalars; allScalars = true; for (i=1;i 2) throw Exception("Arguments to reshape function must be either all scalars or a single vector"); t = arg[1]; t.promoteType(FM_UINT32); dp = (int*) t.getDataPointer(); for (i=0;i= 0); if (!allPositive) throw Exception("reshape function requires positive arguments"); dims.simplify(); x.reshape(dims); ArrayVector retval; retval.push_back(x); return retval; } //! //@Module ZEROS Array of Zeros //@@Section ARRAY //@@Usage //Creates an array of zeros of the specified size. Two seperate //syntaxes are possible. The first syntax specifies the array //dimensions as a sequence of scalar dimensions: //@[ // y = zeros(d1,d2,...,dn). //@] //The resulting array has the given dimensions, and is filled with //all zeros. The type of @|y| is @|double|, a 64-bit floating //point array. To get arrays of other types, use the typecast //functions (e.g., @|uint8|, @|int8|, etc.). An alternative syntax //is to use the following notation: //@[ // y = zeros(d1,d2,...,dn,classname) //@] //where @|classname| is one of 'double', 'single', 'int8', 'uint8', //'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', 'float', 'logical'. // //The second syntax specifies the array dimensions as a vector, //where each element in the vector specifies a dimension length: //@[ // y = zeros([d1,d2,...,dn]), //@] //or //@[ // y = zeros([d1,d2,...,dn],classname). //@] //This syntax is more convenient for calling @|zeros| using a //variable for the argument. In both cases, specifying only one //dimension results in a square matrix output. //@@Example //The following examples demonstrate generation of some zero arrays //using the first form. //@< //zeros(2,3,2) //zeros(1,3) //@> //The same expressions, using the second form. //@< //zeros([2,6]) //zeros([1,3]) //@> //Finally, an example of using the type casting function @|uint16| to generate an array of 16-bit unsigned integers with zero values. //@< //uint16(zeros(3)) //@> //Here we use the second syntax where the class of the output is specified //explicitly //@< //zeros(3,'int16') //@> //@@Tests //@{ test_sparse69.m //% Test the zeros function //function x = test_sparse69 //xi = int32(sparse(100,200)); //yi = int32(zeros(100,200)); //xf = float(sparse(100,200)); //yf = float(zeros(100,200)); //xd = double(sparse(100,200)); //yd = double(zeros(100,200)); //xc = complex(sparse(100,200)); //yc = complex(zeros(100,200)); //xz = dcomplex(sparse(100,200)); //yz = dcomplex(zeros(100,200)); //x = testeq(xi,yi) & testeq(xf,yf) & testeq(xd,yd) & testeq(xc,yc) & testeq(xz,yz); //@} //! ArrayVector ZerosFunction(int nargout, const ArrayVector& arg) { Array t, s; Dimensions dims; int32 *dp; Class cls = FM_DOUBLE; int i; // Trim out the classname if it was specified ArrayVector trim_arg(arg); if (trim_arg.size() > 0) { // Check for the classname if (trim_arg.back().isString()) { // Get the classname as a string string cp = ArrayToString(trim_arg.back()); // Convert to lowercase string dp(cp); std::transform(dp.begin(),dp.end(),dp.begin(),(int(*)(int))tolower); if (cp=="double") cls = FM_DOUBLE; else if (cp=="single") cls = FM_FLOAT; else if (cp=="float") cls = FM_FLOAT; else if (cp=="int8") cls = FM_INT8; else if (cp=="uint8") cls = FM_UINT8; else if (cp=="int16") cls = FM_INT16; else if (cp=="uint16") cls = FM_UINT16; else if (cp=="int32") cls = FM_INT32; else if (cp=="uint32") cls = FM_UINT32; else if (cp=="int64") cls = FM_INT64; else if (cp=="uint64") cls = FM_UINT64; else if (cp=="logical") cls = FM_LOGICAL; else throw Exception(std::string("Unsupported type ") + cp + std::string(" as classname argument to zeros function")); // Remove the classspec trim_arg.pop_back(); } } if (trim_arg.size() == 0) dims.makeScalar(); else { // Case 1 - all of the entries are scalar bool allScalars; allScalars = true; for (i=0;i 1) throw Exception("Arguments to zeros function must be either all scalars or a single vector"); t = trim_arg[0]; t.promoteType(FM_UINT32); dp = (int*) t.getDataPointer(); for (i=0;i= 0); if (!allPositive) throw Exception("Zeros function requires positive arguments"); } s = Array(cls,dims,Calloc(TypeSize(cls)*dims.getElementCount())); ArrayVector retval; retval.push_back(s); return retval; } //! //@Module CELL Cell Array of Empty Matrices //@@Section ARRAY //@@Usage //Creates a cell array of empty matrix entres. Two seperate //syntaxes are possible. The first syntax specifies the array //dimensions as a sequence of scalar dimensions: //@[ // y = cell(d1,d2,...,dn). //@] //The resulting array has the given dimensions, and is filled with //all zeros. The type of @|y| is @|cell|, a cell array. // //The second syntax specifies the array dimensions as a vector, //where each element in the vector specifies a dimension length: //@[ // y = cell([d1,d2,...,dn]). //@] //This syntax is more convenient for calling @|zeros| using a //variable for the argument. In both cases, specifying only one //dimension results in a square matrix output. //@@Example //The following examples demonstrate generation of some zero arrays //using the first form. //@< //cell(2,3,2) //cell(1,3) //@> //The same expressions, using the second form. //@< //cell([2,6]) //cell([1,3]) //@> //! ArrayVector CellFunction(int nargout, const ArrayVector& arg) { Array t, s; Dimensions dims; int32 *dp; int i; if (arg.size() == 0) dims.makeScalar(); else { // Case 1 - all of the entries are scalar bool allScalars; allScalars = true; for (i=0;i 1) throw Exception("Arguments to cell function must be either all scalars or a single vector"); t = arg[0]; t.promoteType(FM_UINT32); dp = (int*) t.getDataPointer(); for (i=0;i= 0); if (!allPositive) throw Exception("Zeros function requires positive arguments"); } s = Array(FM_CELL_ARRAY,dims,Array::allocateArray(FM_CELL_ARRAY,dims.getElementCount())); ArrayVector retval; retval.push_back(s); return retval; } //! //@Module ONES Array of Ones //@@Section ARRAY //@@Usage //Creates an array of ones of the specified size. Two seperate //syntaxes are possible. The first syntax specifies the array //dimensions as a sequence of scalar dimensions: //@[ // y = ones(d1,d2,...,dn). //@] //The resulting array has the given dimensions, and is filled with //all ones. The type of @|y| is @|float|, a 32-bit floating //point array. To get arrays of other types, use the typecast //functions (e.g., @|uint8|, @|int8|, etc.). // //The second syntax specifies the array dimensions as a vector, //where each element in the vector specifies a dimension length: //@[ // y = ones([d1,d2,...,dn]). //@] //This syntax is more convenient for calling @|ones| using a //variable for the argument. In both cases, specifying only one //dimension results in a square matrix output. //@@Example //The following examples demonstrate generation of some arrays of ones //using the first form. //@< //ones(2,3,2) //ones(1,3) //@> //The same expressions, using the second form. //@< //ones([2,6]) //ones([1,3]) //@> //Finally, an example of using the type casting function @|uint16| to generate an array of 16-bit unsigned integers with a value of 1. //@< //uint16(ones(3)) //@> //! ArrayVector OnesFunction(int nargout, const ArrayVector& arg) { Array t, s; Dimensions dims; int32 *dp; int i; if (arg.size() == 0) dims.makeScalar(); else { // Case 1 - all of the entries are scalar bool allScalars; allScalars = true; for (i=0;i 1) throw Exception("Arguments to ones function must be either all scalars or a single vector"); t = arg[0]; t.promoteType(FM_UINT32); dp = (int*) t.getDataPointer(); for (i=0;i= 0); if (!allPositive) throw Exception("Ones function requires positive arguments"); } int len; len = dims.getElementCount(); float *qp; qp = (float*) Malloc(sizeof(float)*len); for (i=0;i // //An alternate way to create a structure array is to initialize the last //element of each field of the structure //@< //Test(2,3).Type = 'Beer'; //Test(2,3).Ounces = 12; //Test(2,3).Container = 'Can'; //Test(2,3) //Test(1,1) //@> //@@Tests //@{ test_struct1.m //% Test the ability to combine structures with different ordering in their elements. //function test_val = test_struct1 //a.foo = 1; //a.goo = 2; //b.goo = 5; //b.foo = 4; //c = [a,b]; //test_val = (c(1).foo == 1) & (c(2).foo == 4) & (c(1).goo == 2) & (c(2).foo == 4); //@} //@{ test_struct2.m //% Test the ability to combine structues with different fields - when valid //function test_val = test_struct2 //a.foo = 1; //a.goo = 2; //b.goo = 5; //c = [a,b]; //test_val = (c(1).foo == 1) & (c(1).goo == 2) & (c(2).goo == 5); //@} //@{ test_struct3.m //% Test the ability to add a new field name to a structure //function test_val = test_struct3 //a.foo = 1; //a.goo = 2; //c(1) = a; //c(2) = a; //c(1).hoo = 6; //test_val = (c(1).foo == 1) & (c(2).foo == 1) & (c(1).goo == 2) & (c(2).goo == 2) & (c(1).hoo == 6); //@} //@{ test_struct4.m //% Test the structure constructor //function test_val = test_struct4 //a = struct('foo',4,'goo',{5},'hoo',{'time',8}); //test_val = test(a(1).foo == 4) & test(a(2).foo == 4) ... // & test(a(1).goo == 5) & test(a(2).goo == 5) ... // & test(strcmp(a(1).hoo,'time')) & test(a(2).hoo == 8); //@} //@{ test_struct5.m //% Test the field dereference as an expression list //function test_val = test_struct5 // a = struct('foo',{5,8,10}); // sm = test_struct5_assist(a.foo); // test_val = test(sm == 23); // //function a = test_struct5_assist(b,c,d) // a = b + c + d; //@} //@{ test_struct6.m //% Test the field set function with a scalar argument //function test_val = test_struct6 // a = struct('foo',5,'color','blue'); // a.color = 'red'; // test_val = test(strcmp(a.color,'red')); //@} //@{ test_struct7.m //% Test the field set function with a vector argument //function test_val = test_struct7 // a = struct('foo',{6,5,3},'color','blue'); // test_val = 0; // try // a.foo = 7; // catch // test_val = 1; // end //@} //@{ test_struct8.m //% Test the structure field-based multiple assign in a function call //function test_val = test_struct8 //a = struct('foo',{0,0,0,0}); //[a.foo] = test_struct8_assist; //test_val = test(a(1).foo == 1) & test(a(2).foo == 2) & ... // test(a(3).foo == 3) & test(a(4).foo == 4); // //function [a,b,c,d] = test_struct8_assist // a = 1; // b = 2; // c = 3; // d = 4; //@} //@{ test_struct9.m //% Test the ability to assign a single element in a structure array //function test_val = test_struct9 //d = struct('foo',3,'goo','hello','shoo',1:5); //d(3).shoo = 3; //test_val = test(d(3).shoo == 3); //@} //! ArrayVector StructFunction(int nargout, const ArrayVector& arg) { if (arg.size() == 1) { Array t(arg[0]); if (!t.isUserClass() && t.dataClass() == FM_STRUCT_ARRAY) return singleArrayVector(t); if (!t.isUserClass()) throw Exception("can only convert objects (user-defined types) into structs"); t.setClassName(rvstring()); return singleArrayVector(t); } if (arg.size() % 2) throw Exception("struct function requires pairs of field names and values"); int pairCount = arg.size() / 2; rvstring names; ArrayVector values; for (int i=0;i