runmat-runtime 0.4.1

Core runtime for RunMat with builtins, BLAS/LAPACK integration, and execution APIs
Documentation
{
  "title": "ismatrix",
  "category": "array/introspection",
  "keywords": [
    "ismatrix",
    "matrix detection",
    "metadata query",
    "logical",
    "gpu"
  ],
  "summary": "Return true when an array has at most two dimensions (m-by-n, including vectors and scalars).",
  "references": [],
  "gpu_support": {
    "elementwise": false,
    "reduction": false,
    "precisions": [],
    "broadcasting": "none",
    "notes": "Inspects tensor metadata directly on GPU handles; falls back to gathering when providers omit shape information."
  },
  "fusion": {
    "elementwise": false,
    "reduction": false,
    "max_inputs": 0,
    "constants": "inline"
  },
  "requires_feature": null,
  "tested": {
    "unit": "builtins::array::introspection::ismatrix::tests",
    "integration": "builtins::array::introspection::ismatrix::tests::ismatrix_gpu_tensor_uses_handle_shape"
  },
  "description": "`ismatrix(A)` returns logical `true` when the input has two dimensions (`m`-by-`n`) and logical `false` otherwise. Scalars and vectors are considered matrices because they occupy a 1-by-1 or 1-by-`n` grid. The builtin mirrors MATLAB semantics across numeric, logical, character, string, cell, struct, and GPU-resident data.",
  "behaviors": [
    "Returns `true` for scalars, row vectors, column vectors, and ordinary 2-D matrices.",
    "Returns `false` for arrays whose rank exceeds two, even if trailing dimensions are singleton (for example, `1×1×1`).",
    "Empty arrays such as `0×0`, `1×0`, and `0×1` are matrices; higher-rank empties such as `0×0×3` are not.",
    "Character arrays, string arrays, and cell arrays honor their reported MATLAB dimensions.",
    "GPU tensors rely on their `GpuTensorHandle` metadata; if a provider omits the shape, RunMat gathers once to inspect it.",
    "Objects, structs, numeric scalars, and logical scalars behave like their underlying dimensions (`1×1`)."
  ],
  "examples": [
    {
      "description": "Confirming that a 2-D matrix returns true",
      "input": "tf = ismatrix([1 2 3; 4 5 6])",
      "output": "tf = logical(1)"
    },
    {
      "description": "Showing that vectors and scalars count as matrices",
      "input": "scalar_tf = ismatrix(42);\nrow_tf = ismatrix(1:5);\ncol_tf = ismatrix((1:5)')",
      "output": "scalar_tf = logical(1)\nrow_tf = logical(1)\ncol_tf = logical(1)"
    },
    {
      "description": "Detecting that higher-dimensional arrays are not matrices",
      "input": "tf = ismatrix(ones(2,2,3))",
      "output": "tf = logical(0)"
    },
    {
      "description": "Working with empty arrays",
      "input": "tf_empty = ismatrix([]);\ntf_row0 = ismatrix(zeros(1,0));\ntf_col0 = ismatrix(zeros(0,1));\ntf_3d_empty = ismatrix(zeros(0,0,3))",
      "output": "tf_empty = logical(1)\ntf_row0 = logical(1)\ntf_col0 = logical(1)\ntf_3d_empty = logical(0)"
    },
    {
      "description": "Character and string arrays follow their visible dimensions",
      "input": "tf_char = ismatrix('RunMat');\ntf_string = ismatrix([\"a\",\"b\",\"c\"])",
      "output": "tf_char = logical(1)\ntf_string = logical(1)"
    },
    {
      "description": "Cell and struct arrays respect their grid layout",
      "input": "C = {1, 2; 3, 4};\nS = repmat(struct(\"field\", 1), 1, 3, 1);\ntf_cell = ismatrix(C);\ntf_struct = ismatrix(S)",
      "output": "tf_cell = logical(1)\ntf_struct = logical(0)"
    },
    {
      "description": "Inspecting GPU arrays without explicit gathers",
      "input": "G = gpuArray(rand(4,4));\ntf_gpu = ismatrix(G)",
      "output": "tf_gpu = logical(1)"
    }
  ],
  "faqs": [
    {
      "question": "Does `ismatrix` treat scalars as matrices?",
      "answer": "Yes. Scalars occupy a 1-by-1 grid, which is a valid two-dimensional matrix in MATLAB semantics."
    },
    {
      "question": "Are vectors considered matrices?",
      "answer": "Yes. Row and column vectors are 1-by-`N` and `N`-by-1 matrices, so `ismatrix` returns `true`."
    },
    {
      "question": "Do trailing singleton dimensions change the result?",
      "answer": "Yes. Any array whose rank exceeds two returns `false`, even if the extra dimensions are size one (for example, `1×1×1`)."
    },
    {
      "question": "How are empty arrays handled?",
      "answer": "Empty arrays with at most two dimensions (such as `0×0`, `1×0`, or `0×1`) return `true`. Higher-rank empties return `false`."
    },
    {
      "question": "What about character, string, or cell arrays?",
      "answer": "They follow their MATLAB-visible dimensions. A character row vector or 1-by-`N` string array returns `true`, whereas a 1-by-1-by-`N` cell array returns `false`."
    },
    {
      "question": "Will `ismatrix` download GPU data?",
      "answer": "Only when the active provider fails to populate shape metadata on the `GpuTensorHandle`. Providers that supply the shape avoid any data transfer."
    },
    {
      "question": "Does `ismatrix` participate in fusion or GPU kernels?",
      "answer": "No. The builtin is a metadata query, always returns a host logical scalar, and never dispatches GPU work."
    },
    {
      "question": "How does `ismatrix` relate to `isvector` and `isscalar`?",
      "answer": "`isscalar(A)` and `isvector(A)` both imply `ismatrix(A)` because they describe special cases of 2-D arrays. The reverse implication does not necessarily hold."
    },
    {
      "question": "Are objects and structs supported?",
      "answer": "Yes. Objects and structs are treated as 1-by-1 unless they represent arrays of instances, in which case the reported dimensions determine the answer."
    },
    {
      "question": "Does sparse support change the behaviour?",
      "answer": "Future sparse tensors will report their dimensions through the same metadata, so the `ismatrix` predicate will remain unchanged."
    }
  ],
  "links": [
    {
      "label": "isscalar",
      "url": "./isscalar"
    },
    {
      "label": "isvector",
      "url": "./isvector"
    },
    {
      "label": "ndims",
      "url": "./ndims"
    },
    {
      "label": "size",
      "url": "./size"
    },
    {
      "label": "gpuArray",
      "url": "./gpuarray"
    },
    {
      "label": "gather",
      "url": "./gather"
    },
    {
      "label": "isempty",
      "url": "./isempty"
    },
    {
      "label": "length",
      "url": "./length"
    },
    {
      "label": "numel",
      "url": "./numel"
    }
  ],
  "source": {
    "label": "`crates/runmat-runtime/src/builtins/array/introspection/ismatrix.rs`",
    "url": "https://github.com/runmat-org/runmat/blob/main/crates/runmat-runtime/src/builtins/array/introspection/ismatrix.rs"
  },
  "gpu_residency": "You do not need to move data between host and device to call `ismatrix`. The builtin respects existing residency and only downloads data when the provider fails to report shapes. Users who prefer MATLAB-compatible workflows can still call `gpuArray` explicitly, but it is not required for this metadata check.",
  "gpu_behavior": [
    "`ismatrix` never launches GPU kernels. For `gpuArray` inputs, the builtin first inspects the shape metadata stored inside the `GpuTensorHandle`. Providers such as the WGPU backend fully populate that metadata so no data transfer occurs. If metadata is absent, RunMat gathers the tensor once to recover its dimensions and then evaluates the predicate on the host. The result is always a host logical scalar, so fusion treats `ismatrix` as a metadata query rather than a device-side operation."
  ]
}