{
"title": "cosh",
"category": "math/trigonometry",
"keywords": [
"cosh",
"hyperbolic cosine",
"trigonometry",
"elementwise",
"gpu"
],
"summary": "Hyperbolic cosine of scalars, vectors, matrices, complex numbers, or character arrays with MATLAB broadcasting and GPU acceleration.",
"references": [],
"gpu_support": {
"elementwise": true,
"reduction": false,
"precisions": [
"f32",
"f64"
],
"broadcasting": "matlab",
"notes": "Prefers provider unary_cosh hooks; falls back to the host path when a provider is unavailable or cannot service the operand type."
},
"fusion": {
"elementwise": true,
"reduction": false,
"max_inputs": 1,
"constants": "inline"
},
"requires_feature": null,
"tested": {
"unit": "builtins::math::trigonometry::cosh::tests",
"integration": "builtins::math::trigonometry::cosh::tests::cosh_gpu_provider_roundtrip"
},
"description": "`Y = cosh(X)` computes the hyperbolic cosine of every element in `X`, extending naturally to complex values.",
"behaviors": [
"Works on scalars, vectors, matrices, and N-D tensors with MATLAB broadcasting semantics for scalar expansion.",
"Logical inputs are converted to double precision (`true → 1.0`, `false → 0.0`) before applying `cosh`.",
"Complex inputs follow the analytic rule `cosh(a + bi) = cosh(a)cos(b) + i·sinh(a)sin(b)`, propagating `NaN`/`Inf` components independently.",
"Character arrays are converted to their numeric code points prior to evaluation, with double-precision outputs that preserve the input shape.",
"Empty arrays return empty results that respect MATLAB’s shape semantics."
],
"examples": [
{
"description": "Hyperbolic cosine of a scalar",
"input": "y = cosh(2)",
"output": "y = 3.7622"
},
{
"description": "Applying `cosh` elementwise to a vector",
"input": "x = linspace(-2, 2, 5);\ny = cosh(x)",
"output": "y = [3.7622 1.5431 1.0000 1.5431 3.7622]"
},
{
"description": "Evaluating `cosh` on a matrix",
"input": "A = [0 0.5; 1.0 1.5];\nB = cosh(A)",
"output": "B = [1.0000 1.1276; 1.5431 2.3524]"
},
{
"description": "Executing `cosh` on a GPU tensor",
"input": "G = gpuArray([0.25 0.75; 1.25 1.75]);\nresult_gpu = cosh(G);\nresult = gather(result_gpu)",
"output": "result = [1.0314 1.2947; 1.8884 2.9642]"
},
{
"description": "Working with complex inputs",
"input": "z = 1 + 2i;\nw = cosh(z)",
"output": "w = -0.6421 + 1.0686i"
},
{
"description": "Hyperbolic cosine for character codes",
"input": "chars = 'AZ';\ncodes = cosh(chars)",
"output": "codes = [8.4744e27 6.1020e38]"
}
],
"faqs": [
{
"question": "When should I use `cosh`?",
"answer": "Use `cosh` for hyperbolic modelling, solving differential equations, or transforming signals where the hyperbolic cosine naturally appears."
},
{
"question": "Does `cosh` work with complex inputs?",
"answer": "Yes. Real and imaginary components are evaluated using the analytic continuation, matching MATLAB’s `cosh` semantics."
},
{
"question": "What happens if the GPU provider lacks `unary_cosh`?",
"answer": "RunMat falls back to the host implementation. Tensors are gathered to the CPU, evaluated, and left on the host unless later operations request GPU residency (`'like'`, planner decisions, etc.)."
},
{
"question": "Can `cosh` participate in fusion?",
"answer": "Yes. The fusion planner can inline `cosh` inside elementwise groups, generating WGSL kernels that execute directly on the GPU when supported."
},
{
"question": "Are integers preserved?",
"answer": "Inputs are promoted to double precision before evaluation, matching MATLAB behaviour. Cast back explicitly if you need integer outputs."
},
{
"question": "How does `cosh` handle NaN or Inf values?",
"answer": "`cosh` propagates `NaN` and `Inf` in the same way as MATLAB: each component is treated independently, and results mirror IEEE-754 expectations."
},
{
"question": "Is there a warmup penalty on first GPU use?",
"answer": "Providers may compile elementwise pipelines during initialization. If `unary_cosh` is unavailable, the CPU fallback avoids the warmup altogether."
}
],
"links": [
{
"label": "cos",
"url": "./cos"
},
{
"label": "sinh",
"url": "./sinh"
},
{
"label": "tanh",
"url": "./tanh"
},
{
"label": "gpuArray",
"url": "./gpuarray"
},
{
"label": "gather",
"url": "./gather"
},
{
"label": "acos",
"url": "./acos"
},
{
"label": "acosh",
"url": "./acosh"
},
{
"label": "asin",
"url": "./asin"
},
{
"label": "asinh",
"url": "./asinh"
},
{
"label": "atan",
"url": "./atan"
},
{
"label": "atan2",
"url": "./atan2"
},
{
"label": "atanh",
"url": "./atanh"
},
{
"label": "sin",
"url": "./sin"
},
{
"label": "tan",
"url": "./tan"
}
],
"source": {
"label": "`crates/runmat-runtime/src/builtins/math/trigonometry/cosh.rs`",
"url": "https://github.com/runmat-org/runmat/blob/main/crates/runmat-runtime/src/builtins/math/trigonometry/cosh.rs"
},
"gpu_residency": "You usually do **not** need to call `gpuArray` explicitly. The fusion planner keeps tensors on the GPU whenever the active provider exposes the required kernels (such as `unary_cosh`). Manual `gpuArray` / `gather` calls remain available for MATLAB compatibility or when you must control residency before interoperating with external code.",
"gpu_behavior": [
"When RunMat Accelerate is active, tensors that already reside on the GPU stay there. Providers implementing the optional `unary_cosh` hook execute the operation entirely on the device (and fused elementwise kernels can inline `cosh` alongside other operations). If the active provider lacks this hook, RunMat gathers the data back to the host, computes the reference result, and only re-uploads when downstream operations demand GPU residency."
]
}