import type { TUnaryOperationLeftName, TBinaryOperationName } from './ComplexInterface'; import { ComplexType } from './Complex'; import { CharString } from './CharString'; import type { RuntimeDisplay, RuntimeEvaluationContext } from './RuntimeDisplay'; /** * Object-like runtime values that may be stored directly inside a `MultiArray`. * * This structural type intentionally avoids importing concrete runtime classes * such as function handles, class instances, class metadata, and bound methods. * Array storage only needs the shared runtime value contract; behavior-specific * dispatch remains in the corresponding runtime modules. */ type RuntimeObjectElement = object & { type: number; parent?: unknown; copy?: () => unknown; }; /** * Scalar runtime values that may be stored directly inside a `MultiArray`. * * Nested `MultiArray` values are handled by `ElementType` because MATLAB cell * arrays can contain arrays as elements, while numeric arrays generally store * scalar `ComplexType` values. */ type Elements = ComplexType | CharString | RuntimeObjectElement; /** * Runtime value accepted in array slots and expression evaluation results. * * `null` and `undefined` are tolerated because parser/evaluator paths use empty * slots while constructing MATLAB-like empty arrays, structure fields, and * omitted values. */ type ElementType = MultiArray | ELEMENT | null | undefined; /** * Reduce factory function types. */ type ReduceComparisonType = 'lt' | 'gt'; type ReduceType = 'reduce' | 'cumulative' | 'cumcomparison' | 'comparison'; type ReduceElementType = ElementType; type ReduceCallbackType = (prev: ReduceElementType, curr: ReduceElementType, index?: number) => ReduceElementType; type ReduceCallbackOrComparisonType = ReduceCallbackType | ReduceComparisonType; type ReduceInitialType = ReduceElementType; type ReduceReduceHandlerType = (M: ReduceElementType, DIM?: ReduceElementType) => ReduceElementType; type ReduceComparisonHandlerType = (...args: ElementType[]) => MultiArray | NodeReturnList | undefined; type ReduceHandlerType = ReduceReduceHandlerType | ReduceComparisonHandlerType; type ReturnHandlerResult = { length: number; } & Record; type ReturnSelector = (evaluated: ReturnHandlerResult, index: number) => ElementType; type ReturnHandler = (length: number) => ReturnHandlerResult; type ReducedArrayLine = ElementType[]; type NodeReturnList = { type: 'RETLIST'; selector: ReturnSelector; handler?: ReturnHandler; parent?: unknown; }; type IndexAssignmentScope = { resolveName(name: string): { node?: unknown; } | undefined; defineName(name: string, node: ElementType): { node?: unknown; }; }; /** * Runtime values accepted by native MATLAB/Octave array indexing. * * Parser nodes, structures, class objects, and arbitrary expression results * must be reduced or rejected before they enter the low-level indexing engine. */ type IndexArgument = ComplexType | MultiArray; /** * MATLAB/Octave-like multidimensional array container. * * `dimension` stores MATLAB-style shape metadata: `[rows, columns, pages, ...]`. * The backing `array` is a two-dimensional row-major page-flattened structure: * rows for all pages are stacked into the first dimension, while columns remain * the second dimension. Indexing helpers translate MATLAB column-major logical * indexing semantics into this internal representation. * * `isCell` distinguishes ordinary arrays from cell arrays. Cell arrays preserve * element identity and may contain nested arrays; ordinary arrays usually * contain scalar numeric/logical/string/runtime values. */ declare class MultiArray { /** * MATLAB-style dimensions (`[rows, columns, pages, blocks, ...]`). */ dimension: number[]; /** * Dimensions excluding the column axis (`[rows, pages, blocks, ...]`). */ get dimensionR(): number[]; /** * Row-major page-flattened storage. */ array: ElementType[][]; /** * Runtime type tag inferred from contained values. */ type: number; /** * Test whether an object is a `MultiArray` instance. * * @param obj Object to test. * @returns `true` when `obj` is a `MultiArray`. */ static readonly isInstanceOf: (obj: unknown) => obj is MultiArray; /** * Test whether a runtime value can be consumed directly by native indexing. * * Valid subscripts are numeric/logical scalar values or numeric/logical * arrays. Colon ranges are represented as numeric `MultiArray` instances * before this boundary is reached. * * @param value Candidate subscript value. * @returns True when `value` is a native array-index argument. */ static isIndexArgument(value: unknown): value is IndexArgument; /** * Validate a list of values before passing them into the indexing engine. * * Keeping this check in `MultiArray` makes every caller share the same * supported-subscript contract while preserving specialized error handlers * at higher interpreter layers. * * @param values Candidate subscript values. * @param role Diagnostic label used in thrown errors. * @returns The same values narrowed to native index arguments. * @throws EvalError When any value is not a valid native subscript. */ static indexArguments(values: unknown[], role?: string): IndexArgument[]; /** * Read an array element that must be a numeric scalar. * * Native numeric/logical array operations should only reach this helper for * arrays whose storage is known to be numeric. The explicit guard keeps * malformed runtime arrays from failing later through opaque method calls. * * @param value Candidate array element. * @param role Diagnostic operation name. * @returns Numeric scalar element. */ private static readonly numericElement; /** Runtime tag for logical arrays. */ static readonly LOGICAL: number; /** Runtime tag for real numeric arrays. */ static readonly REAL: number; /** Runtime tag for complex numeric arrays. */ static readonly COMPLEX: number; /** Runtime tag for string arrays. */ static readonly STRING = 3; /** Runtime tag for structure arrays. */ static readonly STRUCTURE = 4; /** Runtime tag for function-handle arrays. */ static readonly FUNCTION_HANDLE = 5; /** * Whether this array uses cell-array semantics. */ isCell: boolean; /** * Field schema for empty structure arrays. * * Empty MATLAB/Octave structure arrays still remember their field names * even though no concrete `Structure` elements exist in storage. */ emptyStructureFields?: string[]; /** * Optional AST-style parent pointer used by generic value handling. */ parent?: unknown; private static readonly invalidStructureReferenceMessage; /** * Create a multidimensional array. * * Scalar object fills are copied when they have value semantics (`MultiArray`, * `Structure`, and value-class instances). Primitive/scalar immutable values * are reused. Function fills receive MATLAB-style subscripts. * * @param shape Dimensions ([rows, columns, pages, blocks, ...]). * @param fill Fill value, fill callback, or row-major storage. * @param iscell Whether to create a cell array. */ constructor(shape?: number[], fill?: ElementType | ((...dims: number[]) => ElementType) | ElementType[][], iscell?: boolean); /** * Check if object is a scalar. * @param obj Any object. * @returns `true` if object is a scalar. false otherwise. */ static readonly isScalar: (obj: unknown) => boolean; /** * Check if object is a MultiArray and it is a row vector. * @param obj Any object. * @returns `true` if object is a row vector. false otherwise. */ static readonly isRowVector: (obj: unknown) => boolean; /** * Convert a flat value list into a 1-by-N row vector. * * @param vector Values to store in row order. * @returns Row-vector `MultiArray`. */ static readonly toRowVector: (vector: ElementType[]) => MultiArray; /** * Return the first row of a row-vector array. * * @param vector Row-vector `MultiArray`. * @returns Backing first row. */ static readonly fromRowVector: (vector: MultiArray) => ElementType[]; /** * Check if object is a MultiArray and it is a row vector. * @param obj Any object. * @returns `true` if object is a row vector. false otherwise. */ static readonly isColumnVector: (obj: unknown) => boolean; /** * Convert a flat value list into an N-by-1 column vector. * * @param vector Values to store in column order. * @returns Column-vector `MultiArray`. */ static readonly toColumnVector: (vector: ElementType[]) => MultiArray; /** * Return the first column of a column-vector array. * * @param vector Column-vector `MultiArray`. * @returns Backing first column. */ static readonly fromColumnVector: (vector: MultiArray) => ElementType[]; /** * Check if a MultiArray is a row vector or a column vector. * @param array MultiArray to test. * @returns `true` if `array` is a vector (column vector or row vector), otherwise `false`. */ static readonly arrayIsVector: (array: MultiArray) => boolean; /** * Check if object is a MultiArray and it is a row vector or a column vector. * @param obj Any object. * @returns `true` if object is a row vector or a column vector. false otherwise. */ static readonly isVector: (obj: unknown) => boolean; /** * Convert a flat value list into a square diagonal matrix. * * @param vector Diagonal values. * @returns Square matrix with `vector` on the main diagonal. */ static readonly toDiagonalMatrix: (vector: ElementType[]) => MultiArray; /** * Check if object is a scalar or a 2-D MultiArray. * @param obj Any object. * @returns `true` if object is a row vector or a column vector. false otherwise. */ static readonly isMatrix: (obj: unknown) => 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 readonly isEmpty: (obj: unknown) => boolean; /** * Test whether a temporary reduced-array slot stores collected elements. * @param value Slot value produced by `reduceToArray`. * @returns `true` when the slot contains a reduced element line. */ private static readonly isReducedArrayLine; /** * Test whether a reduced line contains numeric scalar values. * @param value Reduced line produced by `reduceToArray`. * @returns `true` when all collected values are complex scalars. */ private static readonly isReducedComplexArrayLine; /** * Check if object is a MultiArray and it is a cell array. * @param obj Any object. * @returns `true` if object is a cell array. false otherwise. */ static readonly isCellArray: (obj: unknown) => boolean; /** * Test whether any array element is a complex numeric value. * * @param M Array to scan. * @returns `true` when at least one element has a nonzero imaginary part. */ static readonly isComplexMultiArray: (M: MultiArray) => boolean; /** * Set type property in place with maximum value of array items type. * @param M MultiArray to set type property. */ static readonly setType: (M: MultiArray) => void; /** * Test if two array are equals. * @param left Array. * @param right Array. * @returns true if two arrays are equals. false otherwise. */ static readonly arrayEquals: (a: (boolean | number | string)[], b: (boolean | number | string)[]) => boolean; /** * Returns a one-based range array ([1, 2, ..., length]). * @param length Length or last value of range array. * @returns Range array. */ static readonly rangeArray: (length: number) => number[]; /** * Converts linear index to subscript. * @param dimension Dimensions of multidimensional array ([line, column, page, block, ...]). * @param index Zero-based linear index. * @returns One-based subscript ([line, column, page, block, ...]). */ static readonly linearIndexToSubscript: (dimension: number[], index: number) => number[]; /** * Converts subscript to linear index. * @param dimension Dimensions of multidimensional array ([lines, columns, pages, blocks, ...]). * @param subscript One-based subscript ([line, column, page, block, ...]). * @returns Zero-based linear index. */ static readonly subscriptToLinearIndex: (dimension: number[], subscript: number[]) => number; /** * Converts linear index to MultiArray.array subscript. * @param row Row dimension. * @param column Column dimension. * @param index Zero-based linear index. * @returns MultiArray.array subscript ([row, column]). */ static readonly linearIndexToMultiArrayRowColumn: (row: number, column: number, index: number) => [number, number]; /** * Converts MultiArray subscript to MultiArray.array subscript. * @param dimension MultiArray dimension. * @param subscript Subscript. * @returns MultiArray.array subscript ([row, column]). */ static readonly subscriptToMultiArrayRowColumn: (dimension: number[], subscript: number[]) => [number, number]; /** * 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 readonly rowColumnToLinearIndex: (dimension: number[], i: number, j: number) => number; /** * Convert a physical storage row/column pair to MATLAB-style subscripts. * * @param dimension Logical array dimensions. * @param i Physical row in the page-flattened backing storage. * @param j Physical column in the backing storage. * @returns One-based logical subscript list. */ static readonly rowColumnToSubscript: (dimension: number[], i: number, j: number) => number[]; /** * Compute stride vector (column-major order). * Example: [3,4,2] → [1, 3, 12] */ static readonly computeStrides: (dim: number[]) => number[]; /** * Return the internal page stride after a dimension. * * @param M Source array. * @param dim Zero-based dimension index. * @returns Product of dimensions after `dim`. */ static readonly getStride: (M: MultiArray, dim: number) => number; /** * Return a 2-D page slice from an N-D array. * * @param M Source array. * @param pageIndex Zero-based page index. * @returns 2-D numeric page data. */ static readonly pageSlice: (M: MultiArray, pageIndex: number) => ComplexType[][]; /** * Replace a 2-D page inside an N-D array. * * @param M Target array. * @param pageIndex Zero-based page index. * @param pageData Replacement page values. */ static readonly setPage: (M: MultiArray, pageIndex: number, pageData: ComplexType[][]) => void; /** * Flatten array content in MATLAB column-major logical order. * * @param arr Source array. * @returns Linear element array with `prod(size(arr))` entries. */ static readonly toFlatArray: (arr: MultiArray) => ComplexType[]; /** * Reconstruct backing storage from a MATLAB column-major linear vector. * * @param arr Target array whose dimensions define the output shape. * @param flat Linear values to place into `arr`. */ static readonly fromFlatArray: (arr: MultiArray, flat: ComplexType[]) => void; /** * Check if two MultiArrays have the same shape, or if they are identical * except for one dimension d where both have size 3. * * Returns true if either: * - A.dimension equals B.dimension (exact match), or * - there exists an index d such that A.dimension[d] === 3 and B.dimension[d] === 3 * and for every i !== d we have A.dimension[i] === B.dimension[i]. * * This matches the requirement of cross(A,B) where the operation dimension * must have length 3 while all other dimensions must match. * @param A Left array. * @param B Right array. * @returns `true` when shapes match or only a length-3 operation dimension differs. */ static readonly sameSizeExcept: (A: MultiArray, B: MultiArray) => boolean; /** * Base method of the ind2sub function. Returns dimension.length + 1 * dimensions. If the index exceeds the dimensions, the last dimension * will contain the multiplier of the other dimensions. Otherwise it will * be 1. * @param dimension Array of dimensions. * @param index One-base linear index. * @returns One-based subscript ([line, column, page, block, ...]). */ static readonly ind2subNumber: (dimension: number[], index: number) => number[]; /** * Returns the number of elements in M. * @param M Multidimensional array. * @returns Number of elements in M. */ static readonly linearLength: (M: MultiArray) => number; /** * Get dimension at index d of MultiArray M * @param M MultiArray. * @param d Zero-based dimension index. * @returns Dimension d. */ static readonly getDimension: (M: MultiArray, d: number) => number; /** * Remove singleton tail of dimension array in place. * @param dimension Dimension array. */ static readonly removeSingletonTail: (dimension: number[]) => void; /** * Append singleton tail of dimension array in place. * @param dimension Dimension array. * @param length Resulting length of dimension array. */ static readonly appendSingletonTail: (dimension: number[], length: number) => void; /** * Find first non-single dimension. * @param M MultiArray. * @returns First non-single dimension of `M`. */ static readonly firstNonSingleDimension: (M: MultiArray) => number; /** * Creates a MultiArray object from the first row of elements (for * parsing purposes). * @param row Array of objects. * @returns MultiArray with `row` parameter as first line. */ private static readonly linkArrayElementParent; static readonly firstRow: (row: ElementType[], iscell?: boolean) => MultiArray; /** * Append a row of elements to a MultiArray object (for parsing * purposes). * @param M MultiArray. * @param row Array of objects to append as row of MultiArray. * @returns MultiArray with row appended. */ static readonly appendRow: (M: MultiArray, row: ElementType[]) => MultiArray; /** * Unparse MultiArray. * @param M MultiArray object. * @returns String of unparsed MultiArray. */ static readonly unparse: (M: MultiArray, interpreter: RuntimeDisplay, _parentPrecedence?: number) => string; /** * Create a compact dimension-only string representation. * * @returns Human-readable array shape. */ toString(): string; /** * Unparse MultiArray as MathML language. * @param M MultiArray object. * @returns String of unparsed MultiArray in MathML language. */ static readonly unparseMathML: (M: MultiArray, interpreter: RuntimeDisplay, _parentPrecedence?: number) => string; /** * Converts CharString to MultiArray. * @param text CharString. * @returns Numeric character-code scalar or row vector. */ static readonly fromCharString: (text: CharString) => ElementType; /** * Converts a runtime character string to a row vector of character scalars. * * This preserves text contents for MATLAB/Octave-style string indexing, * unlike `fromCharString`, which converts characters to numeric codes. * * @param text Character string value. * @returns Row vector containing one scalar `CharString` per character. */ static readonly characterVectorFromCharString: (text: CharString) => MultiArray; /** * Rebuild a character string from character-scalar indexing results. * * @param value Scalar or array result produced from a character vector. * @param quote Quote style to preserve. * @returns Joined character string. */ static readonly charStringFromCharacterVectorResult: (value: ElementType, quote: CharString["quote"]) => CharString; /** * Linearize MultiArray in an array of ElementType using row-major * order. * @param M Array to flatten. * @returns Elements in column-major logical order. */ static readonly flatten: (M: MultiArray) => ElementType[]; /** * Linearize a `MultiArray` in MATLAB/Octave column-major logical order. * * `MultiArray.array` stores the first two dimensions as a row/column grid * and stacks later pages in the physical row dimension. This method walks * that storage through the same mapping as * `linearIndexToMultiArrayRowColumn`, preserving logical linear-index order * without allocating one slice per page column. * * @param M Multidimensional array or scalar value. * @returns Elements of `M` in logical linear-index order. */ static readonly linearize: (M: ElementType) => ElementType[]; /** * Returns a empty array (0x0 matrix). * @returns Empty array (0x0 matrix). */ static readonly emptyArray: (iscell?: boolean) => MultiArray; /** Test whether a structural candidate can expose runtime fields. */ private static readonly isObjectRecord; /** Test whether a structural field bag can store concrete structure fields. */ private static readonly isElementRecord; /** Test whether a value is structurally a scalar MATLAB/Octave structure. */ private static readonly isStructureScalar; /** * Return structure elements from a scalar structure or structure array. * * @param value Candidate scalar or array. * @returns Structure elements, or an empty list for non-structure values. */ private static readonly structureElements; /** Convert an optional structure-field assignment value to concrete storage. */ private static readonly structureFieldValue; /** Return sorted field names for a structure scalar or array. */ private static readonly structureFieldNames; /** * Create and validate a runtime structure through the decoupled factory. * * @param field Field map or nested field path. * @returns Validated structure scalar. */ private static readonly createStructureValue; /** Create an empty scalar structure carrying a set of top-level fields. */ private static readonly createEmptyStructureWithFields; /** Copy empty-structure schema metadata to empty selection results. */ private static readonly preserveEmptyStructureSchema; /** Test whether a linearized value list contains only character scalars. */ private static readonly isCharStringList; /** * Create an empty structure value that mirrors a reference field schema. * * @param reference Structure whose field names should be copied. * @returns New structure with each field initialized to `[]`. */ private static readonly cloneStructureFields; /** * Collect values reached by a nested structure field path. * * Structure arrays expand to one collected value per element, preserving * linear order. Missing fields and non-structure intermediates use the * common MATLAB-like dot-indexing diagnostic. * * @param value Structure scalar or array to read. * @param field Field path to resolve. * @returns Values reached by the path. */ private static readonly structureCollectFieldPath; /** * Read a structure field path and collapse a single collected value. * * @param value Structure scalar or array to read. * @param field Field path to resolve. * @returns The scalar field value, or a row vector for comma-list fields. */ private static readonly getStructureField; /** * Assign a structure field path inside a scalar or every element of an array. * * Missing or empty intermediate fields are promoted to empty structures so * chained assignments such as `S(2).b(3).c = value` can create the path * incrementally while preserving the parent structure-array schema. * * @param target Structure scalar or structure array to mutate. * @param field Field path to assign. * @param value Value to store, or `[]` when omitted. */ private static readonly structureAssignFieldPath; /** * Complete a structure array with one top-level field. * * MATLAB structure arrays share a field schema. This helper fills only * missing fields, deliberately preserving values that may already have * been written into selected elements during indexed assignment. * * @param M Structure array to mutate. * @param field Top-level field to ensure. */ private static readonly setEmptyStructureField; private static readonly blankValueForExpansion; /** * Convert scalar to MultiArray with aditional test if it is MultiArray. * @param value Scalar or array candidate. * @param test Whether an existing `MultiArray` should be preserved. * @returns Existing array or scalar wrapped in a 1-by-1 array. */ private static readonly scalarToMultiArrayWithTest; /** * If value is a scalar then convert to a 1x1 MultiArray. If is cell array * the cell is put in a 1x1 MultiArray too. * @param value MultiArray or scalar. * @returns MultiArray 1x1 if value is scalar. */ static readonly scalarToMultiArray: (value: ElementType) => MultiArray; /** * If value is a scalar then convert to a 1x1 MultiArray. If is common * array or cell array returns `value` unchanged. * @param value MultiArray or scalar. * @returns MultiArray 1x1 if value is scalar. */ static readonly scalarOrCellToMultiArray: (value: ElementType) => MultiArray; /** * If `value` parameter is a MultiArray of size 1x1 then returns as scalar. * @param value MultiArray or scalar. * @returns Scalar value if `value` parameter has all dimensions as singular. */ static readonly MultiArrayToScalar: (value: ElementType) => ElementType; /** * If `value` parameter is a non empty MultiArray returns it's first element. * Otherwise returns `value` parameter. * @param value Scalar or array candidate. * @returns First element of a non-empty array, otherwise `value`. */ static readonly firstElement: (value: ElementType) => ElementType; /** * If M is a line vector then return the line of M else return first column of M. * @param M Scalar or array candidate. * @returns First row for row vectors, first column otherwise. */ static readonly firstVector: (M: ElementType) => ElementType[]; /** * Copy of MultiArray. * @param M MultiArray. * @returns Copy of MultiArray. */ static readonly copy: (M: MultiArray) => MultiArray; /** * Copy this array and its stored runtime values. * * @returns Copied array preserving generic element type. */ copy(): MultiArray; /** * Convert a `MultiArray` to the scalar truth value used by conditions. * * MATLAB/Octave conditions are true only when the array is non-empty and * every element is logically true. Empty arrays therefore evaluate to * false, not true by vacuity. * * @param M Array to test. * @returns Logical scalar truth value. */ static readonly toLogical: (M: MultiArray) => ComplexType; /** * Convert this array to the scalar truth value used by conditions. * * @returns Logical scalar truth value. */ toLogical(): ComplexType; /** * Expand Multidimensional array dimensions if dimensions in `dim` is greater than dimensions of `M`. * If a dimension of `M` is greater than corresponding dimension in `dim` it's unchanged. * The array is filled with zeros and is expanded in place. * @param M Multidimensional array. * @param dim New dimensions. */ static readonly expand: (M: MultiArray, dim: number[], fill?: ElementType) => void; /** * Reshape an array acording dimensions in `dim`. * @param M MultiArray. * @param dim Result dimensions. * @param d Undefined dimension index (optional). * @returns */ static readonly reshape: (M: MultiArray, dim: number[], d?: number) => MultiArray; /** * Expand range. * @param startNode Start of range. * @param stopNode Stop of range. * @param strideNode Optional stride value. * @returns MultiArray of range expanded. */ static readonly expandRange: (start: ComplexType, stop: ComplexType, stride?: ComplexType | null) => MultiArray; /** * Expand colon to a column vector. * @param length * @returns */ static readonly expandColon: (length: number) => MultiArray; /** * Detect whether MultiArray `M` contains any non-zero imaginary part. * @param M MultiArray to test. * @returns `true` if any element has non-zero imaginary component. * `false` otherwise. */ static readonly haveAnyComplex: (M: MultiArray) => boolean; /** * Check if subscript is a integer number, convert Complex to * number. * @param k Index as Complex. * @param prefix Optional id reference of object. * @returns k as number, if real part is integer greater than 1 and imaginary part is 0. */ static readonly testInteger: (k: ComplexType, prefix?: string, infix?: string, constraint?: number | [number, number]) => number; /** * Check if subscript is a integer number, convert Complex to * number. * @param k Index as Complex. * @param input Optional id reference of object. * @returns k as number, if real part is integer greater than 1 and imaginary part is 0. */ static readonly testIndex: (k: ComplexType, input?: string) => number; /** * Check if subscript is a integer number, convert Complex to * number, then check if it's less than bound. * @param k Index as Complex. * @param bound Maximum acceptable value for the index * @param dim Dimensions (to generate error message) * @param input Optional string to generate error message. * @returns Index as number. */ static readonly testIndexBound: (k: ComplexType, bound: number, dim: number[], input?: string) => number; /** * Converts subscript to linear index. Performs checks and throws * comprehensive errors if dimension bounds are exceeded. * @param dimension Dimension of multidimensional array ([line, column, page, block, ...]) as number[]. * @param subscript Subscript ([line, column, page, block, ...]) as a Complex[]. * @param input Input string to generate error messages (the id of array). * @returns linear index. */ static readonly parseSubscript: (dimension: number[], subscript: ComplexType[], input?: string, interpreter?: RuntimeDisplay) => number; /** * Binary operation 'scalar `operation` array'. * @param op Binary operation name. * @param left Left operand (scalar). * @param right Right operand (array). * @returns Result of operation. */ static readonly scalarOpMultiArray: (op: TBinaryOperationName, left: ComplexType, right: MultiArray) => MultiArray; /** * Binary operation 'array `operation` scalar'. * @param op Binary operation name. * @param left Left operand (array). * @param right Right operaand (scalar). * @returns Result of operation. */ static readonly MultiArrayOpScalar: (op: TBinaryOperationName, left: MultiArray, right: ComplexType) => MultiArray; /** * Unary left operation. * @param op Unary operation name. * @param right Operand (array) * @returns Result of operation. */ static readonly leftOperation: (op: TUnaryOperationLeftName, right: MultiArray) => MultiArray; /** * Binary element-wise operation with full MATLAB-compatible broadcasting. * Supports N-D arrays and row/column vector expansion. * @param op Binary operation. * @param left Left operand. * @param right Right operand. * @returns Binary element-wise result. */ static readonly elementWiseOperation: (op: TBinaryOperationName, left: MultiArray, right: MultiArray) => MultiArray; /** * Map two arrays with MATLAB/Octave singleton expansion. * * The callback receives values in logical linear order while this helper * translates those coordinates back to the project page-stacked physical * row/column storage. Use it when an operation is element-wise but not * necessarily one of the `Complex` dispatcher names. * * @param left Left operand. * @param right Right operand. * @param diagnosticName Name used in nonconformance diagnostics. * @param callback Element mapper. * @returns Broadcasted mapping result. */ static readonly mapBroadcasted: (left: MultiArray, right: MultiArray, diagnosticName: string, callback: (left: ElementType, right: ElementType) => ElementType) => MultiArray; /** * 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 readonly 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 readonly rawMapRowColumn: (M: MultiArray, callback: (element: ElementType, i: number, j: number) => ElementType) => 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 readonly rawMapLinearIndex: (M: MultiArray, callback: (element: ElementType, index: number, i?: number, j?: number) => ElementType) => 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 readonly alongDimensionMap: (dimension: number, M: MultiArray, callback: (element: ElementType, d: number, i: number, j: number) => ElementType) => MultiArray; /** * * @param M * @param DIM * @returns */ static readonly sizeAlongDimension: (M: MultiArray, DIM?: ElementType) => number; /** * Returns the element at the given index along the specified dimension. * @param M MultiArray instance * @param dimension Dimension index (0-based) * @param index Index along the dimension (0-based) * @returns ElementType */ static readonly getElementAlongDimension: (M: MultiArray, dimension: number, index: number) => ElementType; /** * * @param elem * @param scalar * @returns */ static readonly divideElementByScalar: (elem: ElementType, scalar: ComplexType) => ElementType; /** * * @param meanElem * @param dim * @param d * @returns */ static readonly getMeanElementForPosition: (meanElem: ElementType, dim: number, d: number) => ElementType; /** * Reduce one dimension of MultiArray putting entire dimension in one * element of resulting MultiArray as an Array. The resulting MultiArray * cannot be unparsed or used as argument of any other method of * MultiArray class. * @param dimension Dimension to reduce to Array * @param M MultiArray to be reduced. * @returns MultiArray whose slots contain collected element lines. */ static readonly reduceToArray: (dimension: number, M: MultiArray) => MultiArray; /** * Contract MultiArray along `dimension` calling callback. This method is * analogous to the JavaScript Array.reduce function. * @param dimension Dimension to operate callback and contract. * @param M Multidimensional array. * @param callback Reduce function. * @param initial Optional initial value to set as previous in the first * call of callback. If not set the previous will be set to the first * element of dimension. * @returns Multiarray with `dimension` reduced using `callback`. */ static readonly reduce: (dimension: number, M: MultiArray, callback: (previous: ElementType, current: ElementType, index?: number) => ElementType, initial?: ElementType) => ElementType; /** * Return the concatenation of N-D array objects, ARRAY1, ARRAY2, ..., * ARRAYN along `dimension` parameter (zero-based). * @param dimension Dimension of concatenation. * @param fname Function name (for error messages). * Empty arrays are neutral when at least one non-empty operand is present, * matching MATLAB/Octave concatenation such as `[[], 1]`. * @param ARRAY Arrays to concatenate. * @returns Concatenated arrays along `dimension` parameter. */ static readonly concatenate: (dimension: number, fname: string, ...ARRAY: MultiArray[]) => MultiArray; /** * Split the MultiArray in the last dimension. * @param M * @returns */ private static readonly splitLastDimension; /** * Calls `splitLastDimension` and recursively calls `evaluate` for each * result, concatenating on the last dimension, until the array is 2-D, * then then concatenates the elements row by row horizontally, then * concatenates the rows vertically. * @param M MultiArray object. * @param interpreter Runtime evaluation context. * @param local Local context (function evaluation). * @param fname Function name (context). * @returns Evaluated MultiArray object. */ private static readonly evaluateRecursive; /** * Wrapper to not pass the null array to `MultiArray.interpreterRecursive`. * @param M MultiArray object. * @param interpreter Runtime evaluation context. * @param local Local context (function evaluation). * @param fname Function name (context). * @returns Evaluated MultiArray object. */ static readonly evaluate: (M: MultiArray, interpreter?: RuntimeEvaluationContext | null | undefined, scope?: unknown) => ElementType; /** * # MATLAB/Octave Array Indexing - Complete Rules (Concise Specification) * * This document synthesizes the official rules of MATLAB/Octave array indexing, * based on MathWorks documentation and related references. It defines how arrays * are accessed, reshaped, and modified under all indexing modes. * * ## 1. Core Concepts * * - Arrays use **1-based indexing**. * - Storage and traversal follow **column-major order**. * - Indexing modes: * - **Linear indexing** (single index) * - **Subscript indexing** (multiple indices) * - **Logical indexing** * * ## 2. Linear Indexing * * ```matlab * A(k) * ``` * * - Treats `A` as a single column vector in column-major order. * - Accesses elements sequentially down columns. * - Result: * - Same number of elements as index * - Orientation follows index (row vs column) * * ### Special Case: `(:)` * * ```matlab * A(:) * ``` * * - Returns all elements as a **column vector** * - Equivalent to full linearization * * ## 3. Subscript (Multidimensional) Indexing * * ```matlab * A(i,j,k,...) * ``` * * - Each index corresponds to one dimension. * - Indices may be scalars, vectors, or `:`. * - Result size: * * ```text * size(A(i,j,k,...)) = [numel(i), numel(j), numel(k), ...] * ``` * * - Colon `:` selects all elements in that dimension. * * ## 4. Index Vectors and Shape Rules * * - For `A(id)`: * - Result has same number of elements as `id` * - Orientation follows `A` if both are vectors * * - For `A(id1,id2)`: * - Result is a matrix of size: * * ```text * [numel(id1), numel(id2)] * ``` * * - General case: * * ```text * size = [numel(id1), numel(id2), ..., numel(idn)] * ``` * * ## 5. Fewer Indices Than Dimensions (Dimension Folding) * * If fewer indices are provided than dimensions: * * ```matlab * A(i,j) % A is N-D * ``` * * - MATLAB **folds all remaining dimensions into the last index**. * - Equivalent to reshaping: * * ```matlab * reshape(A, dim1, dim2*dim3*...) * ``` * * ### Consequences * * - `A(:, :)` flattens higher dimensions into columns * - `A(i,:)` traverses across all higher dimensions * - `A(:,j)` does **not** traverse higher dimensions * * ## 6. Colon Operator (`:`) * * - Selects full dimension: * * ```matlab * A(:,j) * A(i,:) * ``` * * - Equivalent to `1:end` in that dimension * * - Also used to generate ranges: * * ```matlab * a:b * a:s:b * ``` * * ## 7. Logical Indexing * * ```matlab * A(mask) * ``` * * - `mask` is evaluated in **linear order** * - Must not exceed `numel(A)` * - Result: * - Column vector of selected elements * * ## 8. The `end` Keyword * * - Refers to last index of a dimension: * * ```matlab * A(end) * A(1:end) * A(:,end) * ``` * * - Evaluated independently per dimension * * ## 9. Indexed Assignment * * ```matlab * A(I) = B * ``` * * ### Rules * * - If `B` is scalar → scalar expansion * - Otherwise: * * ```text * numel(B) == numel(I) * ``` * * - Indices may be repeated (last assignment wins) * - Colon selects full dimension * * ## 10. Deletion via Empty Array * * ```matlab * A(I) = [] * ``` * * ### Rules * * - Removes elements along **one dimension only** * - Valid when indexing selects: * - Entire rows * - Entire columns * - Entire slices of a single dimension * * - Invalid if assignment would produce irregular shape * * ## 11. Array Expansion * * ```matlab * A(10) = 5 * ``` * * - Array automatically grows * - Missing elements filled with default values (e.g., `0`) * * ## 12. Linear vs Subscript Distinction * * ```matlab * A(2) % linear * A(2,:) % subscript * ``` * * - These operations are **fundamentally different** * - Linear indexing ignores dimensions * - Subscript indexing respects dimensional structure * * ## 13. Evaluation Order * * 1. Index expressions evaluated * 2. Converted to subscripts or linear indices * 3. Bounds checked * 4. Elements accessed or assigned * * ## 14. Key Behavioral Summary * * - Column-major order governs all indexing * - `(:)` always returns a column vector * - Logical indexing returns column vectors * - Subscript indexing defines output shape explicitly * - Fewer indices ⇒ dimension folding * - Assignment enforces size compatibility or scalar expansion * - Deletion is restricted to one dimension * * ## 15. MathJSLab Engine Implementation Notes * * This section documents how the MathJSLab engine concretely implements * the indexing semantics described above. While fully aligned with MATLAB * behavior, the engine introduces a **unified linear-index pipeline** * to simplify execution and ensure consistency across all operations. * * ### 15.1 Unified Index Resolution * * All indexing modes (linear, subscript, logical) are internally reduced to: * * ```text * → a list of 0-based linear indices * ``` * * This is performed by: * * ```ts * resolveLinearIndices(...) * ``` * * Responsibilities: * - Detect logical vs numeric indexing * - Normalize scalar logicals (`true` → `[1]`, `false` → `[]`) * - Delegate numeric interpretation to: * - `computeIndexingStructure` * - `iterateWithLinearIndex` * * This guarantees a **single source of truth** for index resolution. * * * ### 15.2 Index Normalization Pipeline * * The engine separates indexing into three distinct phases: * * 1. **Structure normalization** * ```ts * computeIndexingStructure(...) * ``` * - Expands missing dimensions with `:` * - Linearizes all index arguments * - Computes total iteration size * * 2. **Index evaluation** * ```ts * iterateWithLinearIndex(...) * ``` * - Resolves `end` * - Converts subscripts → linear indices * - Performs bounds validation via `parseSubscript` * * 3. **Collection** * ```ts * collectLinearIndices(...) * ``` * - Produces final linear index list * * * ### 15.3 Selection Pipeline * * Element access follows: * * ```text * indices → applyLinearSelection → shape reconstruction * ``` * * - `applyLinearSelection(...)` * - Retrieves elements using `getElementByLinearIndex` * * - Shape reconstruction: * - Logical indexing → column vector (or mask-shaped vector) * - Linear indexing: * - `(:)` → column vector * - otherwise → row vector * - Subscript indexing: * - Uses `computeIndexingStructure` * - Uses `resolveIndexPlan` * - Final adjustment via `collapseResult` * * * ### 15.4 Assignment Pipeline * * Assignment is centralized via: * * ```ts * applyLinearAssignment(...) * ``` * * Features: * - Scalar expansion * - Strict size validation * - Field-aware assignment (structures supported) * - Deterministic overwrite (last index wins) * * High-level flow: * * ```text * resolve indices → expand target → assign values * ``` * * Expansion rules: * - Linear growth allowed only for vectors * - Multidimensional growth uses `expand(...)` * * * ### 15.5 Deletion Semantics * * Deletion is handled in two layers: * * - High-level: * ```ts * deleteElements(...) * ``` * - Enforces MATLAB rule: * → exactly one non-colon dimension * * - Low-level: * ```ts * applyDeletionFromIndices(...) * ``` * - Removes elements using linear filtering * - Preserves vector orientation when applicable * * * ### 15.6 Logical Indexing Implementation * * Logical indexing is treated as a specialization of linear indexing: * * ```text * mask → logicalToLinearIndices → linear pipeline * ``` * * Rules: * - Mask is always linearized * - `true` selects index * - `false` skips index * - Scalar logical: * - `true` → first element * - `false` → empty result * * Output shape: * - Always column vector unless mask is a vector (row preserved) * * * ### 15.7 Shape Resolution Strategy * * Shape is **not derived from indices directly**, but from a plan: * * ```ts * resolveIndexPlan(...) * ``` * * This determines: * - Linear vs multidimensional behavior * - Full slice detection (`:`) * - Scalar vs vector indexing * - Active dimensions * - Whether collapse is required * * Final shape adjustments: * - `collapseResult(...)` * - Handles dimension folding * - Preserves MATLAB-compatible edge cases: * - `A(:,j)` * - `A(i,:)` * - N-D flattening * * * ### 15.8 Design Principles * * The implementation follows strict architectural rules: * * - **Single responsibility** * - Index resolution, selection, assignment, and shape are separated * * - **Linear-first execution model** * - All operations operate on linear indices internally * * - **MATLAB compatibility as constraint** * - Edge cases explicitly preserved * * - **Deterministic behavior** * - No ambiguity in index interpretation * * - **Extensibility** * - Logical, numeric, and future index types share the same pipeline * * * ### 15.9 Summary * * The MathJSLab engine implements MATLAB indexing through: * * ```text * Normalize → Resolve → Linearize → Apply → Reshape * ``` * * This unified model ensures: * - Correctness * - Maintainability * - Full compatibility with MATLAB semantics * * while keeping the internal execution model simple and robust. * * ## Sources * * - [MathWorks - Matrix Indexing in MATLAB](https://www.mathworks.com/company/technical-articles/matrix-indexing-in-matlab.html) * - [MathWorks - Array Indexing](https://www.mathworks.com/help/matlab/math/array-indexing.html) * - [MathWorks - Detailed Rules About Array Indexing](https://www.mathworks.com/help/matlab/learn_matlab/array-indexing.html) * - [MathWorks - Indexed Assignment](https://www.mathworks.com/help/matlab/math/detailed-rules-about-array-indexing.html) * - [MathWorks - Learn MATLAB: Array Indexing](https://www.mathworks.com/help/matlab/math/indexed-assignment.html) * - [TutorialsPoint - MATLAB Array Indexing](https://www.tutorialspoint.com/matlab/matlab_array_indexing.htm) */ private static colon; /** * Normalize an indexing expression into a canonical structure used by * MultiArray get/set/delete operations. * * This function is the entry point for interpreting MATLAB-like indexing. * It converts the raw `indexList` (which may contain scalars, vectors, * or MultiArray objects) into a uniform representation that can be used * by iteration and linear index resolution. * * Behavior: * - Detects linear indexing when a single index argument is provided. * - Expands missing dimensions with implicit colon (:) to match the * number of dimensions of the target array. * - Linearizes all index arguments into flat arrays. * - Computes the total number of indexed elements (cartesian product). * * Notes: * - This function does NOT validate bounds or apply indexing; it only * prepares structural information. * - Logical indexing is NOT handled here and must be intercepted before * calling this function. * * @param dimension Shape of the target MultiArray (e.g. [m, n, ...]). * @param indexList Raw index arguments as provided by the interpreter. * * @returns An object describing the normalized indexing plan: * - isLinear: true if indexing uses a single argument (linear indexing) * - originalIndexCount: number of indices provided by the user * - args: array of linearized index arrays (one per dimension) * - argsLength: length of each index array * - total: total number of indexed elements (product of argsLength) * * @throws RangeError if indexList is empty */ private static readonly computeIndexingStructure; /** * Iterate over a normalized indexing structure and resolve each position * into a linear index of the target MultiArray. * * This function bridges the gap between: * - The cartesian product of index arguments (produced by computeIndexingStructure) * - The actual linear indices used to access elements in memory * * Behavior: * - Iterates over all combinations of indices (cartesian product) * - Converts each iteration step `n` into a multi-dimensional subscript * relative to the index arguments (not the target array) * - Maps those subscripts into actual index values (subscriptArgs) * - Resolves each subscriptArgs into a linear index using MATLAB rules * (including support for `end` via parseSubscript) * - Invokes the callback with: * - subscriptArgs: the resolved indices per dimension (1-based) * - linearIndex: the corresponding linear index in the target array (0-based) * - n: the iteration counter (0-based) * * Notes: * - This function assumes `idx` was produced by computeIndexingStructure. * - Bounds checking and `end` resolution are delegated to parseSubscript. * - The iteration order follows column-major semantics (MATLAB-compatible). * - This function does NOT perform any read/write; it only drives iteration. * * @param idx Normalized indexing structure (args, argsLength, total). * @param dimension Shape of the target MultiArray. * @param callback Function invoked for each indexed element. * @param input Optional input string (used for error reporting). * @param interpreter Optional interpreter (used for resolving expressions like `end`). */ private static readonly iterateWithLinearIndex; /** * Resolve the structural "indexing plan" for a given indexing operation. * * This function analyzes the normalized indexing structure and extracts * semantic information about how the result should be shaped and interpreted. * * It does NOT perform indexing itself. Instead, it provides metadata used by: * - getElements → to shape the output (row/column/folding) * - collapseResult → to decide dimensional reduction * * The plan captures both: * 1. Legacy compatibility flags (MATLAB-like behavior) * 2. Structural semantics per dimension (more expressive and future-proof) * * ------------------------------------------------------------ * CONCEPTUAL MODEL * ------------------------------------------------------------ * * Each dimension is classified as: * - full slice → ":" (entire dimension selected) * - scalar index → single position (dimension collapses) * - partial → subset of elements * * From this, we derive: * - activeDimensions → dimensions that are actually being restricted * - isFullSlice → per-dimension ":" detection * - isScalarIndex → per-dimension scalar selection * * ------------------------------------------------------------ * SPECIAL CASE: LINEAR INDEXING * ------------------------------------------------------------ * * When idx.isLinear === true: * - The operation ignores multi-dimensional structure * - The array is treated as a column-major linear vector * - activeDimensions is reduced to a single conceptual dimension * * ------------------------------------------------------------ * COMPATIBILITY FLAGS (LEGACY BEHAVIOR) * ------------------------------------------------------------ * * These flags preserve MATLAB-like shaping behavior: * * - isColonOnly: * True when linear indexing selects the entire array (A(:)) * * - isRowSelection: * Detects A(1,:) pattern → result should be a row vector * * - isColumnSelection: * Detects A(:,1) pattern → result should be a column vector * * - requiresCollapse: * True when fewer indices than dimensions were provided. * This triggers dimensional folding (e.g., A(2,:) on 3D arrays) * * ------------------------------------------------------------ * NOTES * ------------------------------------------------------------ * * - Dimension padding with ":" is applied implicitly before classification. * - This function is purely analytical (no data access or mutation). * - The returned plan is consumed downstream by shape resolution logic. * * @param dimension Shape of the target MultiArray. * @param idx Normalized indexing structure from computeIndexingStructure. * * @returns Indexing plan describing structural semantics of the operation. */ private static readonly resolveIndexPlan; /** * Retrieve an element from a MultiArray using a 0-based linear index. * * This method provides a unified access path for both plain values and * structured field access. It converts the linear index into (row, column) * coordinates assuming column-major order (MATLAB semantics), then retrieves * the corresponding element. * * If a non-empty `field` path is provided, the access is delegated to * Structure.getField, allowing nested field resolution (e.g., A(i).field.subfield). * * @param M Source MultiArray. * @param linearIndex Zero-based linear index (column-major order). * @param field Structure field access path. If empty, returns the raw element. * @returns The selected element or nested field value. * * @throws RangeError If the linear index is out of bounds (indirectly via index conversion). * * @remarks * - Assumes that `linearIndex` has already been validated. * - This function is intentionally minimal and side-effect free. * - Used as the core primitive by higher-level selection helpers such as * `applyLinearSelection` and indexing pipelines. */ private static readonly getElementByLinearIndex; /** * Set element in a MultiArray using a linear index (column-major order). * * This function is the write counterpart of `getElementByLinearIndex` and * centralizes all element assignment at the lowest level of the indexing pipeline. * * The linear index is assumed to be **0-based** and mapped to (row, column) * coordinates according to MATLAB/Octave column-major semantics. * * If a field path is provided, the assignment is performed on a nested * structure field instead of directly replacing the element. * * @param M Target MultiArray. * @param linearIndex Zero-based linear index in column-major order. * @param value Value to assign at the specified position. * @param field Optional structure field access path. * * @throws RangeError If the linear index is out of bounds (indirectly via index conversion). * @throws Error If field access is invalid for the target element. */ private static readonly setElementByLinearIndex; /** * Collapse an intermediate indexing result to its final shape according to MATLAB rules. * * After element selection, the intermediate result (`resultFull`) is typically constructed * as a full N-dimensional array. This function applies MATLAB's post-processing rules * to determine the final output shape, including dimension collapsing and vector orientation. * * Behavior: * * 1) No collapse required: * - If the number of index arguments matches the array dimensionality, * the result is returned as-is. * * 2) Special 2D cases (highest priority, MATLAB-compatible): * - Column selection: A(:, j) * → returns a column vector (n×1) * * - Row selection: A(i, :) * → returns a row vector (1×n) * → also applies to higher dimensions with implicit folding * * 3) General MATLAB folding rule: * - When indexing reduces dimensionality (partial indexing), * higher dimensions are folded into columns. * - Result becomes a 2D matrix: * rows = size along first dimension * cols = total elements / rows * * - Elements are filled in column-major order (MATLAB layout). * * 4) Default: * - If none of the above applies, the intermediate result is returned unchanged. * * Notes: * - This function enforces MATLAB-compatible shape semantics after indexing. * - It does not modify element values, only their arrangement. * - The `plan` parameter encodes structural properties of the indexing operation, * but only a subset is currently used for collapse decisions. * * @param resultFull Intermediate full result (before collapse). * @param originalDimension Original dimensions of the source array. * @param idx Indexing structure (argument counts and shapes). * @param plan Precomputed indexing plan describing selection semantics. * * @returns Final MultiArray with correct MATLAB-compatible shape. */ private static readonly collapseResult; /** * Shape the result of linear indexing according to MATLAB/Octave rules. * * `A(:)` is always a column vector. For explicit `A(P)`, vector sources keep * their own row/column orientation when `P` is also a vector; matrix-shaped * sources or matrix-shaped `P` use the shape of `P`. */ private static readonly linearIndexResult; /** * Shape the result of logical indexing as the equivalent linear indexing by * `find(mask)`. * * For vector sources and vector masks, MATLAB/Octave preserve the source * orientation. For matrix-shaped sources with vector masks, the result follows * the mask orientation. Matrix-shaped logical masks produce a column vector. */ private static readonly logicalIndexResult; /** * Normalize a scalar or array logical subscript to a `MultiArray` mask. * @param arg Logical index argument. * @returns Logical mask as a `MultiArray`. */ private static readonly logicalMaskFromIndexArgument; /** * Linearize and validate a logical mask as numeric/logical complex values. * @param items Logical mask. * @param id Optional identifier for diagnostics. * @returns Linearized logical mask values. */ private static readonly linearizedLogicalMask; /** * Convert a logical mask into a list of linear indices (0-based). * * MATLAB semantics: * - Logical indexing is interpreted in linear (column-major) order. * - The mask is first linearized, then applied element-wise to the * linearized target array. * - Each `true` value selects the corresponding linear position. * - `false` values are ignored. * * Validation rules: * - The mask length must not exceed the number of elements in `M`. * - If the mask is shorter than `M`, it is applied only to the * corresponding leading elements (MATLAB-compatible behavior). * * Notes: * - Returned indices are 0-based (internal engine convention). * - The returned list may be empty (e.g., when mask is all false). * - This function does NOT handle scalar logicals; those must be * normalized beforehand by the caller (e.g., via `scalarToMultiArray`). * * @param M Target MultiArray being indexed. * @param items Logical mask as a MultiArray. * @param id Optional identifier (used for error messages). * @returns Array of selected linear indices (0-based). * * @throws EvalError If the mask length exceeds the number of elements in `M`. */ private static readonly logicalToLinearIndices; /** * Normalize logical indexing input into a list of linear indices (0-based). * * This is a thin wrapper around {@link logicalToLinearIndices}, introduced to: * - Provide a stable abstraction point for logical index resolution * - Allow future extensions (e.g., scalar logical handling, special cases) * - Keep dispatcher and high-level indexing code decoupled from low-level logic * * The logical mask is interpreted in linear (column-major) order, following * MATLAB semantics: * - True values select corresponding linear positions * - False values are ignored * - Mask length must not exceed the number of elements in `M` * * @param M Target MultiArray being indexed. * @param items Logical mask as a MultiArray. * @param id Identifier (used for error reporting). * @returns Array of selected linear indices (0-based). */ private static logicalMaskToIndexList; /** * Determine whether an argument represents logical indexing. * * This function identifies both supported forms of logical indices: * * 1) Logical MultiArray * - e.g., A([true false true]) * * 2) Logical scalar (Complex) * - e.g., A(true), A(false) * * This distinction is important because scalar logicals behave differently * from numeric scalars: * - A(true) → selects the first element (linear index 1 in MATLAB) * - A(false) → selects no elements (returns empty array) * * Notes: * - This function is used by indexing dispatchers to route execution * into the logical indexing pipeline. * - It does not validate shape or size compatibility; it only detects type. * - Scalar logicals must be normalized (e.g., via scalarToMultiArray) * before further processing. * * @param arg Index argument (scalar or MultiArray). * @returns True if the argument should be treated as logical indexing. */ private static isLogicalIndex; /** * Apply linear selection on a MultiArray and return the extracted elements. * * This function performs the core data extraction step of the indexing pipeline: * given a list of linear indices (0-based), it retrieves the corresponding * elements from the source array in order. * * Selection follows MATLAB semantics: * - Indices refer to positions in column-major (linearized) order * - The output preserves the order of `indices` * - No reshaping is performed here (result is always a flat array) * * If a field path is provided, each selected element is resolved through * structure field access instead of returning the raw element. * * @param M Source MultiArray. * @param indices Linear indices (0-based, column-major order). * @param field Optional structure field access path. * @returns Flat array of selected elements, in the same order as `indices`. * * @remarks * - This function is side-effect free. * - It assumes indices have already been validated. * - Shape/orientation (row/column/matrix) is handled later in the pipeline * (e.g., in getElements and collapseResult). * - Acts as the core primitive for both numeric and logical indexing. */ private static applyLinearSelection; /** * Apply linear assignment on a MultiArray using a list of linear indices. * * This function performs the core write operation of the indexing pipeline. * Given a set of linear indices (0-based), it assigns values to the corresponding * positions in the target array, following MATLAB assignment semantics. * * Behavior: * * 1) Scalar expansion (broadcast): * - If `values` contains a single element, it is assigned to all indices. * * 2) Element-wise assignment: * - If `values.length > 1`, its length must match `indices.length`. * - Each value is assigned to the corresponding index in order. * * 3) Structure field assignment: * - If a non-empty `field` path is provided, assignment is delegated to * nested structure fields instead of replacing the element itself. * * Validation: * - Throws if the number of values does not match the number of indices * (unless scalar expansion applies). * * @param M Target MultiArray. * @param indices Linear indices (0-based, column-major order). * @param values Linearized right-hand side values. * @param field Optional structure field access path. * * @throws EvalError If dimensions are nonconformant. * * @remarks * - This function does not handle deletion (A(I) = []); that is handled upstream. * - Assumes indices are already validated and within bounds. * - Does not perform resizing or expansion of `M`; that is also handled upstream. * - Acts as the unified assignment primitive for both numeric and logical indexing. */ private static applyLinearAssignment; /** * Resolve an index list (logical or numeric) into linear indices (0-based). * * This function is the core of the indexing engine. It normalizes all supported * indexing modes into a unified representation: a list of linear indices in * column-major order. * * It does NOT perform element access or assignment — only index resolution. * * Supported indexing modes: * * 1) Logical indexing: * - Triggered when a single logical argument is provided. * - Accepts both logical MultiArray and logical scalar. * - Scalar logicals are normalized: * true → selects first element * false → selects no elements * - The mask is applied in linear (column-major) order. * * 2) Numeric indexing: * - Supports linear indexing (single argument) * - Supports multi-dimensional indexing (A(i,j,...)) * - Supports colon (:) and range expressions * - Supports `end` keyword via interpreter * * Processing steps (numeric case): * a) Normalize index structure via `computeIndexingStructure` * b) Iterate over all index combinations * c) Convert each subscript tuple into a linear index using `parseSubscript` * * Output: * - A flat array of 0-based linear indices * - Order matches MATLAB evaluation order (column-major traversal) * * @param M Target MultiArray being indexed. * @param id Identifier (used for error reporting and `end` resolution). * @param indexList Raw index arguments (scalars, arrays, or logical masks). * @param interpreter Optional interpreter used to resolve dynamic expressions (e.g., `end`). * * @returns Array of linear indices (0-based). * * @throws EvalError or RangeError for invalid indices or out-of-bounds access. * * @remarks * - This function unifies logical and numeric indexing into a single pipeline. * - It is side-effect free. * - It guarantees that downstream operations (selection or assignment) * operate only on validated linear indices. * * - The returned indices may: * * be empty (e.g., a(false)) * * contain duplicates (allowed in MATLAB) * * be unordered (depending on index expressions) * * - Shape/orientation semantics are handled separately (e.g., in getElements * and collapseResult). */ static resolveLinearIndices: (M: MultiArray, id: string, indexList: IndexArgument[], interpreter?: RuntimeDisplay) => number[]; /** * Collect linear indices from a normalized indexing structure. * * This is a convenience wrapper around {@link iterateWithLinearIndex} that * gathers all computed linear indices into a flat array. * * It is used in numeric indexing to convert a precomputed indexing structure * (`idx`) into a list of linear indices (0-based), ready for selection or * assignment. * * Behavior: * - Iterates over all index combinations defined in `idx` * - Converts each subscript tuple into a linear index * - Preserves iteration order (column-major traversal) * * @param idx Normalized indexing structure (from computeIndexingStructure). * @param dimension Target array dimensions. * @param input Optional input string (used for error reporting). * @param interpreter Optional interpreter (used to resolve dynamic expressions such as `end`). * * @returns Array of linear indices (0-based). * * @remarks * - This function is side-effect free. * - It does not perform validation; assumes `idx` is already normalized. * - Equivalent to manually accumulating results from iterateWithLinearIndex. * - Used to simplify and centralize index collection logic. */ private static collectLinearIndices; /** * Apply deletion on a MultiArray using a list of linear indices. * * This function performs linear deletion (A(I) = []) by removing the elements * at the specified linear indices and compacting the remaining data. * * Behavior: * - The array is first linearized (column-major order) * - Elements at positions in `indices` are removed * - The remaining elements are compacted into a new linear sequence * * Shape reconstruction: * - If the original array is a vector: * - Row vector: result remains a row vector * - Column vector: result remains a column vector * * - If the original array is not a vector: * - The result is converted to a column vector * - This matches MATLAB behavior for ambiguous linear deletions * * Notes: * - Indices are assumed to be 0-based and already validated * - Duplicate indices are ignored (set semantics) * - Order of remaining elements is preserved * * @param M Target MultiArray (modified in-place). * @param indices Linear indices to remove (0-based). * * @remarks * - This function implements the core of logical and linear deletion. * - It does not validate index correctness or dimensional constraints; * such checks must be performed upstream. * - Multi-dimensional structural deletions (e.g., A(:,2) = []) are handled * elsewhere (e.g., in deleteElements). */ private static applyDeletionFromIndices; /** * Retrieve elements from a MultiArray using MATLAB-like indexing semantics. * * This is the main entry point for element access (RHS indexing). It supports * both logical and numeric indexing, including multi-dimensional access, * linear indexing, colon expressions, and `end`. * * The indexing pipeline is divided into three stages: * * 1) Index resolution: * - All index expressions are normalized into linear indices (0-based) * - Performed by {@link resolveLinearIndices} * * 2) Element selection: * - Elements are extracted in column-major order * - Performed by {@link applyLinearSelection} * * 3) Shape reconstruction: * - Result is reshaped according to MATLAB rules * - Includes special handling for logical indexing and partial indexing * * Supported indexing modes: * * - Logical indexing: * A(mask) * • mask may be a logical array or scalar * • scalar true → selects first element * • scalar false → returns empty array * • result shape follows mask orientation: * - vector mask → preserves row/column orientation * - matrix mask → result is a column vector * * - Linear indexing: * A(I) * • returns row vector unless I is ":" (full selection) * • A(:) → column vector * * - Multi-dimensional indexing: * A(i,j,...) * • supports colon (:), ranges, and `end` * • result shape determined by MATLAB collapsing rules * * @param M Source MultiArray. * @param id Identifier (used for error reporting and `end` resolution). * @param field Optional structure field access path. * @param indexList Index arguments (numeric or logical). * @param interpreter Optional interpreter (used for dynamic expressions such as `end`). * * @returns Resulting element(s), as a MultiArray or scalar. * * @throws EvalError or RangeError for invalid indexing operations. * * @remarks * - This function is side-effect free. * - Logical indexing is handled as a special case due to its distinct * shape semantics. * - Numeric indexing follows a unified pipeline using index structures * and index plans. * * - Internally, all indexing is reduced to linear index operations, * ensuring a consistent and extensible implementation. */ static readonly getElements: (M: MultiArray, id: string, field: string[], indexList: IndexArgument[], interpreter?: RuntimeDisplay) => ElementType; /** * Assign values to elements of a MultiArray using numerical (non-logical) indexing. * * This method implements MATLAB-compatible assignment semantics, including: * * • Linear indexing: * A(I) = V * * • Subscript indexing: * A(i, j, k, ...) = V * * • Scalar expansion (broadcasting): * A(I) = scalar → scalar is replicated to match target size * * • Shape conformity: * numel(V) must be either 1 or equal to the number of indexed elements * * • Automatic array expansion: * - Vectors grow when indexed beyond current bounds * - N-D arrays expand per-dimension when valid * * • Deletion via empty assignment: * A(I) = [] * - Only allowed when exactly one index is non-colon * - Delegated to deleteElements() * * Internal pipeline: * * 1. Linearize RHS → `linearizedRight` * 2. Handle deletion case early * 3. Normalize indexing via computeIndexingStructure() * 4. Validate RHS conformity * 5. Resolve or create target array (including expansion) * 6. Collect linear indices via collectLinearIndices() * → fully supports `end` and N-D indexing * 7. Apply assignment via applyLinearAssignment() * * Notes: * * • Index validation and bounds checking are delegated to: * - testIndex() * - parseSubscript() * * • This function does NOT handle logical indexing. * Logical indexing is resolved upstream via resolveLinearIndices(). * * • Deletion logic is intentionally separated to preserve MATLAB constraints. * * * @param scope Execution scope (symbol table) * @param id Target variable name * @param field Structure field access path (empty if none) * @param indexList Raw index expressions (already evaluated) * @param right Right-hand side MultiArray * @param input Optional original expression (for error reporting / `end`) * @param interpreter Interpreter instance (used for `end` resolution) * * @throws RangeError If indexing is invalid or nonconformant * @throws EvalError If assignment dimensions are incompatible */ private static readonly setElementsNumerical; /** * Unified assignment entry point for MultiArray. * * Dispatches between logical indexing and numerical indexing semantics, * implementing MATLAB-compatible behavior. * * Supported assignment modes: * - Logical indexing: A(mask) = value * - Linear indexing: A(I) = value * - Subscript indexing: A(i,j,k,...) = value * * Logical indexing behavior: * - The mask is interpreted in linear (column-major) order * - Scalar logicals are promoted to a 1-element mask: * - true → selects first element * - false → selects no elements * - Deletion is supported: A(mask) = [] * - Shape of the mask does not need to match M exactly (linear semantics) * * Numerical indexing behavior: * - Delegated to setElementsNumerical * - Supports: * - multi-dimensional indexing * - `end` keyword (via interpreter) * - scalar expansion (broadcasting) * - automatic array expansion * - deletion via [] * * Deletion semantics: * - Logical deletion: handled here via linear filtering * - Numerical deletion: delegated to deleteElements (MATLAB constraints apply) * * Structure field assignment: * - If `field` is provided, assignment targets nested structure fields * * Error handling: * - Invalid variable or non-MultiArray target → EvalError * - Conformance and bounds errors are delegated to lower-level helpers * * @param scope Execution scope (variable resolution) * @param id Target variable name * @param field Structure field access path (empty for direct assignment) * @param indexList Raw index expressions (logical or numeric) * @param right Right-hand side value (MultiArray) * @param input Optional source string (used for error reporting / `end`) * @param interpreter Optional interpreter for dynamic expressions (e.g., `end`) */ static readonly setElements: (scope: IndexAssignmentScope, id: string, field: string[], indexList: IndexArgument[], right: MultiArray, input?: string, interpreter?: RuntimeDisplay) => void; /** * Delete elements from a MultiArray using MATLAB-compatible semantics. * * This function implements deletion via empty assignment: * A(I) = [] * * Supported modes: * * 1) Linear deletion * - Triggered when a single index is provided (A(I)) * - Indices are resolved in column-major linear order * - Result is a vector: * - Preserves orientation if A is already a vector * - Falls back to column vector otherwise * * 2) Dimension-based deletion (subscript indexing) * Examples: * A(:, j) → remove columns * A(i, :) → remove rows * A(:, :, k) → remove slices (N-D) * * Rules (MATLAB-compatible): * - Exactly ONE dimension may differ from a full slice (:) * - All other dimensions must be complete (i.e., ":" behavior) * - The size of the affected dimension is reduced accordingly * * Behavior details: * - Indices are first normalized via computeIndexingStructure * - Subscripts (including "end") are resolved via parseSubscript * - Linear indices are collected through iterateWithLinearIndex * - Deletion is performed by filtering the linearized data and rebuilding * the array with updated dimensions * * Error conditions: * - Empty index list → RangeError * - More than one non-colon dimension → RangeError * - No effective deletion dimension → RangeError * * Notes: * - Linear deletion is delegated to applyDeletionFromIndices * - N-D deletion reconstructs the array in column-major order * - Structure fields are preserved during deletion * * @param M Target MultiArray (modified in-place) * @param indexList Raw index expressions (logical or numeric) * @param input Optional original input string (used for error context) * @param interpreter Optional interpreter (used to resolve expressions like "end") */ static readonly deleteElements: (M: MultiArray, indexList: IndexArgument[], input?: string, interpreter?: RuntimeDisplay) => void; /** * Factory function that creates MATLAB-compatible reduction functions * (e.g., sum, prod, min, max, all, any) using MultiArray.reduce. * @param callback Binary operation applied elementwise along dimension. * @param type * @param initial Optional initial value for reduction. * @returns A function (M, DIM?) -> ElementType or MultiArray */ static readonly reduceFactory: (callback: ReduceCallbackOrComparisonType, type: ReduceType, initial?: ReduceInitialType) => ReduceHandlerType; } export { type ElementType, type IndexArgument, MultiArray }; declare const _default: { MultiArray: typeof MultiArray; }; export default _default;