runmat-runtime 0.4.1

Core runtime for RunMat with builtins, BLAS/LAPACK integration, and execution APIs
Documentation
{
  "title": "sign",
  "category": "math/elementwise",
  "keywords": [
    "sign",
    "signum",
    "elementwise",
    "complex",
    "gpu"
  ],
  "summary": "Sign of scalars, vectors, matrices, or N-D tensors with real or complex values.",
  "references": [],
  "gpu_support": {
    "elementwise": true,
    "reduction": false,
    "precisions": [
      "f32",
      "f64"
    ],
    "broadcasting": "matlab",
    "notes": "Falls back to the host when the active provider lacks unary_sign or when complex inputs require host-side normalisation."
  },
  "fusion": {
    "elementwise": true,
    "reduction": false,
    "max_inputs": 1,
    "constants": "inline"
  },
  "requires_feature": null,
  "tested": {
    "unit": "builtins::math::elementwise::sign::tests",
    "integration": "builtins::math::elementwise::sign::tests::sign_gpu_provider_roundtrip"
  },
  "description": "`y = sign(x)` returns the sign of each element of `x`. Real inputs become `-1`, `0`, or `1` depending on their value, while complex inputs are normalised to unit magnitude (`x ./ abs(x)`).",
  "behaviors": [
    "Real scalars, vectors, matrices, and higher-dimensional tensors produce `-1`, `0`, or `1` for each element.",
    "Complex inputs return `x ./ abs(x)`; zero-valued elements remain exactly `0 + 0i`.",
    "Logical inputs are promoted to doubles before applying the sign function.",
    "Character arrays are treated as their numeric code points and return doubles of the same shape.",
    "NaN inputs propagate (`sign(NaN)` is `NaN`), matching MATLAB semantics.",
    "`Inf` and `-Inf` map to `1` and `-1` respectively; complex numbers with infinite parts normalise accordingly."
  ],
  "examples": [
    {
      "description": "Determining the sign of a scalar",
      "input": "result = sign(-42)",
      "output": "result = -1"
    },
    {
      "description": "Applying `sign` to a vector of mixed values",
      "input": "v = [-3 -0.0 0 2 5];\ns = sign(v)",
      "output": "s = [-1 0 0 1 1]"
    },
    {
      "description": "Normalising complex numbers to unit magnitude",
      "input": "z = [3+4i, -1+1i, 0+0i];\nu = sign(z)",
      "output": "u = [0.6+0.8i, -0.7071+0.7071i, 0]"
    },
    {
      "description": "Using `sign` with character data",
      "input": "codes = sign('RunMat')",
      "output": "codes = [1 1 1 1 1 1]"
    },
    {
      "description": "Working with logical masks",
      "input": "mask = [false true false; true false true];\nnumeric = sign(mask)",
      "output": "numeric = [0 1 0; 1 0 1]"
    },
    {
      "description": "Executing `sign` on a GPU-resident tensor",
      "input": "G = randn(4096, 4096, 'gpuArray');\nS = sign(G)"
    },
    {
      "description": "Handling infinities and NaNs",
      "input": "values = [Inf, -Inf, NaN, 0];\nout = sign(values)",
      "output": "out = [1 -1 NaN 0]"
    }
  ],
  "faqs": [
    {
      "question": "Does `sign` modify NaN values?",
      "answer": "No. NaN inputs remain NaN, matching IEEE behaviour and MATLAB semantics."
    },
    {
      "question": "How does `sign` handle complex zeros?",
      "answer": "`0 + 0i` stays `0 + 0i`. Other complex values are scaled to lie on the unit circle (`x ./ abs(x)`)."
    },
    {
      "question": "What happens for infinite complex components?",
      "answer": "If either component is infinite, RunMat returns a direction vector with unit magnitude (e.g., `1 + 0i` or `±1/√2 ± 1/√2 i`), mirroring MATLAB."
    },
    {
      "question": "Can I call `sign` on string arrays?",
      "answer": "No. `sign` accepts numeric, logical, or character arrays. Use `double(string)` followed by `sign` if needed."
    },
    {
      "question": "Does `sign` allocate a new array?",
      "answer": "Yes. The builtin returns a fresh array; downstream fusion may combine operations to reduce allocations."
    },
    {
      "question": "Is GPU execution numerically identical to CPU?",
      "answer": "Results match within the provider's precision (`single` or `double`). NaN propagation and zero handling remain consistent between CPU and GPU paths."
    },
    {
      "question": "Will `sign` participate in fusion?",
      "answer": "Yes. The fusion planner can fold `sign` into neighbouring elementwise kernels, keeping data on the GPU when possible."
    },
    {
      "question": "How do I keep results on the GPU?",
      "answer": "Avoid `gather` unless host data is required. RunMat keeps the outputs of fused expressions device-resident when beneficial."
    }
  ],
  "links": [
    {
      "label": "abs",
      "url": "./abs"
    },
    {
      "label": "sin",
      "url": "./sin"
    },
    {
      "label": "sum",
      "url": "./sum"
    },
    {
      "label": "gpuArray",
      "url": "./gpuarray"
    },
    {
      "label": "gather",
      "url": "./gather"
    },
    {
      "label": "angle",
      "url": "./angle"
    },
    {
      "label": "conj",
      "url": "./conj"
    },
    {
      "label": "double",
      "url": "./double"
    },
    {
      "label": "exp",
      "url": "./exp"
    },
    {
      "label": "expm1",
      "url": "./expm1"
    },
    {
      "label": "factorial",
      "url": "./factorial"
    },
    {
      "label": "gamma",
      "url": "./gamma"
    },
    {
      "label": "hypot",
      "url": "./hypot"
    },
    {
      "label": "imag",
      "url": "./imag"
    },
    {
      "label": "ldivide",
      "url": "./ldivide"
    },
    {
      "label": "log",
      "url": "./log"
    },
    {
      "label": "log10",
      "url": "./log10"
    },
    {
      "label": "log1p",
      "url": "./log1p"
    },
    {
      "label": "log2",
      "url": "./log2"
    },
    {
      "label": "minus",
      "url": "./minus"
    },
    {
      "label": "plus",
      "url": "./plus"
    },
    {
      "label": "pow2",
      "url": "./pow2"
    },
    {
      "label": "power",
      "url": "./power"
    },
    {
      "label": "rdivide",
      "url": "./rdivide"
    },
    {
      "label": "real",
      "url": "./real"
    },
    {
      "label": "single",
      "url": "./single"
    },
    {
      "label": "sqrt",
      "url": "./sqrt"
    },
    {
      "label": "times",
      "url": "./times"
    }
  ],
  "source": {
    "label": "`crates/runmat-runtime/src/builtins/math/elementwise/sign.rs`",
    "url": "https://github.com/runmat-org/runmat/blob/main/crates/runmat-runtime/src/builtins/math/elementwise/sign.rs"
  },
  "gpu_residency": "You usually do **not** need to call `gpuArray` manually. RunMat's planner tracks residency and keeps tensors on the GPU whenever it is profitable. Explicit `gpuArray` / `gather` calls remain available for MATLAB compatibility or interoperability with external GPU code.",
  "gpu_behavior": [
    "**Hook available:** The sign is evaluated directly on the device with no host transfers.",
    "**Hook missing or unsupported dtype:** RunMat gathers the tensor, applies the CPU logic (including complex handling), and continues execution transparently."
  ]
}