Comparing version 1.2.1 to 1.2.2
@@ -5,4 +5,13 @@ # Release notes | ||
## 1.2.2 | ||
- Bug fix in function 'cat'. | ||
- User functions cummin, cummax, cumsum, cumprod, ndims, rows, columns, length, numel, isempty and reshape. | ||
- Bug fix in MultiArray.unparse and MultiArray.unparseMathML (null array). | ||
- Bug fix in MultiArray constructor (dimension.length >= 2). | ||
- Bug fix in MultiArray.isEmpty. | ||
- Functions newFilled and newFilledEach in MultiArray class moved to CoreFunctions and optimized. | ||
- Some methods related to multiple assignment in Evaluator changed to static functions. | ||
## 1.2.1 | ||
- Several methods and properties have been renamed to express their functions more clearly. | ||
- More methods and properties have been renamed to express their functions more clearly. | ||
- Code cleaning by hand. | ||
@@ -9,0 +18,0 @@ - Bug fix in MultiArray.newFilledEach (used in rand and randi functions). |
@@ -20,3 +20,3 @@ import { Decimal } from 'decimal.js'; | ||
/** | ||
* Functions with one argument (mappings) | ||
* Functions with one argument (mappers) | ||
*/ | ||
@@ -23,0 +23,0 @@ static mapFunction: Record<string, Function>; |
import { ComplexDecimal } from './complex-decimal'; | ||
import { MultiArray } from './multi-array'; | ||
import { NodeReturnList } from './evaluator'; | ||
import { CharString } from './char-string'; | ||
export declare abstract class CoreFunctions { | ||
@@ -9,2 +10,39 @@ static functions: { | ||
/** | ||
* | ||
* @param name | ||
*/ | ||
static throwInvalidCallError(name: string): void; | ||
/** | ||
* | ||
* @param M | ||
* @returns | ||
*/ | ||
static isempty(M: MultiArray | ComplexDecimal): ComplexDecimal; | ||
/** | ||
* Return the number of dimensions of M. | ||
* @param M | ||
* @returns | ||
*/ | ||
static ndims(M: MultiArray | ComplexDecimal): ComplexDecimal | undefined; | ||
/** | ||
* eturn the number of rows of M. | ||
* @param M | ||
* @returns | ||
*/ | ||
static rows(M: MultiArray | ComplexDecimal): ComplexDecimal | undefined; | ||
/** | ||
* Return the number of columns of M. | ||
* @param M | ||
* @returns | ||
*/ | ||
static columns(M: MultiArray | ComplexDecimal): ComplexDecimal | undefined; | ||
/** | ||
* Return the length of the object M. The length is the number of elements | ||
* along the largest dimension. | ||
* @param M | ||
* @returns | ||
*/ | ||
static Length(M: MultiArray | ComplexDecimal): ComplexDecimal | undefined; | ||
static numel(M: MultiArray | ComplexDecimal, ...IDX: (MultiArray | ComplexDecimal | CharString)[]): ComplexDecimal; | ||
/** | ||
* Convert linear indices to subscripts. | ||
@@ -29,4 +67,26 @@ * @param DIMS | ||
*/ | ||
static size(M: MultiArray | ComplexDecimal, ...DIM: any): MultiArray | ComplexDecimal; | ||
static size(M: MultiArray | ComplexDecimal, ...DIM: any): MultiArray | ComplexDecimal | undefined; | ||
/** | ||
* | ||
* @param M | ||
* @param dimension | ||
* @returns | ||
*/ | ||
static reshape(M: MultiArray | ComplexDecimal, ...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal; | ||
/** | ||
* Create MultiArray with all elements equals `fill` parameter. | ||
* @param fill Value to fill MultiArray. | ||
* @param dimension Dimensions of created MultiArray. | ||
* @returns MultiArray filled with `fill` parameter. | ||
*/ | ||
private static newFilled; | ||
/** | ||
* Create MultiArray with all elements filled with `fillFunction` result. | ||
* The parameter passed to `fillFunction` is a linear index of element. | ||
* @param fillFunction Function to be called and the result fills element of MultiArray created. | ||
* @param dimension Dimensions of created MultiArray. | ||
* @returns MultiArray filled with `fillFunction` results for each element. | ||
*/ | ||
private static newFilledEach; | ||
/** | ||
* Create array of all zeros. | ||
@@ -36,3 +96,3 @@ * @param dimension | ||
*/ | ||
static zeros(...dimension: any): MultiArray | ComplexDecimal; | ||
static zeros(...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal; | ||
/** | ||
@@ -43,3 +103,3 @@ * Create array of all ones. | ||
*/ | ||
static ones(...dimension: any): MultiArray | ComplexDecimal; | ||
static ones(...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal; | ||
/** | ||
@@ -51,3 +111,3 @@ * Uniformly distributed pseudorandom numbers distributed on the | ||
*/ | ||
static rand(...dimension: any): MultiArray | ComplexDecimal; | ||
static rand(...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal; | ||
/** | ||
@@ -59,3 +119,3 @@ * Uniformly distributed pseudorandom integers. | ||
*/ | ||
static randi(range: MultiArray | ComplexDecimal, ...dimension: any): MultiArray | ComplexDecimal; | ||
static randi(range: MultiArray | ComplexDecimal, ...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal; | ||
/** | ||
@@ -87,3 +147,3 @@ * Return the concatenation of N-D array objects, ARRAY1, ARRAY2, ..., | ||
*/ | ||
static sum(M: MultiArray, DIM?: ComplexDecimal): MultiArray | ComplexDecimal; | ||
static sum(M: MultiArray, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal; | ||
/** | ||
@@ -95,3 +155,3 @@ * Calculate sum of squares of elements along dimension DIM. | ||
*/ | ||
static sumsq(M: MultiArray, DIM?: ComplexDecimal): MultiArray | ComplexDecimal; | ||
static sumsq(M: MultiArray, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal; | ||
/** | ||
@@ -103,3 +163,3 @@ * Calculate product of elements along dimension DIM. | ||
*/ | ||
static prod(M: MultiArray, DIM?: ComplexDecimal): MultiArray | ComplexDecimal; | ||
static prod(M: MultiArray, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal; | ||
/** | ||
@@ -111,6 +171,6 @@ * Calculate average or mean of elements along dimension DIM. | ||
*/ | ||
static mean(M: MultiArray, DIM?: ComplexDecimal): MultiArray | ComplexDecimal; | ||
static mean(M: MultiArray, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal; | ||
/** | ||
* Base method of min and max user functions. | ||
* @param op 'min' or 'max' | ||
* @param op 'min' or 'max'. | ||
* @param args One to three arguments like user function. | ||
@@ -125,3 +185,3 @@ * @returns Return like user function. | ||
*/ | ||
static min(...args: any[]): MultiArray | NodeReturnList; | ||
static min(...args: any[]): MultiArray | NodeReturnList | undefined; | ||
/** | ||
@@ -132,3 +192,47 @@ * Maximum elements of array. | ||
*/ | ||
static max(...args: any[]): MultiArray | NodeReturnList; | ||
static max(...args: any[]): MultiArray | NodeReturnList | undefined; | ||
/** | ||
* Base method of cummin and cummax user functions. | ||
* @param op 'min' or 'max'. | ||
* @param M MultiArray. | ||
* @param DIM Dimension in which the cumulative operation occurs. | ||
* @returns MultiArray with cumulative values along dimension DIM. | ||
*/ | ||
private static cumMinMax; | ||
/** | ||
* | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
static cummin(M: MultiArray, DIM?: MultiArray | ComplexDecimal): NodeReturnList; | ||
/** | ||
* | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
static cummax(M: MultiArray, DIM?: MultiArray | ComplexDecimal): NodeReturnList; | ||
/** | ||
* | ||
* @param op | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
private static cumSumProd; | ||
/** | ||
* | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
static cumsum(M: MultiArray | ComplexDecimal, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal; | ||
/** | ||
* | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
static cumprod(M: MultiArray | ComplexDecimal, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal; | ||
} |
@@ -246,3 +246,3 @@ /** | ||
readonly evaluateTensor: typeof MultiArray.evaluate; | ||
readonly mapTensor: typeof MultiArray.map; | ||
readonly mapTensor: typeof MultiArray.rawMap; | ||
readonly getElements: typeof MultiArray.getElements; | ||
@@ -255,3 +255,3 @@ readonly getElementsLogical: typeof MultiArray.getElementsLogical; | ||
readonly appendRow: typeof MultiArray.appendRow; | ||
readonly tensor0x0: typeof MultiArray.array_0x0; | ||
readonly tensor0x0: typeof MultiArray.emptyArray; | ||
readonly linearize: typeof MultiArray.linearize; | ||
@@ -373,3 +373,3 @@ readonly toTensor: typeof MultiArray.scalarToMultiArray; | ||
*/ | ||
nodeReturnList(selector: ReturnSelector): NodeReturnList; | ||
static nodeReturnList(selector: ReturnSelector): NodeReturnList; | ||
/** | ||
@@ -381,3 +381,3 @@ * Throws error if left hand side length of multiple assignment greater | ||
*/ | ||
throwErrorIfGreaterThanReturnList(maxLength: number, currentLength: number): void; | ||
static throwErrorIfGreaterThanReturnList(maxLength: number, currentLength: number): void; | ||
/** | ||
@@ -384,0 +384,0 @@ * Tests if it is a NodeReturnList and if so reduces it to its first |
@@ -36,3 +36,5 @@ import { ComplexDecimal, TBinaryOperationName, TUnaryOperationLeftName } from './complex-decimal'; | ||
/** | ||
* Check if object is a MultiArray. | ||
* Check if object is a MultiArray. For efficiency reasons, this method | ||
* should not be used internally in this class. Use the test | ||
* `'array' in obj` instead. | ||
* @param obj Any object. | ||
@@ -46,7 +48,14 @@ * @returns true if object is a MultiArray. false otherwise. | ||
* imposed by parser can restrict the check only to `obj.dimension[0] === 1`. | ||
* @param obj | ||
* @returns true if object is a row vector. false otherwise. | ||
* @param obj Any object. | ||
* @returns `true` if object is a row vector. false otherwise. | ||
*/ | ||
static isRowVector(obj: any): boolean; | ||
/** | ||
* Returns `true` if `obj` any one of its dimensions is zero. | ||
* Returns `false` otherwise. | ||
* @param obj Any object. | ||
* @returns `true` if object is an empty array. | ||
*/ | ||
static isEmpty(obj: any): boolean; | ||
/** | ||
* Set type property in place with maximum value of array items type. | ||
@@ -99,2 +108,10 @@ * @param M MultiArray to set type property. | ||
/** | ||
* Converts MultiArray raw row and column to MultiArray linear index. | ||
* @param dimension MultiArray dimension (can be only the two first dimensions) | ||
* @param i Raw row | ||
* @param j Raw column | ||
* @returns Linear index | ||
*/ | ||
static rowColumnToLinearIndex(dimension: number[], i: number, j: number): number; | ||
/** | ||
* Base method of the ind2sub function. Returns dimension.length + 1 | ||
@@ -174,4 +191,6 @@ * dimensions. If the index exceeds the dimensions, the last dimension | ||
/** | ||
* Evaluate array. Calls `global.EvaluatorPointer.Evaluator` function for each element of page (matrix row-ordered) | ||
* @param array Matrix. | ||
* Evaluate array. Calls `global.EvaluatorPointer.Evaluator` for each | ||
* element of page (matrix row-ordered). Performs horizontal or vertical | ||
* concatenation if the evaluation of element results in an MultiArray. | ||
* @param array MultiArray page. | ||
* @param local `local` Evaluator parameter. | ||
@@ -200,6 +219,6 @@ * @param fname `fname` Evaluator parameter. | ||
/** | ||
* Returns a null array (0x0 matrix). | ||
* @returns Null array (0x0 matrix). | ||
* Returns a empty array (0x0 matrix). | ||
* @returns Empty array (0x0 matrix). | ||
*/ | ||
static array_0x0(): MultiArray; | ||
static emptyArray(): MultiArray; | ||
/** | ||
@@ -218,3 +237,3 @@ * Convert a scalar value to 1x1 MultiArray. | ||
/** | ||
* If `value` parameter is a MultiArray returns it's first element. | ||
* If `value` parameter is a non empty MultiArray returns it's first element. | ||
* Otherwise returns `value` parameter. | ||
@@ -226,24 +245,2 @@ * @param value | ||
/** | ||
* Converts a ComplexDecimal array or a single line MultiArray to an array | ||
* or number. | ||
* @param M | ||
* @returns | ||
*/ | ||
static oneRowToDim(M: ComplexDecimal[] | MultiArray): number[]; | ||
/** | ||
* Create MultiArray with all elements equals `fill` parameter. | ||
* @param fill Value to fill MultiArray. | ||
* @param dimension Dimensions of created MultiArray. | ||
* @returns MultiArray filled with `fill` parameter. | ||
*/ | ||
static newFilled(fill: any, ...dimension: any): MultiArray | ComplexDecimal; | ||
/** | ||
* Create MultiArray with all elements filled with `fillFunction` result. | ||
* The parameter passed to `fillFunction` is a linear index of element. | ||
* @param fillFunction Function to be called and the result fills element of MultiArray created. | ||
* @param dimension Dimensions of created MultiArray. | ||
* @returns MultiArray filled with `fillFunction` results for each element. | ||
*/ | ||
static newFilledEach(fillFunction: (index: number) => any, ...dimension: any): MultiArray | ComplexDecimal; | ||
/** | ||
* Copy of MultiArray. | ||
@@ -262,10 +259,2 @@ * @param M MultiArray. | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* and returns an MultiArray that contains the results. | ||
* @param M Matrix. | ||
* @param f Function mapping. | ||
* @returns | ||
*/ | ||
static map(M: MultiArray, f: Function): MultiArray; | ||
/** | ||
* Expand Multidimensional array dimensions if dimensions in `dim` is greater than dimensions of `M`. | ||
@@ -279,2 +268,10 @@ * If a dimension of `M` is greater than corresponding dimension in `dim` it's unchanged. | ||
/** | ||
* Reshape an array acording dimensions in `dim`. | ||
* @param M MultiArray. | ||
* @param dim Result dimensions. | ||
* @param d Undefined dimension index (optional). | ||
* @returns | ||
*/ | ||
static reshape(M: MultiArray, dim: number[], d?: number): MultiArray; | ||
/** | ||
* Expand range. | ||
@@ -346,2 +343,41 @@ * @param startNode Start of range. | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* and returns an MultiArray that contains the results. | ||
* @param M MultiArray. | ||
* @param callback Callback function. | ||
* @returns A new MultiArray with each element being the result of the callback function. | ||
*/ | ||
static rawMap(M: MultiArray, callback: Function): MultiArray; | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* and returns an MultiArray that contains the results. Pass indices | ||
* to callback function. The index parameter is the array linear index | ||
* of element parameter. | ||
* @param M MultiArray | ||
* @param callback Callback function. | ||
* @returns A new MultiArray with each element being the result of the callback function. | ||
*/ | ||
static rawMapRowColumn(M: MultiArray, callback: (element: any, i: number, j: number) => any): MultiArray; | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* and returns an MultiArray that contains the results. Pass indices | ||
* to callback function. The index parameter is the array linear index | ||
* of element parameter. | ||
* @param M MultiArray. | ||
* @param callback Callback function. | ||
* @returns A new MultiArray with each element being the result of the callback function. | ||
*/ | ||
static rawMapLinearIndex(M: MultiArray, callback: (element: any, index: number, i?: number, j?: number) => any): MultiArray; | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* along a specified dimension, and returns an MultiArray that contains | ||
* the results. Pass dimension index and MultiArray row and column to | ||
* callback function. | ||
* @param dimension Dimension to map. | ||
* @param M MultiArray | ||
* @param callback Callback function. | ||
* @returns A new MultiArray with each element being the result of the callback function. | ||
*/ | ||
static alongDimensionMap(dimension: number, M: MultiArray, callback: (element: any, d: number, i: number, j: number) => any): MultiArray; | ||
/** | ||
* Reduce one dimension of MultiArray putting entire dimension in one | ||
@@ -379,5 +415,5 @@ * element of resulting MultiArray as an Array. The resulting MultiArray | ||
* Get selected items from MultiArray by linear indices or subscripts. | ||
* @param M Matrix. | ||
* @param M MultiArray. | ||
* @param id Identifier. | ||
* @param indexList | ||
* @param indexList Linear index or subscript. | ||
* @returns MultiArray of selected items. | ||
@@ -388,3 +424,3 @@ */ | ||
* Get selected items from MultiArray by logical indexing. | ||
* @param M Matrix. | ||
* @param M MultiArray. | ||
* @param id Identifier. | ||
@@ -391,0 +427,0 @@ * @param items Logical index. |
{ | ||
"name": "mathjslab", | ||
"version": "1.2.1", | ||
"version": "1.2.2", | ||
"description": "MathJSLab - An interpreter with language syntax like MATLAB®/Octave. ISBN 978-65-00-82338-7", | ||
@@ -60,3 +60,3 @@ "main": "lib/mathjslab.js", | ||
"@types/jest": "29.5.10", | ||
"@types/node": "^20.9.4", | ||
"@types/node": "^20.10.0", | ||
"@types/supertest": "^2.0.16", | ||
@@ -63,0 +63,0 @@ "@types/webpack": "^5.28.5", |
@@ -10,3 +10,3 @@ import { Decimal } from 'decimal.js'; | ||
* Values equal to or greater than 336 is used to produce correct rounding of | ||
* trigonometric functions. | ||
* trigonometric, hyperbolic and exponential functions. | ||
*/ | ||
@@ -88,3 +88,3 @@ const DecimalPrecision = 336; | ||
/** | ||
* Functions with one argument (mappings) | ||
* Functions with one argument (mappers) | ||
*/ | ||
@@ -479,2 +479,3 @@ public static mapFunction: Record<string, Function> = { | ||
public static minMaxArrayRealWithIndex(cmp: 'lt' | 'gt', ...args: ComplexDecimal[]): [ComplexDecimal, number] { | ||
// TODO: check if reverse can be removed and reducedRight used. | ||
let index: number = 0; | ||
@@ -517,2 +518,3 @@ const result = args.reverse().reduce( | ||
public static minMaxArrayComplexWithIndex(cmp: 'lt' | 'gt', ...args: ComplexDecimal[]): [ComplexDecimal, number] { | ||
// TODO: check if reverse can be removed and reducedRight used. | ||
let index: number = 0; | ||
@@ -519,0 +521,0 @@ const result = args.reverse().reduce( |
import { ComplexDecimal, TBinaryOperationName } from './complex-decimal'; | ||
import { MultiArray } from './multi-array'; | ||
import { NodeReturnList } from './evaluator'; | ||
import { Evaluator, NodeReturnList } from './evaluator'; | ||
import { CharString } from './char-string'; | ||
export abstract class CoreFunctions { | ||
public static functions: { [name: string]: Function } = { | ||
ndims: CoreFunctions.ndims, | ||
rows: CoreFunctions.rows, | ||
columns: CoreFunctions.columns, | ||
length: CoreFunctions.Length, | ||
numel: CoreFunctions.numel, | ||
ind2sub: CoreFunctions.ind2sub, | ||
sub2ind: CoreFunctions.sub2ind, | ||
size: CoreFunctions.size, | ||
isempty: CoreFunctions.isempty, | ||
reshape: CoreFunctions.reshape, | ||
zeros: CoreFunctions.zeros, | ||
@@ -23,5 +31,98 @@ ones: CoreFunctions.ones, | ||
max: CoreFunctions.max, | ||
cummin: CoreFunctions.cummin, | ||
cummax: CoreFunctions.cummax, | ||
cumsum: CoreFunctions.cumsum, | ||
cumprod: CoreFunctions.cumprod, | ||
}; | ||
/** | ||
* | ||
* @param name | ||
*/ | ||
public static throwInvalidCallError(name: string): void { | ||
throw new Error(`Invalid call to ${name}. Type 'help ${name}' to see correct usage.`); | ||
} | ||
/** | ||
* | ||
* @param M | ||
* @returns | ||
*/ | ||
public static isempty(M: MultiArray | ComplexDecimal): ComplexDecimal { | ||
return MultiArray.isEmpty(M) ? ComplexDecimal.true() : ComplexDecimal.false(); | ||
} | ||
/** | ||
* Return the number of dimensions of M. | ||
* @param M | ||
* @returns | ||
*/ | ||
public static ndims(M: MultiArray | ComplexDecimal): ComplexDecimal | undefined { | ||
if (arguments.length === 1) { | ||
return new ComplexDecimal(MultiArray.scalarToMultiArray(M).dimension.length); | ||
} else { | ||
CoreFunctions.throwInvalidCallError('ndims'); | ||
} | ||
} | ||
/** | ||
* eturn the number of rows of M. | ||
* @param M | ||
* @returns | ||
*/ | ||
public static rows(M: MultiArray | ComplexDecimal): ComplexDecimal | undefined { | ||
if (arguments.length === 1) { | ||
return new ComplexDecimal(MultiArray.scalarToMultiArray(M).dimension[0]); | ||
} else { | ||
CoreFunctions.throwInvalidCallError('rows'); | ||
} | ||
} | ||
/** | ||
* Return the number of columns of M. | ||
* @param M | ||
* @returns | ||
*/ | ||
public static columns(M: MultiArray | ComplexDecimal): ComplexDecimal | undefined { | ||
if (arguments.length === 1) { | ||
return new ComplexDecimal(MultiArray.scalarToMultiArray(M).dimension[1]); | ||
} else { | ||
CoreFunctions.throwInvalidCallError('columns'); | ||
} | ||
} | ||
/** | ||
* Return the length of the object M. The length is the number of elements | ||
* along the largest dimension. | ||
* @param M | ||
* @returns | ||
*/ | ||
public static Length(M: MultiArray | ComplexDecimal): ComplexDecimal | undefined { | ||
// Capitalized name so as not to conflict with the built-in 'Function.length' property. | ||
if (arguments.length === 1) { | ||
return new ComplexDecimal(Math.max(...MultiArray.scalarToMultiArray(M).dimension)); | ||
} else { | ||
CoreFunctions.throwInvalidCallError('length'); | ||
} | ||
} | ||
public static numel(M: MultiArray | ComplexDecimal, ...IDX: (MultiArray | ComplexDecimal | CharString)[]): ComplexDecimal { | ||
if (IDX.length === 0) { | ||
return 'array' in M ? new ComplexDecimal(MultiArray.linearLength(M)) : ComplexDecimal.one(); | ||
} else { | ||
const m = MultiArray.scalarToMultiArray(M); | ||
const index = IDX.map((idx, i) => { | ||
if ('array' in idx) { | ||
return MultiArray.linearLength(idx); | ||
} else if ('str' in idx && idx.string === ':') { | ||
return i < m.dimension.length ? m.dimension[i] : 1; | ||
} else { | ||
return 1; | ||
} | ||
}); | ||
return new ComplexDecimal(index.reduce((p, c) => p * c, 1)); | ||
} | ||
} | ||
/** | ||
* Convert linear indices to subscripts. | ||
@@ -34,3 +135,3 @@ * @param DIMS | ||
if (arguments.length === 2) { | ||
return global.EvaluatorPointer.nodeReturnList((length: number, index: number): any => { | ||
return Evaluator.nodeReturnList((length: number, index: number): any => { | ||
if (length === 1) { | ||
@@ -60,3 +161,3 @@ return IND; | ||
} else { | ||
throw new Error(`Invalid call to ind2sub. Type 'help ind2sub' to see correct usage.`); | ||
CoreFunctions.throwInvalidCallError('ind2sub'); | ||
} | ||
@@ -72,3 +173,3 @@ } | ||
public static sub2ind(DIMS: any, ...S: any) { | ||
if (arguments.length > 1) { | ||
if (arguments.length === 2) { | ||
const dims = MultiArray.linearize(DIMS).map((value) => value.re.toNumber()); | ||
@@ -94,3 +195,3 @@ const subscript: MultiArray[] = S.map((s: any) => MultiArray.scalarToMultiArray(s)); | ||
} else { | ||
throw new Error(`Invalid call to sub2ind. Type 'help su2ind' to see correct usage.`); | ||
CoreFunctions.throwInvalidCallError('sub2ind'); | ||
} | ||
@@ -105,26 +206,30 @@ } | ||
*/ | ||
public static size(M: MultiArray | ComplexDecimal, ...DIM: any): MultiArray | ComplexDecimal { | ||
const parseDimension = (dimension: ComplexDecimal): number => { | ||
const dim = dimension.re.toNumber(); | ||
if (dim < 1 || !dimension.re.trunc().eq(dimension.re)) { | ||
throw new Error(`size: requested dimension DIM (= ${dim}) out of range. DIM must be a positive integer.`); | ||
public static size(M: MultiArray | ComplexDecimal, ...DIM: any): MultiArray | ComplexDecimal | undefined { | ||
if (arguments.length > 0) { | ||
const parseDimension = (dimension: ComplexDecimal): number => { | ||
const dim = dimension.re.toNumber(); | ||
if (dim < 1 || !dimension.re.trunc().eq(dimension.re)) { | ||
throw new Error(`size: requested dimension DIM (= ${dim}) out of range. DIM must be a positive integer.`); | ||
} | ||
return dim; | ||
}; | ||
const sizeDim = 'array' in M ? M.dimension.slice() : [1, 1]; | ||
if (DIM.length === 0) { | ||
const result = new MultiArray([1, sizeDim.length]); | ||
result.array[0] = sizeDim.map((d) => new ComplexDecimal(d)); | ||
result.type = ComplexDecimal.numberClass.real; | ||
return result; | ||
} else { | ||
const dims = | ||
DIM.length === 1 && 'array' in DIM[0] | ||
? MultiArray.linearize(DIM[0]).map((dim) => parseDimension(dim)) | ||
: DIM.map((dim: any) => parseDimension(MultiArray.firstElement(dim))); | ||
MultiArray.appendSingletonTail(sizeDim, Math.max(...dims)); | ||
const result = new MultiArray([1, dims.length]); | ||
result.array[0] = dims.map((dim: number) => new ComplexDecimal(sizeDim[dim - 1])); | ||
result.type = ComplexDecimal.numberClass.real; | ||
return MultiArray.MultiArrayToScalar(result); | ||
} | ||
return dim; | ||
}; | ||
const sizeDim = 'array' in M ? M.dimension.slice() : [1, 1]; | ||
if (DIM.length === 0) { | ||
const result = new MultiArray([1, sizeDim.length]); | ||
result.array[0] = sizeDim.map((d) => new ComplexDecimal(d)); | ||
result.type = ComplexDecimal.numberClass.real; | ||
return result; | ||
} else { | ||
const dims = | ||
DIM.length === 1 && 'array' in DIM[0] | ||
? MultiArray.linearize(DIM[0]).map((dim) => parseDimension(dim)) | ||
: DIM.map((dim: any) => parseDimension(MultiArray.firstElement(dim))); | ||
MultiArray.appendSingletonTail(sizeDim, Math.max(...dims)); | ||
const result = new MultiArray([1, dims.length]); | ||
result.array[0] = dims.map((dim: number) => new ComplexDecimal(sizeDim[dim - 1])); | ||
result.type = ComplexDecimal.numberClass.real; | ||
return MultiArray.MultiArrayToScalar(result); | ||
CoreFunctions.throwInvalidCallError('size'); | ||
} | ||
@@ -134,2 +239,75 @@ } | ||
/** | ||
* | ||
* @param M | ||
* @param dimension | ||
* @returns | ||
*/ | ||
public static reshape(M: MultiArray | ComplexDecimal, ...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal { | ||
const m = MultiArray.scalarToMultiArray(M); | ||
let d: number = -1; | ||
const dims = dimension.map((dim, i) => { | ||
const element = MultiArray.firstElement(dim); | ||
if (MultiArray.isEmpty(element)) { | ||
if (d < 0) { | ||
d = i; | ||
return 1; | ||
} else { | ||
throw new Error('reshape: only a single dimension can be unknown.'); | ||
} | ||
} else { | ||
return element.re.toNumber(); | ||
} | ||
}); | ||
return MultiArray.reshape(m, dims, d >= 0 ? d : undefined); | ||
} | ||
/** | ||
* Create MultiArray with all elements equals `fill` parameter. | ||
* @param fill Value to fill MultiArray. | ||
* @param dimension Dimensions of created MultiArray. | ||
* @returns MultiArray filled with `fill` parameter. | ||
*/ | ||
private static newFilled(fill: any, name: string, ...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal { | ||
let dims: number[]; | ||
if (dimension.length === 0) { | ||
return fill; | ||
} else if (dimension.length === 1) { | ||
const m = MultiArray.scalarToMultiArray(dimension[0]); | ||
if (m.dimension.length > 2 || m.dimension[0] !== 1) { | ||
throw new Error(`${name} (A): use ${name} (size (A)) instead.`); | ||
} | ||
dims = m.array[0].map((data) => data.re.toNumber()); | ||
} else { | ||
dims = dimension.map((dim) => { | ||
if ('array' in dim) { | ||
throw new Error(`${name}: dimensions must be scalars.`); | ||
} | ||
return dim.re.toNumber(); | ||
}); | ||
} | ||
return MultiArray.MultiArrayToScalar(new MultiArray(dims, fill)); | ||
} | ||
/** | ||
* Create MultiArray with all elements filled with `fillFunction` result. | ||
* The parameter passed to `fillFunction` is a linear index of element. | ||
* @param fillFunction Function to be called and the result fills element of MultiArray created. | ||
* @param dimension Dimensions of created MultiArray. | ||
* @returns MultiArray filled with `fillFunction` results for each element. | ||
*/ | ||
private static newFilledEach(fillFunction: (index: number) => any, ...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal { | ||
if (dimension.length === 0) { | ||
return fillFunction(0); | ||
} | ||
const dims = dimension.map((dim) => MultiArray.firstElement(dim).re.toNumber()); | ||
const result = new MultiArray(dims); | ||
for (let n = 0; n < MultiArray.linearLength(result); n++) { | ||
const [i, j] = MultiArray.linearIndexToMultiArrayRowColumn(result.dimension[0], result.dimension[1], n); | ||
result.array[i][j] = fillFunction(n); | ||
} | ||
MultiArray.setType(result); | ||
return MultiArray.MultiArrayToScalar(result); | ||
} | ||
/** | ||
* Create array of all zeros. | ||
@@ -139,4 +317,4 @@ * @param dimension | ||
*/ | ||
public static zeros(...dimension: any): MultiArray | ComplexDecimal { | ||
return MultiArray.newFilled(ComplexDecimal.zero(), ...dimension); | ||
public static zeros(...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal { | ||
return CoreFunctions.newFilled(ComplexDecimal.zero(), 'zeros', ...dimension); | ||
} | ||
@@ -149,4 +327,4 @@ | ||
*/ | ||
public static ones(...dimension: any): MultiArray | ComplexDecimal { | ||
return MultiArray.newFilled(ComplexDecimal.one(), ...dimension); | ||
public static ones(...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal { | ||
return CoreFunctions.newFilled(ComplexDecimal.one(), 'ones', ...dimension); | ||
} | ||
@@ -160,4 +338,4 @@ | ||
*/ | ||
public static rand(...dimension: any): MultiArray | ComplexDecimal { | ||
return MultiArray.newFilledEach((n: number) => new ComplexDecimal(Math.random()), ...dimension); | ||
public static rand(...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal { | ||
return CoreFunctions.newFilledEach((n: number) => new ComplexDecimal(Math.random()), ...dimension); | ||
} | ||
@@ -171,3 +349,3 @@ | ||
*/ | ||
public static randi(range: MultiArray | ComplexDecimal, ...dimension: any): MultiArray | ComplexDecimal { | ||
public static randi(range: MultiArray | ComplexDecimal, ...dimension: (MultiArray | ComplexDecimal)[]): MultiArray | ComplexDecimal { | ||
let imin = 0; | ||
@@ -192,3 +370,3 @@ let imax = 0; | ||
if (imax > imin) { | ||
return MultiArray.newFilledEach( | ||
return CoreFunctions.newFilledEach( | ||
imin === 0 | ||
@@ -216,3 +394,3 @@ ? (n: number) => new ComplexDecimal(Math.round(imax * Math.random())) | ||
public static cat(DIM: MultiArray | any, ...ARRAY: (MultiArray | any)[]): MultiArray { | ||
const dimension = MultiArray.firstElement(DIM); | ||
const dimension = MultiArray.firstElement(DIM).re.toNumber() - 1; | ||
const array = ARRAY.map((m) => MultiArray.scalarToMultiArray(m)); | ||
@@ -248,3 +426,4 @@ return MultiArray.concatenate(dimension, 'cat', ...array); | ||
*/ | ||
public static sum(M: MultiArray, DIM?: ComplexDecimal): MultiArray | ComplexDecimal { | ||
public static sum(M: MultiArray, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal { | ||
// TODO: Test if MultiArray.reduceToArray is better than MultiArray.reduce. | ||
const dim = DIM ? MultiArray.firstElement(DIM).re.toNumber() - 1 : MultiArray.firstNonSingleDimension(M); | ||
@@ -260,3 +439,4 @@ return MultiArray.reduce(dim, M, (p, c) => ComplexDecimal.add(p, c)); | ||
*/ | ||
public static sumsq(M: MultiArray, DIM?: ComplexDecimal): MultiArray | ComplexDecimal { | ||
public static sumsq(M: MultiArray, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal { | ||
// TODO: Test if MultiArray.reduceToArray is better than MultiArray.reduce. | ||
const dim = DIM ? MultiArray.firstElement(DIM).re.toNumber() - 1 : MultiArray.firstNonSingleDimension(M); | ||
@@ -272,3 +452,4 @@ return MultiArray.reduce(dim, M, (p, c) => ComplexDecimal.add(ComplexDecimal.mul(p, ComplexDecimal.conj(p)), ComplexDecimal.mul(c, ComplexDecimal.conj(c)))); | ||
*/ | ||
public static prod(M: MultiArray, DIM?: ComplexDecimal): MultiArray | ComplexDecimal { | ||
public static prod(M: MultiArray, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal { | ||
// TODO: Test if MultiArray.reduceToArray is better than MultiArray.reduce. | ||
const dim = DIM ? MultiArray.firstElement(DIM).re.toNumber() - 1 : MultiArray.firstNonSingleDimension(M); | ||
@@ -284,3 +465,4 @@ return MultiArray.reduce(dim, M, (p, c) => ComplexDecimal.mul(p, c)); | ||
*/ | ||
public static mean(M: MultiArray, DIM?: ComplexDecimal): MultiArray | ComplexDecimal { | ||
public static mean(M: MultiArray, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal { | ||
// TODO: Test if MultiArray.reduceToArray is better than MultiArray.reduce. | ||
const dim = DIM ? MultiArray.firstElement(DIM).re.toNumber() - 1 : MultiArray.firstNonSingleDimension(M); | ||
@@ -293,7 +475,7 @@ const sum = MultiArray.reduce(dim, M, (p, c) => ComplexDecimal.add(p, c)); | ||
* Base method of min and max user functions. | ||
* @param op 'min' or 'max' | ||
* @param op 'min' or 'max'. | ||
* @param args One to three arguments like user function. | ||
* @returns Return like user function. | ||
*/ | ||
private static minMax(op: 'min' | 'max', ...args: any[]): MultiArray | NodeReturnList { | ||
private static minMax(op: 'min' | 'max', ...args: any[]): MultiArray | NodeReturnList | undefined { | ||
const minMaxAlogDimension = (M: MultiArray, dimension: number) => { | ||
@@ -311,4 +493,4 @@ const reduced = MultiArray.reduceToArray(dimension, M); | ||
} | ||
return global.EvaluatorPointer.nodeReturnList((length: number, index: number): any => { | ||
global.EvaluatorPointer.throwErrorIfGreaterThanReturnList(2, length); | ||
return Evaluator.nodeReturnList((length: number, index: number): any => { | ||
Evaluator.throwErrorIfGreaterThanReturnList(2, length); | ||
return MultiArray.MultiArrayToScalar(index === 0 ? resultM : indexM); | ||
@@ -327,4 +509,4 @@ }); | ||
// Along selected dimension. | ||
if (!('array' in args[1] && args[1].dimension.length === 2 && args[1].dimension[0] === 0 && args[1].dimension[1] === 0)) { | ||
// Error if second argument is different from []. | ||
if (!MultiArray.isEmpty(args[1])) { | ||
// Error if second argument is different from [](0x0). | ||
throw new Error(`${op}: second argument is ignored`); | ||
@@ -334,3 +516,3 @@ } | ||
default: | ||
throw new Error(`Invalid call to ${op}. Type 'help ${op}' to see correct usage.`); | ||
CoreFunctions.throwInvalidCallError(op); | ||
} | ||
@@ -344,3 +526,3 @@ } | ||
*/ | ||
public static min(...args: any[]): MultiArray | NodeReturnList { | ||
public static min(...args: any[]): MultiArray | NodeReturnList | undefined { | ||
return CoreFunctions.minMax('min', ...args); | ||
@@ -354,5 +536,100 @@ } | ||
*/ | ||
public static max(...args: any[]): MultiArray | NodeReturnList { | ||
public static max(...args: any[]): MultiArray | NodeReturnList | undefined { | ||
return CoreFunctions.minMax('max', ...args); | ||
} | ||
/** | ||
* Base method of cummin and cummax user functions. | ||
* @param op 'min' or 'max'. | ||
* @param M MultiArray. | ||
* @param DIM Dimension in which the cumulative operation occurs. | ||
* @returns MultiArray with cumulative values along dimension DIM. | ||
*/ | ||
private static cumMinMax(op: 'min' | 'max', M: MultiArray | ComplexDecimal, DIM?: MultiArray | ComplexDecimal): NodeReturnList { | ||
const dim = DIM ? MultiArray.firstElement(DIM).re.toNumber() - 1 : 1; | ||
M = MultiArray.scalarToMultiArray(M); | ||
const indexM = new MultiArray(M.dimension); | ||
let compare: ComplexDecimal; | ||
let index: ComplexDecimal; | ||
const result = MultiArray.alongDimensionMap(dim, M, (element, d, i, j) => { | ||
if (d === 0) { | ||
compare = element; | ||
index = ComplexDecimal.one(); | ||
} else { | ||
if (ComplexDecimal[op === 'min' ? 'lt' : 'gt'](element, compare).re.toNumber()) { | ||
index = new ComplexDecimal(d + 1); | ||
compare = element; | ||
} | ||
} | ||
indexM.array[i][j] = index; | ||
return compare; | ||
}); | ||
return Evaluator.nodeReturnList((length: number, index: number): any => { | ||
Evaluator.throwErrorIfGreaterThanReturnList(2, length); | ||
return MultiArray.MultiArrayToScalar(index === 0 ? result : indexM); | ||
}); | ||
} | ||
/** | ||
* | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
public static cummin(M: MultiArray, DIM?: MultiArray | ComplexDecimal): NodeReturnList { | ||
return CoreFunctions.cumMinMax('min', M, DIM); | ||
} | ||
/** | ||
* | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
public static cummax(M: MultiArray, DIM?: MultiArray | ComplexDecimal): NodeReturnList { | ||
return CoreFunctions.cumMinMax('max', M, DIM); | ||
} | ||
/** | ||
* | ||
* @param op | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
private static cumSumProd(op: 'add' | 'mul', M: MultiArray | ComplexDecimal, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal { | ||
M = MultiArray.scalarToMultiArray(M); | ||
const dim = DIM ? MultiArray.firstElement(DIM).re.toNumber() - 1 : MultiArray.firstNonSingleDimension(M); | ||
const initialValue = op === 'add' ? ComplexDecimal.zero() : ComplexDecimal.one(); | ||
const result = MultiArray.alongDimensionMap( | ||
dim, | ||
M, | ||
( | ||
(sum) => (element, dimension) => | ||
(sum = dimension !== 0 ? ComplexDecimal[op](sum, element) : element) | ||
)(initialValue), | ||
); | ||
MultiArray.setType(result); | ||
return result; | ||
} | ||
/** | ||
* | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
public static cumsum(M: MultiArray | ComplexDecimal, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal { | ||
return CoreFunctions.cumSumProd('add', M, DIM); | ||
} | ||
/** | ||
* | ||
* @param M | ||
* @param DIM | ||
* @returns | ||
*/ | ||
public static cumprod(M: MultiArray | ComplexDecimal, DIM?: MultiArray | ComplexDecimal): MultiArray | ComplexDecimal { | ||
return CoreFunctions.cumSumProd('mul', M, DIM); | ||
} | ||
} |
import { ComplexDecimal } from './complex-decimal'; | ||
import { MultiArray } from './multi-array'; | ||
import { Evaluator } from './evaluator'; | ||
@@ -64,6 +65,6 @@ /** | ||
} else { | ||
throw new SyntaxError(`Invalid call to eye. Type 'help eye' to see correct usage.`); | ||
throw new SyntaxError(`Invalid call to eye. Type 'help eye' to see correct usage.`); | ||
} | ||
} else { | ||
throw new SyntaxError(`Invalid call to eye. Type 'help eye' to see correct usage.`); | ||
throw new SyntaxError(`Invalid call to eye. Type 'help eye' to see correct usage.`); | ||
} | ||
@@ -456,3 +457,3 @@ //result = MultiArray.zeros(new ComplexDecimal(rows), new ComplexDecimal(columns)) as MultiArray; | ||
} | ||
return global.EvaluatorPointer.nodeReturnList((length: number, index: number): any => { | ||
return Evaluator.nodeReturnList((length: number, index: number): any => { | ||
if (length === 1) { | ||
@@ -459,0 +460,0 @@ return U; |
@@ -45,2 +45,3 @@ import { ComplexDecimal, TBinaryOperationName, TUnaryOperationLeftName } from './complex-decimal'; | ||
this.dimension = shape.slice(); | ||
MultiArray.appendSingletonTail(this.dimension, 2); | ||
MultiArray.removeSingletonTail(this.dimension); | ||
@@ -67,3 +68,5 @@ this.array = new Array(this.dimensionR.reduce((p, c) => p * c, 1)); | ||
/** | ||
* Check if object is a MultiArray. | ||
* Check if object is a MultiArray. For efficiency reasons, this method | ||
* should not be used internally in this class. Use the test | ||
* `'array' in obj` instead. | ||
* @param obj Any object. | ||
@@ -80,4 +83,4 @@ * @returns true if object is a MultiArray. false otherwise. | ||
* imposed by parser can restrict the check only to `obj.dimension[0] === 1`. | ||
* @param obj | ||
* @returns true if object is a row vector. false otherwise. | ||
* @param obj Any object. | ||
* @returns `true` if object is a row vector. false otherwise. | ||
*/ | ||
@@ -89,2 +92,12 @@ public static isRowVector(obj: any): boolean { | ||
/** | ||
* Returns `true` if `obj` any one of its dimensions is zero. | ||
* Returns `false` otherwise. | ||
* @param obj Any object. | ||
* @returns `true` if object is an empty array. | ||
*/ | ||
public static isEmpty(obj: any): boolean { | ||
return 'array' in obj && (obj as MultiArray).dimension.reduce((p, c) => p * c, 1) === 0; | ||
} | ||
/** | ||
* Set type property in place with maximum value of array items type. | ||
@@ -167,2 +180,13 @@ * @param M MultiArray to set type property. | ||
/** | ||
* Converts MultiArray raw row and column to MultiArray linear index. | ||
* @param dimension MultiArray dimension (can be only the two first dimensions) | ||
* @param i Raw row | ||
* @param j Raw column | ||
* @returns Linear index | ||
*/ | ||
public static rowColumnToLinearIndex(dimension: number[], i: number, j: number): number { | ||
return Math.floor(i / dimension[0]) * dimension[0] * dimension[1] + j * dimension[0] + (i % dimension[0]); | ||
} | ||
/** | ||
* Base method of the ind2sub function. Returns dimension.length + 1 | ||
@@ -282,2 +306,5 @@ * dimensions. If the index exceeds the dimensions, the last dimension | ||
let arraystr: string = ''; | ||
if (M.dimension.reduce((p, c) => p * c, 1) === 0) { | ||
return `[](${M.dimension.join('x')})`; | ||
} | ||
if (M.dimension.length > 2) { | ||
@@ -309,4 +336,4 @@ let result = ''; | ||
const buildMrow = (rows: string) => `<mrow><mo>[</mo><mtable>${rows}</mtable><mo>]</mo></mrow>`; | ||
if (M.dimension[0] === 0 && M.dimension[1] === 0) { | ||
return '<mrow><mo>[</mo><mtable><mspace width="0.5em"/></mtable><mo>]</mo></mrow><mo>(</mo><mn>0</mn><mi>×</mi><mn>0</mn><mo>)</mo>'; | ||
if (M.dimension.reduce((p, c) => p * c, 1) === 0) { | ||
return `<mrow><mo>[</mo><mtable><mspace width="0.5em"/></mtable><mo>]</mo></mrow>(</mo><mn>${M.dimension.join('</mn><mi>×</mi><mn>')}</mn><mo>)</mo>`; | ||
} | ||
@@ -333,4 +360,6 @@ if (M.dimension.length > 2) { | ||
/** | ||
* Evaluate array. Calls `global.EvaluatorPointer.Evaluator` function for each element of page (matrix row-ordered) | ||
* @param array Matrix. | ||
* Evaluate array. Calls `global.EvaluatorPointer.Evaluator` for each | ||
* element of page (matrix row-ordered). Performs horizontal or vertical | ||
* concatenation if the evaluation of element results in an MultiArray. | ||
* @param array MultiArray page. | ||
* @param local `local` Evaluator parameter. | ||
@@ -423,6 +452,6 @@ * @param fname `fname` Evaluator parameter. | ||
/** | ||
* Returns a null array (0x0 matrix). | ||
* @returns Null array (0x0 matrix). | ||
* Returns a empty array (0x0 matrix). | ||
* @returns Empty array (0x0 matrix). | ||
*/ | ||
public static array_0x0(): MultiArray { | ||
public static emptyArray(): MultiArray { | ||
return new MultiArray([0, 0]); | ||
@@ -461,3 +490,3 @@ } | ||
/** | ||
* If `value` parameter is a MultiArray returns it's first element. | ||
* If `value` parameter is a non empty MultiArray returns it's first element. | ||
* Otherwise returns `value` parameter. | ||
@@ -469,8 +498,12 @@ * @param value | ||
if ('array' in value) { | ||
// It is a MultiArray. | ||
if (value.dimension.reduce((p: number, c: number) => p * c, 1) > 0) { | ||
// Return first element. | ||
return value.array[0][0]; | ||
} else { | ||
throw new Error('Cannot get first element of array. Array is [](0x0).'); | ||
// Some dimension is null. | ||
return value; | ||
} | ||
} else { | ||
// It is not a MultiArray. | ||
return value; | ||
@@ -481,64 +514,2 @@ } | ||
/** | ||
* Converts a ComplexDecimal array or a single line MultiArray to an array | ||
* or number. | ||
* @param M | ||
* @returns | ||
*/ | ||
public static oneRowToDim(M: ComplexDecimal[] | MultiArray): number[] { | ||
if (Array.isArray(M)) { | ||
return M.map((data) => data.re.toNumber()); | ||
} else { | ||
return M.array[0].map((data) => data.re.toNumber()); | ||
} | ||
} | ||
/** | ||
* Create MultiArray with all elements equals `fill` parameter. | ||
* @param fill Value to fill MultiArray. | ||
* @param dimension Dimensions of created MultiArray. | ||
* @returns MultiArray filled with `fill` parameter. | ||
*/ | ||
public static newFilled(fill: any, ...dimension: any): MultiArray | ComplexDecimal { | ||
if (dimension.length === 0) { | ||
return fill; | ||
} else if (dimension.length === 1) { | ||
if ('array' in dimension[0]) { | ||
return MultiArray.MultiArrayToScalar(new MultiArray(MultiArray.oneRowToDim(dimension[0]), fill)); | ||
} else { | ||
return MultiArray.MultiArrayToScalar(new MultiArray([dimension[0].re.toNumber(), dimension[0].re.toNumber()], fill)); | ||
} | ||
} else { | ||
return MultiArray.MultiArrayToScalar(new MultiArray(MultiArray.oneRowToDim(dimension), fill)); | ||
} | ||
} | ||
/** | ||
* Create MultiArray with all elements filled with `fillFunction` result. | ||
* The parameter passed to `fillFunction` is a linear index of element. | ||
* @param fillFunction Function to be called and the result fills element of MultiArray created. | ||
* @param dimension Dimensions of created MultiArray. | ||
* @returns MultiArray filled with `fillFunction` results for each element. | ||
*/ | ||
public static newFilledEach(fillFunction: (index: number) => any, ...dimension: any): MultiArray | ComplexDecimal { | ||
let result: MultiArray; | ||
if (dimension.length === 0) { | ||
return fillFunction(0); | ||
} else if (dimension.length === 1) { | ||
if ('array' in dimension[0]) { | ||
result = new MultiArray(MultiArray.oneRowToDim(dimension[0])); | ||
} else { | ||
result = new MultiArray([dimension[0].re.toNumber(), dimension[0].re.toNumber()]); | ||
} | ||
} else { | ||
result = new MultiArray(MultiArray.oneRowToDim(dimension)); | ||
} | ||
for (let n = 0; n < MultiArray.linearLength(result); n++) { | ||
const [i, j] = MultiArray.linearIndexToMultiArrayRowColumn(result.dimension[0], result.dimension[1], n); | ||
result.array[i][j] = fillFunction(n); | ||
} | ||
MultiArray.setType(result); | ||
return MultiArray.MultiArrayToScalar(result); | ||
} | ||
/** | ||
* Copy of MultiArray. | ||
@@ -575,16 +546,2 @@ * @param M MultiArray. | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* and returns an MultiArray that contains the results. | ||
* @param M Matrix. | ||
* @param f Function mapping. | ||
* @returns | ||
*/ | ||
public static map(M: MultiArray, f: Function): MultiArray { | ||
const result = new MultiArray(M.dimension); | ||
result.array = M.array.map((row) => row.map(f as any)); | ||
MultiArray.setType(result); | ||
return result; | ||
} | ||
/** | ||
* Expand Multidimensional array dimensions if dimensions in `dim` is greater than dimensions of `M`. | ||
@@ -622,2 +579,36 @@ * If a dimension of `M` is greater than corresponding dimension in `dim` it's unchanged. | ||
/** | ||
* Reshape an array acording dimensions in `dim`. | ||
* @param M MultiArray. | ||
* @param dim Result dimensions. | ||
* @param d Undefined dimension index (optional). | ||
* @returns | ||
*/ | ||
public static reshape(M: MultiArray, dim: number[], d?: number): MultiArray { | ||
const lengthM = M.dimension.reduce((p, c) => p * c, 1); | ||
const dimension = dim.slice(); | ||
if (typeof d !== 'undefined') { | ||
dimension[d as number] = 1; | ||
const restDimension = dimension.reduce((p, c) => p * c, 1); | ||
if (restDimension <= lengthM && Number.isInteger(lengthM / restDimension)) { | ||
dimension[d as number] = lengthM / restDimension; | ||
} else { | ||
throw new Error(`reshape: SIZE is not divisible by the product of known dimensions (= ${restDimension})`); | ||
} | ||
} else { | ||
const dimensionLength = dimension.reduce((p, c) => p * c, 1); | ||
if (lengthM !== dimensionLength) { | ||
throw new Error(`reshape: can't reshape ${M.dimension.join('x')} array to ${dimension.join('x')} array`); | ||
} | ||
} | ||
const result = new MultiArray(dimension); | ||
MultiArray.rawMapLinearIndex(M, (element, index) => { | ||
const [i, j] = MultiArray.linearIndexToMultiArrayRowColumn(result.dimension[0], result.dimension[1], index); | ||
result.array[i][j] = element; | ||
return element; | ||
}); | ||
result.type = M.type; | ||
return result; | ||
} | ||
/** | ||
* Expand range. | ||
@@ -821,2 +812,3 @@ * @param startNode Start of range. | ||
for (let d = 0; d < leftDimension.length; d++) { | ||
// TODO: check if more than one dimension can broadcast (Check in MATLAB broadcasting rules!). If not this code must be changed. | ||
if (leftDimension[d] === rightDimension[d]) { | ||
@@ -857,2 +849,83 @@ leftBroadcast[d] = false; | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* and returns an MultiArray that contains the results. | ||
* @param M MultiArray. | ||
* @param callback Callback function. | ||
* @returns A new MultiArray with each element being the result of the callback function. | ||
*/ | ||
public static rawMap(M: MultiArray, callback: Function): MultiArray { | ||
const result = new MultiArray(M.dimension); | ||
result.array = M.array.map((row) => row.map(callback as any)); | ||
MultiArray.setType(result); | ||
return result; | ||
} | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* and returns an MultiArray that contains the results. Pass indices | ||
* to callback function. The index parameter is the array linear index | ||
* of element parameter. | ||
* @param M MultiArray | ||
* @param callback Callback function. | ||
* @returns A new MultiArray with each element being the result of the callback function. | ||
*/ | ||
public static rawMapRowColumn(M: MultiArray, callback: (element: any, i: number, j: number) => any): MultiArray { | ||
const result = new MultiArray(M.dimension); | ||
result.array = M.array.map((row, i) => row.map((element, j) => callback(element, i, j))); | ||
MultiArray.setType(result); | ||
return result; | ||
} | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* and returns an MultiArray that contains the results. Pass indices | ||
* to callback function. The index parameter is the array linear index | ||
* of element parameter. | ||
* @param M MultiArray. | ||
* @param callback Callback function. | ||
* @returns A new MultiArray with each element being the result of the callback function. | ||
*/ | ||
public static rawMapLinearIndex(M: MultiArray, callback: (element: any, index: number, i?: number, j?: number) => any): MultiArray { | ||
const result = new MultiArray(M.dimension); | ||
result.array = M.array.map((row, i) => | ||
row.map((element, j) => callback(element, Math.floor(i / M.dimension[0]) * M.dimension[0] * M.dimension[1] + j * M.dimension[0] + (i % M.dimension[0]), i, j)), | ||
); | ||
MultiArray.setType(result); | ||
return result; | ||
} | ||
/** | ||
* Calls a defined callback function on each element of an MultiArray, | ||
* along a specified dimension, and returns an MultiArray that contains | ||
* the results. Pass dimension index and MultiArray row and column to | ||
* callback function. | ||
* @param dimension Dimension to map. | ||
* @param M MultiArray | ||
* @param callback Callback function. | ||
* @returns A new MultiArray with each element being the result of the callback function. | ||
*/ | ||
public static alongDimensionMap(dimension: number, M: MultiArray, callback: (element: any, d: number, i: number, j: number) => any): MultiArray { | ||
const result = new MultiArray(M.dimension); | ||
if (dimension >= M.dimension.length) { | ||
result.array = M.array.map((row, i) => row.map((element, j) => callback(element, 0, i, j))); | ||
} else { | ||
const subscriptC = M.dimension.slice(); | ||
subscriptC[dimension] = 1; | ||
const length = subscriptC.reduce((p, c) => p * c, 1); | ||
const range = subscriptC.map((s) => MultiArray.rangeArray(s)); | ||
for (let n = 0; n < length; n++) { | ||
for (let d = 1; d <= M.dimension[dimension]; d++) { | ||
const args = range.slice(); | ||
args[dimension] = [d]; | ||
const subscriptM = MultiArray.linearIndexToSubscript(subscriptC, n).map((s, r) => args[r][s - 1]); | ||
const [i, j] = MultiArray.subscriptToMultiArrayRowColumn(M.dimension, subscriptM); | ||
result.array[i][j] = callback(M.array[i][j], subscriptM[dimension] - 1, i, j); | ||
} | ||
} | ||
} | ||
MultiArray.setType(result); | ||
return result; | ||
} | ||
/** | ||
* Reduce one dimension of MultiArray putting entire dimension in one | ||
@@ -867,3 +940,5 @@ * element of resulting MultiArray as an Array. The resulting MultiArray | ||
public static reduceToArray(dimension: number, M: MultiArray): MultiArray { | ||
// TODO: check if subscriptC inside for can be removed and if forS can be inverted like in mapAlongDimension. | ||
if (dimension >= M.dimension.length) { | ||
// TODO: check if it is consistent | ||
return M; | ||
@@ -992,5 +1067,5 @@ } else { | ||
* Get selected items from MultiArray by linear indices or subscripts. | ||
* @param M Matrix. | ||
* @param M MultiArray. | ||
* @param id Identifier. | ||
* @param indexList | ||
* @param indexList Linear index or subscript. | ||
* @returns MultiArray of selected items. | ||
@@ -1024,3 +1099,3 @@ */ | ||
* Get selected items from MultiArray by logical indexing. | ||
* @param M Matrix. | ||
* @param M MultiArray. | ||
* @param id Identifier. | ||
@@ -1027,0 +1102,0 @@ * @param items Logical index. |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
559109
8225