mplapack-interop-0.5.1/0000755000230300031750000000000015274353471014242 5ustar rafaelrafaelmplapack-interop-0.5.1/LICENSE0000644000230300031750000000246315274353471015254 0ustar rafaelrafaelBSD 2-Clause License Copyright (c) 2026, MPLAPACK contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. mplapack-interop-0.5.1/doc/0000755000230300031750000000000015274353471015007 5ustar rafaelrafaelmplapack-interop-0.5.1/doc/mplapack-interop.texi0000644000230300031750000013270315274353471021156 0ustar rafaelrafael\input texinfo @setfilename mplapack-interop.info @settitle mplapack-interop User Manual @documentencoding UTF-8 @dircategory Scientific software @direntry * mplapack-interop: (mplapack-interop). Multiple-precision Octave values. @end direntry @copying Copyright @copyright{} 2026 MPLAPACK contributors. This manual is distributed under the BSD 2-Clause license. See the @file{LICENSE} file in the source distribution. @end copying @titlepage @title mplapack-interop User Manual @subtitle Dense arbitrary-precision real and complex values for GNU Octave @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @node Top @top mplapack-interop This manual documents the @code{mplapack-interop} Octave package. It provides a dense, two-dimensional @code{mp} value with MPFR real storage and MPC complex storage. MPLAPACK is used for the supported dense linear-algebra drivers; other operations use package-owned MPFR/MPC algorithms. This is the @code{0.5.1} maintenance release, published under the annotated GitHub tag @code{v0.5.1}. The earlier published @code{v0.5.0} tag and archive remain immutable. Debian/PPA packaging and uploads are deferred. The dependency stack uses the official MPLAPACK @code{3.0.1} release and gmpfrxx_mkII @code{1.5.0}; see the D04R1 release-stack handoff for exact source identities and checksums. @menu * Introduction:: * Installation and package loading:: * Creating mp values:: * Precision model:: * Real and complex values:: * Arithmetic and comparisons:: * Dense matrices and indexing:: * Matrix factorizations and linear solves:: * Eigenvalues SVD Schur QZ:: * Matrix functions:: * Elementary and special functions:: * Polynomial operations:: * Set operations:: * Serialization and save/load:: * Graphics:: * Arbitrary-precision random numbers:: * Interpolation:: * Nonlinear equations:: * Numerical integration:: * Optimization:: * Performance notes:: * Octave compatibility:: * Deferred and unsupported functionality:: * Troubleshooting:: * API quick reference:: @end menu @node Introduction @chapter Introduction @code{mp} is a user-facing Octave class. An object owns its represented MPFR/MPC value, shape, and stored precision. Public values are immutable at the native boundary; destructive MPLAPACK calls receive operation-owned copies. The package does not silently route supported numerical work through builtin binary64 arithmetic. Use this package when the input data, intermediate values, or requested tolerances require more precision than binary64 provides. Use ordinary Octave values when binary64 is sufficient or when a deferred API is needed. @node Installation and package loading @chapter Installation and package loading Install the source package with Octave's package manager: @verbatim pkg install mplapack-interop-0.5.1.tar.gz pkg load mplapack-interop @end verbatim For a local dependency installation, the repository helper selects the official gmpfrxx_mkII @code{1.5.0} archive by default and repairs installed MPLAPACK @code{.pc} metadata on Ubuntu systems whose @code{libmpc-dev} package does not provide @code{mpc.pc}. The published 0.5.1 package is the installer default; set @code{OCTAVE_VERSION=0.5.0} to use the immutable previous release. After starting the configured Octave session, load the package with: @verbatim pkg load mplapack-interop @end verbatim The package requires GNU Octave 11.1 or newer and an installed MPLAPACK MPFR interface discoverable through @code{pkg-config}. The package does not vendor MPLAPACK or search a developer-specific source path. Check the active stack with @code{mplapack_version ()}. @node Creating mp values @chapter Creating @code{mp} values Decimal text is parsed directly at the current default precision: @verbatim mpbits (256); x = mp ("0.1"); A = mp ({"1.0", "2.0"; "3.0", "4.0"}); @end verbatim A builtin double has already been rounded before @code{mp} receives it: @verbatim binary64_value = mp (0.1); decimal_value = mp ("0.1"); @end verbatim These values intentionally preserve different source information. A complex scalar can be made directly from two decimal strings: @verbatim z = mp ("1.25", "-0.5"); @end verbatim Dense matrices are two-dimensional and have one uniform stored precision. Use @code{char}, @code{disp}, and explicit @code{double} when inspecting or converting values. Only the last of these is an intentional binary64 conversion. @node Precision model @chapter Precision model @code{mpbits ()} reports the project default; @code{mpbits (p)} changes it for subsequently constructed values. @code{mpdigits (d)} requests @code{ceil(d*log2(10))} bits. A fresh process starts at 512 bits. Changing the default does not recreate information already lost: @verbatim mpbits (128); low = mp ("0.1"); mpbits (1024); high = mp ("0.1"); % low remains a 128-bit value; high is newly constructed at 1024 bits. @end verbatim Existing operands determine the operation precision. For two @code{mp} operands it is the maximum stored precision; a builtin double is converted at the @code{mp} operand precision. The ambient default does not retroactively change operands or select an arithmetic result precision. Linear-algebra and other native calls enter one operation-owned precision scope, normalize temporaries to that precision, and restore the caller's thread-local backend context. Real-to-complex promotion happens once at the selected precision. Guard precision is used only where the function-specific documentation says so; it is not a hidden binary64 fallback. @node Real and complex values @chapter Real and complex values Real and complex values share the public @code{mp} class but have different native payload kinds. @code{real}, @code{imag}, @code{conj}, @code{isreal}, @code{abs}, @code{arg}, and @code{angle} inspect or transform those payloads using MPFR/MPC operations. A real input is kept on a real path when the operation permits it. A result is promoted to complex @code{mp} when the mathematical branch requires a complex value, for example a negative real square root or a general real matrix with complex eigenvalues. A builtin complex double may be an input, but it is converted into the operation precision. A raw builtin-double-only operation remains an Octave operation outside this package's contract. @node Arithmetic and comparisons @chapter Arithmetic and comparisons The element-wise arithmetic functions and operators are @code{plus}, @code{minus}, @code{times}, @code{rdivide}, @code{uplus}, @code{uminus}, @code{power}, and @code{mpower}. Dense multiplication uses @code{mtimes} and MPLAPACK @code{Rgemm} or @code{Cgemm}. Mixed real/complex inputs promote to MPC at one operation precision. Comparisons use native MPFR/MPC equality and the documented complex magnitude/phase ordering for supported extrema and sorting operations. Ordered comparisons on complex values remain rejected. @verbatim mpbits (512); a = mp ("0.1"); b = mp ("0.2"); c = a + b; d = a .* b; e = c ^ 2; @end verbatim @node Dense matrices and indexing @chapter Dense matrices and indexing The dense public type is two-dimensional, column-major, and contiguous at the native boundary. @code{size}, @code{rows}, @code{columns}, @code{numel}, @code{ndims}, @code{length}, and @code{isempty} inspect shape without changing stored precision. @code{subsref}, @code{subsasgn}, and @code{end} provide normal dense indexing and value-semantic in-bounds assignment. @code{reshape}, @code{transpose}, @code{ctranspose}, @code{horzcat}, @code{vertcat}, and @code{cat} preserve native values. @code{diag}, @code{triu}, @code{tril}, @code{repmat}, @code{flip}, @code{fliplr}, @code{flipud}, and @code{rot90} are supported for the dense two-dimensional forms. @code{zeros}, @code{ones}, @code{eye}, @code{NaN}, and @code{Inf} support @code{"like"} construction with an @code{mp} template. Sparse, N-dimensional, deletion, growth assignment, and packed triangular forms are not part of the public dense contract. @node Matrix factorizations and linear solves @chapter Matrix factorizations and linear solves Use @code{A \ b} or @code{A / B} instead of explicitly forming an inverse for a solve. Square left division uses @code{Rgesv} or @code{Cgesv}; rectangular and rank-revealing forms use @code{Rgelss} or @code{Cgelsy}. Right division uses the conjugate-transpose solve identity and preserves complex conjugation. @code{chol} uses @code{Rpotrf}/@code{Cpotrf}; @code{qr} uses @code{Rgeqrf}/@code{Rorgqr} or @code{Cgeqrf}/@code{Cungqr}; pivoted QR uses @code{Rgeqp3}/@code{Cgeqp3}; and @code{lu} uses @code{Rgetrf}/@code{Cgetrf}. Every destructive call receives an operation-owned copy. @verbatim A = mp ({"4", "2"; "2", "10"}); b = mp ({"1"; "2"}); x = A \ b; [Q, R] = qr (A); [L, U, P] = lu (A); @end verbatim Result tolerances should be based on the stored operation precision and the conditioning of the problem, not on a fixed binary64 epsilon. @node Eigenvalues SVD Schur QZ @chapter Eigenvalues, SVD, Schur and QZ This chapter covers the dense eigenvalue, singular-value, Schur, Hessenberg, and generalized Schur interfaces. These routines are useful for analysing conditioning and invariant subspaces, but their factors are not unique. A successful call therefore must be checked with a residual, an orthogonality or unitarity relation, and a precision-aware tolerance rather than by comparing vectors element by element. @menu * Standard eigenproblems:: * Difficult nonsymmetric eigensystem suite:: * NEIGT verified eigensystem tiers:: * Tiered worked examples:: * Generalized eigenproblems:: * Singular value decomposition:: * Schur Hessenberg and QZ decompositions:: * Precision and validation:: @end menu @section Standard eigenproblems The standard dense interface accepts a square @code{mp} matrix @code{A}: @verbatim lambda = eig (A) [V, D] = eig (A) [V, d] = eig (A, "vector") [V, D, W] = eig (A) [V, D] = eig (A, "balance") [V, D] = eig (A, "nobalance") @end verbatim The default one-output form returns a column vector of eigenvalues. The explicit @code{"matrix"} form returns a diagonal eigenvalue matrix, while @code{"vector"} returns a column. The two-output forms return right eigenvectors and eigenvalues; the three-output form additionally returns left eigenvectors. For the matrix form the identities are @code{A*V = V*D} and @code{W'*A = D*W'}. For the vector form replace @code{D} by @code{diag(d)}. An exactly represented real symmetric matrix uses the structured MPFR @code{Rsyevd} path. An exactly represented complex Hermitian matrix uses @code{Cheevd}. Structured real eigenvalues and eigenvectors are real @code{mp}; a Hermitian problem has real eigenvalues but generally complex eigenvectors. The structured path does not need balancing. All other square real matrices use MPLAPACK @code{Rgeevx}, and all other complex matrices use @code{Cgeevx}. General real results are returned as complex @code{mp} values even when every eigenvalue happens to be real. This keeps the imaginary parts of conjugate pairs and gives one output type for the general driver. @code{"balance"} and @code{"nobalance"} select the expert-driver mode explicitly; balancing can improve the scaling of a badly scaled problem but changes the returned vectors. The structured/general decision is based on the represented values, not on a floating-point closeness test. A nearly symmetric matrix, a non-Hermitian complex matrix, a defective or nearly defective matrix, and a badly scaled matrix therefore exercise the general path. Sparse, non-square, and N-dimensional eigenproblems are outside the dense @code{mp} contract. This example deliberately uses a nonnormal Grcar matrix. It checks the right-eigenvector residual without assuming a particular eigenvalue order, vector scale, or complex phase: @verbatim mpbits (1024); G = mp (gallery ("grcar", 32)); [V, D] = eig (G, "nobalance"); right_residual = norm (G*V - V*D, "fro") / norm (G, "fro"); disp (right_residual); @end verbatim For a three-output call also check the left relation. Near repeated eigenvalues can have very sensitive eigenvectors even when the residual is small, so report the residual and inspect the eigenvalue separation before interpreting the vectors. @section Difficult nonsymmetric eigensystem suite The repository includes a runnable difficult-eigensystem experiment based on the existing public @code{mp}, @code{mpbits}, @code{eig}, @code{norm}, and MP inspection functions. It is a QA/example harness, not an additional package-level API. Run it from a checkout with: @verbatim tools/run-nonsymmetric-eig-suite.sh smoke tools/run-nonsymmetric-eig-suite.sh demo @end verbatim The smoke profile has 30 rows and the demo profile has 40 rows. Each row is one of five representations (Hadamard-similar, Frank, companion, Forsythe original, or explicitly scaled Forsythe), one of @code{balance} and @code{nobalance}, and one explicit native-binary64 or MP work precision. Native rows are rounded-input controls; they are never substituted for MP rows. The harness constructs MP input matrices at the requested work precision, restores the ambient @code{mpbits ()} default, and evaluates the actual solver outputs at a separate high precision. It checks @code{A*V = V*D}, @code{W'*A = D*W'}, column residuals, one-to-one eigenvalue matches, and left/right eigenvector condition estimates. It does not assume solver output ordering or vector normalization. For a high-quality example, the Hadamard-similar model has exact integer eigenvalues but can be highly nonnormal, while the Forsythe pair separates a small coupling from a native underflow control. The result writer accepts an @code{output_dir} option and creates @file{summary.tsv}, @file{eigenvalues.tsv}, @file{environment.txt}, and @file{report.md}. Existing result files are rejected rather than overwritten. MP numerical fields are serialized with @code{char(mp)}. An optional @code{plot = true} output is a display-only conversion to a PNG and is not numerical evidence. Full construction details and limitations are in @file{docs/nonsymmetric-eig-suite.md}; the runnable package example is @file{examples/13_nonsymmetric_eig_suite.m}. @section NEIGT verified eigensystem tiers The repository also contains a larger, manifest-driven nonsymmetric eigensystem example and verification suite. It is a repository-local example/QA surface, not an additional package-level numerical API. The four numbered entry points are: @verbatim run examples/14_neig_tier_s.m run examples/15_neig_tier_a.m run examples/16_neig_verified_vs.m run examples/17_neig_verified_va.m @end verbatim The first two run the ordinary Tier-S and Tier-A model families. They use the existing public @code{mp}, @code{mpbits}, and @code{eig} interfaces and keep the exact generation model, frozen solver input, work precision, native control, reference values, and returned eigentriples separate. Tier-S includes the specified Ozaki--Ogita paired-block generator, exact simple, repeated, defective, and merged similarity models, Toeplitz/Forsythe controls, and the complex Hadamard control. Tier-A includes Hadamard-bidiagonal, Frank, Wilkinson, Grcar, MKS, and positive stochastic/Perron models. The latter two run the verified V-S and V-A jobs. They are conservative outward-safe finite-matrix proof baselines: counted Gershgorin coverage, invariant graph/projector bounds, pseudospectrum point/cell enclosures, compatible eigenfactor and Schur/block-Schur factors, finite-pencil reduction, and normalized positive Perron pairs. A broad residual or a numerical agreement between precisions is not a certificate. Defective cases are reported as clusters or block Schur factors; they are never labeled as a diagonalizable eigenbasis. The manifest profiles are @code{smoke} and @code{demo}. The mandatory ordinary profiles contain respectively 120 and 168 measured native/MP @code{eig} rows, and each profile has 26 separately counted verification jobs. Stress is opt-in and has no authority over the mandatory results. A direct API call is useful for selecting a tier: @verbatim S = mp_neig_tiers ("smoke", struct ("tier", "S", "plot", false)); A = mp_neig_tiers ("demo", struct ("tier", "A", "plot", false)); VS = mp_neig_verify_examples ("smoke", struct ("tier", "V-S", "plot", false)); VA = mp_neig_verify_examples ("smoke", struct ("tier", "V-A", "plot", false)); @end verbatim These helpers preserve the one-operation/one-precision contract. MP model construction and all certificate arithmetic use MPFR/MPC values; no supported proof path falls through builtin binary64 complex arithmetic. Each operation restores the caller's @code{mpbits ()} default. Candidate solves are auxiliary and are recorded with their own precision and source; known roots, generator columns, and higher-precision replacements are not silently substituted into measured outputs. For a durable result bundle, use a new output directory: @verbatim bundle = mp_neig_write_outputs ("smoke", "/tmp/neigt-results", ... struct ("tier", "all", "plot", false)); replay = mp_neig_replay ("/tmp/neigt-results/proof-vs1-01.json"); @end verbatim The writer refuses an existing output path. It records measured rows, environment/provenance, a schema-versioned exact MP proof record, and a report. Replay verifies the content hash, decodes the recorded MP values at the stored precision, and reruns the recorded certificate without calling @code{eig} or reconstructing an ideal matrix. Plotting, when requested, is display-only; it cannot alter numerical rows or proof status. The detailed manifests, preconditions, limitations, and source attribution are in @file{docs/codex/neigt/NEIGT-LUNA-XHIGH.md} and @file{docs/codex/neigt/ACCEPTANCE.md}. @section Tiered worked examples The difficult NEIGT and SVD fixtures have one short runnable example and one matching explanation per conceptual case. The master index is @file{docs/examples/tiered/README.md}; its four family pages are @file{docs/examples/tiered/neig-tier-s/README.md}, @file{docs/examples/tiered/neig-tier-a/README.md}, @file{docs/examples/tiered/svd-tier-s/README.md}, and @file{docs/examples/tiered/svd-tier-a/README.md}. The short files select one case from the existing manifest and call the existing public @code{mp_neig_tiers} or @code{mp_svd_tiers} runner with its @code{case_id}. For example: @verbatim run examples/tiered/neig-tier-s/sim_simple.m run examples/tiered/svd-tier-a/hadamard_rank5.m @end verbatim The detailed Markdown files explain the matrix formula, provenance, intended difficulty, residual and conditioning diagnostics, precision behavior, and common interpretation mistakes. Tier S and Tier A are project-specific QA labels defined by the existing manifests; they are not universal numerical classifications. The split is deliberately explicit: NEIG has 12 Tier S and 9 Tier A cases, while SVD has 9 Tier S and 14 Tier A cases. Tier S contains the fixed-precision generator, near/repeated/defective eigensystem cases, non-normal reciprocal singular groups, combinatorial growth, exponent-range controls, and diagonal-dominance cases. Tier A broadens coverage with Hadamard, Frank, companion, Grcar, MKS, Markov/Perron, Pascal, Vandermonde, bidiagonal, Läuchli, known-rank, and complex controls. The common equations should be read before any individual page. For a nonsymmetric eigensystem, @math{V} and @math{W} are right and left factors: @display @math{A V = V D}, @math{A^H W = W D^H} @end display For an SVD, the measured factorization is: @display @math{A = U \Sigma V^H} @end display The corresponding normalized equation diagnostics are: @display @math{r_e = ||A V - V D||_F/(||A||_F ||V||_F)}, @math{r_s = ||A-U \Sigma V^H||_F/||A||_F} @end display These are backward-error-style diagnostics. Forward error also depends on conditioning, scale, separation, multiplicity, and the exact represented input. Repeated or defective eigenspaces and repeated or null singular groups must be interpreted as subspaces, not as canonical individual vectors. Complex cases use the conjugate-transpose convention. The mathematical background includes Higham's @uref{https://doi.org/10.1137/1.9780898718027,Accuracy and Stability of Numerical Algorithms}, Rump's @uref{https://doi.org/10.1137/21M1451440,verified all-spectrum eigenvalue and eigenvector bounds}, and Wedin's @uref{https://doi.org/10.1007/BF01932678,SVD perturbation bounds}; the case-specific attributions and adaptation boundaries are recorded in each Markdown page. The master Markdown page is a learning map rather than a second measurement implementation. Its table names every case ID, its one runnable file, its one detailed explanation, the defining equation or phenomenon, and an external reference. Use @file{docs/examples/tiered/GLOSSARY.md} for the symbols and diagnostics, and @file{docs/examples/tiered/MIGRATION.md} to audit the one-case/one-example/one-document correspondence. This separation keeps the explanatory material detailed without changing the existing counted QA runners. The historical numbered entry points remain deterministic family indexes: @file{examples/14_neig_tier_s.m}, @file{examples/15_neig_tier_a.m}, @file{examples/14_svd_tier_s.m}, and @file{examples/15_svd_tier_a.m}. They do not replace the complete measured profile walls. Those walls remain in @file{examples/neig_tiers/} and @file{examples/svd_tiers/}, and the migration map is @file{docs/examples/tiered/MIGRATION.md}. @section Generalized eigenproblems The generalized interface solves the pencil @code{A - lambda*B}: @verbatim lambda = eig (A, B) [V, D] = eig (A, B) [V, d] = eig (A, B, "vector") [V, D, W] = eig (A, B) [V, D] = eig (A, B, "chol") [V, D] = eig (A, B, "qz") @end verbatim Right and left eigenvectors satisfy @code{A*V = B*V*D} and @code{W'*A = D*W'*B}. The default one-output form is a column vector; an explicit @code{"matrix"} option returns a diagonal matrix. @code{"vector"} selects the column layout for two- and three-output forms. The output and algorithm options can be supplied together, for example @code{eig (A, B, "chol", "vector")}; duplicate or contradictory options are rejected. The @code{"chol"} algorithm is valid only for an exactly symmetric real or Hermitian complex @code{A}, with a positive-definite @code{B}. It uses @code{Rsygvd} or @code{Chegvd}. The default chooses this definite path when the represented pair satisfies those conditions. @code{"qz"} forces the generalized Schur path, using @code{Rggev} for real input and @code{Cggev} for complex or promoted input. If @code{B} is singular or not positive definite, the default falls back to QZ; an explicit @code{"chol"} request reports the invalid pair instead. Generalized @code{"balance"} and @code{"nobalance"} options are not supported. The QZ backend represents an eigenvalue as @code{alpha/beta}. Division is performed at the operation precision. When @code{beta} is zero, the result is an infinite eigenvalue rather than a binary64 overflow or a rejected problem. Real QZ conjugate pairs are returned as complex @code{mp} values so their imaginary components are not discarded. Mixed real/complex pencils are promoted once to MPC at the maximum stored operand precision. For a singular or ill-conditioned pencil, use the residual relations and inspect the @code{beta == 0} cases. Do not compare eigenvalue vectors by position: QZ ordering and eigenvector normalization are not canonical. The detailed compatibility and reconstruction notes are in @file{docs/generalized-eig.md}. @section Singular value decomposition The dense SVD interface is: @verbatim s = svd (A) [U, S, V] = svd (A) [U, S, V] = svd (A, "econ") [U, S, V] = svd (A, 0) @end verbatim The numeric @code{0} form is accepted as the deprecated economy spelling. Two-output SVD calls are rejected; request either the singular values or all three factors. If @code{A} is @code{m} by @code{n}, let @code{k = min (m, n)}. The one-output result is a real @code{mp} column of @code{k} nonnegative singular values in descending order. The full factors have shapes @code{U}: @code{m} by @code{m}, @code{S}: @code{m} by @code{n}, and @code{V}: @code{n} by @code{n}. Economy factors have shapes @code{m} by @code{k}, @code{k} by @code{k}, and @code{n} by @code{k}. For real input the factors are real and the reconstruction is @code{A = U*S*transpose(V)}. For complex input @code{U} and @code{V} are complex @code{mp}, @code{S} remains real, and the reconstruction is @code{A = U*S*ctranspose(V)}. Full factors are orthogonal or unitary; economy factors have orthonormal columns. Singular vectors can change sign or complex phase, especially for repeated or clustered singular values. Check reconstruction and orthogonality rather than individual factor entries. SVD uses MPLAPACK @code{Rgesvd} for real input and @code{Cgesvd} for complex input. The input buffer, factors, singular values, and workspaces are operation-owned storage at one uniform precision. The input is not modified. The operation precision comes from the stored input precision, not from the ambient default at the time of the call. No SVD path calls builtin Octave @code{svd} or reduces through binary64. The following Hilbert example is more informative than a diagonal test: the matrix is dense, non-diagonal, and ill-conditioned. Its entries are created from decimal @code{mp} values, so the Hilbert matrix is not first created by the builtin binary64 @code{hilb} function: @verbatim mpbits (512); n = 8; H = mp (zeros (n, n)); for i = 1:n for j = 1:n H(i,j) = mp (1) / mp (i + j - 1); endfor endfor [U, S, V] = svd (H); reconstruction = norm (H - U*S*V', "fro") / norm (H, "fro"); left_orthogonality = norm (U'*U - mp (eye (n)), "fro"); right_orthogonality = norm (V'*V - mp (eye (n)), "fro"); disp (diag (S)); disp (reconstruction); disp (left_orthogonality); disp (right_orthogonality); @end verbatim @section Tier S/A/V SVD example suite The repository contains an example-local suite for difficult dense singular value problems in @file{examples/svd_tiers/}. It is a measurement and verification harness around the public @code{mp}/@code{svd} path, not a second SVD implementation and not an installed package API. The suite keeps the stored SVD precision, model-construction precision, reference precision, and interval-evaluation precision separate. The smoke profile has 20 cases and exactly 120 measured SVD rows. The demo profile has 23 cases and exactly 184 measured rows. References, inverse solves, and Tier V jobs are counted separately. The demo adds a complex Lauchli control and global-scale NRO controls; the optional stress profile is not part of the default acceptance wall. Run the complete profile from a configured checkout as follows: @verbatim pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "svd_tiers")); smoke = mp_svd_tiers ("smoke"); demo = mp_svd_tiers ("demo", struct ("tier", "all", ... "output_dir", fullfile (pwd (), "svt-demo"), "plot", false)); assert (demo.ok); @end verbatim The numbered top-level files are family indexes and full smoke aggregators; the one-case worked examples are listed in @file{docs/examples/tiered/README.md}: @itemize @item @file{examples/14_svd_tier_s.m} lists and runs the Tier-S smoke family. @item @file{examples/15_svd_tier_a.m} lists and runs the Tier-A smoke family. @item @file{examples/16_svd_verified.m} certifies singular values and an inverse using the Tier V baselines. @end itemize The complete construction inventory and measured-output schema are in @file{docs/svd-tiers.md}. The finite-arithmetic claim boundary, exact dyadic replay format, and failure classifications are in @file{docs/svd-verification.md}. The normative source and attribution ledger is @file{docs/codex/svt/SOURCES.md}. Tier V uses conservative baseline method IDs @code{svt_polar_weyl_v1}, @code{svt_dilation_projector_v1}, @code{svt_dilation_factor_boxes_v1}, and @code{svt_neumann_inverse_v1}. Certificates bind to the actual represented target and factors. They use exact MPFR/MPC dyadic snapshots, not decimal round trips, and record @code{paper_algorithm_reproduction=false}. A broad valid interval is distinct from a narrow accuracy target; @code{INCONCLUSIVE} is not a singularity proof. The examples preserve the one-operation/one-precision MPFR/MPC contract and never route numerical evidence through builtin binary64 arithmetic. Optional plots are presentation-only. Existing SVD and nonsymmetric-eigenproblem tests remain in the standard test runner; the SVT tests extend that runner rather than replacing earlier coverage. For a high-condition-number problem, increase @code{mpbits} before creating the input and choose tolerances from the requested precision and problem conditioning. A later change to @code{mpbits} does not change an existing matrix or the precision of an already-created SVD result. @code{pinv}, @code{null}, @code{orth}, and @code{rref} use singular values or related rank decisions and therefore require the same tolerance discipline. @section Schur Hessenberg and QZ decompositions The Hessenberg and Schur interfaces provide useful intermediate forms: @verbatim H = hess (A) [P, H] = hess (A) S = schur (A) [U, S] = schur (A) [U, S] = schur (A, "complex") [AA, BB, Q, Z] = qz (A, B) [AA, BB, Q, Z] = qz (A, B, "real") @end verbatim The two-output Hessenberg form satisfies @code{P*H*P' = A}; @code{H} is upper Hessenberg and @code{P} is orthogonal or unitary. The default Schur type is @code{"real"} for real input and @code{"complex"} for complex input. The two-output Schur form satisfies @code{S = U'*A*U}. A real Schur form can contain 2-by-2 blocks for conjugate pairs; a complex Schur form is triangular. The factors and their ordering are not unique, and Schur reordering selectors are not part of this public interface. The generalized Schur (QZ) interface returns the orientation used by this package: @code{Q*A*Z = AA} and @code{Q*B*Z = BB}. The default QZ type is complex; @code{"real"} requests the real generalized Schur form for a real pencil. The diagonal or 2-by-2 blocks encode the generalized eigenvalues; the @code{alpha}/@code{beta} interpretation and infinite-eigenvalue rule are the same as for generalized @code{eig}. QZ is a decomposition of a pencil, not an inverse of @code{B}, so it remains usable when @code{B} is singular. For all of these routines use the exact reconstruction orientation above. Do not substitute a transpose for a conjugate transpose in a complex test, and do not assume that two valid runs return the same signs, phases, or block ordering. The optional Schur/QZ ordering helpers remain intentionally deferred. @section Precision and validation Every eig, SVD, Hessenberg, Schur, and QZ call selects one operation precision from its stored input operands. For a generalized problem this is the maximum stored precision of @code{A} and @code{B}. The native wrapper enters the matching MPFR/MPC precision scope, converts real values to complex values once when promotion is required, and restores the caller's ambient precision on return. A new worker thread does not inherit a parent thread's precision automatically; a worker must establish its own scope at entry. The LAPACK drivers destructively overwrite their input buffers. The public @code{mp} payload is immutable, so the wrapper always passes an operation-owned copy and leaves the input unchanged. Workspace queries and driver status values are checked before results are returned. The complex paths use MPC-native storage throughout and never silently fall back to builtin binary64 complex arithmetic. For a normal validation, compute a relative residual such as @code{norm (A*V - V*D, "fro") / norm (A, "fro")}, an orthogonality or unitarity residual such as @code{norm (U'*U - eye (n), "fro")}, and the appropriate generalized relation. Keep the residual as an @code{mp} value until the final display or an explicitly justified pass/fail conversion. At 1024 bits, test a @code{2^-700} tail; at 2048 bits, test a @code{2^-1500} tail. Also test with a low ambient default, a high ambient default, and a restored default to ensure that the operation precision belongs to the input and not to unrelated global state. The focused API and backend notes are maintained in @file{docs/eig.md}, @file{docs/generalized-eig.md}, and @file{docs/svd.md}; the runnable examples are @file{examples/06_grcar_eig.m}, @file{examples/07_svd_hilbert.m}, @file{examples/08_advanced_dense.m}, and the Tier S/A/V examples @file{examples/14_svd_tier_s.m}, @file{examples/15_svd_tier_a.m}, and @file{examples/16_svd_verified.m}. @node Matrix functions @chapter Matrix functions @code{expm}, @code{logm}, and @code{sqrtm} use package-owned arbitrary- precision matrix algorithms with MPFR/MPC working values. Principal branches and branch cuts can promote a real input to complex. Validate matrix identities and inspect conditioning near a branch cut. @code{mpower} for integer square matrices uses exponentiation by squaring; noninteger matrix powers are deferred. @code{polyvalm} evaluates a polynomial at a dense matrix. @node Elementary and special functions @chapter Elementary and special functions The supported scalar/element-wise elementary family includes @code{sqrt}, @code{cbrt}, @code{exp}, @code{expm1}, @code{log}, @code{log1p}, @code{log10}, @code{log2}, @code{sin}, @code{cos}, @code{tan}, @code{asin}, @code{acos}, @code{atan}, @code{sinh}, @code{cosh}, @code{tanh}, @code{asinh}, @code{acosh}, @code{atanh}, @code{hypot}, and @code{atan2}. Real domain crossings use the documented MPC promotion rules. Real @code{log2} uses MPFR directly; complex @code{log2} uses the gmpfrxx @code{mpfrxx::log2} MPC compatibility wrapper at the stored operation precision and does not require a direct @code{mpc_log2} symbol. The supported MPFR-backed special family is @code{gamma}, @code{gammaln}, @code{lgamma}, @code{erf}, and @code{erfc}. Poles, signed zeros, infinities, NaNs, and domain branches are tested explicitly. Other special-function families are deferred and rejected cleanly. @node Polynomial operations @chapter Polynomial operations @code{poly}, @code{polyval}, @code{polyvalm}, @code{roots}, @code{conv}, @code{deconv}, @code{polyder}, @code{polyint}, and @code{compan} operate on arbitrary-precision coefficient or root data. Polynomial roots are conditioning-sensitive; clustered roots can move materially when precision changes. Use residuals such as @code{polyval (p, roots (p))} and not only elementwise root matching. @verbatim p = mp ({"1", "-3", "2"}); r = roots (p); residual = norm (polyval (p, r)); disp (residual); @end verbatim @code{polyfit} and @code{polyeig} remain deferred. @node Set operations @chapter Set operations @code{unique}, @code{union}, @code{intersect}, @code{setdiff}, @code{setxor}, and @code{ismember} support the documented dense real/complex forms, including stable and row options where implemented. Equality and ordering use native values; NaN membership follows the documented Octave compatibility rule. @code{ismembertol} is deferred. @node Serialization and save/load @chapter Serialization and save/load The @code{saveobj} and @code{loadobj} hooks use schema @code{octave-mplapack-mp}, version 1. The schema records kind, shape, stored precision, and canonical text elements in column-major order. It preserves finite values, signed zero, infinity, NaN classification, and complex components without raw pointers or MPFR limb dumps. @verbatim mpbits (1024); A = mp ({"1.234567890123456789", "-0"; "Inf", "NaN"}); save ("/tmp/mp-example.mat", "A"); clear A; load ("/tmp/mp-example.mat"); disp (A); @end verbatim The package must be loaded before loading an @code{mp} object. Malformed or newer schemas are rejected rather than guessed. @node Graphics @chapter Graphics @code{plot}, @code{plot3}, @code{loglog}, @code{semilogx}, @code{semilogy}, @code{scatter}, @code{scatter3}, @code{stem}, @code{stairs}, @code{mesh}, @code{surf}, @code{contour3}, @code{meshc}, @code{surfc}, and @code{waterfall} are boundary wrappers. They explicitly convert only final visualization data to builtin @code{double}; all numerical calculation before plotting remains MPFR/MPC. This is the documented exception to the no-binary64-fallback rule. @verbatim t = linspace (mp ("0"), mp ("6.283185307179586476925286766559"), 32); y = sin (t); plot (double (t), double (y)); @end verbatim For a package @code{mp} graphics call, the wrapper performs the conversion. For values outside the binary64 range, transform or scale in @code{mp} before the graphics boundary. N-D and volume graphics, and @code{meshgrid} for @code{mp}, are deferred. @node Arbitrary-precision random numbers @chapter Arbitrary-precision random numbers @code{mprand}, @code{mprandn}, and @code{mprandi} use the package's @code{xorshift128plus-v1} engine and generate p-bit values directly. They are not cryptographic. @code{mprng} controls the seed and serializable state. Fixed seed/state is required for reproducibility. @verbatim mprng ("seed", uint64 (7)); u1 = mprand (2, 1); mprng ("seed", uint64 (7)); u2 = mprand (2, 1); assert (isequal (u1, u2)); @end verbatim @node Interpolation @chapter Interpolation @code{interp1} and @code{interp2} use MPFR/MPC grids, query points, and piecewise-polynomial values. @code{pchip}, @code{spline}, @code{mkpp}, @code{unmkpp}, @code{ppval}, @code{ppder}, and @code{ppint} operate on the supported scalar/vector piecewise-polynomial contract. Query-grid precision matters: a query that collapses to a double grid point may remain distinct at MPFR precision. Extrapolation is explicit. @code{interp3}, @code{interpn}, and matrix-valued PP output are deferred. @node Nonlinear equations @chapter Nonlinear equations @code{fzero} accepts a scalar start or sign-changing bracket; @code{fsolve} accepts real scalar/vector starts. Callbacks receive @code{mp} values and must return @code{mp} values. @code{TolX}, @code{TolFun}, finite-difference steps, and stopping checks are precision-aware. Complex nonlinear callbacks are deferred. @verbatim mpbits (512); target = mp ("1.25"); [root, fval, info] = fzero (@(x) x*x - target*target, mp ({"0", "2"})); assert (info == 1); assert (abs (root - target) < mp ("1e-40")); @end verbatim @node Numerical integration @chapter Numerical integration @code{integral} and @code{quadgk} use MP nodes, weights, transforms, and error estimates. Scalar callbacks may return real or complex @code{mp}; builtin double and array-valued callback results are rejected. Finite and infinite intervals, waypoints, and precision-aware absolute/relative tolerances are supported. @code{ArrayValued} remains deferred. @verbatim options = struct ("AbsTol", mp ("1e-40"), "RelTol", mp ("1e-40")); [value, err] = integral (@(x) x*x, mp ("0"), mp ("1"), options); assert (abs (value - mp ("1")/mp ("3")) < mp ("1e-35")); @end verbatim @node Optimization @chapter Optimization @code{fminbnd} uses an MPFR safeguarded golden-section search and @code{fminsearch} uses an MPFR Nelder--Mead simplex. Objective callbacks must return finite real @code{mp} scalars. @code{TolX}, @code{TolFun}, iteration limits, and evaluation limits are precision-aware. @code{fminunc} remains deferred. @node Performance notes @chapter Performance notes Higher precision increases scalar arithmetic cost and can increase workspace and serialization size. Dense algorithm dimension scaling remains that of the selected algorithm. MPLAPACK-backed calls and package-owned MPFR/MPC algorithms have different constant factors. RNG generation cost grows with requested precision. Graphics deliberately loses arbitrary precision at the final display boundary. @node Octave compatibility @chapter Octave compatibility The supported surface follows ordinary Octave syntax where the dense two-dimensional @code{mp} contract permits it. The authoritative compatibility boundaries are @file{docs/octave-script-compatibility.md} and @file{docs/advanced-numerics-compatibility.md}. Unsupported calls involving @code{mp} fail through package-owned diagnostics rather than silently delegating to builtin binary64 implementations. For exact supported forms, consult @file{docs/public-api-inventory.md}. The public package name is @code{mplapack-interop}; the public numeric class is @code{mp}. Native @code{__mplapack_core__} operations are implementation details and are not user API. @node Deferred and unsupported functionality @chapter Deferred and unsupported functionality The following are intentionally deferred: optional Schur/QZ ordering helpers, @code{funm}, @code{polyfit}, @code{polyeig}, @code{ismembertol}, remaining special-function families, @code{meshgrid} for @code{mp}, volume/N-D graphics, matrix-valued PP output, @code{interp3}, @code{interpn}, complex nonlinear callbacks, @code{ArrayValued} quadrature, and @code{fminunc}. Sparse, symbolic, N-D, and unrelated ODE/PDE surfaces are also outside the current contract. Each deferred item has a re-entry record under @file{docs/todo/}; a missing form must not be implemented by a builtin-double fallback. These limitations are part of the release documentation, not hidden omissions. @node Troubleshooting @chapter Troubleshooting @table @asis @item @code{pkg load} fails Confirm the package is installed, the package name is @code{mplapack-interop}, and Octave's package directory is on its path. @item MPLAPACK runtime is not found Check @code{pkg-config --modversion mplapack_mpfr}, the installed library search path, and the runtime environment used to start Octave. Do not add a developer source directory as a workaround. @item Precision unexpectedly looks low Construct from decimal text, set @code{mpbits} before construction, and remember that changing the default cannot restore information lost by a previous binary64 constructor. @item Version or dependency mismatch Use @code{mplapack_version ()} and @code{pkg-config}. The 0.5.1 maintenance stack records MPLAPACK 3.0.1 and gmpfrxx_mkII 1.5.0. If @code{pkg-config --cflags --libs mplapack_mpfr} fails because the host lacks @code{mpc.pc}, use the local installer or apply its downstream metadata normalization; do not add a fake @code{mpc.pc}. @item Graphics overflow or underflow Perform scaling or logarithms in @code{mp}, then explicitly convert the final display data. @item Callback or serialization error Return @code{mp} from nonlinear/integration/optimization callbacks and load the package before restoring an @code{mp} object. Check schema version and stored precision. @end table @node API quick reference @chapter API quick reference The following entries make every public name searchable. Related functions share a short example in the preceding task chapter and have individual help text in the corresponding Octave method/function file. The inventory is the machine-auditable coverage matrix. @subheading Construction and inspection @code{mp}, @code{mpbits}, @code{mpdigits}, @code{mplapack_version}, @code{properties}, @code{char}, @code{disp}, @code{double}, @code{real}, @code{imag}, @code{conj}, @code{isreal}, @code{isnumeric}, @code{isnan}, @code{isinf}, @code{isfinite}, @code{isequal}, @code{isequaln}. @subheading Arithmetic @code{plus}, @code{minus}, @code{times}, @code{rdivide}, @code{uplus}, @code{uminus}, @code{mtimes}, @code{mldivide}, @code{mrdivide}, @code{power}, @code{mpower}, @code{abs}, @code{arg}, @code{angle}, @code{sign}. @subheading Dense structure and indexing @code{size}, @code{rows}, @code{columns}, @code{numel}, @code{ndims}, @code{length}, @code{isempty}, @code{subsref}, @code{subsasgn}, @code{end}, @code{reshape}, @code{transpose}, @code{ctranspose}, @code{horzcat}, @code{vertcat}, @code{cat}, @code{diag}, @code{triu}, @code{tril}, @code{repmat}, @code{flip}, @code{fliplr}, @code{flipud}, @code{rot90}, @code{zeros}, @code{ones}, @code{eye}, @code{nan}, @code{NaN}, @code{inf}, @code{Inf}. @subheading Logical operations and reductions @code{eq}, @code{ne}, @code{lt}, @code{le}, @code{gt}, @code{ge}, @code{logical}, @code{and}, @code{or}, @code{xor}, @code{not}, @code{any}, @code{all}, @code{find}, @code{sum}, @code{prod}, @code{cumsum}, @code{cumprod}, @code{sumsq}, @code{min}, @code{max}, @code{mean}, @code{median}, @code{var}, @code{std}, @code{range}, @code{bounds}, @code{sort}, @code{diff}, @code{signbit}, @code{floor}, @code{ceil}, @code{fix}, @code{round}, @code{rem}, @code{mod}, @code{hypot}, @code{atan2}, @code{eps}, @code{colon}, @code{linspace}, @code{logspace}. @subheading Factorizations and conditioning @code{chol}, @code{qr}, @code{lu}, @code{norm}, @code{det}, @code{inv}, @code{rank}, @code{cond}, @code{rcond}, @code{svd}, @code{pinv}, @code{null}, @code{orth}, @code{rref}. @subheading Eigenproblems and matrix functions @code{eig}, @code{hess}, @code{balance}, @code{schur}, @code{qz}, @code{kron}, @code{expm}, @code{logm}, @code{sqrtm}. @subheading Elementary and special functions @code{sqrt}, @code{cbrt}, @code{exp}, @code{expm1}, @code{log}, @code{log1p}, @code{log10}, @code{log2}, @code{sin}, @code{cos}, @code{tan}, @code{asin}, @code{acos}, @code{atan}, @code{sinh}, @code{cosh}, @code{tanh}, @code{asinh}, @code{acosh}, @code{atanh}, @code{gamma}, @code{gammaln}, @code{lgamma}, @code{erf}, @code{erfc}. @subheading Polynomials and sets @code{poly}, @code{polyval}, @code{polyvalm}, @code{roots}, @code{conv}, @code{deconv}, @code{polyder}, @code{polyint}, @code{compan}, @code{unique}, @code{union}, @code{intersect}, @code{setdiff}, @code{setxor}, @code{ismember}. @subheading Serialization, random numbers, interpolation, solvers, and optimization @code{saveobj}, @code{loadobj}, @code{mprand}, @code{mprandn}, @code{mprandi}, @code{mprng}, @code{interp1}, @code{interp2}, @code{pchip}, @code{spline}, @code{ppval}, @code{mkpp}, @code{unmkpp}, @code{ppder}, @code{ppint}, @code{fzero}, @code{fsolve}, @code{integral}, @code{quadgk}, @code{fminbnd}, @code{fminsearch}. @subheading Graphics boundary @code{plot}, @code{plot3}, @code{loglog}, @code{semilogx}, @code{semilogy}, @code{scatter}, @code{scatter3}, @code{stem}, @code{stairs}, @code{mesh}, @code{surf}, @code{contour3}, @code{meshc}, @code{surfc}, @code{waterfall}. @subheading See also @file{docs/public-api-inventory.md}, @file{docs/advanced-numerics-compatibility.md}, @file{docs/precision-semantics.md}, and the per-topic documents in @file{docs/}. mplapack-interop-0.5.1/INDEX0000644000230300031750000000157615274353471015045 0ustar rafaelrafaelmplapack-interop >> MPLAPACK Interop Information mplapack_version Core multiprecision type mp Precision mpbits mpdigits Matrix inspection size rows columns numel ndims isempty Arithmetic and structure mtimes mldivide mrdivide rdivide transpose ctranspose reshape horzcat vertcat Factorizations chol qr lu eig det inv Reductions norm rank cond rcond Advanced dense numerics hess balance schur qz pinv null orth rref kron expm logm sqrtm polyval polyvalm roots poly conv deconv polyder polyint compan unique union intersect setdiff setxor ismember gamma gammaln lgamma erf erfc saveobj loadobj mprand mprandn mprandi mprng interp1 pchip spline ppval mkpp unmkpp ppder ppint interp2 fzero fsolve integral quadgk fminbnd fminsearch Graphics boundary plot3 scatter3 mesh surf contour3 meshc surfc waterfall mplapack-interop-0.5.1/CONTRIBUTING.md0000644000230300031750000000107115274353471016472 0ustar rafaelrafael# Contributing Read `AGENTS.md` and the active milestone before making changes. Work against an explicit milestone and keep each contribution within that milestone's scope and gate. Include automated tests with every user-visible numerical change. Keep source, comments, tests, documentation, commit messages, and metadata in English. Do not vendor MPLAPACK or copy its implementation into this repository. Do not add another numerical backend before the MPFR baseline is complete. Avoid unrelated formatting churn, and update contracts when public behavior changes. mplapack-interop-0.5.1/examples/0000755000230300031750000000000015274353471016060 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/07_svd_hilbert.m0000644000230300031750000000150015274353471021045 0ustar rafaelrafael% SVD of a non-diagonal, ill-conditioned Hilbert matrix. if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif saved_bits = mpbits (); unwind_protect mpbits (512); n = 8; H = mp (zeros (n, n)); for i = 1:n for j = 1:n H(i, j) = mp (1) / mp (i + j - 1); endfor endfor [U, S, V] = svd (H); sigma = diag (S); residual = norm (H - U * S * V', "fro") / norm (H, "fro"); disp ("Hilbert singular values:"); disp (sigma); disp ("relative reconstruction residual:"); disp (residual); fprintf ("Hilbert SVD PASS: n=%d, mpbits=%d\n", n, mpbits ()); assert (double (residual) < 1e-100); assert (double (norm (U' * U - mp (eye (n)), "fro")) < 1e-100); assert (double (norm (V' * V - mp (eye (n)), "fro")) < 1e-100); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/examples/15_neig_tier_a.m0000644000230300031750000000536715274353471021023 0ustar rafaelrafael% NEIGT Tier-A case index. % % This short numbered entry point preserves the historical family entry. % It lists one runnable example per manifest case. The full measured wall is % run by mp_neig_tiers ("smoke"/"demo") and by the repository test suite. % % Question: Which nonsymmetric eigensystem cases belong to Tier-A, and where is the % detailed interpretation for each one? % Steps: inspect the list, then run any matching .m file directly. % Matching documentation: docs/examples/tiered/README.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (mfilename ("fullpath")); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); repo_root = fileparts (fileparts (mfilename ("fullpath"))); case_ids = { "HAD_BIDIAG"; ... "FRANK0"; ... "FRANK1"; ... "WILKINSON"; ... "GRCAR"; ... "MKS"; ... "MARKOV"; ... "PERRON_POS"; ... "HAD_COMPLEX" }; case_examples = { "examples/tiered/neig-tier-a/had_bidiag.m"; ... "examples/tiered/neig-tier-a/frank0.m"; ... "examples/tiered/neig-tier-a/frank1.m"; ... "examples/tiered/neig-tier-a/wilkinson.m"; ... "examples/tiered/neig-tier-a/grcar.m"; ... "examples/tiered/neig-tier-a/mks.m"; ... "examples/tiered/neig-tier-a/markov.m"; ... "examples/tiered/neig-tier-a/perron_pos.m"; ... "examples/tiered/neig-tier-a/had_complex.m" }; case_docs = { "docs/examples/tiered/neig-tier-a/had_bidiag.md"; ... "docs/examples/tiered/neig-tier-a/frank0.md"; ... "docs/examples/tiered/neig-tier-a/frank1.md"; ... "docs/examples/tiered/neig-tier-a/wilkinson.md"; ... "docs/examples/tiered/neig-tier-a/grcar.md"; ... "docs/examples/tiered/neig-tier-a/mks.md"; ... "docs/examples/tiered/neig-tier-a/markov.md"; ... "docs/examples/tiered/neig-tier-a/perron_pos.md"; ... "docs/examples/tiered/neig-tier-a/had_complex.md" }; assert (numel (case_ids) == numel (case_examples)); assert (numel (case_ids) == numel (case_docs)); for case_index = 1:numel (case_ids) assert (exist (fullfile (repo_root, case_examples{case_index}), "file") == 2); assert (exist (fullfile (repo_root, case_docs{case_index}), "file") == 2); fprintf ("%s\t%s\t%s\n", case_ids{case_index}, case_examples{case_index}, case_docs{case_index}); endfor fprintf ("NEIGT Tier-A index: %d cases.\n", numel (case_ids)); % Preserve the historical full-profile aggregator contract. The split files % above are the teaching surface; this call remains the counted regression. result = mp_neig_tiers ("smoke", struct ("tier", "A", "plot", false)); assert (result.scope_ok); assert (strcmp (result.status, "NUMERICS_COMPLETE")); fprintf ("NEIGT Tier-A smoke PASS: %d measured rows.\n", ... result.coverage.measured_eig_rows); clear cleanup_path; mplapack-interop-0.5.1/examples/16_svd_verified.m0000644000230300031750000000264015274353472021220 0ustar rafaelrafael% Small reproducible Tier V verification example. % % The certificate consumes the actual MPFR SVD factors; it does not call a % second SVD internally and it never converts numerical evidence to double. % The complete V wall is available with: % mp_svd_tiers ("demo", struct ("tier", "V", "plot", false)) if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (mfilename ("fullpath")); private_root = fullfile (example_root, "svd_tiers", "private"); addpath (private_root); cleanup_path = onCleanup (@() rmpath (private_root)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); A = mp ({"3", "0"; "0", "1"}); [U, S, V] = svd (A, "econ"); values_certificate = svt_certify_values (A, U, S, V, 256); assert (strcmp (values_certificate.status, "CERTIFIED")); assert (values_certificate.epsilon.hi < mp ("1e-60")); X = A \ mp (eye (2)); inverse_certificate = svt_certify_inverse (A, X, 256); assert (strcmp (inverse_certificate.status, "CERTIFIED")); assert (inverse_certificate.sigma_min_lower > mp (0)); fprintf ("Tier V SVD/inverse certificates PASS: mpbits=%d\n", mpbits ()); fprintf (" V1 method: %s\n", values_certificate.method); fprintf (" V3 method: %s\n", inverse_certificate.method); fprintf (" certified sigma_min lower bound = %s\n", ... char (inverse_certificate.sigma_min_lower)); clear cleanup_precision; clear cleanup_path; mplapack-interop-0.5.1/examples/05_hilbert_inverse.m0000644000230300031750000000225215274353472021730 0ustar rafaelrafael% High-precision Hilbert matrix inverse using the public mp API. % % The inverse is intentionally computed as H \ I. The public package does % not use inv(H) here; solving for all identity columns uses the same % MPLAPACK-backed left-division path without converting through binary64. if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif previous_bits = mpbits (); unwind_protect mpbits (1024); n = 6; % Build 1/(i+j-1) from decimal MP values. This avoids hilb(n), whose % builtin implementation first creates a binary64 matrix. H = mp (zeros (n, n)); for j = 1:n for i = 1:n H(i, j) = mp ("1") ./ mp (sprintf ("%d", i + j - 1)); endfor endfor I = mp (eye (n)); Hinv = H \ I; residual = H * Hinv - I; disp ("H^(-1) computed at 1024 bits:"); disp (Hinv); disp ("H * H^(-1) - I:"); disp (residual); % norm/abs are not part of the public mp API. Explicit conversion is used % only for a compact binary64 residual diagnostic. residual_double = double (residual); fprintf ("binary64 residual infinity norm: %.3e\n", norm (residual_double, inf)); unwind_protect_cleanup mpbits (previous_bits); end_unwind_protect mplapack-interop-0.5.1/examples/01_scalar_precision.m0000644000230300031750000000026615274353472022063 0ustar rafaelrafael% Scalar construction keeps text and binary64 semantics distinct. mpbits (512); a = mp ("0.1"); b = mp (0.1); fprintf ("text: %s\n", char (a)); fprintf ("double: %s\n", char (b)); mplapack-interop-0.5.1/examples/10_interpolation.m0000644000230300031750000000155315274353472021432 0ustar rafaelrafael% One- and two-dimensional arbitrary-precision interpolation. if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif saved_bits = mpbits (); unwind_protect mpbits (512); x = mp ({"0", "1", "3", "7"}); y = mp ({"0", "1", "9", "49"}); q = mp ({"0.5", "2", "5"}); linear = interp1 (x, y, q, "linear"); assert (linear(1) == mp ("0.5")); assert (linear(2) == mp (5)); pp = pchip (x, y); assert (ppval (pp, mp ("2")) > mp ("1")); grid = mp ({"0", "1", "3"}); z = mp ({"0", "1", "3"; "2", "3", "5"; "5", "6", "8"}); value = interp2 (grid, grid, z, mp ("0.5"), mp ("0.5")); % The four surrounding samples are 0, 1, 2, and 3, so bilinear % interpolation at (0.5, 0.5) is exactly 1.5. assert (value == mp ("1.5")); fprintf ("interpolation PASS: interp1/pchip/interp2\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/examples/16_neig_verified_vs.m0000644000230300031750000000101715274353472022053 0ustar rafaelrafael% NEIGT verified nonsymmetric-eigenvalue (V-S) entry point. if (exist ("mp_neig_verify_examples", "file") != 2) example_root = fileparts (mfilename ("fullpath")); addpath (fullfile (example_root, "neig_tiers")); endif result = mp_neig_verify_examples ("smoke", struct ("tier", "V-S", ... "plot", false)); assert (result.scope_ok); fprintf ("NEIGT V-S scope parsed: %d verification jobs; status=%s\n", ... result.coverage.verification_job_count, result.status); mplapack-interop-0.5.1/examples/02_matrix_arithmetic.m0000644000230300031750000000017615274353472022261 0ustar rafaelrafael% Dense real MPFR matrix arithmetic. A = mp ([1, 2; 3, 4]); B = mp ([5, 6; 7, 8]); disp (A + B); disp (A .* B); disp (A * B); mplapack-interop-0.5.1/examples/12_graphics_boundary.m0000644000230300031750000000175515274353472022254 0ustar rafaelrafael% Headless graphics-boundary example. Numerical data stays mp until plotting. if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif toolkits = available_graphics_toolkits (); if (! any (strcmp (toolkits, "gnuplot"))) fprintf ("graphics example SKIP: no headless gnuplot toolkit available\n"); return; endif saved_bits = mpbits (); old_visible = get (0, "defaultfigurevisible"); unwind_protect mpbits (512); graphics_toolkit ("gnuplot"); set (0, "defaultfigurevisible", "off"); t = linspace (mp ("0"), mp ("6.283185307179586476925286766559"), 24); x = cos (t); y = sin (t); z = t; fig = figure ("visible", "off"); ax = axes ("parent", fig); h = plot3 (ax, x, y, z, "o-"); assert (isgraphics (h, "line")); assert (get (h, "xdata"), double (x)); close (fig); fprintf ("graphics boundary PASS: final mp-to-double conversion only\n"); unwind_protect_cleanup set (0, "defaultfigurevisible", old_visible); close all; mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/examples/nonsymmetric_eig/0000755000230300031750000000000015274353472021434 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/nonsymmetric_eig/nes_write.m0000644000230300031750000001537315274353472023622 0ustar rafaelrafael% Write deterministic, non-overwriting NEIG result files. function paths = nes_write (results, output_dir) if (nargin != 2 || ! isstruct (results) || ! isscalar (results) ... || ! ischar (output_dir) || rows (output_dir) != 1 || isempty (output_dir)) error ("NEIG:WriteArguments", ... "nes_write expects a scalar result and a nonempty output directory"); endif if (! exist (output_dir, "dir")) [created, message] = mkdir (output_dir); if (! created) error ("NEIG:WriteDirectory", "cannot create output directory: %s", message); endif elseif (! isfolder (output_dir)) error ("NEIG:WriteDirectory", "output path is not a directory: %s", output_dir); endif names = {"summary.tsv", "eigenvalues.tsv", "environment.txt", "report.md"}; paths = struct ("summary", fullfile (output_dir, names{1}), ... "eigenvalues", fullfile (output_dir, names{2}), ... "environment", fullfile (output_dir, names{3}), ... "report", fullfile (output_dir, names{4})); if (isfield (results.options, "plot") && results.options.plot) names{end + 1} = "spectrum.png"; paths.plot = fullfile (output_dir, names{end}); endif for k = 1:numel (names) if (exist (fullfile (output_dir, names{k}), "file")) error ("NEIG:WriteExists", ... "refusing to overwrite existing result file: %s", names{k}); endif endfor write_summary (paths.summary, results); write_eigenvalues (paths.eigenvalues, results); write_environment (paths.environment, results); write_report (paths.report, results, paths); if (isfield (paths, "plot")) nes_plot (results, paths.plot); endif endfunction function write_summary (path, results) file = open_new (path); unwind_protect fprintf (file, ["family\trepresentation\tn\ta\ts\tbackend\twork_bits\t", ... "mode\tnative\tsolver_status\tinput_precision\t", ... "reference_status\taccuracy_status\tright_residual\t", ... "left_residual\tabsolute_error\trelative_error\tcircle_error\t", ... "condition_status\tsolver_time\n"]); for k = 1:numel (results.rows) row = results.rows(k); fprintf (file, "%s\t%s\t%d\t%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", ... row.family, row.representation, row.n, scalar_text (row.a), ... scalar_text (row.s), row.backend, row.work_bits, row.mode, ... scalar_text (row.native), row.solver_status, row.input_precision, ... row.reference_status, row.accuracy_status, ... scalar_text (row.right_residual), scalar_text (row.left_residual), ... scalar_text (row.absolute_error), scalar_text (row.relative_error), ... scalar_text (row.circle_error), row.condition_status, ... scalar_text (row.solver_time)); endfor unwind_protect_cleanup fclose (file); end_unwind_protect endfunction function write_eigenvalues (path, results) file = open_new (path); unwind_protect fprintf (file, ["row\tfamily\trepresentation\tmode\tbackend\twork_bits\t", ... "index\tcomputed_real\tcomputed_imag\treference_real\t", ... "reference_imag\n"]); for k = 1:numel (results.rows) row = results.rows(k); if (isempty (row.computed_values)) continue; endif for j = 1:numel (row.computed_values) computed = row.computed_values(j); reference = row.reference_values(j); fprintf (file, "%d\t%s\t%s\t%s\t%s\t%d\t%d\t%s\t%s\t%s\t%s\n", ... k, row.family, row.representation, row.mode, row.backend, ... row.work_bits, j, scalar_text (real (computed)), ... scalar_text (imag (computed)), scalar_text (real (reference)), ... scalar_text (imag (reference))); endfor endfor unwind_protect_cleanup fclose (file); end_unwind_protect endfunction function write_environment (path, results) file = open_new (path); unwind_protect fprintf (file, "schema=%s\n", results.schema); fprintf (file, "profile=%s\n", results.profile); fprintf (file, "family=%s\n", results.family); fprintf (file, "status=%s\n", results.status); fprintf (file, "rows=%d\n", numel (results.rows)); fprintf (file, "evaluation_bits=%d\n", results.evaluation_bits); fprintf (file, "reference_low_bits=%d\n", min (results.work_precisions)); fprintf (file, "octave_version=%s\n", version ()); fprintf (file, "architecture=%s\n", computer ()); fprintf (file, "working_directory=%s\n", pwd ()); fprintf (file, "mpbits_after=%s\n", scalar_text (mpbits ())); unwind_protect_cleanup fclose (file); end_unwind_protect endfunction function write_report (path, results, paths) file = open_new (path); unwind_protect fprintf (file, "# NEIG result bundle\n\n"); fprintf (file, "- Status: **%s**\n", results.status); fprintf (file, "- Profile: `%s`\n", results.profile); fprintf (file, "- Family selection: `%s`\n", results.family); fprintf (file, "- Rows: `%d`\n", numel (results.rows)); fprintf (file, "- Evaluation precision: `%d` bits\n", results.evaluation_bits); fprintf (file, "- MP values in `eigenvalues.tsv` are serialized with `char(mp)`; no\n"); fprintf (file, " binary64 conversion is used for the numerical result columns.\n\n"); fprintf (file, "Files:\n\n"); fprintf (file, "- `summary.tsv`: one row per solver run.\n"); fprintf (file, "- `eigenvalues.tsv`: computed/reference MP real and imaginary parts.\n"); fprintf (file, "- `environment.txt`: execution metadata.\n"); if (isfield (paths, "plot")) fprintf (file, "- `spectrum.png`: explicitly labeled visualization conversion.\n"); endif unwind_protect_cleanup fclose (file); end_unwind_protect endfunction function file = open_new (path) [file, message] = fopen (path, "w"); if (file < 0) error ("NEIG:WriteFile", "cannot create result file %s: %s", path, message); endif endfunction function text = scalar_text (value) if (ischar (value)) text = value; elseif (isa (value, "mp")) text = char (value); elseif (islogical (value)) text = ternary (value, "true", "false"); elseif (isnumeric (value) && isscalar (value)) if (isnan (value)) text = "NaN"; elseif (isinf (value)) text = ternary (value > 0, "Inf", "-Inf"); else text = sprintf ("%.17g", value); endif else error ("NEIG:WriteScalar", "result contains a non-scalar output value"); endif text = strrep (text, sprintf ("\t"), " "); text = strrep (text, sprintf ("\n"), " "); endfunction function answer = ternary (condition, if_true, if_false) if (condition), answer = if_true; else, answer = if_false; endif endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/nes_plot.m0000644000230300031750000000266215274353472023443 0ustar rafaelrafael% Make the optional NEIG spectrum visualization. function nes_plot (results, output_path) if (nargin != 2 || ! isstruct (results) || ! ischar (output_path)) error ("NEIG:PlotArguments", "nes_plot expects results and an output path"); endif if (exist (output_path, "file")) error ("NEIG:PlotExists", "refusing to overwrite plot: %s", output_path); endif figure ("visible", "off"); unwind_protect hold on; legend_entries = {}; for k = 1:numel (results.rows) row = results.rows(k); if (isempty (row.computed_values)) continue; endif % This is a presentation-only conversion. Solver and metric paths % retain MP values; the plot is explicitly labeled as visualization. values = double (row.computed_values); plot (real (values), imag (values), ".", "markersize", 12); legend_entries{end + 1} = sprintf ("%s/%s/%s/%db", ... row.family, row.representation, ... row.mode, row.work_bits); endfor xlabel ("real(lambda) [visualization]"); ylabel ("imag(lambda) [visualization]"); title (sprintf ("NEIG %s spectrum (display conversion only)", results.profile)); grid on; if (! isempty (legend_entries)) legend (legend_entries, "location", "eastoutside"); endif print (output_path, "-dpng"); unwind_protect_cleanup close; end_unwind_protect endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/0000755000230300031750000000000015274353472023106 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_frank_characteristic_coefficients.m0000644000230300031750000000151015274353472033020 0ustar rafaelrafael% Return Frank characteristic coefficients by its independent recurrence. function coefficients = nes_frank_characteristic_coefficients (n, bits) if (nargin != 2 || ! (isnumeric (n) && isscalar (n) && n == fix (n) && n >= 0)) error ("NEIG:FrankPolynomial", "Frank polynomial degree must be nonnegative"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); p0 = mp (1); p1 = mp ([1, -1]); if (n == 0) coefficients = p0; elseif (n == 1) coefficients = p1; else for degree = 2:n zero = mp ("0"); p = [p1, zero] - [zero, p1] ... - (degree - 1) * [zero, p0, zero]; p0 = p1; p1 = p; endfor coefficients = p1; endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_cases.m0000644000230300031750000000675415274353472025243 0ustar rafaelrafael% Profile validation and NEIG01 case selection. function cases = nes_cases (profile, family) if (nargin != 2 || ! ischar (profile) || ! ischar (family)) error ("NEIG:CaseArguments", "profile and family must be character rows"); endif if (! any (strcmp (profile, {"smoke", "demo", "stress"}))) error ("NEIG:Profile", "profile must be smoke, demo, or stress"); endif if (! any (strcmp (family, {"all", "hadamard", "frank", "companion", "forsythe"}))) error ("NEIG:CaseFamily", ... "unknown nonsymmetric eigensystem family"); endif if (strcmp (family, "all")) if (strcmp (profile, "smoke")) hadamard_n = 8; hadamard_s = 16; frank_n = 8; companion_n = 10; forsythe_n = 8; forsythe_a = 4; elseif (strcmp (profile, "demo")) hadamard_n = 16; hadamard_s = 128; frank_n = 24; companion_n = 20; forsythe_n = 20; forsythe_a = 20; else hadamard_n = 16; hadamard_s = 16; frank_n = 16; companion_n = 30; forsythe_n = 20; forsythe_a = 80; endif cases(1) = struct ("family", "hadamard", "representation", ... "hadamard_similar", "n", hadamard_n, ... "s", hadamard_s, "a", NaN); cases(2) = struct ("family", "frank", "representation", "frank", ... "n", frank_n, "s", NaN, "a", NaN); cases(3) = struct ("family", "companion", "representation", ... "companion", "n", companion_n, "s", NaN, "a", NaN); cases(4) = struct ("family", "forsythe", "representation", ... "original", "n", forsythe_n, "s", NaN, ... "a", forsythe_a); cases(5) = struct ("family", "forsythe", "representation", ... "explicitly_scaled", "n", forsythe_n, "s", NaN, ... "a", forsythe_a); return; endif if (strcmp (family, "frank")) if (strcmp (profile, "smoke")) cases = struct ("family", "frank", "representation", "frank", "n", 8); elseif (strcmp (profile, "demo")) cases = struct ("family", "frank", "representation", "frank", "n", 24); else cases = struct ("family", "frank", "representation", "frank", "n", 16); endif return; endif if (strcmp (family, "companion")) if (strcmp (profile, "smoke")) cases = struct ("family", "companion", "representation", "companion", "n", 10); elseif (strcmp (profile, "demo")) cases = struct ("family", "companion", "representation", "companion", "n", 20); else cases = struct ("family", "companion", "representation", "companion", "n", 30); endif return; endif if (strcmp (family, "forsythe")) if (strcmp (profile, "smoke")) n = 8; a = 4; elseif (strcmp (profile, "demo")) n = 20; a = 20; else n = 20; a = 80; endif cases(1) = struct ("family", "forsythe", "representation", "original", ... "n", n, "a", a); cases(2) = struct ("family", "forsythe", "representation", ... "explicitly_scaled", "n", n, "a", a); return; endif switch (profile) case "smoke" cases = struct ("family", "hadamard", "representation", "hadamard_similar", ... "n", 8, "s", 16); case "demo" cases = struct ("family", "hadamard", "representation", "hadamard_similar", ... "n", 16, "s", 128); otherwise cases = struct ("family", "hadamard", "representation", "hadamard_similar", ... "n", 16, "s", 16); endswitch endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_build.m0000644000230300031750000001674115274353472025241 0ustar rafaelrafael% Exact mathematical constructors used by the nonsymmetric eigensystem suite. function result = nes_build (family, parameters, work_bits) if (nargin != 3 || ! ischar (family) || ! isstruct (parameters)) error ("NEIG:BuildArguments", "nes_build expects a family, parameter struct, and precision"); endif if (! (isnumeric (work_bits) && isscalar (work_bits) && isreal (work_bits) && isfinite (work_bits) && work_bits == fix (work_bits) && work_bits >= 1)) error ("NEIG:BuildPrecision", "work precision must be a positive integer"); endif if (strcmp (family, "hadamard")) if (! isfield (parameters, "n") || ! isfield (parameters, "s")) error ("NEIG:BuildParameters", "Hadamard construction requires n and s"); endif n = parameters.n; s = parameters.s; if (! (isnumeric (n) && isscalar (n) && isreal (n) && isfinite (n) && n == fix (n) && n >= 1 && is_power_of_two (n))) error ("NEIG:BuildParameters", "Hadamard n must be a positive power of two"); endif if (! (isnumeric (s) && isscalar (s) && isreal (s) && isfinite (s) && s == fix (s) && s >= 1)) error ("NEIG:BuildParameters", "Hadamard s must be a positive integer"); endif elseif (strcmp (family, "frank")) if (! isfield (parameters, "n")) error ("NEIG:BuildParameters", "Frank construction requires n"); endif n = parameters.n; if (! (isnumeric (n) && isscalar (n) && isreal (n) && isfinite (n) && n == fix (n) && n >= 2)) error ("NEIG:BuildParameters", "Frank n must be an integer at least two"); endif elseif (strcmp (family, "companion")) if (! isfield (parameters, "n")) error ("NEIG:BuildParameters", "companion construction requires n"); endif n = parameters.n; if (! (isnumeric (n) && isscalar (n) && isreal (n) && isfinite (n) && n == fix (n) && n >= 1)) error ("NEIG:BuildParameters", "companion n must be a positive integer"); endif if (work_bits < nes_companion_min_bits (n)) error ("NEIG:BuildPrecision", ... "companion work precision is below its exact-coefficient guard"); endif elseif (strcmp (family, "forsythe")) if (! isfield (parameters, "n") || ! isfield (parameters, "a") || ! isfield (parameters, "representation")) error ("NEIG:BuildParameters", ... "Forsythe construction requires n, a, and representation"); endif n = parameters.n; a = parameters.a; representation = parameters.representation; if (! (isnumeric (n) && isscalar (n) && isreal (n) && isfinite (n) && n == fix (n) && n >= 3)) error ("NEIG:BuildParameters", "Forsythe n must be an integer at least three"); endif if (! (isnumeric (a) && isscalar (a) && isreal (a) && isfinite (a) && a == fix (a) && a >= 1)) error ("NEIG:BuildParameters", "Forsythe a must be a positive integer"); endif if (! any (strcmp (representation, {"original", "explicitly_scaled"}))) error ("NEIG:BuildParameters", "invalid Forsythe representation"); endif else error ("NEIG:BuildFamily", "family is not implemented by the current milestone"); endif saved_bits = mpbits (); unwind_protect mpbits (work_bits); if (strcmp (family, "hadamard")) H_native = nes_hadamard_native (n); T = mp (zeros (n, n)); for k = 1:n T(k, k) = mp (k); if (k < n) T(k, k + 1) = mp (s); endif endfor H = mp (H_native); A = (H * T * transpose (H)) / n; result = struct ("family", family, "representation", "hadamard_similar", ... "n", n, "s", s, "H", H, "T", T, "A", A, ... "work_bits", work_bits, "native_A", ... nes_hadamard_native_matrix (n, s), ... "native_exact_bound", n * (n + s), ... "native_exact_safe", n * (n + s) < 2^53); elseif (strcmp (family, "frank")) A = mp (zeros (n, n)); for i = 1:n for j = 1:n if (j >= i - 1) A(i, j) = mp (n + 1 - max (i, j)); endif endfor endfor result = struct ("family", family, "representation", "frank", ... "n", n, "A", A, "work_bits", work_bits, ... "native_A", nes_frank_native_matrix (n)); elseif (strcmp (family, "companion")) coefficients = nes_companion_coefficients (n, work_bits); A = mp (zeros (n, n)); for j = 1:n A(1, j) = -coefficients(j + 1); endfor for i = 2:n A(i, i - 1) = mp ("1"); endfor result = struct ("family", family, "representation", "companion", ... "n", n, "A", A, "coefficients", coefficients, ... "work_bits", work_bits, "native_A", ... nes_companion_native_matrix (n, work_bits)); else radius = mp ("1"); for k = 1:a radius = radius * mp ("0.5"); endfor epsilon = mp ("1"); for k = 1:(a * n) epsilon = epsilon * mp ("0.5"); endfor original = mp (eye (n)); for k = 1:(n - 1) original(k, k + 1) = mp ("1"); endfor original(n, 1) = epsilon; shift = mp (zeros (n, n)); for k = 1:(n - 1) shift(k, k + 1) = mp ("1"); endfor shift(n, 1) = mp ("1"); scaled = mp (eye (n)) + radius * shift; scaling = mp (zeros (n, n)); power = mp ("1"); for k = 1:n scaling(k, k) = power; power = power * radius; endfor if (strcmp (representation, "original")) A = original; else A = scaled; endif result = struct ("family", family, "representation", representation, ... "n", n, "a", a, "radius", radius, ... "epsilon", epsilon, "A", A, "original_A", original, ... "scaled_A", scaled, "scaling", scaling, ... "native_A", nes_forsythe_native_matrix (n, a, representation), ... "native_epsilon", 2^(-(a * n)), ... "native_underflow", 2^(-(a * n)) == 0); endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function answer = nes_hadamard_native (n) answer = 1; while (rows (answer) < n) answer = [answer, answer; answer, -answer]; endwhile endfunction function answer = nes_hadamard_native_matrix (n, s) H = nes_hadamard_native (n); T = diag (1:n) + s * diag (ones (n - 1, 1), 1); answer = H * T * transpose (H) / n; endfunction function answer = nes_frank_native_matrix (n) answer = zeros (n, n); for i = 1:n for j = 1:n if (j >= i - 1) answer(i, j) = n + 1 - max (i, j); endif endfor endfor endfunction function answer = nes_companion_native_matrix (n, bits) coefficients = double (nes_companion_coefficients (n, bits)); answer = zeros (n, n); answer(1, :) = -coefficients(2:end); for i = 2:n answer(i, i - 1) = 1; endfor endfunction function answer = nes_forsythe_native_matrix (n, a, representation) radius = 2^(-a); epsilon = 2^(-(a * n)); shift = zeros (n, n); for k = 1:(n - 1) shift(k, k + 1) = 1; endfor shift(n, 1) = 1; if (strcmp (representation, "original")) answer = eye (n) + shift; answer(n, 1) = epsilon; else answer = eye (n) + radius * shift; endif endfunction function answer = is_power_of_two (n) answer = false; k = 1; while (k < n) k = k * 2; endwhile answer = (k == n); endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_forsythe_run.m0000644000230300031750000001045415274353472026664 0ustar rafaelrafael% Run one original or explicitly scaled Forsythe eigensystem. function row = nes_forsythe_run (parameters, work_bits, mode, model_q, reference, native) n = parameters.n; q = reference.reference_bits; if (native) built = nes_build ("forsythe", parameters, q); actual = built.native_A; source_bits = 53; input_precision = "native-binary64"; backend = "native"; else built = nes_build ("forsythe", parameters, work_bits); actual = built.A; source_bits = work_bits; input_precision = "mp"; backend = "mpfr"; endif actual_q = nes_promote (actual, q, source_bits); input_error = norm (actual_q - model_q, "fro"); input_error_relative = input_error / norm (model_q, "fro"); solver_status = "success"; solver_error = ''; solver_time = NaN; saved_bits = mpbits (); try if (! native) mpbits (work_bits); endif started = tic (); [vectors, diagonal, left_vectors] = eig (actual, mode); solver_time = toc (started); catch exception solver_status = "error"; solver_error = exception.message; end_try_catch mpbits (saved_bits); row = struct ("schema", "neig-v1", "family", "forsythe", ... "representation", parameters.representation, "n", n, ... "a", parameters.a, "s", NaN, "backend", backend, ... "work_bits", work_bits, "evaluation_bits", q, ... "reference_bits", reference.reference_bits, ... "low_reference_bits", reference.low_reference_bits, ... "reference_agreement", reference.reference_agreement, ... "reference_agreement_limit", reference.reference_agreement_limit, ... "mode", mode, "input_precision", input_precision, ... "native", native, "native_underflow", ternary (native, ... nes_build ("forsythe", parameters, q).native_underflow, false), ... "solver_status", solver_status, "solver_error", solver_error, ... "solver_time", solver_time, "input_error", input_error, ... "input_error_relative", input_error_relative, ... "accuracy_status", "not_targeted", ... "reference_status", reference.reference_status, ... "condition_status", "unresolved", "max_imaginary", mp ("NaN"), ... "absolute_error", mp ("NaN"), "relative_error", mp ("NaN"), ... "circle_error", mp ("NaN"), "right_residual", mp ("NaN"), ... "left_residual", mp ("NaN"), "right_column_residual", mp ("NaN"), ... "left_column_residual", mp ("NaN"), "condition_estimates", ... mp ("NaN"), "vector_condition", mp ("NaN"), ... "condition_disagreement", mp ("NaN"), "absolute_mapping", [], ... "relative_mapping", [], "circle_mapping", [], ... "computed_values", [], "reference_values", reference.eigenvalues); if (! strcmp (solver_status, "success")) return; endif vectors_q = nes_promote (vectors, q, source_bits); diagonal_q = nes_promote (diagonal, q, source_bits); left_vectors_q = nes_promote (left_vectors, q, source_bits); metrics = nes_metrics (actual_q, vectors_q, diagonal_q, left_vectors_q, ... reference.eigenvalues); circle_match = nes_match (metrics.values, reference.unit_roots, "circle", ... mp ("1"), reference.radius); row.condition_status = metrics.condition_status; row.max_imaginary = max (abs (imag (metrics.values))); row.absolute_error = metrics.absolute_match.threshold; row.relative_error = metrics.relative_match.threshold; row.circle_error = circle_match.threshold; row.right_residual = metrics.right_residual; row.left_residual = metrics.left_residual; row.right_column_residual = metrics.right_column_residual; row.left_column_residual = metrics.left_column_residual; row.condition_estimates = metrics.condition_estimates; row.vector_condition = metrics.vector_condition; row.absolute_mapping = metrics.absolute_match.mapping; row.relative_mapping = metrics.relative_match.mapping; row.circle_mapping = circle_match.mapping; row.computed_values = metrics.values; endfunction function answer = ternary (condition, if_true, if_false) if (condition), answer = if_true; else, answer = if_false; endif endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_promote.m0000644000230300031750000000236215274353472025621 0ustar rafaelrafael% Promote a represented value for diagnostics without recomputing it. function value = nes_promote (source, bits, source_bits) if (nargin != 3) error ("NEIG:PromotionArguments", ... "nes_promote expects source, destination bits, and source bits"); endif if (! (isnumeric (bits) && isscalar (bits) && isreal (bits) && isfinite (bits) && bits == fix (bits) && bits >= 1)) error ("NEIG:PromotionPrecision", "destination precision must be a positive integer"); endif if (! (isnumeric (source_bits) && isscalar (source_bits) && isreal (source_bits) && isfinite (source_bits) && source_bits == fix (source_bits) && source_bits >= 1 && bits >= source_bits)) error ("NEIG:PromotionPrecision", ... "destination precision must not be below the recorded source precision"); endif if (! (isa (source, "mp") || isa (source, "double"))) error ("NEIG:PromotionType", "source must be an mp value or a native double value"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); if (isa (source, "mp")) value = source + mp (zeros (size (source))); else value = mp (source); endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_frank_run.m0000644000230300031750000000725515274353472026127 0ustar rafaelrafael% Run one Frank eigensystem using the actual input representation. function row = nes_frank_run (parameters, work_bits, mode, model_q, reference, native) n = parameters.n; q = reference.reference_bits; if (native) built = nes_build ("frank", parameters, q); actual = built.native_A; source_bits = 53; input_precision = "native-binary64"; backend = "native"; else built = nes_build ("frank", parameters, work_bits); actual = built.A; source_bits = work_bits; input_precision = "mp"; backend = "mpfr"; endif actual_q = nes_promote (actual, q, source_bits); input_error = norm (actual_q - model_q, "fro"); input_error_relative = input_error / norm (model_q, "fro"); solver_status = "success"; solver_error = ''; solver_time = NaN; saved_bits = mpbits (); try if (! native) mpbits (work_bits); endif started = tic (); [vectors, diagonal, left_vectors] = eig (actual, mode); solver_time = toc (started); catch exception solver_status = "error"; solver_error = exception.message; end_try_catch mpbits (saved_bits); row = struct ("schema", "neig-v1", "family", "frank", ... "representation", "frank", "n", n, "s", NaN, ... "backend", backend, "work_bits", work_bits, ... "evaluation_bits", q, "reference_bits", reference.reference_bits, ... "low_reference_bits", reference.low_reference_bits, ... "reference_agreement", reference.reference_agreement, ... "reference_agreement_limit", reference.reference_agreement_limit, ... "mode", mode, "input_precision", input_precision, ... "native", native, "solver_status", solver_status, ... "solver_error", solver_error, "solver_time", solver_time, ... "input_error", input_error, "input_error_relative", ... input_error_relative, "accuracy_status", "not_targeted", ... "reference_status", reference.reference_status, ... "condition_status", "unresolved", "max_imaginary", mp ("NaN"), ... "absolute_error", mp ("NaN"), "relative_error", mp ("NaN"), ... "right_residual", mp ("NaN"), "left_residual", mp ("NaN"), ... "right_column_residual", mp ("NaN"), "left_column_residual", ... mp ("NaN"), "condition_estimates", mp ("NaN"), ... "vector_condition", mp ("NaN"), "condition_disagreement", ... mp ("NaN"), "absolute_mapping", [], "relative_mapping", [], ... "computed_values", [], "reference_values", reference.eigenvalues); if (! strcmp (solver_status, "success")) return; endif vectors_q = nes_promote (vectors, q, source_bits); diagonal_q = nes_promote (diagonal, q, source_bits); left_vectors_q = nes_promote (left_vectors, q, source_bits); metrics = nes_metrics (actual_q, vectors_q, diagonal_q, left_vectors_q, ... reference.eigenvalues); row.condition_status = metrics.condition_status; row.max_imaginary = max (abs (imag (metrics.values))); row.absolute_error = metrics.absolute_match.threshold; row.relative_error = metrics.relative_match.threshold; row.right_residual = metrics.right_residual; row.left_residual = metrics.left_residual; row.right_column_residual = metrics.right_column_residual; row.left_column_residual = metrics.left_column_residual; row.condition_estimates = metrics.condition_estimates; row.vector_condition = metrics.vector_condition; row.absolute_mapping = metrics.absolute_match.mapping; row.relative_mapping = metrics.relative_match.mapping; row.computed_values = metrics.values; endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_companion_run.m0000644000230300031750000000730615274353472027006 0ustar rafaelrafael% Run one Wilkinson-polynomial companion eigensystem. function row = nes_companion_run (parameters, work_bits, mode, model_q, reference, native) n = parameters.n; q = reference.reference_bits; minimum_bits = nes_companion_min_bits (n); if (native) built = nes_build ("companion", parameters, q); actual = built.native_A; source_bits = 53; input_precision = "native-binary64"; backend = "native"; else built = nes_build ("companion", parameters, work_bits); actual = built.A; source_bits = work_bits; input_precision = "mp"; backend = "mpfr"; endif actual_q = nes_promote (actual, q, source_bits); input_error = norm (actual_q - model_q, "fro"); input_error_relative = input_error / norm (model_q, "fro"); solver_status = "success"; solver_error = ''; solver_time = NaN; saved_bits = mpbits (); try if (! native) mpbits (work_bits); endif started = tic (); [vectors, diagonal, left_vectors] = eig (actual, mode); solver_time = toc (started); catch exception solver_status = "error"; solver_error = exception.message; end_try_catch mpbits (saved_bits); row = struct ("schema", "neig-v1", "family", "companion", ... "representation", "companion", "n", n, "s", NaN, ... "backend", backend, "work_bits", work_bits, ... "evaluation_bits", q, "reference_bits", reference.reference_bits, ... "low_reference_bits", NaN, "reference_agreement", mp ("NaN"), ... "reference_agreement_limit", mp ("NaN"), "mode", mode, ... "input_precision", input_precision, "native", native, ... "minimum_coefficient_bits", minimum_bits, ... "solver_status", solver_status, "solver_error", solver_error, ... "solver_time", solver_time, "input_error", input_error, ... "input_error_relative", input_error_relative, ... "accuracy_status", "not_targeted", "reference_status", ... reference.reference_status, "condition_status", "unresolved", ... "max_imaginary", mp ("NaN"), "absolute_error", mp ("NaN"), ... "relative_error", mp ("NaN"), "right_residual", mp ("NaN"), ... "left_residual", mp ("NaN"), "right_column_residual", mp ("NaN"), ... "left_column_residual", mp ("NaN"), "condition_estimates", ... mp ("NaN"), "vector_condition", mp ("NaN"), ... "condition_disagreement", mp ("NaN"), "absolute_mapping", [], ... "relative_mapping", [], "computed_values", [], ... "reference_values", reference.eigenvalues); if (! strcmp (solver_status, "success")) return; endif vectors_q = nes_promote (vectors, q, source_bits); diagonal_q = nes_promote (diagonal, q, source_bits); left_vectors_q = nes_promote (left_vectors, q, source_bits); metrics = nes_metrics (actual_q, vectors_q, diagonal_q, left_vectors_q, ... reference.eigenvalues); row.condition_status = metrics.condition_status; row.max_imaginary = max (abs (imag (metrics.values))); row.absolute_error = metrics.absolute_match.threshold; row.relative_error = metrics.relative_match.threshold; row.right_residual = metrics.right_residual; row.left_residual = metrics.left_residual; row.right_column_residual = metrics.right_column_residual; row.left_column_residual = metrics.left_column_residual; row.condition_estimates = metrics.condition_estimates; row.vector_condition = metrics.vector_condition; row.absolute_mapping = metrics.absolute_match.mapping; row.relative_mapping = metrics.relative_match.mapping; row.computed_values = metrics.values; endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_reference.m0000644000230300031750000001563515274353472026101 0ustar rafaelrafael% Independent references for the nonsymmetric eigensystem suite. function result = nes_reference (family, parameters, reference_bits, reference_low_bits) if (nargin < 3 || nargin > 4 || ! ischar (family) || ! isstruct (parameters)) error ("NEIG:ReferenceArguments", ... "nes_reference expects a family, parameter struct, and precision"); endif if (! any (strcmp (family, {"hadamard", "frank", "companion", "forsythe"}))) error ("NEIG:ReferenceFamily", "family reference is not implemented yet"); endif n = parameters.n; if (! (isnumeric (reference_bits) && isscalar (reference_bits) && isreal (reference_bits) && isfinite (reference_bits) && reference_bits == fix (reference_bits) && reference_bits >= 1)) error ("NEIG:ReferencePrecision", "reference precision must be a positive integer"); endif saved_bits = mpbits (); unwind_protect mpbits (reference_bits); if (strcmp (family, "hadamard")) values = mp (transpose (1:n)); condition_numbers = mp (zeros (n, 1)); for root = 1:n left_sum = mp ("1"); term = mp ("1"); for j = 1:(root - 1) term = term * mp (parameters.s) / mp (j); left_sum = left_sum + term * term; endfor right_sum = mp ("1"); term = mp ("1"); for j = 1:(n - root) term = term * mp (parameters.s) / mp (j); right_sum = right_sum + term * term; endfor condition_numbers(root) = sqrt (left_sum) * sqrt (right_sum); endfor result = struct ("family", family, "reference_status", "analytic_exact", ... "reference_bits", reference_bits, "eigenvalues", values, ... "condition_numbers", condition_numbers); elseif (strcmp (family, "frank")) if (nargin == 4) low_bits = reference_low_bits; else low_bits = reference_bits - 128; endif if (! (isnumeric (low_bits) && isscalar (low_bits) && isreal (low_bits) && isfinite (low_bits) && low_bits == fix (low_bits) && low_bits >= 1 && low_bits < reference_bits)) error ("NEIG:ReferencePrecision", ... "low Frank reference precision must be below high reference precision"); endif low_values = nes_frank_reference_at (parameters.n, low_bits); values = nes_frank_reference_at (parameters.n, reference_bits); promoted_low = nes_promote (low_values, reference_bits, low_bits); agreement = nes_match (values, promoted_low, "relative"); agreement_limit = nes_reference_power (floor (low_bits / 2), reference_bits); if (agreement.threshold <= agreement_limit) status = "evaluated_consistent"; else status = "unresolved"; endif result = struct ("family", family, "reference_status", status, ... "reference_bits", reference_bits, "low_reference_bits", ... low_bits, "eigenvalues", values, "condition_numbers", ... mp ("NaN"), "reference_agreement", agreement.threshold, ... "reference_agreement_limit", agreement_limit); elseif (strcmp (family, "companion")) values = mp (transpose (1:n)); result = struct ("family", family, "reference_status", "analytic_exact", ... "reference_bits", reference_bits, "eigenvalues", values, ... "condition_numbers", mp ("NaN")); else if (nargin == 4) low_bits = reference_low_bits; else low_bits = reference_bits - 128; endif low = nes_forsythe_reference_at (parameters.n, parameters.a, low_bits); high = nes_forsythe_reference_at (parameters.n, parameters.a, reference_bits); low_units = nes_promote (low.unit_roots, reference_bits, low_bits); agreement = nes_match (high.unit_roots, low_units, "absolute"); agreement_limit = nes_reference_power (floor (low_bits / 2), reference_bits); if (agreement.threshold <= agreement_limit) status = "evaluated_consistent"; else status = "unresolved"; endif result = struct ("family", family, "reference_status", status, ... "reference_bits", reference_bits, "low_reference_bits", ... low_bits, "eigenvalues", high.eigenvalues, ... "unit_roots", high.unit_roots, "radius", high.radius, ... "reference_agreement", agreement.threshold, ... "reference_agreement_limit", agreement_limit, ... "condition_numbers", mp ("NaN")); endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = nes_forsythe_reference_at (n, a, bits) saved_bits = mpbits (); unwind_protect mpbits (bits); radius = nes_reference_power (a, bits); unit_roots = mp (complex (zeros (n, 1), zeros (n, 1))); eigenvalues = unit_roots; pi_value = acos (mp ("-1")); for k = 0:floor (n / 2) if (k == 0) real_part = mp ("1"); imaginary_part = mp ("0"); else angle = mp ("2") * pi_value * mp (k) / mp (n); real_part = cos (angle); imaginary_part = sin (angle); endif if (k == 0) root = mp (char (mp ("1") + radius), "0"); elseif (mod (n, 2) == 0 && k == n / 2) root = mp (char (mp ("1") - radius), "0"); else root = mp (char (mp ("1") + radius * real_part), ... char (radius * imaginary_part)); endif unit = mp (char (real_part), char (imaginary_part)); unit_roots(k + 1) = unit; eigenvalues(k + 1) = root; if (k > 0 && k < n / 2) unit_roots(n - k + 1) = conj (unit); eigenvalues(n - k + 1) = conj (root); endif endfor result = struct ("radius", radius, "unit_roots", unit_roots, ... "eigenvalues", eigenvalues); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function value = nes_reference_power (exponent, bits) saved_bits = mpbits (); unwind_protect mpbits (bits); value = mp ("1"); half = mp ("0.5"); for k = 1:exponent value = value * half; endfor unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function values = nes_frank_reference_at (n, bits) saved_bits = mpbits (); unwind_protect mpbits (bits); K = mp (zeros (n, n)); for j = 1:(n - 1) entry = sqrt (mp (j)); K(j, j + 1) = entry; K(j + 1, j) = entry; endfor [unused, diagonal] = eig (K, "nobalance"); z = diag (diagonal); values = mp (zeros (n, 1)); for j = 1:n radical = sqrt (z(j) * z(j) + mp ("4")); if (z(j) >= mp ("0")) root = (z(j) + radical) / mp ("2"); else root = mp ("2") / (radical - z(j)); endif values(j) = root * root; endfor unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_ceil_log2_integer.m0000644000230300031750000000062415274353472027507 0ustar rafaelrafael% Exact integer ceil(log2(n)) for positive native dimensions. function exponent = nes_ceil_log2_integer (n) if (! (isnumeric (n) && isscalar (n) && isreal (n) && isfinite (n) && n == fix (n) && n >= 1)) error ("NEIG:IntegerLog", "argument must be a positive integer"); endif power = 1; exponent = 0; while power < n power = power * 2; exponent += 1; endwhile endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_companion_coefficients.m0000644000230300031750000000151415274353472030636 0ustar rafaelrafael% Construct prod(x-k) coefficients with MP arithmetic at the requested bits. function coefficients = nes_companion_coefficients (n, bits) if (nargin != 2 || ! (isnumeric (n) && isscalar (n) && isreal (n) && isfinite (n) && n == fix (n) && n >= 1)) error ("NEIG:CompanionArguments", "companion degree must be a positive integer"); endif if (bits < nes_companion_min_bits (n)) error ("NEIG:CompanionPrecision", ... "precision is below the exact-coefficient guard"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); coefficients = mp (1); for k = 1:n zero = mp ("0"); coefficients = [coefficients, zero] ... - mp (k) * [zero, coefficients]; endfor unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_metrics.m0000644000230300031750000000706615274353472025610 0ustar rafaelrafael% High-precision diagnostics for an actual returned eigentriple. function result = nes_metrics (A_input_q, V_q, D_q, W_q, reference) if (nargin != 5 || ! isa (A_input_q, "mp") || ! isa (V_q, "mp") || ! isa (D_q, "mp") || ! isa (W_q, "mp") || ! isa (reference, "mp")) error ("NEIG:MetricArguments", "nes_metrics expects five mp values"); endif if (rows (A_input_q) != columns (A_input_q) || rows (V_q) != rows (A_input_q) || columns (V_q) != rows (A_input_q) || rows (W_q) != rows (A_input_q) || columns (W_q) != rows (A_input_q) || rows (D_q) != rows (A_input_q) || columns (D_q) != rows (A_input_q)) error ("NEIG:MetricShape", "A, V, D, and W must be compatible square eigensystem values"); endif values = diag (D_q); n = rows (A_input_q); if (numel (reference) != n) error ("NEIG:MetricReference", "reference spectrum has the wrong size"); endif if (! all (isfinite (A_input_q)) || ! all (isfinite (V_q)) || ! all (isfinite (D_q)) || ! all (isfinite (W_q)) || ! all (isfinite (reference))) error ("NEIG:MetricFinite", "eigensystem diagnostics require finite values"); endif a_norm = norm (A_input_q, "fro"); v_norm = norm (V_q, "fro"); w_norm = norm (W_q, "fro"); right_numerator = norm (A_input_q * V_q - V_q * D_q, "fro"); left_numerator = norm (ctranspose (W_q) * A_input_q ... - D_q * ctranspose (W_q), "fro"); right_denominator = a_norm * v_norm; left_denominator = a_norm * w_norm; if (right_denominator == mp ("0") || left_denominator == mp ("0")) error ("NEIG:MetricDenominator", "eigensystem residual denominator is zero"); endif eta_right = mp (zeros (n, 1)); eta_left = mp (zeros (n, 1)); condition = mp (zeros (n, 1)); condition_status = "resolved"; for column = 1:n v = V_q(:, column); w = W_q(:, column); nv = norm (v); nw = norm (w); if (nv == mp ("0") || nw == mp ("0")) error ("NEIG:MetricZeroVector", "eigensystem contains a zero eigenvector column"); endif scale = a_norm + abs (values(column)); if (scale == mp ("0")) error ("NEIG:MetricDenominator", "column residual denominator is zero"); endif eta_right(column) = norm (A_input_q * v - v * values(column)) / (scale * nv); eta_left(column) = norm (ctranspose (A_input_q) * w ... - w * conj (values(column))) / (scale * nw); overlap = abs (ctranspose (w) * v); if (overlap == mp ("0")) condition(column) = mp ("Inf"); condition_status = "unresolved_zero_overlap"; else condition(column) = nv * nw / overlap; endif endfor normalized = mp (zeros (n, n)); for column = 1:n nv = norm (V_q(:, column)); normalized(:, column) = V_q(:, column) * (mp ("1") / nv); endfor vector_condition = cond (normalized); absolute_match = nes_match (values, reference, "absolute"); relative_match = nes_match (values, reference, "relative"); result = struct ("values", values, "absolute_match", absolute_match, ... "relative_match", relative_match, ... "right_residual", right_numerator / right_denominator, ... "left_residual", left_numerator / left_denominator, ... "right_column_residual", max (eta_right), ... "left_column_residual", max (eta_left), ... "eta_right", eta_right, "eta_left", eta_left, ... "condition_estimates", condition, ... "condition_status", condition_status, ... "vector_condition", vector_condition); endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_exact_small_determinant.m0000644000230300031750000000144415274353472031022 0ustar rafaelrafael% Exact small determinant for independent Frank polynomial checks. function determinant = nes_exact_small_determinant (matrix) n = rows (matrix); if (n > 5 || n != columns (matrix)) error ("NEIG:FrankDeterminant", "exact determinant helper is limited to square n<=5"); endif determinant = mp ("0"); permutations = perms (1:n); for row = 1:rows (permutations) product = mp ("1"); inversions = 0; for i = 1:n product = product * matrix(i, permutations(row, i)); if (i < n) for j = (i + 1):n inversions += permutations(row, i) > permutations(row, j); endfor endif endfor if (mod (inversions, 2) == 1) determinant = determinant - product; else determinant = determinant + product; endif endfor endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_match.m0000644000230300031750000000774215274353472025237 0ustar rafaelrafael% Deterministic minimum-bottleneck one-to-one eigenvalue matching. function result = nes_match (computed, reference, kind, varargin) if (nargin < 3 || nargin > 5 || ! isa (computed, "mp") || ! isa (reference, "mp") || ! ischar (kind)) error ("NEIG:MatchArguments", ... "nes_match expects two mp vectors, a cost kind, and optional circle data"); endif computed = computed(:); reference = reference(:); n = numel (computed); if (n < 1 || numel (reference) != n) error ("NEIG:MatchSize", "computed and reference spectra must have equal nonzero size"); endif if (! any (strcmp (kind, {"absolute", "relative", "circle"}))) error ("NEIG:MatchKind", "matching kind must be absolute, relative, or circle"); endif if (! all (isfinite (computed)) || ! all (isfinite (reference))) error ("NEIG:MatchFinite", "matching spectra must contain only finite values"); endif if (strcmp (kind, "circle")) if (nargin != 5 || ! isa (varargin{1}, "mp") || ! isa (varargin{2}, "mp") || ! isscalar (varargin{1}) || ! isscalar (varargin{2}) || varargin{2} == mp ("0")) error ("NEIG:MatchCircle", "circle matching requires nonzero mp center and radius"); endif center = varargin{1}; radius = varargin{2}; elseif (nargin != 3) error ("NEIG:MatchArguments", "non-circle matching does not accept circle data"); endif costs = mp (zeros (n, n)); for row = 1:n for col = 1:n if (strcmp (kind, "absolute")) costs(row, col) = abs (computed(row) - reference(col)); elseif (strcmp (kind, "relative")) denominator = abs (reference(col)); if (denominator == mp ("0")) error ("NEIG:MatchReferenceZero", ... "relative matching requires nonzero reference roots"); endif costs(row, col) = abs (computed(row) - reference(col)) / denominator; else costs(row, col) = abs ((computed(row) - center) / radius - reference(col)); endif endfor endfor if (! all (isfinite (costs))) error ("NEIG:MatchFinite", "matching cost matrix contains a nonfinite value"); endif candidates = sort (costs(:)); lower = 1; upper = numel (candidates); while (lower < upper) middle = floor ((lower + upper) / 2); if (has_perfect_matching (costs, candidates(middle))) upper = middle; else lower = middle + 1; endif endwhile threshold = candidates(lower); [possible, mapping] = find_perfect_matching (costs, threshold); if (! possible) error ("NEIG:MatchInternal", "final bottleneck threshold has no perfect matching"); endif for row = 1:n if (mapping(row) < 1 || mapping(row) > n) error ("NEIG:MatchInternal", "matching did not return a bijection"); endif endfor if (numel (unique (mapping)) != n) error ("NEIG:MatchInternal", "matching did not return distinct reference indices"); endif result = struct ("kind", kind, "threshold", threshold, "mapping", mapping, ... "costs", costs, "status", "resolved"); endfunction function answer = has_perfect_matching (costs, threshold) [answer, unused] = find_perfect_matching (costs, threshold); endfunction function [possible, mapping] = find_perfect_matching (costs, threshold) n = rows (costs); matched_column = zeros (1, n); seen = false (1, n); for row = 1:n seen(:) = false; if (! visit_row (row)) possible = false; mapping = zeros (1, n); return; endif endfor mapping = zeros (1, n); for col = 1:n if (matched_column(col) == 0) possible = false; return; endif mapping(matched_column(col)) = col; endfor possible = true; function found = visit_row (row) found = false; for col = 1:n if (costs(row, col) <= threshold && ! seen(col)) seen(col) = true; if (matched_column(col) == 0 || visit_row (matched_column(col))) matched_column(col) = row; found = true; return; endif endif endfor endfunction endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_companion_min_bits.m0000644000230300031750000000057315274353472030005 0ustar rafaelrafael% Conservative sufficient precision for exact companion coefficients. function minimum = nes_companion_min_bits (n) if (! (isnumeric (n) && isscalar (n) && isreal (n) && isfinite (n) && n == fix (n) && n >= 1)) error ("NEIG:CompanionArguments", "companion degree must be a positive integer"); endif minimum = n * nes_ceil_log2_integer (n + 1) + 2; endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/private/nes_hadamard_run.m0000644000230300031750000001137315274353472026563 0ustar rafaelrafael% Run the NEIG03 Hadamard experiment at one work precision and mode. function row = nes_hadamard_run (parameters, work_bits, mode, model_q, reference, native) if (nargin != 6 || ! isstruct (parameters) || ! isstruct (reference) || ! ischar (mode) || ! islogical (native) || ! isscalar (native)) error ("NEIG:RunArguments", "invalid Hadamard run arguments"); endif if (! any (strcmp (mode, {"balance", "nobalance"}))) error ("NEIG:RunMode", "eig mode must be balance or nobalance"); endif n = parameters.n; q = reference.reference_bits; model = model_q; if (native) built = nes_build ("hadamard", parameters, q); actual = built.native_A; source_bits = 53; input_precision = "native-binary64"; else built = nes_build ("hadamard", parameters, work_bits); actual = built.A; source_bits = work_bits; input_precision = "mp"; endif actual_q = nes_promote (actual, q, source_bits); input_error = norm (actual_q - model, "fro"); model_norm = norm (model, "fro"); if (model_norm == mp ("0")) error ("NEIG:RunModel", "Hadamard model norm is zero"); endif input_error_relative = input_error / model_norm; solver_status = "success"; solver_error = ''; solver_time = NaN; saved_bits = mpbits (); try if (! native) mpbits (work_bits); endif started = tic (); if (native) [vectors, diagonal, left_vectors] = eig (actual, mode); else [vectors, diagonal, left_vectors] = eig (actual, mode); endif solver_time = toc (started); catch exception solver_status = "error"; solver_error = exception.message; end_try_catch mpbits (saved_bits); row = struct ("schema", "neig-v1", "family", "hadamard", ... "representation", "hadamard_similar", "n", n, ... "s", parameters.s, "backend", ternary (native, "native", "mpfr"), ... "work_bits", work_bits, "evaluation_bits", q, ... "reference_bits", reference.reference_bits, "mode", mode, ... "input_precision", input_precision, "native", native, ... "solver_status", solver_status, "solver_error", solver_error, ... "solver_time", solver_time, "input_error", input_error, ... "input_error_relative", input_error_relative, ... "accuracy_status", "not_targeted", "reference_status", ... reference.reference_status, "condition_status", "unresolved", ... "max_imaginary", mp ("NaN"), "absolute_error", mp ("NaN"), ... "relative_error", mp ("NaN"), "right_residual", mp ("NaN"), ... "left_residual", mp ("NaN"), "right_column_residual", mp ("NaN"), ... "left_column_residual", mp ("NaN"), "condition_estimates", ... mp ("NaN"), "vector_condition", mp ("NaN"), ... "condition_disagreement", mp ("NaN"), "absolute_mapping", [], ... "relative_mapping", [], "computed_values", [], ... "reference_values", reference.eigenvalues); if (! strcmp (solver_status, "success")) return; endif if (native) vectors_q = nes_promote (vectors, q, 53); diagonal_q = nes_promote (diagonal, q, 53); left_vectors_q = nes_promote (left_vectors, q, 53); else vectors_q = nes_promote (vectors, q, work_bits); diagonal_q = nes_promote (diagonal, q, work_bits); left_vectors_q = nes_promote (left_vectors, q, work_bits); endif metrics = nes_metrics (actual_q, vectors_q, diagonal_q, left_vectors_q, ... reference.eigenvalues); values = metrics.values; absolute_mapping = metrics.absolute_match.mapping; relative_mapping = metrics.relative_match.mapping; disagreement = mp (zeros (n, 1)); for j = 1:n target = reference.condition_numbers(absolute_mapping(j)); disagreement(j) = abs (metrics.condition_estimates(j) - target) / target; endfor row.accuracy_status = "meets_target"; row.condition_status = metrics.condition_status; row.max_imaginary = max (abs (imag (values))); row.absolute_error = metrics.absolute_match.threshold; row.relative_error = metrics.relative_match.threshold; row.right_residual = metrics.right_residual; row.left_residual = metrics.left_residual; row.right_column_residual = metrics.right_column_residual; row.left_column_residual = metrics.left_column_residual; row.condition_estimates = metrics.condition_estimates; row.vector_condition = metrics.vector_condition; row.condition_disagreement = max (disagreement); row.absolute_mapping = absolute_mapping; row.relative_mapping = relative_mapping; row.computed_values = values; endfunction function answer = ternary (condition, if_true, if_false) if (condition) answer = if_true; else answer = if_false; endif endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/mp_eig_suite_selftest.m0000644000230300031750000003006615274353472026201 0ustar rafaelrafael% Focused NEIG self-tests; this function uses only the public mp interface. function mp_eig_suite_selftest () helper_dir = fileparts (mfilename ("fullpath")); addpath (helper_dir); saved_bits = mpbits (); unwind_protect mpbits (256); fixture = nes_build ("hadamard", struct ("n", 8, "s", 16), 256); H = fixture.H; assert (double (norm (H * transpose (H) - 8 * eye (8), "fro")) == 0); assert (double (norm (tril (fixture.A, -1), "fro")) > 0); assert (double (norm (triu (fixture.A, 1), "fro")) > 0); assert (double (norm (fixture.A - transpose (fixture.A), "fro")) > 0); native_as_mp = mp (fixture.native_A); assert (double (norm (native_as_mp - fixture.A, "fro")) == 0); reference = nes_reference ("hadamard", struct ("n", 8, "s", 16), 512); assert (double (norm (reference.eigenvalues - mp (transpose (1:8)), "fro")) == 0); before = fixture.A; mpbits (1024); promoted = nes_promote (fixture.A, 1024, 256); assert (double (norm (promoted - fixture.A, "fro")) == 0); assert (double (norm (fixture.A - before, "fro")) == 0); for setting_index = 1:2 if (setting_index == 1) setting = [1024, 700]; else setting = [2048, 1500]; endif mpbits (setting(1)); tiny = mp ("1"); for k = 1:setting(2) tiny = tiny * mp ("0.5"); endfor widened = nes_promote (tiny, setting(1), setting(1)); assert (! strcmp (char (widened), "0")); endfor small_reference = nes_reference ("hadamard", struct ("n", 2, "s", 1), 512); assert (double (small_reference.condition_numbers(1)) == sqrt (2)); assert (double (small_reference.condition_numbers(2)) == sqrt (2)); frank5 = nes_build ("frank", struct ("n", 5), 512); expected_frank5 = mp ([5, 4, 3, 2, 1; 4, 4, 3, 2, 1; ... 0, 3, 3, 2, 1; 0, 0, 2, 2, 1; ... 0, 0, 0, 1, 1]); assert (double (norm (frank5.A - expected_frank5, "fro")) == 0); expected_coefficients = {[1, -3, 1], [1, -6, 6, -1], ... [1, -10, 21, -10, 1], ... [1, -15, 55, -55, 15, -1]}; for degree = 2:5 coefficients = nes_frank_characteristic_coefficients (degree, 512); assert (double (norm (coefficients - mp (expected_coefficients{degree - 1}))) == 0); for x = -1:6 polynomial_value = mp ("0"); for coefficient = 1:(degree + 1) polynomial_value = polynomial_value * mp (x) + coefficients(coefficient); endfor matrix = nes_build ("frank", struct ("n", degree), 512).A; determinant = nes_exact_small_determinant (mp (x) * mp (eye (degree)) - matrix); assert (polynomial_value == determinant); endfor endfor frank_reference = nes_reference ("frank", struct ("n", 8), 640, 512); assert (strcmp (frank_reference.reference_status, "evaluated_consistent")); assert (isreal (frank_reference.eigenvalues)); assert (all (isfinite (frank_reference.eigenvalues))); for j = 1:4 assert (abs (frank_reference.eigenvalues(j) ... * frank_reference.eigenvalues(9 - j) - mp ("1")) < mp ("1e-150")); endfor odd_reference = nes_reference ("frank", struct ("n", 7), 640, 512); assert (abs (odd_reference.eigenvalues(4) - mp ("1")) < mp ("1e-150")); companion4 = nes_companion_coefficients (4, 512); assert (double (norm (companion4 - mp ([1, -10, 35, -50, 24]))) == 0); for degree = [10, 20] low_coefficients = nes_companion_coefficients (degree, 128); high_coefficients = nes_companion_coefficients (degree, 512); widened_coefficients = nes_promote (low_coefficients, 512, 128); assert (double (norm (widened_coefficients - high_coefficients)) == 0); q_check = 2 * degree * nes_ceil_log2_integer (degree + 1) + 32; check_coefficients = nes_companion_coefficients (degree, q_check); for root = 1:degree polynomial_value = mp ("0"); for coefficient = 1:(degree + 1) polynomial_value = polynomial_value * mp (root) ... + check_coefficients(coefficient); endfor assert (polynomial_value == mp ("0")); endfor endfor exact20 = nes_companion_coefficients (20, 512); native20 = mp (poly (1:20)); assert (double (norm (native20 - exact20)) > 0); saved_for_guard = mpbits (); caught = false; try nes_companion_coefficients (20, nes_companion_min_bits (20) - 1); catch caught = true; end_try_catch assert (caught && mpbits () == saved_for_guard); companion_fixture = nes_build ("companion", struct ("n", 20), 512); native_fixture_q = nes_promote (companion_fixture.native_A, 768, 53); exact_fixture_q = nes_promote (companion_fixture.A, 768, 512); assert (norm (native_fixture_q - exact_fixture_q, "fro") > mp ("0")); for representation = {"original", "explicitly_scaled"} forsythe_parameters = struct ("n", 8, "a", 4, ... "representation", representation{1}); forsythe_fixture = nes_build ("forsythe", forsythe_parameters, 512); assert (strcmp (forsythe_fixture.representation, representation{1})); assert (forsythe_fixture.epsilon == mp ("2")^(-32)); assert (forsythe_fixture.radius == mp ("2")^(-4)); assert (all (isfinite (forsythe_fixture.A))); if (strcmp (representation{1}, "original")) assert (norm (forsythe_fixture.A * forsythe_fixture.A' ... - forsythe_fixture.A' * forsythe_fixture.A, "fro") > mp ("0")); else assert (norm (forsythe_fixture.A * forsythe_fixture.A' ... - forsythe_fixture.A' * forsythe_fixture.A, "fro") == mp ("0")); endif endfor original_forsythe = nes_build ("forsythe", ... struct ("n", 8, "a", 4, ... "representation", "original"), 512); scaled_forsythe = nes_build ("forsythe", ... struct ("n", 8, "a", 4, ... "representation", "explicitly_scaled"), 512); assert (norm (original_forsythe.A * original_forsythe.scaling ... - original_forsythe.scaling * scaled_forsythe.A, "fro") == mp ("0")); forsythe_even_reference = nes_reference ("forsythe", ... struct ("n", 8, "a", 4, ... "representation", "original"), ... 640, 512); assert (strcmp (forsythe_even_reference.reference_status, ... "evaluated_consistent")); assert (all (isfinite (forsythe_even_reference.eigenvalues))); assert (all (abs (abs (forsythe_even_reference.unit_roots)) ... - mp ("1") < mp ("1e-150"))); assert (abs (forsythe_even_reference.eigenvalues(1) ... - (mp ("1") + mp ("2")^(-4))) < mp ("1e-150")); assert (abs (forsythe_even_reference.eigenvalues(5) ... - (mp ("1") - mp ("2")^(-4))) < mp ("1e-150")); forsythe_odd_reference = nes_reference ("forsythe", ... struct ("n", 7, "a", 4, ... "representation", "original"), ... 640, 512); assert (abs (forsythe_odd_reference.eigenvalues(1) ... - (mp ("1") + mp ("2")^(-4))) < mp ("1e-150")); assert (abs (forsythe_odd_reference.eigenvalues(2) ... - conj (forsythe_odd_reference.eigenvalues(7))) < mp ("1e-150")); high_a_forsythe = nes_build ("forsythe", ... struct ("n", 20, "a", 80, ... "representation", "original"), 2048); assert (high_a_forsythe.epsilon > mp ("0")); assert (high_a_forsythe.native_underflow); high_a_scaled = nes_build ("forsythe", ... struct ("n", 20, "a", 80, ... "representation", "explicitly_scaled"), 2048); assert (high_a_scaled.A(1, 2) == mp ("2")^(-80)); one = mp ("1"); match = nes_match (mp ([3; 1; 2]), mp ([1; 2; 3]), "absolute"); assert (double (match.threshold) == 0); assert (match.mapping, [3, 1, 2]); duplicate = nes_match (mp ([0; 0; 2]), mp ([0; 1; 2]), "absolute"); assert (double (duplicate.threshold) == 1); augment = nes_match (mp ([2; 0]), mp ([1; 3]), "absolute"); assert (double (augment.threshold) == 1); circle_reference = mp (zeros (1, 4)); circle_reference(1) = mp ("1", "0"); circle_reference(2) = mp ("0", "1"); circle_reference(3) = mp ("-1", "0"); circle_reference(4) = mp ("0", "-1"); circle_computed = circle_reference([3, 1, 4, 2]); circle_match = nes_match (circle_computed, circle_reference, "circle", ... mp ("0"), one); assert (double (circle_match.threshold) == 0); for setting_index = 1:2 if (setting_index == 1) precision = 1024; exponent = 700; else precision = 2048; exponent = 1500; endif mpbits (precision); tiny = mp ("1"); for k = 1:exponent, tiny = tiny * mp ("0.5"); endfor near = mp (zeros (2, 1)); near(1) = mp ("0"); near(2) = tiny; tiny_match = nes_match (near, mp (zeros (2, 1)), "absolute"); assert (tiny_match.threshold == tiny); endfor mpbits (512); rotation = mp ([0, 1; -1, 0]); [V, D, W] = eig (rotation, "nobalance"); values = nes_promote (diag (D), 768, 512); metrics = nes_metrics (nes_promote (rotation, 768, 512), ... nes_promote (V, 768, 512), ... nes_promote (D, 768, 512), ... nes_promote (W, 768, 512), values); assert (metrics.right_residual < mp ("1e-200")); assert (metrics.left_residual < mp ("1e-200")); scaled_metrics = nes_metrics (nes_promote (rotation, 768, 512), ... nes_promote (V * mp ("2"), 768, 512), ... nes_promote (D, 768, 512), ... nes_promote (W * mp ("3"), 768, 512), values); assert (norm (metrics.condition_estimates ... - scaled_metrics.condition_estimates) < mp ("1e-200")); W_bad = W(:, [2, 1]); bad_metrics = nes_metrics (nes_promote (rotation, 768, 512), ... nes_promote (V, 768, 512), ... nes_promote (D, 768, 512), ... nes_promote (W_bad, 768, 512), values); assert (bad_metrics.left_residual > mp ("1e-5")); V_bad = V; V_bad(1, 1) = V_bad(1, 1) + mp ("1e-3"); perturbed_metrics = nes_metrics (nes_promote (rotation, 768, 512), ... nes_promote (V_bad, 768, 512), ... nes_promote (D, 768, 512), ... nes_promote (W, 768, 512), values); assert (perturbed_metrics.right_residual > mp ("1e-6")); exhaustive_values = mp (transpose (1:6)); permutations = perms (1:6); for permutation_row = 1:rows (permutations) candidate = exhaustive_values(permutations(permutation_row, :)); exhaustive_match = nes_match (candidate, exhaustive_values, "absolute"); assert (exhaustive_match.threshold == mp ("0")); endfor caught = false; try nes_match (mp (zeros (0, 1)), mp (zeros (0, 1)), "absolute"); catch caught = true; end_try_catch assert (caught); caught = false; try nes_match (mp ([0; 1]), mp ([0; 0]), "relative"); catch caught = true; end_try_catch assert (caught); caught = false; try nes_match (mp ([NaN; 1]), mp ([0; 1]), "absolute"); catch caught = true; end_try_catch assert (caught); mpbits (333); assert (mpbits () == uint64 (333)); assert (mpbits () == uint64 (333)); fprintf ("PASS: NEIG06 Forsythe constructors, references, and precision isolation\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/nonsymmetric_eig/mp_eig_suite.m0000644000230300031750000002134115274353472024264 0ustar rafaelrafael% Entry point for the repository-local difficult nonsymmetric eigensystem suite. function results = mp_eig_suite (profile, options) if (nargin < 1) profile = "smoke"; endif if (nargin > 2) error ("NEIG:Arguments", "mp_eig_suite accepts a profile and optional options"); endif if (! ischar (profile) || rows (profile) != 1) error ("NEIG:Profile", "profile must be a character row"); endif if (! any (strcmp (profile, {"smoke", "demo", "stress"}))) error ("NEIG:Profile", "profile must be smoke, demo, or stress"); endif defaults = struct ("output_dir", '', "plot", false, "family", "all"); if (nargin == 1) options = defaults; elseif (! isstruct (options) || ! isscalar (options)) error ("NEIG:Options", "options must be a scalar struct"); else names = fieldnames (options); for k = 1:numel (names) if (! isfield (defaults, names{k})) error ("NEIG:Options", "unknown option name: %s", names{k}); endif endfor options = merge_options (defaults, options); endif if (! (ischar (options.output_dir) && (isempty (options.output_dir) || rows (options.output_dir) == 1))) error ("NEIG:Options", "output_dir must be a character row"); endif if (! (islogical (options.plot) && isscalar (options.plot))) error ("NEIG:Options", "plot must be a logical scalar"); endif if (! ischar (options.family) || rows (options.family) != 1) error ("NEIG:Options", "family must be a character row"); endif if (! any (strcmp (options.family, {"all", "hadamard", "frank", ... "companion", "forsythe"}))) error ("NEIG:Options", "unknown family: %s", options.family); endif selected = nes_cases (profile, options.family); if (strcmp (profile, "smoke")) work_precisions = [128, 256]; elseif (strcmp (profile, "demo")) work_precisions = [128, 256, 512]; else work_precisions = [256, 512, 1024, 2048]; endif pmax = max (work_precisions); q0 = max (512, pmax + 128); q = q0 + 128; rows_out = struct ([]); ok = true; for case_index = 1:numel (selected) parameters = selected(case_index); reference = nes_reference (parameters.family, parameters, q, q0); model = nes_build (parameters.family, parameters, q).A; for mode_index = 1:2 mode = {"balance", "nobalance"}{mode_index}; native_row = run_case (parameters, 53, mode, model, reference, true); native_row = normalize_row (native_row); rows_out(end + 1) = native_row; for precision_index = 1:numel (work_precisions) work_bits = work_precisions(precision_index); row = run_case (parameters, work_bits, mode, model, reference, false); row = normalize_row (row); rows_out(end + 1) = row; [row_ok, row] = check_row (row, profile, work_bits, q); if (! row_ok) ok = false; endif rows_out(end) = row; endfor endfor endfor results = struct ("schema", "neig-v1", "profile", profile, ... "family", options.family, "options", options, ... "cases", selected, "work_precisions", work_precisions, ... "q0", q0, "evaluation_bits", q, "rows", rows_out, ... "ok", ok, "status", ternary (ok, "PASS", "FAIL")); if (! isempty (options.output_dir)) results.output = nes_write (results, options.output_dir); else results.output = struct ("summary", "", "eigenvalues", "", ... "environment", "", "report", ""); endif endfunction function row = normalize_row (row) common = struct ("schema", "neig-v1", "family", "", "representation", ... "", "n", NaN, "a", NaN, "s", NaN, "backend", "", ... "work_bits", NaN, "evaluation_bits", NaN, ... "reference_bits", NaN, "low_reference_bits", NaN, ... "reference_agreement", mp ("NaN"), ... "reference_agreement_limit", mp ("NaN"), "mode", "", ... "input_precision", "", "native", false, ... "native_underflow", false, "minimum_coefficient_bits", NaN, ... "solver_status", "", "solver_error", "", ... "solver_time", NaN, "input_error", mp ("NaN"), ... "input_error_relative", mp ("NaN"), ... "accuracy_status", "", "reference_status", "", ... "condition_status", "", "max_imaginary", mp ("NaN"), ... "absolute_error", mp ("NaN"), "relative_error", mp ("NaN"), ... "circle_error", mp ("NaN"), "right_residual", mp ("NaN"), ... "left_residual", mp ("NaN"), ... "right_column_residual", mp ("NaN"), ... "left_column_residual", mp ("NaN"), ... "condition_estimates", mp ("NaN"), ... "vector_condition", mp ("NaN"), ... "condition_disagreement", mp ("NaN"), ... "absolute_mapping", [], "relative_mapping", [], ... "circle_mapping", [], "computed_values", [], ... "reference_values", []); names = fieldnames (common); for k = 1:numel (names) if (isfield (row, names{k})) common.(names{k}) = row.(names{k}); endif endfor row = common; endfunction function row = run_case (parameters, work_bits, mode, model, reference, native) switch parameters.family case "hadamard" row = nes_hadamard_run (parameters, work_bits, mode, model, reference, native); case "frank" row = nes_frank_run (parameters, work_bits, mode, model, reference, native); case "companion" row = nes_companion_run (parameters, work_bits, mode, model, reference, native); case "forsythe" row = nes_forsythe_run (parameters, work_bits, mode, model, reference, native); otherwise error ("NEIG:Family", "unsupported family: %s", parameters.family); endswitch endfunction function [ok, row] = check_row (row, profile, work_bits, q) ok = true; if (strcmp (row.solver_status, "error") ... || strcmp (row.reference_status, "unresolved") ... || row.right_residual > residual_tolerance (row.n, work_bits, q) ... || row.left_residual > residual_tolerance (row.n, work_bits, q)) ok = false; endif target = mp ("NaN"); metric_name = "absolute_error"; family = row.family; if (strcmp (family, "hadamard")) if (strcmp (profile, "smoke") && work_bits == 256) target = negative_power_of_two (120, q); elseif (strcmp (profile, "demo") && work_bits == 256) target = negative_power_of_two (100, q); elseif (strcmp (profile, "demo") && work_bits == 512) target = negative_power_of_two (300, q); endif if (strcmp (profile, "demo") && work_bits == 512 && row.condition_disagreement > negative_power_of_two (80, q)) ok = false; endif elseif (strcmp (family, "frank")) metric_name = "relative_error"; if (strcmp (profile, "smoke") && work_bits == 256) target = negative_power_of_two (120, q); elseif (strcmp (profile, "demo") && work_bits == 512) target = negative_power_of_two (200, q); endif elseif (strcmp (family, "companion")) if (strcmp (profile, "smoke") && work_bits == 256) target = negative_power_of_two (120, q); elseif (strcmp (profile, "demo") && work_bits == 512) target = negative_power_of_two (200, q); endif elseif (strcmp (family, "forsythe")) if (strcmp (profile, "smoke") && work_bits == 256) target = negative_power_of_two (120, q); elseif (strcmp (profile, "demo") && work_bits == 512) if (strcmp (row.representation, "original")) target = negative_power_of_two (64, q); else target = negative_power_of_two (200, q); endif endif metric_name = "circle_error"; endif if (! isnan (target)) if (row.(metric_name) > target) ok = false; row.accuracy_status = "failed"; else row.accuracy_status = "meets_target"; endif endif endfunction function result = residual_tolerance (n, work_bits, q) result = mp ("65536") * mp (n * n) * negative_power_of_two (work_bits, q); endfunction function result = negative_power_of_two (exponent, bits) saved_bits = mpbits (); unwind_protect mpbits (bits); result = mp ("1"); half = mp ("0.5"); for k = 1:exponent result = result * half; endfor unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = ternary (condition, if_true, if_false) if (condition), result = if_true; else, result = if_false; endif endfunction function result = merge_options (defaults, supplied) result = defaults; names = fieldnames (supplied); for k = 1:numel (names) result.(names{k}) = supplied.(names{k}); endfor endfunction mplapack-interop-0.5.1/examples/18_complex_log2.m0000644000230300031750000000046015274353472021141 0ustar rafaelrafael## Demonstrate the native arbitrary-precision complex log2 path. ## ## The complex operation is routed through the gmpfrxx MPC compatibility ## wrapper and does not require a direct mpc_log2 symbol. mpbits (256); z = mp ("1", "2"); w = log2 (z); assert (isa (w, "mp")); assert (! isreal (w)); disp (w); mplapack-interop-0.5.1/examples/14_neig_tier_s.m0000644000230300031750000000632415274353472021037 0ustar rafaelrafael% NEIGT Tier-S case index. % % This short numbered entry point preserves the historical family entry. % It lists one runnable example per manifest case. The full measured wall is % run by mp_neig_tiers ("smoke"/"demo") and by the repository test suite. % % Question: Which nonsymmetric eigensystem cases belong to Tier-S, and where is the % detailed interpretation for each one? % Steps: inspect the list, then run any matching .m file directly. % Matching documentation: docs/examples/tiered/README.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (mfilename ("fullpath")); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); repo_root = fileparts (fileparts (mfilename ("fullpath"))); case_ids = { "OO53_REAL"; ... "OO53_PAIR"; ... "OO128_CLOSE"; ... "SIM_SIMPLE"; ... "SIM_REPEAT"; ... "SIM_JORDAN"; ... "SIM_TWO_JORDAN"; ... "TOEPLITZ"; ... "TOEPLITZ_SYM"; ... "FORSYTHE"; ... "FORSYTHE_SCALED"; ... "FORSYTHE_ZERO" }; case_examples = { "examples/tiered/neig-tier-s/oo53_real.m"; ... "examples/tiered/neig-tier-s/oo53_pair.m"; ... "examples/tiered/neig-tier-s/oo128_close.m"; ... "examples/tiered/neig-tier-s/sim_simple.m"; ... "examples/tiered/neig-tier-s/sim_repeat.m"; ... "examples/tiered/neig-tier-s/sim_jordan.m"; ... "examples/tiered/neig-tier-s/sim_two_jordan.m"; ... "examples/tiered/neig-tier-s/toeplitz.m"; ... "examples/tiered/neig-tier-s/toeplitz_sym.m"; ... "examples/tiered/neig-tier-s/forsythe.m"; ... "examples/tiered/neig-tier-s/forsythe_scaled.m"; ... "examples/tiered/neig-tier-s/forsythe_zero.m" }; case_docs = { "docs/examples/tiered/neig-tier-s/oo53_real.md"; ... "docs/examples/tiered/neig-tier-s/oo53_pair.md"; ... "docs/examples/tiered/neig-tier-s/oo128_close.md"; ... "docs/examples/tiered/neig-tier-s/sim_simple.md"; ... "docs/examples/tiered/neig-tier-s/sim_repeat.md"; ... "docs/examples/tiered/neig-tier-s/sim_jordan.md"; ... "docs/examples/tiered/neig-tier-s/sim_two_jordan.md"; ... "docs/examples/tiered/neig-tier-s/toeplitz.md"; ... "docs/examples/tiered/neig-tier-s/toeplitz_sym.md"; ... "docs/examples/tiered/neig-tier-s/forsythe.md"; ... "docs/examples/tiered/neig-tier-s/forsythe_scaled.md"; ... "docs/examples/tiered/neig-tier-s/forsythe_zero.md" }; assert (numel (case_ids) == numel (case_examples)); assert (numel (case_ids) == numel (case_docs)); for case_index = 1:numel (case_ids) assert (exist (fullfile (repo_root, case_examples{case_index}), "file") == 2); assert (exist (fullfile (repo_root, case_docs{case_index}), "file") == 2); fprintf ("%s\t%s\t%s\n", case_ids{case_index}, case_examples{case_index}, case_docs{case_index}); endfor fprintf ("NEIGT Tier-S index: %d cases.\n", numel (case_ids)); % Preserve the historical full-profile aggregator contract. The split files % above are the teaching surface; this call remains the counted regression. result = mp_neig_tiers ("smoke", struct ("tier", "S", "plot", false)); assert (result.scope_ok); assert (strcmp (result.status, "NUMERICS_COMPLETE")); fprintf ("NEIGT Tier-S smoke PASS: %d measured rows.\n", ... result.coverage.measured_eig_rows); clear cleanup_path; mplapack-interop-0.5.1/examples/14_svd_tier_s.m0000644000230300031750000000534515274353472020713 0ustar rafaelrafael% SVT Tier-S case index. % % This short numbered entry point preserves the historical family entry. % It lists one runnable example per manifest case. The full measured wall is % run by mp_svd_tiers ("smoke"/"demo") and by the repository test suite. % % Question: Which singular-value cases belong to Tier-S, and where is the % detailed interpretation for each one? % Steps: inspect the list, then run any matching .m file directly. % Matching documentation: docs/examples/tiered/README.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (mfilename ("fullpath")); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); repo_root = fileparts (fileparts (mfilename ("fullpath"))); case_ids = { "S1-NRO-TWO"; ... "S1-NRO-THREE"; ... "S1-NRO-GRADED"; ... "S1-NRO-SCALE-UP"; ... "S1-NRO-SCALE-DOWN"; ... "S2-JS"; ... "S3-LAH"; ... "S4-DD-SYM"; ... "S4-DD-NONSYM" }; case_examples = { "examples/tiered/svd-tier-s/nro_two.m"; ... "examples/tiered/svd-tier-s/nro_three.m"; ... "examples/tiered/svd-tier-s/nro_graded.m"; ... "examples/tiered/svd-tier-s/nro_scale_up.m"; ... "examples/tiered/svd-tier-s/nro_scale_down.m"; ... "examples/tiered/svd-tier-s/jacobi_stirling.m"; ... "examples/tiered/svd-tier-s/lah.m"; ... "examples/tiered/svd-tier-s/dd_sym.m"; ... "examples/tiered/svd-tier-s/dd_nonsym.m" }; case_docs = { "docs/examples/tiered/svd-tier-s/nro_two.md"; ... "docs/examples/tiered/svd-tier-s/nro_three.md"; ... "docs/examples/tiered/svd-tier-s/nro_graded.md"; ... "docs/examples/tiered/svd-tier-s/nro_scale_up.md"; ... "docs/examples/tiered/svd-tier-s/nro_scale_down.md"; ... "docs/examples/tiered/svd-tier-s/jacobi_stirling.md"; ... "docs/examples/tiered/svd-tier-s/lah.md"; ... "docs/examples/tiered/svd-tier-s/dd_sym.md"; ... "docs/examples/tiered/svd-tier-s/dd_nonsym.md" }; assert (numel (case_ids) == numel (case_examples)); assert (numel (case_ids) == numel (case_docs)); for index = 1:numel (case_ids) assert (exist (fullfile (repo_root, case_examples{index}), "file") == 2); assert (exist (fullfile (repo_root, case_docs{index}), "file") == 2); fprintf ("%s\t%s\t%s\n", case_ids{index}, case_examples{index}, case_docs{index}); endfor fprintf ("SVT Tier-S index: %d cases.\n", numel (case_ids)); % Preserve the historical full-profile aggregator contract. The split files % above are the teaching surface; this call remains the counted regression. result = mp_svd_tiers ("smoke", struct ("tier", "S", "plot", false)); assert (result.scope_ok); assert (strcmp (result.status, "PASS")); fprintf ("SVT Tier-S smoke PASS: %d measured rows.\n", ... result.measured_svd_rows); clear cleanup_path; mplapack-interop-0.5.1/examples/11_solvers_quadrature_optimization.m0000644000230300031750000000217515274353472025305 0ustar rafaelrafael% Precision-aware nonlinear solve, quadrature, and optimization. if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif saved_bits = mpbits (); unwind_protect mpbits (256); target = mp ("1.25"); options = struct ("TolX", mp ("1e-35"), "TolFun", mp ("1e-35"), ... "MaxIter", 600); [root_value, fval, info] = fzero (@(x) x * x - target * target, ... mp ({"0", "2"}), options); assert (info == 1); assert (abs (root_value - target) < mp ("1e-30")); assert (abs (fval) < mp ("1e-30")); quad_options = struct ("AbsTol", mp ("1e-25"), "RelTol", mp ("1e-25")); [value, err] = integral (@(x) x * x, mp ("0"), mp ("1"), quad_options); assert (abs (value - mp ("1") / mp ("3")) < mp ("1e-25")); assert (err < mp ("1e-25")); [argument, minimum, opt_info] = fminbnd ( ... @(x) (x - target) * (x - target), mp ("0"), mp ("2"), options); assert (opt_info == 1); assert (abs (argument - target) < mp ("1e-20")); assert (minimum < mp ("1e-35")); fprintf ("solver/quadrature/optimization PASS\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/examples/neig_tiers/0000755000230300031750000000000015274353472020211 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/neig_tiers/mp_neig_verify_examples.m0000644000230300031750000004006015274353472025267 0ustar rafaelrafael## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mp_neig_verify_examples (@var{profile}) ## @deftypefnx {} {@var{result} =} mp_neig_verify_examples (@var{profile}, @var{options}) ## Run the repository-local NEIGT verified V-S and V-A jobs. ## @var{profile} is @code{"smoke"} or @code{"demo"}; @var{options.tier} ## selects @code{"V-S"}, @code{"V-A"}, or @code{"V"}. The checker uses ## outward-safe MP arithmetic and records candidate provenance separately from ## frozen targets. A result is complete only when every selected manifest job ## and its proof preconditions pass; no native binary64 numerical fallback is ## used. Use @code{mp_neig_write_outputs} for a replayable proof artifact. ## @end deftypefn function result = mp_neig_verify_examples (profile, options) if (nargin < 1 || nargin > 2) error ("mplapack:neigt:Arguments", ... "mp_neig_verify_examples expects a profile and optional options"); endif if (nargin == 1) options = struct (); endif helper_root = fileparts (mfilename ("fullpath")); private_root = fullfile (helper_root, "private"); added = false; if (! any (strcmp (strsplit (path (), pathsep), private_root))) addpath (private_root); added = true; endif saved_bits = mpbits (); unwind_protect opts = net_options (profile, options); bundle = net_manifest (); if (strcmp (opts.profile, "stress")) jobs = struct ([]); else all_jobs = bundle.jobs.profiles.(opts.profile).jobs; if (any (strcmp (opts.tier, {"all", "V"}))) jobs = all_jobs; else keep = false (numel (all_jobs), 1); for index = 1:numel (all_jobs) keep(index) = strcmp (all_jobs{index}.tier, opts.tier); endfor jobs = all_jobs(keep); endif endif status = repmat (job_status_template (), numel (jobs), 1); for index = 1:numel (jobs) status(index).id = jobs{index}.id; if (strncmp (jobs{index}.id, "VS1-", 4)) fprintf (2, "NEIGT14: starting %s (%s)\n", jobs{index}.id, opts.profile); status(index) = run_vs1_job (jobs{index}, ... bundle.cases.profiles.(opts.profile), opts.profile); fprintf (2, "NEIGT14: finished %s status=%s pass=%d\n", ... status(index).id, status(index).status, status(index).pass); elseif (strncmp (jobs{index}.id, "VS2-", 4)) fprintf (2, "NEIGT16: starting %s (%s)\n", jobs{index}.id, opts.profile); try graph_job = net_v_s2_job (jobs{index}, ... bundle.cases.profiles.(opts.profile), opts.profile); status(index).status = graph_job.status; status(index).claim_status = graph_job.claim_status; status(index).claim_quality = graph_job.claim_quality; status(index).milestone_pass = graph_job.milestone_pass; status(index).details = graph_job; status(index).certificate = graph_job.graph; status(index).candidate_source = graph_job.candidate_source; status(index).candidate_bits = graph_job.candidate_bits; status(index).evaluation_bits = graph_job.evaluation_bits; status(index).pass = graph_job.pass; catch exception status(index).status = "FAILED_PREPARATION"; status(index).error_identifier = exception.identifier; status(index).error_message = exception.message; end_try_catch fprintf (2, "NEIGT16: finished %s status=%s milestone_pass=%d\n", ... status(index).id, status(index).status, status(index).milestone_pass); elseif (strncmp (jobs{index}.id, "VS3-", 4)) fprintf (2, "NEIGT17: starting %s (%s)\n", jobs{index}.id, opts.profile); try pseudospectrum_job = net_v_s3_job (jobs{index}, ... bundle.jobs.profiles.(opts.profile), ... opts.profile); status(index) = pseudospectrum_job; catch exception status(index).status = "FAILED_VERIFIER"; status(index).claim_status = "ERROR"; status(index).error_identifier = exception.identifier; status(index).error_message = exception.message; end_try_catch fprintf (2, "NEIGT17: finished %s status=%s milestone_pass=%d\n", ... status(index).id, status(index).status, status(index).milestone_pass); elseif (strncmp (jobs{index}.id, "VA1-", 4)) fprintf (2, "NEIGT18: starting %s (%s)\n", jobs{index}.id, opts.profile); try factor_job = net_v_a1_schur_job (jobs{index}, ... bundle.jobs.profiles.(opts.profile), ... opts.profile); status(index) = factor_job; catch exception status(index).status = "FAILED_VERIFIER"; status(index).claim_status = "ERROR"; status(index).error_identifier = exception.identifier; status(index).error_message = exception.message; end_try_catch fprintf (2, "NEIGT18: finished %s status=%s milestone_pass=%d\n", ... status(index).id, status(index).status, status(index).milestone_pass); elseif (strncmp (jobs{index}.id, "VA2-", 4)) fprintf (2, "NEIGT20: starting %s (%s)\n", jobs{index}.id, opts.profile); try pencil_job = net_v_a2_job (jobs{index}, ... bundle.jobs.profiles.(opts.profile), ... opts.profile); status(index).status = pencil_job.status; status(index).claim_status = pencil_job.claim_status; status(index).claim_quality = pencil_job.claim_quality; status(index).milestone_pass = pencil_job.milestone_pass; status(index).details = pencil_job; status(index).certificate = pencil_job.finite_certificate; status(index).candidate_source = pencil_job.candidate_source; status(index).candidate_bits = pencil_job.candidate_bits; status(index).evaluation_bits = pencil_job.evaluation_bits; status(index).raw_V_hash = pencil_job.raw_V_hash; status(index).raw_D_hash = pencil_job.raw_D_hash; status(index).raw_W_hash = pencil_job.raw_W_hash; status(index).input_hash = pencil_job.input_hash_A; status(index).source = pencil_job.source; status(index).input_status = pencil_job.input_status; status(index).raw_V = pencil_job.raw_V; status(index).raw_D = pencil_job.raw_D; status(index).raw_W = pencil_job.raw_Wc; status(index).pass = pencil_job.pass; catch exception status(index).status = "FAILED_VERIFIER"; status(index).claim_status = "ERROR"; status(index).error_identifier = exception.identifier; status(index).error_message = exception.message; end_try_catch fprintf (2, "NEIGT20: finished %s status=%s milestone_pass=%d\n", ... status(index).id, status(index).status, status(index).milestone_pass); elseif (strncmp (jobs{index}.id, "VA3-", 4)) fprintf (2, "NEIGT21: starting %s (%s)\n", jobs{index}.id, opts.profile); try perron_job = net_v_a3_job (jobs{index}, ... bundle.jobs.profiles.(opts.profile), ... opts.profile); status(index).status = perron_job.status; status(index).claim_status = perron_job.claim_status; status(index).claim_quality = perron_job.claim_quality; status(index).milestone_pass = perron_job.milestone_pass; status(index).details = perron_job; status(index).certificate = perron_job.pair; status(index).candidate_source = perron_job.candidate_source; status(index).candidate_bits = perron_job.candidate_bits; status(index).evaluation_bits = perron_job.evaluation_bits; status(index).raw_V_hash = perron_job.raw_V_hash; status(index).raw_D_hash = perron_job.raw_D_hash; status(index).raw_W_hash = perron_job.raw_W_hash; status(index).input_hash = perron_job.input_hash; status(index).source = perron_job.source; status(index).input_status = perron_job.input_status; status(index).raw_V = perron_job.raw_V; status(index).raw_D = perron_job.raw_D; status(index).raw_W = perron_job.raw_W; status(index).pass = perron_job.pass; catch exception status(index).status = "FAILED_VERIFIER"; status(index).claim_status = "ERROR"; status(index).error_identifier = exception.identifier; status(index).error_message = exception.message; end_try_catch fprintf (2, "NEIGT21: finished %s status=%s milestone_pass=%d\n", ... status(index).id, status(index).status, status(index).milestone_pass); endif endfor vs1 = status(starts_with ({status.id}, "VS1-")); vs2_active = active_vs2 ({status.id}); implemented = sum (starts_with ({status.id}, "VS1-")) ... + sum (vs2_active) + sum (active_prefix ({status.id}, "VS3-")); vs1_complete = ! isempty (vs1) && all ([vs1.pass]); vs2 = status(vs2_active); vs2_milestone_complete = ! isempty (vs2) ... && all ([vs2.milestone_pass]); vs3_active = active_prefix ({status.id}, "VS3-"); vs3 = status(vs3_active); vs3_complete = ! isempty (vs3) && all ([vs3.milestone_pass]); va1_active = active_prefix ({status.id}, "VA1-"); va1 = status(va1_active); va1_complete = ! isempty (va1) && all ([va1.pass]); implemented += sum (va1_active); va2_active = active_prefix ({status.id}, "VA2-"); va2 = status(va2_active); va2_complete = ! isempty (va2) && all ([va2.pass]); implemented += sum (va2_active); va3_active = active_prefix ({status.id}, "VA3-"); va3 = status(va3_active); va3_complete = ! isempty (va3) && all ([va3.pass]); implemented += sum (va3_active); selected_complete = ! isempty (status) && all ([status.pass]); if (isempty (status)) overall_status = "NOT_APPLICABLE"; elseif (selected_complete) overall_status = "COMPLETE"; else overall_status = "PARTIAL_NOT_IMPLEMENTED"; endif result = struct ("schema", "neigt-v1", "profile", opts.profile, ... "tier", opts.tier, "status", overall_status, ... "ok", selected_complete, "scope_ok", true, "jobs", status, ... "coverage", struct ("verification_job_count", numel (jobs), ... "expected_all_verification_job_count", 26, ... "verification_jobs_implemented", implemented, ... "vs1_job_count", numel (vs1), ... "vs1_complete", vs1_complete, ... "vs2_invariant_job_count", sum (vs2_active), ... "vs2_invariant_complete", vs2_milestone_complete, ... "vs3_job_count", sum (vs3_active), ... "vs3_complete", vs3_complete, ... "va1_job_count", sum (va1_active), ... "va1_complete", va1_complete, ... "va2_job_count", sum (va2_active), ... "va2_complete", va2_complete, ... "va3_job_count", sum (va3_active), ... "va3_complete", va3_complete), ... "manifest", struct ("cases", bundle.cases_path, ... "verification_jobs", bundle.jobs_path), ... "options", opts, "source", "NEIGT17_VS3_SVD_POLAR_WEYL_V1"); if (added) rmpath (private_root); endif unwind_protect_cleanup mpbits (saved_bits); if (added && any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect endfunction function result = job_status_template () result = struct ("id", "", "tier", "", "kind", "", ... "status", "NOT_IMPLEMENTED", "pass", false, "milestone_pass", false, ... "claim_status", "", "claim_quality", "", "details", [], ... "candidate_source", "", ... "candidate_bits", NaN, "evaluation_bits", NaN, "raw_V_hash", "", ... "raw_D_hash", "", "raw_W_hash", "", "certificate", [], ... "raw_B_hash", "", "raw_U_hash", "", "raw_s_hash", "", ... "raw_lambda_hash", "", ... "input_hash", "", "source", "", "input_status", "", "target", "", ... "raw_V", [], "raw_D", [], "raw_W", [], "error_identifier", "", ... "error_message", ""); endfunction function result = run_vs1_job (job, profile_data, profile) result = job_status_template (); result.id = job.id; result.tier = job.tier; result.kind = job.kind; result.candidate_source = job.candidate_source; result.candidate_bits = job.source_bits; result.evaluation_bits = profile_data.evaluation_bits; case_entry = find_case (profile_data.cases, job.core_case); saved_bits = mpbits (); unwind_protect try mpbits (job.source_bits); stage = tic (); model = net_case_model (case_entry, job.source_bits); fprintf (2, "NEIGT14: %s model %.3fs\n", job.id, toc (stage)); stage = tic (); [V, D, W] = eig (model.A_frozen, "nobalance"); fprintf (2, "NEIGT14: %s eig %.3fs\n", job.id, toc (stage)); result.raw_V = V; result.raw_D = D; result.raw_W = W; result.raw_V_hash = net_raw_hash (V, [job.id, "_raw_V"]); result.raw_D_hash = net_raw_hash (D, [job.id, "_raw_D"]); result.raw_W_hash = net_raw_hash (W, [job.id, "_raw_W"]); q = profile_data.evaluation_bits; mpbits (q); stage = tic (); A = net_widen (model.A_frozen, q, job.source_bits); X = net_widen (V, q, job.source_bits); T = net_widen (D, q, job.source_bits); fprintf (2, "NEIGT14: %s widen %.3fs\n", job.id, toc (stage)); stage = tic (); R = X \ mp (eye (rows (X))); fprintf (2, "NEIGT14: %s inverse-candidate %.3fs\n", job.id, toc (stage)); useful_exponent = -40; if (strcmp (profile, "demo")) useful_exponent = -64; endif stage = tic (); certificate = net_v_s1_gershgorin ... (A, X, T, R, q, useful_exponent); fprintf (2, "NEIGT14: %s interval-certificate %.3fs\n", ... job.id, toc (stage)); result.certificate = certificate; result.status = certificate.status; result.pass = strcmp (certificate.status, "CERTIFIED_ALL") ... && certificate.all_roots && certificate.counted_roots == rows (A) ... && certificate.singleton_useful && certificate.useful; result.milestone_pass = result.pass; result.claim_status = certificate.status; result.claim_quality = "resolved"; result.details = certificate; if (result.pass) result.status = "PASS"; endif catch exception result.status = "FAILED_VERIFIER"; result.error_identifier = exception.identifier; result.error_message = exception.message; end_try_catch unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = find_case (cases, id) result = []; for index = 1:numel (cases) if (strcmp (cases(index).id, id)) result = cases(index); return; endif endfor error ("mplapack:neigt:Manifest", "case %s is not in the profile", id); endfunction function result = starts_with (values, prefix) result = false (size (values)); for index = 1:numel (values) result(index) = strncmp (values{index}, prefix, numel (prefix)); endfor endfunction function result = active_vs2 (values) result = active_prefix (values, "VS2-"); endfunction function result = active_prefix (values, prefix) result = false (size (values)); for index = 1:numel (values) result(index) = strncmp (values{index}, prefix, numel (prefix)); endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/mp_neig_tiers.m0000644000230300031750000003355515274353472023226 0ustar rafaelrafael## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mp_neig_tiers (@var{profile}) ## @deftypefnx {} {@var{result} =} mp_neig_tiers (@var{profile}, @var{options}) ## Run the repository-local NEIGT ordinary Tier-S or Tier-A eigensystem suite. ## @var{profile} is @code{"smoke"} or @code{"demo"}; @var{options.tier} ## selects @code{"S"}, @code{"A"}, or @code{"all"}. The measured rows use ## the existing public @code{mp}, @code{mpbits}, and @code{eig} interfaces. ## @var{options.case_id} optionally selects exactly one manifest case; this is ## used by the short case examples and does not change profile coverage. ## MP rows keep their exact model, frozen input, work precision, and returned ## eigentriples distinct; native rows are explicit binary64 controls. An ## @code{"all"} result reports @code{NUMERICS_ONLY_COMPLETE} until verification ## jobs are run by @code{mp_neig_verify_examples}. ## @end deftypefn function result = mp_neig_tiers (profile, options) if (nargin < 1 || nargin > 2) error ("mplapack:neigt:Arguments", ... "mp_neig_tiers expects a profile and optional options"); endif if (nargin == 1) options = struct (); endif helper_root = fileparts (mfilename ("fullpath")); private_root = fullfile (helper_root, "private"); added = false; if (! any (strcmp (strsplit (path (), pathsep), private_root))) addpath (private_root); added = true; endif saved_bits = mpbits (); unwind_protect opts = net_options (profile, options); bundle = net_manifest (); profile_data = bundle.cases.profiles.(opts.profile); selected = select_cases (profile_data.cases, opts.tier); if (! isempty (opts.case_id)) selected = selected(strcmp ({selected.id}, opts.case_id)); if (isempty (selected)) error ("mplapack:neigt:UnknownCase", ... "case_id %s is not in the selected profile/tier", opts.case_id); endif endif expected_rows = 2 * numel (selected) * (numel (profile_data.work_bits) + 1); if (any (strcmp (opts.tier, {"V-S", "V-A", "V"}))) selected = selected([]); expected_rows = 0; endif rows_out = cell (0, 1); references = cell (numel (selected), 1); native_models = cell (numel (selected), 1); numerical_ok = true; reference_ok = true; max_work = max (profile_data.work_bits); for case_index = 1:numel (selected) entry = selected(case_index); native_models{case_index} = net_case_model (entry, max_work); references{case_index} = net_case_reference ... (entry, profile_data.reference_bits(1), profile_data.reference_bits(2)); reference_ok = reference_ok && reference_is_valid (references{case_index}); modes = {"nobalance", "balance"}; for mode_index = 1:2 mode = modes{mode_index}; native_row = run_native_row (entry, native_models{case_index}, mode); rows_out{end + 1} = native_row; numerical_ok = numerical_ok && native_row.complete; for work_index = 1:numel (profile_data.work_bits) work_bits = profile_data.work_bits(work_index); row = run_mp_row (entry, work_bits, mode, references{case_index}, ... profile_data.reference_bits(2), ... profile_data.evaluation_bits, max_work); rows_out{end + 1} = row; numerical_ok = numerical_ok && row.complete && row.gate_pass; endfor endfor endfor expected_all = profile_data.expected_case_count; expected_all_rows = profile_data.expected_measured_eig_rows; ordinary_complete = (numel (rows_out) == expected_rows) && numerical_ok ... && reference_ok; if (strcmp (opts.tier, "all")) status = ternary (ordinary_complete, "NUMERICS_ONLY_COMPLETE", ... "NUMERICS_INCOMPLETE"); ok = false; scope_ok = true; elseif (any (strcmp (opts.tier, {"S", "A"}))) status = ternary (ordinary_complete, "NUMERICS_COMPLETE", ... "NUMERICS_INCOMPLETE"); ok = ordinary_complete; scope_ok = true; else status = "NOT_APPLICABLE"; ok = false; scope_ok = true; endif coverage = struct ("case_count", numel (selected), ... "measured_eig_rows", numel (rows_out), ... "expected_selected_case_count", numel (selected), ... "expected_selected_measured_eig_rows", expected_rows, ... "expected_all_case_count", expected_all, ... "expected_all_measured_eig_rows", expected_all_rows, ... "ordinary_cases_implemented", true, ... "ordinary_complete", ordinary_complete, ... "numerics_only_complete", ordinary_complete, ... "native_rows", 2 * numel (selected), ... "mp_rows", 2 * numel (selected) * numel (profile_data.work_bits)); result = struct ("schema", "neigt-v1", "profile", opts.profile, ... "tier", opts.tier, "status", status, "ok", ok, ... "scope_ok", scope_ok, "rows", {rows_out}, ... "references", {references}, "coverage", coverage, ... "manifest", struct ("cases", bundle.cases_path, ... "verification_jobs", bundle.jobs_path), ... "options", opts, "environment", environment_record (), ... "verification_status", "NOT_IMPLEMENTED", ... "source", "NEIGT12_ORDINARY_PROFILE_RUNNER"); if (! isempty (opts.output_dir)) write_profile_outputs (result, opts.output_dir); endif if (added) rmpath (private_root); endif unwind_protect_cleanup mpbits (saved_bits); if (added && any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect endfunction function selected = select_cases (cases, tier) if (strcmp (tier, "all")) selected = cases; return; endif if (! any (strcmp (tier, {"S", "A"}))) selected = cases([]); return; endif keep = false (numel (cases), 1); for index = 1:numel (cases) keep(index) = strcmp (cases(index).tier, tier); endfor selected = cases(keep); endfunction function row = run_native_row (entry, model, mode) row = base_row (entry.id, mode, "native64", 53); row.input_status = "native_once_rounded_model"; row.input_hash = net_raw_hash (model.native_A, "native_A"); try started = tic (); [V, D, W] = eig (model.native_A, mode); elapsed = toc (started); row.complete = true; row.gate_pass = true; row.status = "MEASURED"; row.elapsed_seconds = elapsed; row.raw_V = V; row.raw_D = D; row.raw_W = W; row.raw_V_hash = net_raw_hash (V, "native_V"); row.raw_D_hash = net_raw_hash (D, "native_D"); row.raw_W_hash = net_raw_hash (W, "native_W"); catch exception row.status = "FAILED_NATIVE_SOLVER"; row.error_identifier = exception.identifier; row.error_message = exception.message; row.complete = false; row.gate_pass = false; end_try_catch endfunction function row = run_mp_row (entry, work_bits, mode, reference, reference_bits, q, ... highest_work_bits) row = base_row (entry.id, mode, sprintf ("mp%d", work_bits), work_bits); row.input_status = "exact_model_at_work_precision"; saved_bits = mpbits (); unwind_protect try mpbits (work_bits); model = net_case_model (entry, work_bits); row.input_status = model.input_status; row.model_hash = net_raw_hash (net_widen (model.A_model, q, work_bits), ... "A_model"); row.input_hash = net_raw_hash (net_widen (model.A_frozen, q, work_bits), ... "A_frozen"); started = tic (); [V, D, W] = eig (model.A_frozen, mode); row.elapsed_seconds = toc (started); Vq = net_widen (V, q, work_bits); Dq = net_widen (D, q, work_bits); Wq = net_widen (W, q, work_bits); Aq = net_widen (model.A_frozen, q, work_bits); reference_q = net_widen (reference.values, q, reference_bits); metrics = net_metrics (Aq, Vq, Dq, Wq, reference_q); row.complete = true; row.status = "MEASURED"; row.raw_V = V; row.raw_D = D; row.raw_W = W; row.raw_V_hash = net_raw_hash (Vq, "raw_V_q"); row.raw_D_hash = net_raw_hash (Dq, "raw_D_q"); row.raw_W_hash = net_raw_hash (Wq, "raw_W_q"); row.values = metrics.values; row.metrics = metrics; row.reference_status = reference.status; row.reference_source = reference.source; row.reference_bits = reference_bits; row.gate = ordinary_gate (entry, work_bits, metrics, Aq, q, ... highest_work_bits, reference_q); row.gate_pass = row.gate.pass; catch exception row.complete = false; row.gate_pass = false; row.status = "FAILED_MP_SOLVER_OR_METRICS"; row.error_identifier = exception.identifier; row.error_message = exception.message; end_try_catch unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function row = base_row (case_id, mode, work_role, work_bits) row = struct ("case_id", case_id, "mode", mode, "work_role", work_role, ... "work_bits", work_bits, "status", "NOT_RUN", "complete", false, ... "gate_pass", false, "elapsed_seconds", NaN, "input_status", "", ... "input_hash", "", "model_hash", "", "raw_V_hash", "", ... "raw_D_hash", "", "raw_W_hash", "", "error_identifier", "", ... "error_message", "", "raw_V", [], "raw_D", [], "raw_W", []); endfunction function gate = ordinary_gate (entry, work_bits, metrics, A, q, ... highest_work_bits, reference_q) case_id = entry.id; n = rows (A); scale = max (mp (1), norm (A, "fro")); normalized_error = metrics.absolute_match.threshold / scale; target_exponent = -80; if (highest_work_bits < work_bits) error ("mplapack:neigt:Gate", "work precision exceeds profile maximum"); endif if (work_bits < highest_work_bits) gate = struct ("pass", true, "status", "NOT_APPLICABLE_LOWER_WORK", ... "target", mp ("NaN"), "target_exponent", NaN, ... "normalized_bottleneck", normalized_error, "n", n, "scale", scale, ... "residual_recorded", true, "method", "ordinary_lower_work_measured_v1"); return; elseif (work_bits >= 512) target_exponent = -160; elseif (strcmp (case_id, "HAD_BIDIAG") || strcmp (case_id, "HAD_COMPLEX") ... || strncmp (case_id, "FORSYTHE", 8)) target_exponent = -120; endif target = net_pow2 (target_exponent, q); pass = normalized_error <= target; nonzero_normalized_bottleneck = mp ("NaN"); zero_target = mp ("NaN"); zero_exponent = NaN; nonzero_target = mp ("NaN"); if (strcmp (case_id, "MKS")) % The MKS reference deliberately contains a repeated defective zero. % Apply the conservative defective-root boundary to the zero subset, % while retaining the simple-root boundary for its nonzero subset. p = entry.parameters; kmax = floor ((n - 1) / p.m) + 1; zero_exponent = -floor (work_bits / (4 * kmax)); zero_target = net_pow2 (zero_exponent, q); nonzero_target = target; mapping = metrics.absolute_match.mapping; nonzero_normalized_bottleneck = mp (0); for index = 1:numel (mapping) ref_index = mapping(index); if (reference_q(ref_index) != mp (0)) denominator = abs (reference_q(ref_index)); if (denominator < mp (1)) denominator = mp (1); endif candidate = metrics.absolute_match.costs(index, ref_index) ... / denominator; if (candidate > nonzero_normalized_bottleneck) nonzero_normalized_bottleneck = candidate; endif endif endfor pass = (normalized_error <= zero_target) ... && (nonzero_normalized_bottleneck <= nonzero_target); endif if (any (strcmp (case_id, {"FRANK0", "FRANK1"}))) pass = pass && ! strcmp (metrics.relative_match.status, ... "undefined_zero_reference") ... && metrics.relative_match.threshold <= target; endif gate = struct ("pass", pass, "status", ternary (pass, "PASS", "FAIL"), ... "target", target, ... "target_exponent", target_exponent, "normalized_bottleneck", ... normalized_error, "n", n, "scale", scale, ... "residual_recorded", true, "method", ternary (strcmp (case_id, "MKS"), ... "ordinary_mks_split_threshold_v1", "ordinary_fixed_threshold_v1"), ... "zero_target", zero_target, "zero_target_exponent", ternary ... (strcmp (case_id, "MKS"), zero_exponent, NaN), ... "nonzero_target", nonzero_target, ... "nonzero_normalized_bottleneck", nonzero_normalized_bottleneck); endfunction function value = reference_is_valid (reference) value = isstruct (reference) && isfield (reference, "values") ... && isfield (reference, "status") && isfield (reference, "source") ... && all (isfinite (reference.values)); endfunction function value = ternary (condition, true_value, false_value) if (condition) value = true_value; else value = false_value; endif endfunction function result = environment_record () path_parts = strsplit (path (), pathsep); result = struct ("octave_version", version (), "architecture", computer (), ... "mpbits", mpbits (), "cwd", pwd (), "path_head", path_parts{1}); endfunction function write_profile_outputs (result, output_dir) if (exist (output_dir, "dir") != 7) [created, message] = mkdir (output_dir); if (! created) error ("mplapack:neigt:Output", "cannot create output directory: %s", message); endif endif target = fullfile (output_dir, sprintf ("neigt-%s-rows.tsv", result.profile)); handle = fopen (target, "w"); if (handle < 0) error ("mplapack:neigt:Output", "cannot open profile output"); endif unwind_protect fprintf (handle, "case_id\tmode\twork_role\tstatus\tgate\telapsed_seconds\n"); for index = 1:numel (result.rows) row = result.rows{index}; fprintf (handle, "%s\t%s\t%s\t%s\t%d\t%.9g\n", row.case_id, ... row.mode, row.work_role, row.status, row.gate_pass, ... row.elapsed_seconds); endfor unwind_protect_cleanup fclose (handle); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/mp_neig_replay.m0000644000230300031750000001210215274353472023355 0ustar rafaelrafael## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mp_neig_replay (@var{proof_file}) ## Re-run a hash-bound NEIGT proof from serialized MP inputs. ## ## Replay does not call @code{eig} and does not reconstruct an ideal model. ## It decodes the stored @code{A}, @code{X}, @code{T}, and @code{R} values and ## re-evaluates the audited V-S1 certificate at its recorded precision and ## fixed usefulness target. A tampered input, target, method, or bound is ## rejected by the content hash or by the certificate predicate. ## @end deftypefn function result = mp_neig_replay (proof_file) if (nargin != 1 || ! ischar (proof_file) || isempty (proof_file)) error ("mplapack:neigt:Replay", "proof_file must be a nonempty path"); endif helper_root = fileparts (mfilename ("fullpath")); private_root = fullfile (helper_root, "private"); added = false; if (! any (strcmp (strsplit (path (), pathsep), private_root))) addpath (private_root); added = true; endif saved_bits = mpbits (); unwind_protect record = net_neigt_json_read (proof_file); required = {"schema", "method_version", "profile", "job_id", ... "stored_precision", "payload"}; for index = 1:numel (required) if (! isfield (record, required{index})) error ("mplapack:neigt:Replay", "proof record lacks %s", required{index}); endif endfor if (! strcmp (record.schema, "neigt-proof-v1") ... || ! strcmp (record.method_version, "neigt-s1-replay-v1")) error ("mplapack:neigt:Replay", "unsupported proof record schema"); endif q = record.stored_precision; if (! isscalar (q) || q != fix (q) || q < 64 || q > 4096) error ("mplapack:neigt:Replay", "invalid proof precision"); endif payload = net_neigt_decode_value (record.payload, q); if (! strcmp (payload.profile, record.profile) ... || ! strcmp (payload.job_id, record.job_id) ... || payload.evaluation_bits != q) error ("mplapack:neigt:Replay", "proof metadata/payload mismatch"); endif required_payload = {"A", "X", "T", "R", "input_hash", ... "usefulness_exponent", "certificate", ... "certificate_status", "certificate_method"}; for index = 1:numel (required_payload) if (! isfield (payload, required_payload{index})) error ("mplapack:neigt:Replay", ... "proof payload lacks %s", required_payload{index}); endif endfor A = payload.A; X = payload.X; T = payload.T; R = payload.R; if (! isa (A, "mp") || ! isa (X, "mp") || ! isa (T, "mp") ... || ! isa (R, "mp") || rows (A) != columns (A) ... || ! isequal (size (A), size (X)) || ! isequal (size (A), size (T)) ... || ! isequal (size (A), size (R))) error ("mplapack:neigt:Replay", "proof matrices have incompatible shapes"); endif input_hash_match = strcmp (payload.input_hash, ... net_raw_hash (A, [payload.job_id, "_A_frozen"])); if (! input_hash_match) error ("mplapack:neigt:Replay", "serialized input hash mismatch"); endif % This is deliberately the only numerical operation in the replay path. % In particular, there is no eig call and no model constructor here. mpbits (q); certificate = net_v_s1_gershgorin (A, X, T, R, q, ... payload.usefulness_exponent); proof_pass = strcmp (certificate.status, "CERTIFIED_ALL") ... && certificate.all_roots ... && certificate.counted_roots == rows (A) ... && certificate.singleton_useful && certificate.useful; method_match = strcmp (certificate.method, payload.certificate_method); status_match = strcmp (certificate.status, payload.certificate_status); % Re-encode the stored and recomputed certificate so a changed bound or % field cannot be silently ignored even when the high-level status agrees. stored_encoded = record.payload.fields.certificate; recomputed_encoded = net_neigt_encode_value (certificate, q); certificate_encoding_match = strcmp (net_neigt_json_encode (stored_encoded), ... net_neigt_json_encode (recomputed_encoded)); result = struct ("schema", record.schema, "profile", record.profile, ... "job_id", record.job_id, "status", "REPLAY_PASS", "ok", ... proof_pass && method_match && status_match && certificate_encoding_match, ... "proof_pass", proof_pass, "method_match", method_match, ... "status_match", status_match, "certificate_encoding_match", ... certificate_encoding_match, "input_hash_match", input_hash_match, ... "called_eig", false, "reconstructed_ideal_model", false, ... "replayed_certificate", certificate, "source", ... "NEIGT23_VS1_EXACT_REPLAY"); if (! result.ok) result.status = "REPLAY_CERTIFICATE_MISMATCH"; endif if (added) rmpath (private_root); endif unwind_protect_cleanup mpbits (saved_bits); if (added && any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/0000755000230300031750000000000015274353472021663 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a1_validate_assembly.m0000644000230300031750000000157015274353472027310 0ustar rafaelrafael% Verify the interval compatibility equation for an assembled E/Lambda box. function result = net_v_a1_validate_assembly (A, E_box, Lambda_box, q) if (nargin != 4 || ! isa (A, "mp") || ! isstruct (E_box) ... || ! isstruct (Lambda_box) || q != fix (q) || q < 64) error ("mplapack:neigt:VA1", "invalid assembled-factor arguments"); endif A_box = net_iv_cmatrix_point (A, q); residual = net_iv_cmatrix_sub ... (net_iv_cmatrix_mul (A_box, E_box, q), ... net_iv_cmatrix_mul (E_box, Lambda_box, q), q); result = struct ("residual", residual, "encloses_zero", contains_zero (residual), ... "method", "neigt_interval_compatibility_residual_v1"); endfunction function result = contains_zero (matrix) result = all (matrix.rl(:) <= mp (0) & matrix.rh(:) >= mp (0) ... & matrix.il(:) <= mp (0) & matrix.ih(:) >= mp (0)); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_dyadic_parameter.m0000644000230300031750000000240415274353472026204 0ustar rafaelrafael% Parse the bounded dyadic/ratio grammar used by the NEIGT manifests. function value = net_dyadic_parameter (text, bits) if (nargin != 2 || ! ischar (text) || bits != fix (bits) || bits < 64) error ("mplapack:neigt:Parameter", "invalid dyadic parameter"); endif pieces = strsplit (text, "/"); if (numel (pieces) != 2 || isempty (pieces{1}) || isempty (pieces{2})) error ("mplapack:neigt:Parameter", "only integer ratios are accepted"); endif numerator = parse_integer (pieces{1}); denominator = parse_integer (pieces{2}); if (denominator <= 0 || numerator <= 0) error ("mplapack:neigt:Parameter", "dyadic ratio must be positive"); endif value = mp (numerator) / mp (denominator); decomposition = net_dyadic_decompose (value, bits); if (! decomposition.exact) error ("mplapack:neigt:Parameter", "ratio is not an exact MP dyadic"); endif endfunction function value = parse_integer (text) if (isempty (regexp (text, "^[0-9]+$", "once"))) error ("mplapack:neigt:Parameter", "invalid bounded integer token"); endif value = 0; for index = 1:numel (text) value = value * 10 + (text(index) - "0"); if (value > 2147483647) error ("mplapack:neigt:Parameter", "integer token is out of bounds"); endif endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_cmatrix_mul.m0000644000230300031750000001773315274353472025744 0ustar rafaelrafael% Explicit interval matrix multiplication; each scalar endpoint operation is % still rounded and widened independently. The row-vector batching only % reduces Octave interpreter overhead; it is not a replacement by GEMM. function result = net_iv_cmatrix_mul (left, right, q) net_iv_q (q); require_matrix (left, right); if (columns (left.rl) != rows (right.rl)) error ("mplapack:neigt:MatrixInterval", "incompatible interval matrices"); endif m = rows (left.rl); n = columns (right.rl); inner = columns (left.rl); result = zero_matrix (m, n); for i = 1:m sum_rl = mp (zeros (1, n)); sum_rh = mp (zeros (1, n)); sum_il = mp (zeros (1, n)); sum_ih = mp (zeros (1, n)); for k = 1:inner [real_product_lo, real_product_hi] = complex_product_real_row ... (component (left.rl, i, k), component (left.rh, i, k), ... component (left.il, i, k), component (left.ih, i, k), ... row_component (right.rl, k), row_component (right.rh, k), ... row_component (right.il, k), row_component (right.ih, k), q); [imag_product_lo, imag_product_hi] = complex_product_imag_row ... (component (left.rl, i, k), component (left.rh, i, k), ... component (left.il, i, k), component (left.ih, i, k), ... row_component (right.rl, k), row_component (right.rh, k), ... row_component (right.il, k), row_component (right.ih, k), q); [sum_rl, sum_rh] = interval_add_row ... (sum_rl, sum_rh, real_product_lo, real_product_hi, q); [sum_il, sum_ih] = interval_add_row ... (sum_il, sum_ih, imag_product_lo, imag_product_hi, q); endfor if (m == 1 && n == 1) result.rl = sum_rl; result.rh = sum_rh; result.il = sum_il; result.ih = sum_ih; else result.rl(i,:) = sum_rl; result.rh(i,:) = sum_rh; result.il(i,:) = sum_il; result.ih(i,:) = sum_ih; endif endfor endfunction function result = component (value, i, j) if (isscalar (value)) result = value; else result = value(i,j); endif endfunction function result = row_component (value, i) if (isscalar (value)) result = value; else result = value(i,:); endif endfunction function [lo, hi] = complex_product_real_row (arl, arh, ail, aih, ... brl, brh, bil, bih, q) [p1l, p1h] = interval_mul_row (arl, arh, brl, brh, q); [p2l, p2h] = interval_mul_row (ail, aih, bil, bih, q); [lo, hi] = interval_sub_row (p1l, p1h, p2l, p2h, q); endfunction function [lo, hi] = complex_product_imag_row (arl, arh, ail, aih, ... brl, brh, bil, bih, q) [p1l, p1h] = interval_mul_row (arl, arh, bil, bih, q); [p2l, p2h] = interval_mul_row (ail, aih, brl, brh, q); [lo, hi] = interval_add_row (p1l, p1h, p2l, p2h, q); endfunction function [lo, hi] = interval_mul_row (al, ah, bl, bh, q) [p11l, p11h] = array_primitive ("mul", al, bl, q); [p12l, p12h] = array_primitive ("mul", al, bh, q); [p21l, p21h] = array_primitive ("mul", ah, bl, q); [p22l, p22h] = array_primitive ("mul", ah, bh, q); lo = elementwise_min (elementwise_min (p11l, p12l), ... elementwise_min (p21l, p22l)); hi = elementwise_max (elementwise_max (p11h, p12h), ... elementwise_max (p21h, p22h)); endfunction function [lo, hi] = interval_add_row (al, ah, bl, bh, q) [lo, unused] = array_primitive ("add", al, bl, q); [unused, hi] = array_primitive ("add", ah, bh, q); endfunction function [lo, hi] = interval_sub_row (al, ah, bl, bh, q) [lo, unused] = array_primitive ("sub", al, bh, q); [unused, hi] = array_primitive ("sub", ah, bl, q); endfunction % Vectorized independent scalar primitives. Every element uses the same % net_iv_round enclosure as the scalar path, with an exact zero witness. function [lo, hi] = array_primitive (operation, x, y, q) net_iv_q (q); if (mpbits () != q || ! isa (x, "mp") || ! all (all (isfinite (x)))) error ("mplapack:neigt:IntervalPrimitive", "invalid array primitive input"); endif operation = char (operation); switch (operation) case "add" rounded = x + y; zero_witness = (x == -y); case "sub" rounded = x - y; zero_witness = (x == y); case "mul" rounded = x .* y; zero_witness = (x == 0 | y == 0); otherwise error ("mplapack:neigt:IntervalPrimitive", ... "unsupported batched operation %s", operation); endswitch [lo, hi] = array_round (rounded, q, zero_witness, operation); endfunction function [lo, hi] = array_round (rounded, q, zero_witness, operation) persistent cached_q cached_lower_limit cached_upper_limit cached_unit; if (! isa (rounded, "mp") || ! all (all (isfinite (rounded))) ... || ! isequal (size (rounded), size (zero_witness))) error ("mplapack:neigt:IntervalRange", "invalid batched primitive result"); endif % The public mp type deliberately rejects indexing a scalar object. Use % the audited scalar implementation for the 1-by-1 row case; larger rows % take the genuinely batched path below. if (isscalar (rounded)) scalar_box = net_iv_round (rounded, q, zero_witness, operation); lo = scalar_box.lo; hi = scalar_box.hi; return; endif if (any (rounded(:) == 0 & ! zero_witness(:))) error ("mplapack:neigt:IntervalRange", ... "unwitnessed zero in batched primitive %s", operation); endif if (any (zero_witness(:) & rounded(:) != 0)) error ("mplapack:neigt:IntervalRange", ... "inconsistent zero witness in batched primitive %s", operation); endif if (isempty (cached_q) || cached_q != q) cached_q = q; cached_lower_limit = net_pow2 (-8192, q); cached_upper_limit = net_pow2 (8192, q); cached_unit = net_pow2 (-q, q); endif magnitude = abs (rounded); nonzero = ! zero_witness; if (any (nonzero(:) & (magnitude(:) < cached_lower_limit ... | magnitude(:) > cached_upper_limit))) error ("mplapack:neigt:IntervalRange", ... "batched primitive result is outside the verified range for %s", ... operation); endif lo = rounded; hi = rounded; if (any (nonzero(:))) margin = mp (8) .* cached_unit .* magnitude; lo(nonzero) = rounded(nonzero) - margin(nonzero); hi(nonzero) = rounded(nonzero) + margin(nonzero); if (any (! isfinite (lo(nonzero))) || any (! isfinite (hi(nonzero))) ... || any (lo(nonzero) > hi(nonzero))) error ("mplapack:neigt:IntervalRange", ... "batched endpoint construction failed for %s", operation); endif endif endfunction function value = elementwise_min (left, right) if (isscalar (left)) if (right < left) value = right; else value = left; endif return; endif value = left; for index = 1:numel (left) if (right(index) < left(index)) value(index) = right(index); endif endfor endfunction function value = elementwise_max (left, right) if (isscalar (left)) if (right > left) value = right; else value = left; endif return; endif value = left; for index = 1:numel (left) if (right(index) > left(index)) value(index) = right(index); endif endfor endfunction function require_matrix (left, right) if (! valid_matrix (left) || ! valid_matrix (right)) error ("mplapack:neigt:MatrixInterval", "invalid interval matrices"); endif endfunction function value = valid_matrix (matrix) value = isstruct (matrix) && isfield (matrix, "kind") ... && strcmp (matrix.kind, "complex_matrix") && isfield (matrix, "rl") ... && isfield (matrix, "rh") && isfield (matrix, "il") && isfield (matrix, "ih") ... && isequal (size (matrix.rl), size (matrix.rh)) ... && isequal (size (matrix.rl), size (matrix.il)) ... && isequal (size (matrix.rl), size (matrix.ih)); endfunction function result = zero_matrix (m, n) result = struct ("kind", "complex_matrix", ... "rl", mp (zeros (m,n)), "rh", mp (zeros (m,n)), ... "il", mp (zeros (m,n)), "ih", mp (zeros (m,n))); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a1_factors.m0000644000230300031750000002061715274353472025264 0ustar rafaelrafael% Compatible simultaneous eigenfactor boxes from k=1 graph certificates. % This proves one E/Lambda factorization; it does not normalize columns % independently and it does not claim a Schur factor (NEIGT19). function result = net_v_a1_factors (A, V, D, q, useful_exponent) if (nargin != 5 || ! isa (A, "mp") || ! isa (V, "mp") || ! isa (D, "mp") ... || rows (A) != columns (A) || ! isequal (size (A), size (V)) ... || ! isequal (size (D), size (A)) || q != fix (q) || q < 64 ... || useful_exponent != fix (useful_exponent)) error ("mplapack:neigt:VA1", "invalid eigenfactor arguments"); endif n = rows (A); result = failure_template (n, useful_exponent); graphs = cell (n, 1); E_box = zero_matrix (n, n, q); lambda_boxes = cell (n, 1); lambda_values = diag (D); for index = 1:n order = [index, 1:(index - 1), (index + 1):n]; X = V(:, order); graph = net_v_s2_graph (A, X, 1, q); graphs{index} = graph; if (! graph.pass || ! graph.nontrivial) result.status = "INCONCLUSIVE_GRAPH"; result.claim_status = "INCONCLUSIVE"; result.graphs = graphs; return; endif root = entry_box (graph.M_box, 1, 1); lambda_boxes{index} = root; E_box = put_column (E_box, graph.Y1_box, index); endfor roots_disjoint = true; for i = 1:n for j = (i + 1):n difference = net_iv_complex_sub (lambda_boxes{i}, lambda_boxes{j}, q); if (net_iv_complex_abs (difference, q).lo <= mp (0)) roots_disjoint = false; endif endfor endfor E_mid = midpoint_matrix (E_box, q); if (! all (isfinite (real (E_mid))) || ! all (isfinite (imag (E_mid)))) result.status = "INCONCLUSIVE_FACTOR_MIDPOINT"; result.claim_status = "INCONCLUSIVE"; result.graphs = graphs; result.E_box = E_box; result.lambda_boxes = lambda_boxes; return; endif R0 = E_mid \ mp (eye (n)); inverse_witness = interval_inverse_residual (E_box, R0, q); if (! inverse_witness.nonsingular) result.status = "INCONCLUSIVE_FACTOR_INVERSE"; result.claim_status = "INCONCLUSIVE"; result.graphs = graphs; result.E_box = E_box; result.lambda_boxes = lambda_boxes; result.inverse_witness = inverse_witness; return; endif R_box = inverse_box_from_residual (R0, inverse_witness, q); W_box = net_iv_cmatrix_conjtrans (R_box); Lambda_box = diagonal_from_boxes (lambda_boxes, n, q); compatibility = net_v_a1_validate_assembly (A, E_box, Lambda_box, q); if (! compatibility.encloses_zero) result.status = "INCONCLUSIVE_COMPATIBILITY"; result.claim_status = "INCONCLUSIVE"; result.graphs = graphs; result.E_box = E_box; result.Lambda_box = Lambda_box; result.W_box = W_box; result.inverse_witness = inverse_witness; result.compatibility = compatibility; return; endif component_radius = maximum_component_radius (E_box, E_mid, q); scale = max (mp (1), max_entry_modulus (E_mid, q)); width_ratio = component_radius / scale; useful_target = net_pow2 (useful_exponent, q); result.status = "CERTIFIED_EIGENFACTORS"; result.claim_status = "CERTIFIED_EIGENFACTORS"; result.claim_quality = "simultaneous_existence"; result.pass = roots_disjoint && inverse_witness.nonsingular ... && compatibility.encloses_zero && width_ratio <= useful_target; if (! roots_disjoint) result.status = "INCONCLUSIVE_NONISOLATED_ROOTS"; result.claim_status = "INCONCLUSIVE"; result.pass = false; elseif (! result.pass) result.status = "INCONCLUSIVE_USEFUL_WIDTH"; result.claim_status = "INCONCLUSIVE"; endif result.milestone_pass = result.pass; result.graphs = graphs; result.E_box = E_box; result.E_mid = E_mid; result.Lambda_box = Lambda_box; result.W_box = W_box; result.R0 = R0; result.inverse_witness = inverse_witness; result.compatibility = compatibility; result.roots_disjoint = roots_disjoint; result.component_radius = component_radius; result.scale = scale; result.width_ratio = width_ratio; result.useful_target = useful_target; result.raw_V_hash = net_raw_hash (V, "VA1_raw_V"); result.raw_D_hash = net_raw_hash (D, "VA1_raw_D"); result.raw_lambda_hash = net_raw_hash (lambda_values, "VA1_raw_lambda"); endfunction function result = net_v_a1_validate_assembly (A, E_box, Lambda_box, q) A_box = net_iv_cmatrix_point (A, q); residual = net_iv_cmatrix_sub ... (net_iv_cmatrix_mul (A_box, E_box, q), ... net_iv_cmatrix_mul (E_box, Lambda_box, q), q); result = struct ("residual", residual, "encloses_zero", contains_zero (residual)); endfunction function result = inverse_box_from_residual (R0, witness, q) % If G=R0*E-I and ||G||inf<=e<1, then % E^-1=(I+G)^-1 R0 and ||E^-1-R0||inf <= e/(1-e)||R0||inf. e = witness.e; denominator = net_iv_primitive ("sub", mp (1), e, q).lo; ratio = net_iv_primitive ("div", e, denominator, q).hi; rnorm = net_iv_cmatrix_inf_upper (net_iv_cmatrix_point (R0, q), q); radius = net_iv_primitive ("mul", ratio, rnorm, q).hi; result = net_iv_cmatrix_point (R0, q); for index = 1:numel (R0) result.rl(index) = net_iv_primitive ("sub", real (R0(index)), radius, q).lo; result.rh(index) = net_iv_primitive ("add", real (R0(index)), radius, q).hi; result.il(index) = net_iv_primitive ("sub", imag (R0(index)), radius, q).lo; result.ih(index) = net_iv_primitive ("add", imag (R0(index)), radius, q).hi; endfor result.radius = radius; endfunction function result = interval_inverse_residual (E_box, R0, q) residual = net_iv_cmatrix_sub (net_iv_cmatrix_eye (rows (E_box.rl), q), ... net_iv_cmatrix_mul (net_iv_cmatrix_point (R0, q), E_box, q), q); e = net_iv_cmatrix_inf_upper (residual, q); result = struct ("residual", residual, "e", e, "nonsingular", e < mp (1), ... "method", "neigt_interval_neumann_inverse_v1"); endfunction function result = diagonal_from_boxes (boxes, n, q) result = zero_matrix (n, n, q); for index = 1:n box = boxes{index}; result.rl(index,index) = box.rl; result.rh(index,index) = box.rh; result.il(index,index) = box.il; result.ih(index,index) = box.ih; endfor endfunction function result = zero_matrix (m, n, q) result = net_iv_cmatrix_point (mp (zeros (m, n)), q); endfunction function matrix = put_column (matrix, column, index) matrix.rl(:,index) = column.rl; matrix.rh(:,index) = column.rh; matrix.il(:,index) = column.il; matrix.ih(:,index) = column.ih; endfunction function result = midpoint_matrix (matrix, q) result = mp (zeros (size (matrix.rl))); for index = 1:numel (result) re = (matrix.rl(index) + matrix.rh(index)) * mp ("0.5"); im = (matrix.il(index) + matrix.ih(index)) * mp ("0.5"); result(index) = net_mp_complex (re, im); endfor endfunction function result = maximum_component_radius (box, center, q) result = mp (0); for index = 1:numel (box.rl) real_radius = max (abs (box.rl(index) - real (center(index))), ... abs (box.rh(index) - real (center(index)))); imag_radius = max (abs (box.il(index) - imag (center(index))), ... abs (box.ih(index) - imag (center(index)))); value = max (real_radius, imag_radius); if (value > result) result = value; endif endfor endfunction function result = max_entry_modulus (matrix, q) result = mp (0); for index = 1:numel (matrix) value = abs (matrix(index)); if (value > result) result = value; endif endfor endfunction function result = entry_box (matrix, i, j) if (isscalar (matrix.rl)) result = net_iv_complex (matrix.rl, matrix.rh, matrix.il, matrix.ih); else result = net_iv_complex (matrix.rl(i,j), matrix.rh(i,j), ... matrix.il(i,j), matrix.ih(i,j)); endif endfunction function result = contains_zero (matrix) result = all (matrix.rl(:) <= mp (0) & matrix.rh(:) >= mp (0) ... & matrix.il(:) <= mp (0) & matrix.ih(:) >= mp (0)); endfunction function result = failure_template (n, useful_exponent) result = struct ("method", "neigt_eigenfactor_boxes_v1", ... "paper_algorithm_reproduction", false, "status", "INCONCLUSIVE", ... "claim_status", "INCONCLUSIVE", "claim_quality", "not_identified", ... "pass", false, "milestone_pass", false, "n", n, ... "useful_exponent", useful_exponent, "graphs", {{}}, ... "E_box", [], "Lambda_box", [], "W_box", [], "compatibility", [], ... "inverse_witness", [], "roots_disjoint", false, ... "raw_V_hash", "", "raw_D_hash", "", "raw_lambda_hash", ""); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_dyadic_write_json.m0000644000230300031750000000123215274353472026405 0ustar rafaelrafael% Write one canonical, hash-bound dyadic witness. function result = net_dyadic_write_json (record, filename) if (nargin != 2 || ! ischar (filename) || isempty (filename)) error ("mplapack:neigt:Serialize", "invalid witness path"); endif body = net_dyadic_canonical (record, false); record.sha256 = hash ("sha256", body); result = net_dyadic_canonical (record, true); handle = fopen (filename, "w"); if (handle < 0) error ("mplapack:neigt:Serialize", "cannot open witness path"); endif unwind_protect fwrite (handle, result); fwrite (handle, char (10)); unwind_protect_cleanup fclose (handle); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_hadamard_model.m0000644000230300031750000000201215274353472025623 0ustar rafaelrafael% A1 Hadamard-similar upper bidiagonal model. function result = net_hadamard_model (n, s, bits) if (nargin != 3 || n != fix (n) || n < 2 || s != fix (s) || s < 1) error ("mplapack:neigt:Hadamard", "invalid Hadamard model arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); H = net_hadamard (n, bits); T = mp (zeros (n, n)); for i = 1:n T(i, i) = mp (i); if (i < n) T(i, i + 1) = mp (s); endif endfor [HT, ht_metadata] = net_exact_product_dyadic (H, T, bits); [HTH, hth_metadata] = net_exact_product_dyadic (HT, ctranspose (H), bits); A = HTH / mp (n); result = struct ("family", "hadamard_bidiag", "n", n, "s", s, ... "bits", bits, "H", H, "T", T, "A", A, ... "product_metadata", {{ht_metadata, hth_metadata}}, ... "spectrum_reference", mp (transpose (1:n)), ... "source", "A1_HADAMARD_SIMILAR_UPPER_BIDIAG", "status", "MEASURED"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_real_mul.m0000644000230300031750000000076115274353472025211 0ustar rafaelrafaelfunction result = net_iv_real_mul (a, b, q) net_iv_q (q); p11 = net_iv_primitive ("mul", a.lo, b.lo, q); p12 = net_iv_primitive ("mul", a.lo, b.hi, q); p21 = net_iv_primitive ("mul", a.hi, b.lo, q); p22 = net_iv_primitive ("mul", a.hi, b.hi, q); lower_values = mp ([p11.lo; p12.lo; p21.lo; p22.lo]); upper_values = mp ([p11.hi; p12.hi; p21.hi; p22.hi]); [lo, ~] = net_iv_minmax (lower_values); [~, hi] = net_iv_minmax (upper_values); result = net_iv_real (lo, hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_cmatrix_sub.m0000644000230300031750000000020715274353472025724 0ustar rafaelrafaelfunction result = net_iv_cmatrix_sub (left, right, q) result = net_iv_cmatrix_add (left, net_iv_cmatrix_neg (right), q); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_bit_length.m0000644000230300031750000000075515274353472025035 0ustar rafaelrafael% Exact significand-bit length for a nonzero nonnegative integer MP value. function answer = net_bit_length (value, bits) if (nargin != 2 || ! isa (value, "mp") || ! isscalar (value)) error ("mplapack:neigt:BitLength", "expected an MP scalar"); endif if (value == mp (0)) answer = 0; return; endif if (value < mp (0)) value = -value; endif answer = 0; lower = mp (1); while (value >= lower) answer += 1; lower = lower * mp (2); endwhile endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_real_square.m0000644000230300031750000000122315274353472025706 0ustar rafaelrafael% Verified square; the lower endpoint is exactly zero when the interval crosses zero. function result = net_iv_real_square (a, q) net_iv_q (q); p11 = net_iv_primitive ("mul", a.lo, a.lo, q); p12 = net_iv_primitive ("mul", a.lo, a.hi, q); p21 = net_iv_primitive ("mul", a.hi, a.lo, q); p22 = net_iv_primitive ("mul", a.hi, a.hi, q); upper_values = mp ([p11.hi; p12.hi; p21.hi; p22.hi]); [~, hi] = net_iv_minmax (upper_values); if (a.lo <= mp (0) && a.hi >= mp (0)) lo = mp (0); else lower_values = mp ([p11.lo; p12.lo; p21.lo; p22.lo]); [lo, ~] = net_iv_minmax (lower_values); endif result = net_iv_real (lo, hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_cmatrix_eye.m0000644000230300031750000000043215274353472025715 0ustar rafaelrafaelfunction result = net_iv_cmatrix_eye (n, q) net_iv_q (q); if (nargin != 2 || ! isnumeric (n) || ! isscalar (n) || n != fix (n) || n < 1) error ("mplapack:neigt:MatrixInterval", "invalid identity size"); endif result = net_iv_cmatrix_point (mp (eye (n)), q); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_complex_abs.m0000644000230300031750000000204515274353472025702 0ustar rafaelrafael% Return rigorous upper/lower bounds for the modulus of a rectangle. function result = net_iv_complex_abs (a, q) re = net_iv_real (a.rl, a.rh); im = net_iv_real (a.il, a.ih); upper_sq = net_iv_real_add (net_iv_real_square (re, q), ... net_iv_real_square (im, q), q); upper = net_iv_real_sqrt (upper_sq, q); if (re.lo <= mp (0) && re.hi >= mp (0)) dx = mp (0); else dx = min_abs_endpoints (re.lo, re.hi); endif if (im.lo <= mp (0) && im.hi >= mp (0)) dy = mp (0); else dy = min_abs_endpoints (im.lo, im.hi); endif lower_sq = net_iv_real_add (net_iv_real_square (net_iv_iv_point (dx), q), ... net_iv_real_square (net_iv_iv_point (dy), q), q); lower = net_iv_real_sqrt (lower_sq, q); result = net_iv_real (lower.lo, upper.hi); endfunction function value = min_abs_endpoints (lo, hi) if (abs (lo) < abs (hi)) value = abs (lo); else value = abs (hi); endif endfunction function value = net_iv_iv_point (x) value = net_iv_real (x, x); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_oo_generator.m0000644000230300031750000002261515274353472025400 0ustar rafaelrafael% Deterministic Ozaki--Ogita Theorem-1 triple-product generator. % This is the specified S1 generator, not a generic similarity constructor. function result = net_oo_generator (kind, n) if (nargin != 2 || ! ischar (kind) || ! isnumeric (n) ... || ! isscalar (n) || n != fix (n) || n < 2) error ("mplapack:neigt:OO", "invalid generator arguments"); endif if (strcmp (kind, "OO53_REAL") || strcmp (kind, "OO53_PAIR")) generation_bits = 53; elseif (strcmp (kind, "OO128_CLOSE")) generation_bits = 128; else error ("mplapack:neigt:OO", "unknown generator kind"); endif if (strcmp (kind, "OO53_PAIR") && mod (n, 2) != 0) error ("mplapack:neigt:OO", "OO53_PAIR requires even n"); endif saved_bits = mpbits (); unwind_protect mpbits (generation_bits); [X, Y, pair_metadata] = oo_inverse_pair (n, generation_bits); S_requested = net_oo_standard (kind, n, generation_bits); quant = oo_quantization_metadata (S_requested, X, Y, generation_bits); if (quant.predicate_value > mp (1)) error ("mplapack:neigt:OO", ... "Theorem-1 inequality fails at the requested generation precision"); endif sigma = mp (12) * quant.alpha * quant.P; S_realized = mp (zeros (n, n)); pair_rule = false; for i = 1:n for j = 1:n S_realized(i, j) = oo_round_shift (S_requested(i, j), sigma, ... generation_bits); endfor endfor if (strcmp (kind, "OO53_PAIR")) pair_rule = true; for block = 0:(n / 2 - 1) first = 2 * block + 1; a_prime = oo_round_shift (S_requested(first, first), sigma, ... generation_bits); b_prime = oo_round_shift (S_requested(first, first + 1), sigma, ... generation_bits); % One rounded value is copied to both diagonal entries. The lower % entry is a sign copy, never an independent rounding operation. S_realized(first, first) = a_prime; S_realized(first + 1, first + 1) = a_prime; S_realized(first, first + 1) = b_prime; S_realized(first + 1, first) = -b_prime; endfor endif inner_rounded = net_rounded_product (S_realized, X, generation_bits); [inner_exact, inner_exact_metadata] = ... net_exact_product_dyadic (S_realized, X, generation_bits); outer_rounded = net_rounded_product (Y, inner_rounded, generation_bits); [outer_exact, outer_exact_metadata] = ... net_exact_product_dyadic (Y, inner_exact, ... inner_exact_metadata.check_bits); [xy_exact, xy_metadata] = net_exact_product_dyadic (X, Y, generation_bits); [yx_exact, yx_metadata] = net_exact_product_dyadic (Y, X, generation_bits); mpbits (max ([generation_bits, inner_exact_metadata.check_bits, ... outer_exact_metadata.check_bits, xy_metadata.check_bits, ... yx_metadata.check_bits])); identity = mp (eye (n)); exact_xy = (xy_exact == identity); exact_yx = (yx_exact == identity); products_exact = (inner_rounded == inner_exact ... && outer_rounded == outer_exact); if (! exact_xy || ! exact_yx || ! products_exact) error ("mplapack:neigt:OO", ... "independent exact dyadic product check failed"); endif if (all (S_realized == S_requested)) error ("mplapack:neigt:OO", ... "required generator fixture did not realize a quantization change"); endif A = outer_rounded; [requested_spectrum, realized_spectrum] = ... oo_spectra (kind, S_requested, S_realized); model_hash = oo_matrix_hash (kind, n, generation_bits, S_requested, ... S_realized, A); if (strcmp (kind, "OO128_CLOSE")) realized_gap = S_realized(2, 2) - S_realized(1, 1); expected_gap = net_pow2 (-80, generation_bits); else realized_gap = mp (0); expected_gap = mp (0); endif result = struct (... "family", "ozaki_ogita_theorem_1", "kind", kind, "n", n, ... "generation_bits", generation_bits, "source", "OO22_THEOREM_1_SECTION_4", ... "method", "fixed_precision_two_step_RN_triple_product_v1", ... "S_requested", S_requested, "S_realized", S_realized, ... "requested_spectrum", requested_spectrum, ... "realized_spectrum", realized_spectrum, "X", X, "Y", Y, "A", A, ... "A_exact", outer_exact, "sigma", sigma, "alpha", quant.alpha, ... "beta", quant.beta, "gamma", quant.gamma, "theta", quant.theta, ... "omega", quant.omega, "P", quant.P, "nY", quant.nY, ... "nS", quant.nS, "nX", quant.nX, "nprime", quant.nprime, ... "u", quant.u, "predicate_value", quant.predicate_value, ... "theorem_predicate", quant.predicate_value <= mp (1), ... "pair_rule", pair_rule, "pair_metadata", pair_metadata, ... "xy_exact", exact_xy, "yx_exact", exact_yx, ... "products_exact", products_exact, ... "inner_exact_metadata", inner_exact_metadata, ... "outer_exact_metadata", outer_exact_metadata, ... "xy_metadata", xy_metadata, "yx_metadata", yx_metadata, ... "quantization_changed", true, "realized_gap", realized_gap, ... "requested_gap_component", expected_gap, "model_hash", model_hash, ... "hash_encoding", "S1_TEXT_V1", "status", "MEASURED"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function [X, Y, metadata] = oo_inverse_pair (n, bits) N = mp (zeros (n, n)); for i = 1:(n - 1) N(i, i + 1) = mp (1); endfor L = mp (eye (n)) + ctranspose (N); U = mp (eye (n)) + N; X = L * U; U_inverse = net_triangular_inverse (U, bits); L_inverse = net_triangular_inverse (L, bits); Y = U_inverse * L_inverse; metadata = struct ("construction", "L=I+Nprime,U=I+N; finite_nilpotent_series", ... "inverse_method", "finite_nilpotent_series", ... "dyadic", true); endfunction function quant = oo_quantization_metadata (S, X, Y, bits) n = rows (S); phi = mp (zeros (size (X))); psi = mp (zeros (size (Y))); gamma = mp (1); omega = mp (1); for i = 1:n for j = 1:n if (X(i, j) != mp (0)) part = net_dyadic_decompose (X(i, j), bits); phi(i, j) = net_pow2 (part.exponent, bits); gamma = max (gamma, net_ufp (abs (X(i, j))) / phi(i, j)); endif if (Y(i, j) != mp (0)) part = net_dyadic_decompose (Y(i, j), bits); psi(i, j) = net_pow2 (part.exponent, bits); omega = max (omega, net_ufp (abs (Y(i, j))) / psi(i, j)); endif endfor endfor beta = mp (1); theta = mp (1); for j = 1:n nonzero = find (phi(:, j) != mp (0)); if (! isempty (nonzero)) beta = max (beta, max (phi(nonzero, j)) / min (phi(nonzero, j))); endif endfor for i = 1:n nonzero = find (psi(i, :) != mp (0)); if (! isempty (nonzero)) theta = max (theta, max (psi(i, nonzero)) / min (psi(i, nonzero))); endif endfor nY = 0; nS = 0; nX = 0; max_s = mp (0); for i = 1:n nY = max (nY, sum (Y(i, :) != mp (0))); nS = max (nS, sum (S(i, :) != mp (0))); max_s = max (max_s, max (abs (S(i, :)))); endfor for j = 1:n nX = max (nX, sum (X(:, j) != mp (0))); endfor nprime = min (nS, nX); target = mp (nY * nprime) * max_s; alpha = mp (1); while alpha < target alpha = alpha * mp (2); endwhile P = beta * gamma * theta * omega; u = net_pow2 (-bits, bits); predicate_value = mp (4 * nY * nprime) * u * P; quant = struct ("phi", phi, "psi", psi, "beta", beta, ... "gamma", gamma, "theta", theta, "omega", omega, ... "P", P, "nY", nY, "nS", nS, "nX", nX, ... "nprime", nprime, "max_s", max_s, "alpha", alpha, ... "u", u, "predicate_value", predicate_value); endfunction function value = oo_round_shift (entry, sigma, bits) saved_bits = mpbits (); unwind_protect mpbits (bits); first = sigma + entry; first = first + mp (0); second = first - sigma; value = second + mp (0); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function [requested, realized] = oo_spectra (kind, S_requested, S_realized) n = rows (S_requested); requested = mp (zeros (n, 1)); realized = mp (zeros (n, 1)); imaginary_unit = mp ("(0,1)"); if (strcmp (kind, "OO53_PAIR")) for block = 0:(n / 2 - 1) first = 2 * block + 1; requested(first) = S_requested(first, first) ... + S_requested(first, first + 1) * imaginary_unit; requested(first + 1) = S_requested(first, first) ... - S_requested(first, first + 1) * imaginary_unit; realized(first) = S_realized(first, first) ... + S_realized(first, first + 1) * imaginary_unit; realized(first + 1) = S_realized(first, first) ... - S_realized(first, first + 1) * imaginary_unit; endfor else requested = diag (S_requested); realized = diag (S_realized); endif endfunction function result = oo_matrix_hash (kind, n, bits, requested, realized, A) text = sprintf ("%s|n=%d|g=%d|", kind, n, bits); for matrix = {requested, realized, A} value = matrix{1}; tokens = cell (1, numel (value)); for i = 1:numel (value) tokens{i} = char (value(i)); endfor joined = strjoin (tokens, ";"); text = [text, joined]; text = [text, "|"]; endfor result = hash ("sha256", text); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_mks_reference.m0000644000230300031750000000324415274353472025522 0ustar rafaelrafael% MKS reference: solve only the reduced companion and append exact zeros. function result = net_mks_reference (model, bits1, bits2) if (nargin != 3 || ! isstruct (model) || ! isfield (model, "q_companion") ... || bits1 != fix (bits1) || bits2 != fix (bits2) || bits1 < 64 || bits2 < bits1) error ("mplapack:neigt:MKS", "invalid MKS reference arguments"); endif ell = model.ell; saved_bits = mpbits (); unwind_protect mpbits (bits1); C1 = mp (zeros (size (model.q_companion))) + model.q_companion; [unused1, D1] = eig (C1, "nobalance"); nonzero1 = diag (D1); mpbits (bits2); C2 = mp (zeros (size (model.q_companion))) + model.q_companion; [unused2, D2] = eig (C2, "nobalance"); nonzero2 = diag (D2); values1 = mp (zeros (model.n, 1)); values2 = mp (zeros (model.n, 1)); values1(1:ell) = nonzero1; values2(1:ell) = nonzero2; comparison = net_match (nonzero2, nonzero1, "absolute"); derivative = mp (zeros (1, numel (model.q_coefficients) - 1)); for j = 1:numel (derivative) derivative(j) = mp (numel (model.q_coefficients) - j) ... * model.q_coefficients(j); endfor gcd_result = net_polynomial_gcd (model.q_coefficients, derivative, bits2); result = struct ("reference_status", "reduced_companion_plus_exact_zeros", ... "bits1", bits1, "bits2", bits2, "nonzero1", nonzero1, ... "nonzero2", nonzero2, "values1", values1, "values2", values2, ... "nonzero_agreement", comparison, "derivative", derivative, ... "gcd", gcd_result, "source", "A5_MKS_REDUCED_COMPANION_REFERENCE"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_wilkinson_reference.m0000644000230300031750000000252315274353472026744 0ustar rafaelrafael% Exact roots and guarded Horner checks for the Wilkinson polynomial. function result = net_wilkinson_reference (n, bits) if (nargin != 2 || n != fix (n) || n < 1 || bits != fix (bits) || bits < 64) error ("mplapack:neigt:Wilkinson", "invalid Wilkinson reference arguments"); endif model = net_wilkinson_model (n, bits); horner_bits = max (bits, 2 * n * net_ceil_log2_integer (n + 1) + 32); saved_bits = mpbits (); unwind_protect mpbits (horner_bits); coefficients = mp (zeros (1, numel (model.coefficients))); coefficients = coefficients + model.coefficients; roots = mp (transpose (1:n)); values = mp (zeros (n, 1)); checks = false (n, 1); for root_index = 1:n accumulator = mp (0); for coefficient_index = 1:numel (coefficients) accumulator = accumulator * roots(root_index) + coefficients(coefficient_index); endfor values(root_index) = accumulator; checks(root_index) = (accumulator == mp (0)); endfor result = struct ("reference_status", "exact_integer_roots", ... "reference_bits", horner_bits, "roots", roots, ... "coefficients", coefficients, "horner_values", values, ... "horner_exact_zero", checks, ... "source", "A3_WILKINSON_ROOTS_AND_GUARDED_HORNER"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_wilkinson_model.m0000644000230300031750000000366115274353472026112 0ustar rafaelrafael% Exact Wilkinson Frobenius companion and its once-rounded work input. function result = net_wilkinson_model (n, bits) if (nargin != 2 || n != fix (n) || n < 1 || bits != fix (bits) || bits < 64) error ("mplapack:neigt:Wilkinson", "invalid Wilkinson arguments"); endif guard = n * net_ceil_log2_integer (n + 1) + 2; generation_bits = max (bits, guard); saved_bits = mpbits (); unwind_protect mpbits (generation_bits); coefficients = mp (1); for root = 1:n old = coefficients; coefficients = mp (zeros (1, numel (old) + 1)); if (numel (old) == 1) coefficients(1) = old; else coefficients(1) = old(1); endif for index = 2:numel (old) coefficients(index) = old(index) - mp (root) * old(index - 1); endfor if (numel (old) == 1) coefficients(end) = -mp (root) * old; else coefficients(end) = -mp (root) * old(end); endif endfor A_model = mp (zeros (n, n)); A_model(1, :) = -coefficients(2:end); for index = 2:n A_model(index, index - 1) = mp (1); endfor if (bits < generation_bits) mpbits (bits); A_frozen = mp (zeros (n, n)) + A_model; else A_frozen = A_model; endif native_A = double (A_model); result = struct ("family", "wilkinson", "n", n, "bits", bits, ... "generation_bits", generation_bits, "guard_bits", guard, ... "coefficients", coefficients, "A_model", A_model, ... "A_frozen", A_frozen, "native_A", native_A, ... "input_status", ternary_local (bits >= guard, "exact_model", ... "rounded_model"), ... "source", "A3_WILKINSON_EXACT_COEFFICIENT_RECURRENCE"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function value = ternary_local (condition, true_value, false_value) if (condition) value = true_value; else value = false_value; endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_grcar_model.m0000644000230300031750000000175515274353472025175 0ustar rafaelrafael% Exact Grcar integer matrix from the declared Hessenberg definition. function result = net_grcar_model (n, upper_bandwidth, bits) if (nargin != 3 || n != fix (n) || n < 1 ... || upper_bandwidth != fix (upper_bandwidth) || upper_bandwidth < 0 ... || bits != fix (bits) || bits < 64) error ("mplapack:neigt:Grcar", "invalid Grcar arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); A = mp (zeros (n, n)); for i = 1:n for j = 1:n if (j >= i && j - i <= upper_bandwidth) A(i, j) = mp (1); elseif (i - j == 1) A(i, j) = mp (-1); endif endfor endfor result = struct ("family", "grcar", "n", n, ... "upper_bandwidth", upper_bandwidth, "bits", bits, "A_model", A, ... "A_frozen", A, "native_A", double (A), "input_status", "exact_model", ... "source", "A4_GRCAR_EXACT_INTEGER_HESSENBERG"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_matrix_max_bit_length.m0000644000230300031750000000056015274353472027260 0ustar rafaelrafael% Maximum exact bit length for a matrix of integer MP values. function answer = net_matrix_max_bit_length (matrix, bits) if (nargin != 2 || ! isa (matrix, "mp")) error ("mplapack:neigt:BitLength", "expected an MP matrix"); endif answer = 0; for index = 1:numel (matrix) answer = max (answer, net_bit_length (matrix(index), bits)); endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a2_job.m0000644000230300031750000003035415274353472024375 0ustar rafaelrafael% Verified finite generalized-pencil reduction for NEIGT20. % The only spectral candidate is eig(C0), where C0 is obtained by a public % solve. The proof is made against an outward enclosure of the exact % C=B^(-1)A and then mapped back to the original A,B pencil. function result = net_v_a2_job (job, profile_data, profile) result = status_template (job, profile_data); bits = profile_data.source_bits; q = profile_data.evaluation_bits; regime = char (job.fixture.regime); saved_bits = mpbits (); unwind_protect try % The frozen pencil model is generated at the manifest source % precision, independently of the caller's ambient default. mpbits (bits); model = net_v_a2_model (regime, job.fixture.n, bits); result.source = model.source; result.input_status = model.input_status; result.input_hash_A = net_raw_hash (model.A_frozen, [job.id, "_A_frozen"]); result.input_hash_B = net_raw_hash (model.B_frozen, [job.id, "_B_frozen"]); result.input_hash_C = net_raw_hash (model.C_frozen, [job.id, "_C_model"]); % Candidate solve reduction. These values remain separately recorded % from the exact model and from every interval proof target. mpbits (bits); I = mp (eye (rows (model.B_frozen))); RB_candidate = model.B_frozen \ I; C0_candidate = RB_candidate * model.A_frozen; result.candidate_source = "solve_reduction_finite_pencil"; result.candidate_bits = bits; result.raw_RB_hash = net_raw_hash (RB_candidate, [job.id, "_raw_RB"]); result.raw_C0_hash = net_raw_hash (C0_candidate, [job.id, "_raw_C0"]); % Prove B nonsingular and enclose C=B^(-1)A entrywise. mpbits (q); RB = net_widen (RB_candidate, q, bits); C0 = net_widen (C0_candidate, q, bits); A = net_widen (model.A_frozen, q, bits); B = net_widen (model.B_frozen, q, bits); reduction = net_v_a2_reduction (A, B, RB, C0, q); result.reduction = reduction; result.eB = reduction.eB; result.fB = reduction.fB; result.etaB = reduction.etaB; result.B_inverse_residual = reduction.B_inverse_residual; result.A_minus_BC0 = reduction.A_minus_BC0; result.RB_A_minus_BC0 = reduction.RB_A_minus_BC0; result.B_nonsingular_proof = reduction.B_nonsingular; if (! reduction.pass) result.status = reduction.status; result.claim_status = "INCONCLUSIVE"; result.milestone_pass = false; return; endif A_box = reduction.A_box; B_box = reduction.B_box; C_box = reduction.C_box; result.C0_candidate = C0_candidate; result.C_box = C_box; result.reduction_method = "proved_solve_reduction_finite_pencil"; % Public eig supplies candidates only. V-S1 sees the proved C box. [V, D, Wc] = eig (C0, "nobalance"); result.raw_V = V; result.raw_D = D; result.raw_Wc = Wc; result.raw_V_hash = net_raw_hash (V, [job.id, "_raw_V_C0"]); result.raw_D_hash = net_raw_hash (D, [job.id, "_raw_D_C0"]); result.raw_W_hash = net_raw_hash (Wc, [job.id, "_raw_W_C0"]); Vq = net_widen (V, q, bits); Dq = net_widen (D, q, bits); Rq = Vq \ mp (eye (rows (Vq))); finite = net_v_s1_gershgorin (C0, Vq, Dq, Rq, q, -32, ... struct ("A_box", C_box)); result.finite_certificate = finite; result.finite_root_count = finite.counted_roots; result.finite_root_coverage = finite.coverage ... && finite.counted_roots == rows (C0); result.finite_pass = result.finite_root_coverage ... && finite.inverse_residual_pass; % Map the left C eigenvectors back by B^(-H). This is a candidate % calculation; the original-pencil residual is independently widened. W = ctranspose (net_widen (model.B_frozen, q, bits)) \ net_widen (Wc, q, bits); result.raw_W_pencil_hash = net_raw_hash (W, [job.id, "_raw_W_pencil"]); result.right_residual_box = net_iv_cmatrix_sub ... (net_iv_cmatrix_mul (A_box, net_iv_cmatrix_point (Vq, q), q), ... net_iv_cmatrix_mul (net_iv_cmatrix_mul (B_box, ... net_iv_cmatrix_point (Vq, q), q), net_iv_cmatrix_point (Dq, q), q), q); left_A = net_iv_cmatrix_mul (net_iv_cmatrix_conjtrans (net_iv_cmatrix_point (W, q)), A_box, q); left_B = net_iv_cmatrix_mul (net_iv_cmatrix_conjtrans (net_iv_cmatrix_point (W, q)), B_box, q); % For columns W satisfying C'*W=W*D', the pencil convention is % W'*A-D*W'*B; the diagonal factor is D, not ctranspose(D). left_rhs = net_iv_cmatrix_mul (net_iv_cmatrix_point (Dq, q), left_B, q); result.left_residual_box = net_iv_cmatrix_sub (left_A, left_rhs, q); % These are residual evaluations of approximate candidates, not exact % identities. Therefore zero containment is diagnostic only; the % acceptance predicate uses their outward finite norm bounds. result.right_residual_norm_upper = net_iv_cmatrix_fro_upper ... (result.right_residual_box, q); result.left_residual_norm_upper = net_iv_cmatrix_fro_upper ... (result.left_residual_box, q); result.right_residual_encloses_zero = contains_zero (result.right_residual_box); result.left_residual_encloses_zero = contains_zero (result.left_residual_box); result.residual_target = net_pow2 (-64, q); result.residual_accuracy_pass = result.right_residual_norm_upper <= result.residual_target ... && result.left_residual_norm_upper <= result.residual_target; result.finite_pass = result.finite_pass && result.residual_accuracy_pass; result.graph = []; result.cluster = []; result.original_pencil_graph_residual = []; if (strcmp (regime, "defective_cluster")) preparation = net_v_s2_candidate (C0, mp (1), net_pow2 (-2, bits), ... job.leading_cluster_dimension, bits); result.graph_candidate_source = preparation.candidate_source; result.graph_candidate_bits = bits; graph = []; cluster = []; selected_X = []; newton_attempts = cell (0, 1); % Both bounded candidate strategies are candidate-only. The proof % below decides which, if either, has a separated complement. for strategy = 1:min (2, numel (preparation.candidates)) X_try = net_widen (preparation.candidates{strategy}, q, bits); newton = candidate_newton_for_basis (C0, X_try, ... job.leading_cluster_dimension, q); newton_attempts{end + 1} = newton; corrected_X = X_try; if (newton.success) corrected_X = transform_basis (X_try, newton.final_Z, ... job.leading_cluster_dimension, q); endif graph_try = net_v_s2_graph (C0, corrected_X, ... job.leading_cluster_dimension, q, struct ("A_box", C_box)); if (graph_try.pass && graph_try.nontrivial) % VA2 uses a fixed 2^-16 cluster-radius target. This is a % separation/usefulness contract for the n=6 pencil, not a % post-result tolerance and not the VS2 target. cluster_job = struct ("fixture", struct ("regime", "jordan", ... "query_radius", "1/4"), "cluster_dimension", ... job.leading_cluster_dimension, "cluster_radius_target_exponent", ... job.cluster_radius_target_exponent); cluster_try = net_v_s2_cluster (graph_try, corrected_X, mp (1), ... cluster_job, profile, q); else cluster_try = []; endif graph = graph_try; cluster = cluster_try; selected_X = corrected_X; if (! isempty (cluster_try) && cluster_try.pass) break; endif endfor result.graph = graph; result.cluster = cluster; result.cluster_newton_attempts = newton_attempts; result.selected_cluster_candidate = selected_X; if (graph.pass && graph.nontrivial && isstruct (cluster) ... && cluster.pass) Y1 = graph.Y1_box; MY = net_iv_cmatrix_mul (B_box, Y1, q); pencil_lhs = net_iv_cmatrix_mul (A_box, Y1, q); pencil_rhs = net_iv_cmatrix_mul (MY, graph.M_box, q); result.original_pencil_graph_residual = net_iv_cmatrix_sub ... (pencil_lhs, pencil_rhs, q); result.original_pencil_graph_encloses_zero = contains_zero ... (result.original_pencil_graph_residual); else result.original_pencil_graph_encloses_zero = false; endif else result.original_pencil_graph_encloses_zero = true; endif if (! result.finite_pass) result.status = "INCONCLUSIVE_FINITE_ROOT_COVERAGE"; result.claim_status = "INCONCLUSIVE"; result.pass = false; elseif (strcmp (regime, "defective_cluster") ... && (! isstruct (result.cluster) || ! result.cluster.pass ... || ! result.original_pencil_graph_encloses_zero)) result.status = "INCONCLUSIVE_DEFECTIVE_CLUSTER"; result.claim_status = "INCONCLUSIVE"; result.pass = false; else result.status = "CERTIFIED_ALL_FINITE"; result.claim_status = "CERTIFIED_ALL_FINITE"; if (strcmp (regime, "defective_cluster")) result.claim_status = "CERTIFIED_ALL_FINITE_AND_CLUSTER"; endif result.pass = true; endif result.milestone_pass = result.pass; result.claim_quality = "proved_reduction_binds_original_A_B"; catch exception result.status = "FAILED_VERIFIER"; result.claim_status = "ERROR"; result.claim_quality = "not_identified"; result.error_identifier = exception.identifier; result.error_message = exception.message; result.pass = false; result.milestone_pass = false; end_try_catch unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = candidate_newton_for_basis (A, X, k, q) result = struct ("method", "neigt_candidate_graph_newton_v1", ... "candidate_only", true, "success", false, "status", "NOT_RUN", ... "initial_Z", [], "final_Z", [], "steps", struct ([]), ... "steps_used", 0); try C0 = X \ (A * X); h = rows (A) - k; Z0 = -(C0((k + 1):rows(A), (k + 1):rows(A)) \ ... C0((k + 1):rows(A), 1:k)); result = net_v_s2_newton (C0, k, Z0, q); catch exception result.status = "FAILED_PREPARATION"; result.error_identifier = exception.identifier; result.error_message = exception.message; end_try_catch endfunction function result = transform_basis (X, Z, k, q) n = rows (X); h = n - k; transform = mp (zeros (n, n)); transform(1:k, 1:k) = mp (eye (k)); transform((k + 1):n, 1:k) = Z; transform((k + 1):n, (k + 1):n) = mp (eye (h)); result = X * transform; endfunction function result = status_template (job, profile_data) result = struct ("id", job.id, "tier", job.tier, "kind", job.kind, ... "status", "NOT_IMPLEMENTED", "pass", false, "milestone_pass", false, ... "claim_status", "", "claim_quality", "", "candidate_source", "", ... "candidate_bits", profile_data.source_bits, ... "evaluation_bits", profile_data.evaluation_bits, "source", "", ... "input_status", "", "input_hash_A", "", "input_hash_B", "", ... "input_hash_C", "", "raw_RB_hash", "", "raw_C0_hash", "", ... "raw_V_hash", "", "raw_D_hash", "", "raw_W_hash", "", ... "raw_W_pencil_hash", "", "raw_V", [], "raw_D", [], "raw_Wc", [], ... "finite_certificate", [], "graph", [], "cluster", [], ... "finite_root_count", 0, "finite_root_coverage", false, ... "finite_pass", false, "eB", mp ("NaN"), "fB", mp ("NaN"), ... "etaB", mp ("NaN"), "right_residual_norm_upper", mp ("NaN"), ... "left_residual_norm_upper", mp ("NaN"), ... "right_residual_encloses_zero", false, "left_residual_encloses_zero", false, ... "residual_accuracy_pass", false, "original_pencil_graph_encloses_zero", false, ... "error_identifier", "", "error_message", ""); endfunction function result = contains_zero (matrix) result = all (matrix.rl(:) <= mp (0) & matrix.rh(:) >= mp (0) ... & matrix.il(:) <= mp (0) & matrix.ih(:) >= mp (0)); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_s3_classify.m0000644000230300031750000000143315274353472025457 0ustar rafaelrafael% Classify a rigorously enclosed sigma_min interval against epsilon. % This helper deliberately leaves boundary/straddling intervals inconclusive. function result = net_v_s3_classify (lower, upper, epsilon) if (nargin != 3 || ! isa (lower, "mp") || ! isa (upper, "mp") ... || ! isa (epsilon, "mp") || ! isscalar (lower) || ! isscalar (upper) ... || ! isscalar (epsilon) || ! isfinite (lower) || ! isfinite (upper) ... || ! isfinite (epsilon) || lower < mp (0) || upper < lower ... || epsilon <= mp (0)) error ("mplapack:neigt:VS3", "invalid singular-value classification interval"); endif if (upper <= epsilon) result = "CERTIFIED_INSIDE"; elseif (lower > epsilon) result = "CERTIFIED_OUTSIDE"; else result = "INCONCLUSIVE"; endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_ufp.m0000644000230300031750000000125315274353472023502 0ustar rafaelrafael% Exact unit-in-the-first-place power for a positive MP scalar. function exponent = net_ufp (value) if (nargin != 1 || ! isa (value, "mp") || ! isscalar (value) ... || ! isfinite (value) || value <= mp (0)) error ("mplapack:neigt:Ufp", "ufp expects a positive finite MP scalar"); endif value = abs (value); exponent = 0; scale = mp (1); while (value >= mp (2) * scale) scale = scale * mp (2); exponent += 1; endwhile while (value < scale) scale = scale * mp ("0.5"); exponent -= 1; endwhile if (! (scale <= value && value < mp (2) * scale)) error ("mplapack:neigt:Ufp", "exact ufp search did not bracket value"); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_mp_integer_hex.m0000644000230300031750000000131515274353472025704 0ustar rafaelrafael% Convert a bounded nonnegative MP integer to lowercase hexadecimal. function result = net_mp_integer_hex (value) if (nargin != 1 || ! isa (value, "mp") || ! isscalar (value) ... || ! isfinite (value) || value < mp (0) || floor (value) != value) error ("mplapack:neigt:DyadicHex", "expected a finite nonnegative MP integer"); endif if (value == mp (0)) result = "0"; return; endif digits = ""; sixteen = mp (16); while (value > mp (0)) quotient = floor (value / sixteen); remainder = value - sixteen * quotient; digit = double (remainder); hex = "0123456789abcdef"; digits = [hex(digit + 1), digits]; value = quotient; endwhile result = digits; endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_neigt_encode_value.m0000644000230300031750000000534015274353472026530 0ustar rafaelrafael% Encode an arbitrary finite result value without a decimal MP round trip. % The returned tagged structure is consumed by net_neigt_decode_value. function result = net_neigt_encode_value (value, stored_bits) if (nargin != 2 || ! isnumeric (stored_bits) || ! isscalar (stored_bits) ... || stored_bits != fix (stored_bits) || stored_bits < 1) error ("mplapack:neigt:Serialize", "invalid encoded-value precision"); endif if (isa (value, "mp")) result = struct ("kind", "mp_matrix", "shape", size (value), ... "stored_precision", stored_bits, "values", []); encoded = cell (numel (value), 1); for index = 1:numel (value) if (numel (value) == 1) item = value; else item = value(index); endif encoded{index} = net_dyadic_encode_scalar (item, stored_bits); endfor result.values = encoded; return; endif if (islogical (value)) result = struct ("kind", "logical_array", "shape", size (value), ... "values", []); result.values = num2cell (value(:)); return; endif if (isa (value, "double")) if (any (! isfinite (value(:)))) error ("mplapack:neigt:Serialize", ... "nonfinite binary value cannot enter a proof artifact"); endif result = struct ("kind", "double_array", "shape", size (value), ... "values", []); result.values = num2cell (value(:)); return; endif if (ischar (value)) if (rows (value) != 1) error ("mplapack:neigt:Serialize", "character matrices are unsupported"); endif result = struct ("kind", "char", "value", value); return; endif if (iscell (value)) result = struct ("kind", "cell_array", "shape", size (value), ... "items", []); items = cell (numel (value), 1); for index = 1:numel (value) items{index} = net_neigt_encode_value (value{index}, stored_bits); endfor result.items = items; return; endif if (isstruct (value)) if (numel (value) == 1) result = struct ("kind", "struct", "fields", struct ()); names = fieldnames (value); for index = 1:numel (names) name = names{index}; result.fields.(name) = net_neigt_encode_value ... (value.(name), stored_bits); endfor else result = struct ("kind", "struct_array", "shape", size (value), ... "items", []); items = cell (numel (value), 1); for index = 1:numel (value) items{index} = net_neigt_encode_value (value(index), stored_bits); endfor result.items = items; endif return; endif error ("mplapack:neigt:Serialize", ... "unsupported proof-artifact value class %s", class (value)); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_complex_sub.m0000644000230300031750000000021615274353472025724 0ustar rafaelrafaelfunction result = net_iv_complex_sub (a, b, q) result = net_iv_complex_add (a, net_iv_complex (-b.rh, -b.rl, -b.ih, -b.il), q); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_ceil_log2_integer.m0000644000230300031750000000061615274353472026266 0ustar rafaelrafael% Exact ceil(log2(n)) for a bounded positive integer dimension. function answer = net_ceil_log2_integer (n) if (! isnumeric (n) || ! isscalar (n) || ! isreal (n) ... || ! isfinite (n) || n != fix (n) || n < 1) error ("mplapack:neigt:Integer", "expected a positive integer"); endif answer = 0; power = 1; while (power < n) power *= 2; answer += 1; endwhile endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_hadamard_reference.m0000644000230300031750000000215015274353472026464 0ustar rafaelrafael% A1 closed-form eigenvalue conditions for the bidiagonal model. function result = net_hadamard_reference (n, s, bits) if (nargin != 3 || n != fix (n) || n < 2 || s != fix (s) || s < 1) error ("mplapack:neigt:Hadamard", "invalid Hadamard reference arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); eigenvalues = mp (transpose (1:n)); condition_numbers = mp (zeros (n, 1)); for k = 1:n left_sum = mp (1); term = mp (1); for j = 1:(k - 1) term = term * mp (s) / mp (j); left_sum = left_sum + term * term; endfor right_sum = mp (1); term = mp (1); for j = 1:(n - k) term = term * mp (s) / mp (j); right_sum = right_sum + term * term; endfor condition_numbers(k) = sqrt (left_sum) * sqrt (right_sum); endfor result = struct ("reference_status", "analytic_exact", ... "reference_bits", bits, "eigenvalues", eigenvalues, ... "condition_numbers", condition_numbers, "source", "A1_CLOSED_FORM"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_frank_polynomial.m0000644000230300031750000000353615274353472026262 0ustar rafaelrafael% Characteristic polynomial recurrence and independent Horner evaluation. function result = net_frank_polynomial (n, bits) if (nargin != 2 || n != fix (n) || n < 1) error ("mplapack:neigt:Frank", "invalid polynomial arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); coefficients = cell (n + 1, 1); coefficients{1} = mp (1); if (n >= 1) coefficients{2} = mp ([1, -1]); endif for degree = 2:n previous = coefficients{degree}; before_previous = coefficients{degree - 1}; % (x-1)P_(degree-1) - (degree-1)xP_(degree-2). term = mp (zeros (1, numel (previous) + 1)); for j = 1:numel (previous) term(j) = term(j) + previous(j); term(j + 1) = term(j + 1) - previous(j); endfor shifted = mp (zeros (1, numel (before_previous) + 2)); for j = 1:numel (before_previous) if (numel (before_previous) == 1) shifted(j + 1) = before_previous; else shifted(j + 1) = before_previous(j); endif endfor for j = 1:numel (term) term(j) = term(j) - mp (degree - 1) * shifted(j); endfor coefficients{degree + 1} = term; endfor polynomial = coefficients{n + 1}; points = [0, 1, 2, 3, n + 1]; checks = false (numel (points), 1); values = mp (zeros (numel (points), 1)); for p = 1:numel (points) x = mp (points(p)); accumulator = mp (0); for j = 1:numel (polynomial) accumulator = accumulator * x + polynomial(j); endfor values(p) = accumulator; checks(p) = true; endfor result = struct ("coefficients", polynomial, "degree", n, ... "points", points, "values", values, "checks", checks, ... "source", "A2_FRANK_CHARACTERISTIC_RECURRENCE"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_pow2.m0000644000230300031750000000145715274353472023605 0ustar rafaelrafael% Construct an exact power of two through public MP binary operations. function value = net_pow2 (exponent, bits) if (nargin != 2 || ! isnumeric (exponent) || ! isscalar (exponent) ... || ! isreal (exponent) || ! isfinite (exponent) ... || exponent != fix (exponent) || ! isnumeric (bits) ... || ! isscalar (bits) || bits != fix (bits) || bits < 1) error ("mplapack:neigt:Power", "invalid exact power-of-two arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); value = mp (1); if (exponent >= 0) for index = 1:exponent value = value * mp (2); endfor else for index = 1:(-exponent) value = value * mp ("0.5"); endfor endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a2_model.m0000644000230300031750000000401015274353472024711 0ustar rafaelrafael% Exact finite-pencil fixtures from CASES.md Section 11. function result = net_v_a2_model (regime, n, bits) regime = char (regime); if (n != 6 || bits != fix (bits) || bits < 64) error ("mplapack:neigt:VA2", "invalid fixed VA2 model dimensions"); endif pair = net_exact_similarity (n, bits); J = mp (zeros (n, n)); if (strcmp (regime, "real_simple")) for i = 1:n J(i,i) = mp (i); endfor elseif (strcmp (regime, "complex_simple")) J(1,1) = mp (1); J(1,2) = mp ("0.5"); J(2,1) = mp ("-0.5"); J(2,2) = mp (1); for i = 3:n J(i,i) = mp (i); endfor elseif (strcmp (regime, "defective_cluster")) J(1,1) = mp (1); J(1,2) = mp (1); J(2,2) = mp (1); for i = 3:n J(i,i) = mp (i + 1); endfor else error ("mplapack:neigt:VA2", "unsupported fixed VA2 regime %s", regime); endif C_real = pair.Y * J * pair.X; B_real = mp (eye (n)) + pair.N; if (strcmp (regime, "complex_simple")) Z = phase_matrix (n); C = Z * C_real * ctranspose (Z); B = Z * B_real * ctranspose (Z); else C = C_real; B = B_real; endif A = B * C; if (strcmp (regime, "real_simple")) source = "VA2_REAL_SIMPLE_EXACT_SOLVE_REDUCTION"; elseif (strcmp (regime, "complex_simple")) source = "VA2_COMPLEX_SIMPLE_EXACT_SOLVE_REDUCTION"; else source = "VA2_DEFECTIVE_CLUSTER_EXACT_SOLVE_REDUCTION"; endif result = struct ("family", "finite_pencil", "n", n, "A_model", A, ... "A_frozen", A, "B_model", B, "B_frozen", B, "C_model", C, ... "C_frozen", C, "input_status", "exact_model", "source", source); endfunction function result = phase_matrix (n) result = mp (eye (n)); values = mp (zeros (n, 1)); values(1) = net_mp_complex (mp (1), mp (0)); values(2) = net_mp_complex (mp (0), mp (1)); values(3) = net_mp_complex (mp (-1), mp (0)); values(4) = net_mp_complex (mp (0), mp (-1)); values(5) = net_mp_complex (mp (1), mp (0)); values(6) = net_mp_complex (mp (0), mp (1)); for i = 1:n result(i,i) = values(i); endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_s2_candidate.m0000644000230300031750000001352015274353472025555 0ustar rafaelrafael% Candidate-only preparation for the V-S2 graph checker. % The contour projector and QR are numerical suggestions only. No candidate % status is used as proof; net_v_s2_graph rechecks the supplied basis. function result = net_v_s2_candidate (A, center, radius, k, bits) if (nargin != 5 || ! isa (A, "mp") || rows (A) != columns (A) ... || ! isa (center, "mp") || ! isscalar (center) || ! isa (radius, "mp") ... || ! isscalar (radius) || radius <= mp (0) || k != fix (k) ... || k < 1 || k >= rows (A) || bits != fix (bits) || bits < 64) error ("mplapack:neigt:VS2", "invalid candidate preparation arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); n = rows (A); I = mp (eye (n)); node_counts = [16, 32, 64]; projectors = cell (numel (node_counts), 1); q_bases = cell (numel (node_counts), 1); selected_bases = cell (numel (node_counts), 1); records = struct ([]); for count_index = 1:numel (node_counts) node_count = node_counts(count_index); P_hat = mp (zeros (n, n)); solve_count = 0; failed_nodes = 0; for node = 0:(node_count - 1) theta = (mp (2) * pi ()) * (mp (node) + mp ("0.5")) / mp (node_count); unit = net_mp_complex (cos (theta), sin (theta)); z = center + radius * unit; zI = mp (zeros (n, n)); for diagonal = 1:n zI(diagonal, diagonal) = z; endfor shifted = zI - A; try resolvent = shifted \ I; solve_count += 1; P_hat += ((z - center) / mp (node_count)) * resolvent; catch failed_nodes += 1; end_try_catch endfor projectors{count_index} = P_hat; if (failed_nodes == 0) [Q, R] = qr (P_hat); q_bases{count_index} = Q; rank_indicator = abs (R(k,k)); else q_bases{count_index} = []; rank_indicator = mp (0); endif if (failed_nodes == 0) [selected, selected_indices] = select_columns (P_hat, k, bits); selected_bases{count_index} = selected; else selected_indices = []; endif record = struct ("node_count", node_count, "solve_count", solve_count, ... "failed_nodes", failed_nodes, "rank_indicator", rank_indicator, ... "selected_indices", selected_indices, ... "candidate_source", "contour_projector_then_public_qr", ... "candidate_bits", bits); if (isempty (records)) records = record; else records(end + 1) = record; endif endfor final_Q = q_bases{end}; if (isempty (final_Q) || ! isequal (size (final_Q), [n, n])) error ("mplapack:neigt:VS2", "contour candidate did not produce a square QR basis"); endif final_Q1 = selected_bases{end}; if (isempty (final_Q1) || ! isequal (size (final_Q1), [n, k])) error ("mplapack:neigt:VS2", "contour candidate did not produce selected columns"); endif % The first candidate is the full computed QR basis, retained for the % simple/repeated fixtures where its leading columns are already suitable. % The second replaces its selected block by deterministic norm-pivoted % projector columns while retaining the computed QR complement. Both are % bounded computed alternatives and neither uses generator columns. X_normalized_qr = [final_Q1, final_Q(:, (k + 1):n)]; result = struct ("method", "neigt_candidate_contour_qr_v1", ... "paper_algorithm_reproduction", false, "candidate_source", ... "computed_subspace_bounded_schedule", "node_counts", node_counts, ... "records", records, "projectors", {projectors}, "q_bases", {q_bases}, ... "selected_bases", {selected_bases}, "candidates", {{final_Q, X_normalized_qr}}, ... "completion_strategies", 2, ... "selected_node_count", node_counts(end), "candidate_bits", bits, ... "cluster_dimension", k); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function [result, selected_indices] = select_columns (P_hat, k, bits) n = rows (P_hat); result = mp (zeros (n, k)); selected_indices = zeros (1, k); residuals = P_hat; selected = false (1, n); threshold = net_pow2 (-floor (bits / 4), bits); for target = 1:k best = 0; best_norm = mp (0); for column = 1:n if (! selected(column)) candidate_norm = norm (residuals(:, column)); if (candidate_norm > best_norm) best = column; best_norm = candidate_norm; endif endif endfor if (best == 0 || best_norm <= threshold) error ("mplapack:neigt:VS2", "contour projector candidate is rank deficient"); endif selected(best) = true; selected_indices(target) = best; vector = residuals(:, best) / best_norm; result(:, target) = vector; for column = 1:n if (! selected(column)) coefficient = ctranspose (vector) * residuals(:, column); residuals(:, column) = residuals(:, column) - vector * coefficient; endif endfor endfor endfunction function result = coordinate_completion (Q1, Q, k, bits) n = rows (Q1); result = mp (zeros (n, n)); result(:, 1:k) = Q1; used = k; threshold = net_pow2 (-floor (bits / 4), bits); for coordinate = 1:n if (used == n) break; endif e = mp (zeros (n, 1)); e(coordinate) = mp (1); coefficient = ctranspose (result(:,1:used)) * e; residual = e - result(:,1:used) * coefficient; if (norm (residual) > threshold) used += 1; result(:, used) = e; endif endfor if (used < n) for column = (k + 1):columns (Q) if (used == n) break; endif used += 1; result(:, used) = Q(:, column); endfor endif if (used != n) error ("mplapack:neigt:VS2", "coordinate completion did not reach full dimension"); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_point.m0000644000230300031750000000052015274353472024533 0ustar rafaelrafael% Make a point interval without evaluating a proof operation. function result = net_iv_point (value, q) net_iv_q (q); if (nargin != 2 || ! isa (value, "mp") || ! isscalar (value) ... || ! isfinite (value)) error ("mplapack:neigt:Interval", "invalid real point"); endif result = net_iv_real (value, value); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_grcar_reference.m0000644000230300031750000000207415274353472026026 0ustar rafaelrafael% Two independently evaluated general MP eig references for Grcar. function result = net_grcar_reference (model, bits1, bits2) if (nargin != 3 || ! isstruct (model) || ! isfield (model, "A_model") ... || bits1 != fix (bits1) || bits2 != fix (bits2) || bits1 < 64 || bits2 < bits1) error ("mplapack:neigt:Grcar", "invalid Grcar reference arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits1); A1 = mp (zeros (size (model.A_model))) + model.A_model; [unused1, D1] = eig (A1, "nobalance"); values1 = diag (D1); mpbits (bits2); A2 = mp (zeros (size (model.A_model))) + model.A_model; [unused2, D2] = eig (A2, "nobalance"); values2 = diag (D2); comparison = net_match (values2, values1, "absolute"); result = struct ("reference_status", "general_mp_eig_two_precisions", ... "bits1", bits1, "bits2", bits2, "values1", values1, "values2", values2, ... "agreement", comparison, "source", "A4_GENERAL_MP_EIG_REFERENCE"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_s2_newton.m0000644000230300031750000000636015274353472025157 0ustar rafaelrafael% Candidate-only bounded Newton correction for the invariant graph equation. % This routine never supplies a proof result. net_v_s2_graph must recheck % the transformed basis from scratch with outward arithmetic. function result = net_v_s2_newton (C, k, Z0, bits) if (nargin != 4 || ! isa (C, "mp") || rows (C) != columns (C) ... || k != fix (k) || k < 1 || k >= rows (C) || ! isa (Z0, "mp") ... || ! isequal (size (Z0), [rows(C) - k, k]) || bits != fix (bits) ... || bits < 64) error ("mplapack:neigt:VS2", "invalid graph Newton arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); n = rows (C); h = n - k; Z = Z0; max_candidate_entry = net_pow2 (64, bits); initial_residual = mp (0); records = struct ([]); for step = 1:4 C11 = C(1:k, 1:k); C12 = C(1:k, (k + 1):n); C21 = C((k + 1):n, 1:k); C22 = C((k + 1):n, (k + 1):n); F = C21 + C22 * Z - Z * C11 - Z * C12 * Z; before = norm (F, "fro"); if (step == 1) initial_residual = before; endif Kz = kron (mp (eye (k)), C22 - Z * C12) ... - kron (transpose (C11 + C12 * Z), mp (eye (h))); record = struct ("step", step, "status", "NOT_RUN", ... "residual_before", before, "residual_after", mp ("NaN"), ... "solve_source", "public_point_solve", "bits", bits, ... "error_identifier", "", "error_message", ""); try correction = Kz \ (-reshape (F, h * k, 1)); Z = Z + reshape (correction, h, k); if (! all (isfinite (Z(:))) || any (abs (Z(:)) > max_candidate_entry)) record.status = "REJECTED_UNBOUNDED_STEP"; record.error_identifier = "mplapack:neigt:CandidateBound"; record.error_message = "candidate Newton step exceeded bounded preparation range"; if (isempty (records)) records = record; else records(end + 1) = record; endif break; endif F_after = C21 + C22 * Z - Z * C11 - Z * C12 * Z; record.status = "SUCCESS"; record.residual_after = norm (F_after, "fro"); catch exception record.status = "FAILED_SOLVE"; record.error_identifier = exception.identifier; record.error_message = exception.message; end_try_catch if (isempty (records)) records = record; else records(end + 1) = record; endif if (! strcmp (record.status, "SUCCESS")) break; endif if (record.residual_after == mp (0)) break; endif endfor improved = ! isempty (records) && strcmp (records(end).status, "SUCCESS") ... && records(end).residual_after <= initial_residual; result = struct ("method", "neigt_candidate_graph_newton_v1", ... "paper_algorithm_reproduction", false, "candidate_only", true, ... "max_steps", 4, "steps", records, "steps_used", numel (records), ... "initial_Z", Z0, "final_Z", Z, "candidate_bits", bits, ... "initial_residual", initial_residual, "improved", improved, ... "success", improved && all (strcmp ({records.status}, "SUCCESS"))); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_dyadic_encode_matrix.m0000644000230300031750000000163315274353472027050 0ustar rafaelrafael% Encode an MP matrix in column-major order. function result = net_dyadic_encode_matrix (value, stored_bits) if (nargin != 2 || ! isa (value, "mp") || ndims (value) > 2) error ("mplapack:neigt:Serialize", "matrix serialization requires an MP matrix"); endif if (! isnumeric (stored_bits) || ! isscalar (stored_bits) ... || stored_bits != fix (stored_bits) || stored_bits < 1 ... || ! all (isfinite (real (value))) || ! all (isfinite (imag (value)))) error ("mplapack:neigt:Serialize", "invalid matrix serialization input"); endif encoded = cell (numel (value), 1); for index = 1:numel (value) encoded{index} = net_dyadic_encode_scalar (value(index), stored_bits); endfor result = struct ("schema", "neigt-dyadic-v1", ... "method_version", "public-mp-binary-extraction-v1", ... "shape", size (value), "stored_precision", stored_bits, ... "values", {encoded}); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_rounded_product.m0000644000230300031750000000144115274353472026107 0ustar rafaelrafael% Explicit scalar-by-scalar RN_g matrix product. function product = net_rounded_product (left, right, bits) if (nargin != 3 || ! isa (left, "mp") || ! isa (right, "mp") ... || columns (left) != rows (right)) error ("mplapack:neigt:RoundedProduct", "invalid rounded product arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); product = mp (zeros (rows (left), columns (right))); for i = 1:rows (left) for j = 1:columns (right) accumulator = mp (0); for k = 1:columns (left) term = left(i, k) * right(k, j); accumulator = accumulator + term; endfor product(i, j) = accumulator + mp (0); endfor endfor unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_real_add.m0000644000230300031750000000032515274353472025140 0ustar rafaelrafaelfunction result = net_iv_real_add (a, b, q) net_iv_q (q); result = net_iv_real (net_iv_primitive ("add", a.lo, b.lo, q).lo, ... net_iv_primitive ("add", a.hi, b.hi, q).hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_forsythe_reference.m0000644000230300031750000000260515274353472026573 0ustar rafaelrafael% MP unit-circle reference for the nonzero Forsythe cases. function result = net_forsythe_reference (n, a, reference_bits) if (nargin != 3 || n != fix (n) || n < 3 || a != fix (a) || a < 1) error ("mplapack:neigt:Forsythe", "invalid Forsythe reference arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (reference_bits); radius = net_pow2 (-a, reference_bits); pi_value = acos (mp ("-1")); unit_roots = mp (zeros (n, 1)); eigenvalues = mp (zeros (n, 1)); for k = 0:(n - 1) if (k == 0) real_part = mp (1); imaginary_part = mp (0); elseif (mod (n, 2) == 0 && k == n / 2) real_part = mp (-1); imaginary_part = mp (0); else angle = mp (2) * pi_value * mp (k) / mp (n); real_part = cos (angle); imaginary_part = sin (angle); endif unit_roots(k + 1) = net_mp_complex (real_part, imaginary_part); eigenvalues(k + 1) = net_mp_complex (... mp (1) + radius * real_part, radius * imaginary_part); endfor result = struct ("reference_status", "analytic_MP_unit_circle", ... "reference_bits", reference_bits, "radius", radius, ... "unit_roots", unit_roots, "eigenvalues", eigenvalues, ... "source", "S4_CIRCLE_REFERENCE"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_similarity_audit.m0000644000230300031750000001562415274353472026273 0ustar rafaelrafael% Exact-structure and ordinary subspace audit for one S2 similarity model. function result = net_similarity_audit (fixture, characteristic_points) if (nargin < 1 || nargin > 2 || ! isstruct (fixture) ... || ! isfield (fixture, "A_frozen") || ! isfield (fixture, "J") ... || ! isfield (fixture, "similarity")) error ("mplapack:neigt:Similarity", "invalid similarity audit fixture"); endif n = rows (fixture.J); if (nargin == 1) characteristic_points = [0, 1, 2, 3, 4, n + 1]; endif saved_bits = mpbits (); unwind_protect mpbits (max (saved_bits, fixture.generation_bits)); X = fixture.similarity.X; Y = fixture.similarity.Y; A = fixture.A_frozen; J = fixture.J; [XA, xa_metadata] = net_exact_product_dyadic (X, A, fixture.generation_bits); [JX, jx_metadata] = net_exact_product_dyadic (J, X, fixture.generation_bits); [AY, ay_metadata] = net_exact_product_dyadic (A, Y, fixture.generation_bits); [YJ, yj_metadata] = net_exact_product_dyadic (Y, J, fixture.generation_bits); exact_intertwining = (XA == JX && AY == YJ); if (! exact_intertwining) error ("mplapack:neigt:Similarity", ... "exact X*A=J*X or A*Y=Y*J check failed"); endif [groups, diagonalizable, full_basis] = similarity_groups (fixture.regime, J); characteristic_checks = false (numel (characteristic_points), 1); for point_index = 1:numel (characteristic_points) point = mp (characteristic_points(point_index)); polynomial_matrix = point * mp (eye (n)) - J; actual = det (polynomial_matrix); expected = mp (1); for i = 1:n expected = expected * (point - J(i, i)); endfor characteristic_checks(point_index) = (actual == expected); endfor if (! all (characteristic_checks)) error ("mplapack:neigt:Similarity", ... "independent characteristic checks failed"); endif nilpotent_checks = cell (numel (groups), 1); subspace_checks = cell (numel (groups), 1); for group_index = 1:numel (groups) indices = groups(group_index).indices; block = J(indices, indices); root = J(indices(1), indices(1)); nilpotent = block - root * mp (eye (numel (indices))); first_power = (norm (nilpotent, "fro") != mp (0)); second_power = all (all (nilpotent * nilpotent ... == mp (zeros (numel (indices))))); if (groups(group_index).geometric_multiplicity == 2) nilpotent_ok = (! first_power && second_power); elseif (groups(group_index).algebraic_multiplicity == 2) nilpotent_ok = (first_power && second_power); else nilpotent_ok = true; endif nilpotent_checks{group_index} = struct (... "indices", indices, "first_power_nonzero", first_power, ... "second_power_zero", second_power, "status", nilpotent_ok); basis = similarity_basis (fixture, groups(group_index)); [Q, unused] = qr (basis); Q = Q(:, 1:numel (indices)); reduced = ctranspose (Q) * A * Q; invariant_residual = norm (A * Q - Q * reduced, "fro"); projector = Q * ctranspose (Q); subspace_checks{group_index} = struct (... "indices", indices, "dimension", numel (indices), ... "orthogonal_projector", projector, ... "invariant_residual", invariant_residual, ... "status", isfinite (invariant_residual) ... && invariant_residual < mp ("1e-100")); endfor oblique = Y(:, 1:min (2, n)) * X(1:min (2, n), :); oblique_idempotent = oblique * oblique == oblique; result = struct (... "status", "MEASURED", "regime", fixture.regime, ... "groups", groups, "exact_intertwining", exact_intertwining, ... "intertwining_metadata", {{xa_metadata, jx_metadata, ay_metadata, ... yj_metadata}}, ... "characteristic_points", characteristic_points, ... "characteristic_checks", characteristic_checks, ... "nilpotent_checks", {nilpotent_checks}, ... "subspace_checks", {subspace_checks}, ... "diagonalizable", diagonalizable, ... "full_eigenbasis_exists", full_basis, ... "coordinate_columns_diagonalize", ... strcmp (fixture.regime, "semisimple"), ... "multiplicity_source", "exact_J_structure_not_disk_count", ... "oblique_projector_kind", "union_of_full_J_blocks", ... "oblique_projector_idempotent", oblique_idempotent); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function basis = similarity_basis (fixture, group) indices = group.indices; basis = fixture.similarity.Y(:, indices); % The second simple eigenvector of the non-diagonal leading block is not % Y(:,2). Solve that 2-by-2 triangular block exactly in MP coordinates. if (strcmp (fixture.regime, "simple") && numel (indices) == 1 ... && indices == 2) gap = fixture.J(2, 2) - fixture.J(1, 1); coordinates = mp ([1; 0]); coordinates(2) = gap; basis = fixture.similarity.Y(:, 1:2) * coordinates; endif endfunction function [groups, diagonalizable, full_basis] = similarity_groups (regime, J) n = rows (J); groups = struct ("indices", {}, "algebraic_multiplicity", {}, ... "geometric_multiplicity", {}, "root", {}, "kind", {}); if (strcmp (regime, "simple")) groups = append_simple_groups (groups, 1:n, J); diagonalizable = true; full_basis = true; elseif (strcmp (regime, "semisimple")) groups(1) = struct ("indices", [1, 2], "algebraic_multiplicity", 2, ... "geometric_multiplicity", 2, "root", J(1, 1), ... "kind", "semisimple_repeated"); groups = append_simple_groups (groups, 3:n, J); diagonalizable = true; full_basis = true; elseif (strcmp (regime, "jordan")) groups(1) = struct ("indices", [1, 2], "algebraic_multiplicity", 2, ... "geometric_multiplicity", 1, "root", J(1, 1), ... "kind", "defective_jordan"); groups = append_simple_groups (groups, 3:n, J); diagonalizable = false; full_basis = false; else groups(1) = struct ("indices", [1, 2], "algebraic_multiplicity", 2, ... "geometric_multiplicity", 1, "root", J(1, 1), ... "kind", "defective_jordan"); groups(2) = struct ("indices", [3, 4], "algebraic_multiplicity", 2, ... "geometric_multiplicity", 1, "root", J(3, 3), ... "kind", "defective_jordan"); groups = append_simple_groups (groups, 5:n, J); diagonalizable = false; full_basis = false; endif endfunction function groups = append_simple_groups (groups, indices, J) for index = indices groups(end + 1) = struct ("indices", index, ... "algebraic_multiplicity", 1, ... "geometric_multiplicity", 1, ... "root", J(index, index), "kind", "simple"); endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_complex_neg.m0000644000230300031750000000015515274353472025706 0ustar rafaelrafaelfunction result = net_iv_complex_neg (a) result = net_iv_complex (-a.rh, -a.rl, -a.ih, -a.il); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_complex.m0000644000230300031750000000113115274353472025050 0ustar rafaelrafael% Construct a closed complex rectangle from real/imaginary endpoints. function result = net_iv_complex (rl, rh, il, ih) if (nargin != 4 || ! isa (rl, "mp") || ! isa (rh, "mp") ... || ! isa (il, "mp") || ! isa (ih, "mp") ... || ! isscalar (rl) || ! isscalar (rh) || ! isscalar (il) || ! isscalar (ih) ... || ! isfinite (rl) || ! isfinite (rh) || ! isfinite (il) || ! isfinite (ih) ... || rl > rh || il > ih) error ("mplapack:neigt:Rectangle", "invalid complex rectangle"); endif result = struct ("kind", "complex", "rl", rl, "rh", rh, "il", il, "ih", ih); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_toeplitz_audit.m0000644000230300031750000000425615274353472025756 0ustar rafaelrafael% Ordinary forward and condition audit for one S3 representation. function result = net_toeplitz_audit (fixture, reference_bits) if (nargin != 2 || ! isstruct (fixture) || ! isfield (fixture, "A") ... || ! isfield (fixture, "B_symmetric")) error ("mplapack:neigt:Toeplitz", "invalid Toeplitz audit fixture"); endif reference = net_toeplitz_reference (fixture.n, fixture.b, reference_bits); saved_bits = mpbits (); unwind_protect mpbits (max (saved_bits, fixture.bits)); [VB, DB, WB] = eig (fixture.B_symmetric, "nobalance"); symmetric_values = diag (DB); symmetric_match = net_match (symmetric_values, reference.eigenvalues, ... "absolute"); if (strcmp (fixture.representation, "original")) [Vn, Dn, Wn] = eig (fixture.A, "nobalance"); [Vb, Db, Wb] = eig (fixture.A, "balance"); nobalance_metrics = net_metrics (fixture.A, Vn, Dn, Wn, ... reference.eigenvalues); balance_metrics = net_metrics (fixture.A, Vb, Db, Wb, ... reference.eigenvalues); else [Vn, Dn, Wn] = eig (fixture.A, "nobalance"); nobalance_metrics = net_metrics (fixture.A, Vn, Dn, Wn, ... reference.eigenvalues); balance_metrics = nobalance_metrics; endif condition_A = cond (fixture.A); condition_D = cond (fixture.D); similarity_condition = net_pow2 (fixture.b * (fixture.n - 1), fixture.bits); condition_separation = struct (... "matrix_A", condition_A, "scaling_D", condition_D, ... "similarity_scaling_bound", similarity_condition, ... "individual_eigenvalue", reference.condition_numbers, ... "matrix_and_eigenvalue_conditions_separate", true); result = struct (... "status", "MEASURED", "reference", reference, ... "symmetric_eig_match", symmetric_match, ... "nobalance_metrics", nobalance_metrics, ... "balance_metrics", balance_metrics, ... "condition_separation", condition_separation, ... "original_coordinate_label", fixture.representation); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_neigt_json_read.m0000644000230300031750000000145715274353472026050 0ustar rafaelrafael% Read a canonical NEIGT proof record and verify its content hash. function result = net_neigt_json_read (filename) if (nargin != 1 || ! ischar (filename) || isempty (filename)) error ("mplapack:neigt:Deserialize", "invalid proof-record path"); endif text = fileread (filename); result = jsondecode (text); if (! isstruct (result) || ! isscalar (result) ... || ! isfield (result, "sha256") || ! ischar (result.sha256)) error ("mplapack:neigt:Deserialize", "proof record hash is missing"); endif supplied = result.sha256; result = rmfield (result, "sha256"); expected = hash ("sha256", net_neigt_json_encode (result)); if (! strcmp (supplied, expected)) error ("mplapack:neigt:Deserialize", "proof record content hash mismatch"); endif result.sha256 = supplied; endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_complex_conj.m0000644000230300031750000000015415274353472026065 0ustar rafaelrafaelfunction result = net_iv_complex_conj (a) result = net_iv_complex (a.rl, a.rh, -a.ih, -a.il); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a2_expand_modulus.m0000644000230300031750000000141515274353472026646 0ustar rafaelrafael% Enlarge a complex rectangle by a verified entrywise modulus radius. function result = net_v_a2_expand_modulus (matrix, eta, q) net_iv_q (q); if (! isstruct (matrix) || ! isfield (matrix, "kind") ... || ! strcmp (matrix.kind, "complex_matrix") || ! isscalar (eta) ... || ! isfinite (eta) || eta < mp (0)) error ("mplapack:neigt:VA2", "invalid enclosure expansion"); endif result = matrix; for index = 1:numel (matrix.rl) result.rl(index) = net_iv_primitive ("sub", matrix.rl(index), eta, q).lo; result.rh(index) = net_iv_primitive ("add", matrix.rh(index), eta, q).hi; result.il(index) = net_iv_primitive ("sub", matrix.il(index), eta, q).lo; result.ih(index) = net_iv_primitive ("add", matrix.ih(index), eta, q).hi; endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_product_guard.m0000644000230300031750000000105715274353472025554 0ustar rafaelrafael% Conservative exact-product guard for bounded integer matrices. function guard = net_product_guard (left, right, bits) if (nargin != 3 || ! isa (left, "mp") || ! isa (right, "mp") ... || columns (left) != rows (right)) error ("mplapack:neigt:Guard", "incompatible product operands"); endif left_bits = net_matrix_max_bit_length (left, bits); right_bits = net_matrix_max_bit_length (right, bits); terms = columns (left); guard = left_bits + right_bits + net_ceil_log2_integer (max (1, terms)) + 4; guard = max (guard, 64); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_markov_audit.m0000644000230300031750000000472515274353472025404 0ustar rafaelrafael% Markov/Perron ordinary and stationary-vector audit. function result = net_markov_audit (n, epsilon_exponent, bits, reference_bits) markov = net_markov_model (n, epsilon_exponent, bits); perron = net_perron_model (n, epsilon_exponent, bits); markov_reference = net_markov_reference (markov, reference_bits, ... reference_bits + 64, false); perron_reference = net_markov_reference (perron.markov, reference_bits, ... reference_bits + 64, true); saved_bits = mpbits (); unwind_protect mpbits (reference_bits + 64); [V, D, W] = eig (markov.P_frozen, "nobalance"); markov_metrics = net_metrics (markov.P_frozen, V, D, W, ... perron_reference.values2 / (mp (3) / mp (2))); [Vp, Dp, Wp] = eig (perron.A_frozen, "nobalance"); perron_metrics = net_metrics (perron.A_frozen, Vp, Dp, Wp, ... perron_reference.values2); row_sums = markov.P_model * mp (ones (n, 1)); positive_markov = all (markov.P_model(:) > mp (0)); positive_perron = all (perron.A_model(:) > mp (0)); r_difference = max (abs (markov_reference.stationary_formula - ... transpose (markov.r))); perron_right = perron.D * mp (ones (n, 1)); perron_left = perron.D_inverse * transpose (markov_reference.stationary_formula); perron_right = perron_right / sum (perron_right); perron_left = perron_left / (transpose (perron_left) * perron_right); right_equation = perron.A_model * perron_right ... - perron.perron_scale * perron_right; left_equation = transpose (perron_left) * perron.A_model ... - perron.perron_scale * transpose (perron_left); result = struct ("status", "MEASURED", "markov", markov, ... "perron", perron, "markov_reference", markov_reference, ... "perron_reference", perron_reference, "markov_metrics", markov_metrics, ... "perron_metrics", perron_metrics, "row_sums", row_sums, ... "row_sum_exact", all (row_sums == mp (1)), ... "positive_markov", positive_markov, "positive_perron", positive_perron, ... "r_difference_max", r_difference, ... "perron_right", perron_right, "perron_left", perron_left, ... "perron_right_equation", right_equation, ... "perron_left_equation", left_equation, ... "source", "A6_MARKOV_PERRON_AUDIT"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_triangular_inverse.m0000644000230300031750000000100215274353472026603 0ustar rafaelrafael% Finite nilpotent series inverse of a unit triangular matrix. function inverse = net_triangular_inverse (matrix, bits) if (nargin != 2 || ! isa (matrix, "mp") ... || rows (matrix) != columns (matrix)) error ("mplapack:neigt:Inverse", "expected a square MP matrix"); endif n = rows (matrix); identity = mp (eye (n)); nilpotent = matrix - identity; term = identity; inverse = identity; for index = 1:(n - 1) term = -term * nilpotent; inverse = inverse + term; endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_inverse_residual.m0000644000230300031750000000145615274353472026756 0ustar rafaelrafael% Neumann inverse witness for a point matrix, using explicit interval products. function result = net_iv_inverse_residual (X, inverse_candidate, q) net_iv_q (q); if (nargin != 3 || ! isa (X, "mp") || ! isa (inverse_candidate, "mp") ... || rows (X) != columns (X) || ! isequal (size (X), size (inverse_candidate))) error ("mplapack:neigt:Inverse", "invalid square inverse witness"); endif n = rows (X); residual = net_iv_cmatrix_sub (net_iv_cmatrix_eye (n, q), ... net_iv_cmatrix_mul (net_iv_cmatrix_point (inverse_candidate, q), ... net_iv_cmatrix_point (X, q), q), q); e = net_iv_cmatrix_inf_upper (residual, q); result = struct ("residual", residual, "e", e, "nonsingular", e < mp (1), ... "method", "neigt_neumann_inverse_v1"); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a1_interval_qr.m0000644000230300031750000001252615274353472026151 0ustar rafaelrafael% Exact mathematical interval Gram-Schmidt/QR for a verified factor box. % Positive diagonal lower bounds are a hard precondition; no normalization % interval crossing zero is accepted. function result = net_v_a1_interval_qr (E_box, q) if (nargin != 2 || ! isstruct (E_box) || q != fix (q) || q < 64) error ("mplapack:neigt:VA1", "invalid interval QR arguments"); endif n = rows (E_box.rl); if (columns (E_box.rl) != n) error ("mplapack:neigt:VA1", "interval QR requires a square factor"); endif Q = net_iv_cmatrix_point (mp (zeros (n, n)), q); R = net_iv_cmatrix_point (mp (zeros (n, n)), q); diagonal_lower = mp (zeros (n, 1)); diagonal_upper = mp (zeros (n, 1)); for j = 1:n original = column_box (E_box, j); residual = original; for i = 1:(j - 1) qi = column_box (Q, i); rij_matrix = net_iv_cmatrix_mul (net_iv_cmatrix_conjtrans (qi), ... original, q); rij = scalar_entry (rij_matrix); R = set_entry (R, i, j, rij); residual = net_iv_cmatrix_sub (residual, ... net_iv_cmatrix_mul (qi, scalar_matrix (rij, q), q), q); endfor lower_norm = lower_vector_norm (residual, q); upper_norm = net_iv_cmatrix_fro_upper (residual, q); diagonal_lower(j) = lower_norm; diagonal_upper(j) = upper_norm; if (lower_norm <= mp (0)) result = failure (Q, R, diagonal_lower, diagonal_upper, j); return; endif rjj = net_iv_complex (lower_norm, upper_norm, mp (0), mp (0)); R = set_entry (R, j, j, rjj); Q = set_column (Q, j, divide_by_positive_real (residual, ... net_iv_real (lower_norm, upper_norm), q)); endfor result = struct ("method", "neigt_interval_qr_v1", "status", "CERTIFIED_QR", ... "pass", true, "Q_box", Q, "R_box", R, ... "diagonal_lower", diagonal_lower, "diagonal_upper", diagonal_upper, ... "all_normalizations_positive", all (diagonal_lower > mp (0)), ... "paper_algorithm_reproduction", false); endfunction function result = lower_vector_norm (vector, q) sum_box = net_iv_real (mp (0), mp (0)); for index = 1:numel (vector.rl) entry = scalar_at (vector, index); modulus = net_iv_complex_abs (entry, q); lower_point = net_iv_real (modulus.lo, modulus.lo); sum_box = net_iv_real_add (sum_box, net_iv_real_square (lower_point, q), q); endfor result = net_iv_real_sqrt (sum_box, q).lo; endfunction function result = divide_by_positive_real (vector, divisor, q) result = vector; for index = 1:numel (vector.rl) entry = scalar_at (vector, index); re = net_iv_real_div (net_iv_real (entry.rl, entry.rh), divisor, q); im = net_iv_real_div (net_iv_real (entry.il, entry.ih), divisor, q); result = set_linear_entry (result, index, ... net_iv_complex (re.lo, re.hi, im.lo, im.hi)); endfor endfunction function result = scalar_matrix (value, q) result = struct ("kind", "complex_matrix", "rl", value.rl, "rh", value.rh, ... "il", value.il, "ih", value.ih); endfunction function result = column_box (matrix, index) result = matrix; if (isscalar (matrix.rl)) result.rl = matrix.rl; result.rh = matrix.rh; result.il = matrix.il; result.ih = matrix.ih; else result.rl = matrix.rl(:,index); result.rh = matrix.rh(:,index); result.il = matrix.il(:,index); result.ih = matrix.ih(:,index); endif endfunction function result = scalar_entry (matrix) if (! isscalar (matrix.rl)) error ("mplapack:neigt:VA1", "expected a one-by-one interval matrix"); endif result = net_iv_complex (matrix.rl, matrix.rh, matrix.il, matrix.ih); endfunction function result = scalar_at (matrix, index) if (isscalar (matrix.rl)) result = net_iv_complex (matrix.rl, matrix.rh, matrix.il, matrix.ih); else result = net_iv_complex (matrix.rl(index), matrix.rh(index), ... matrix.il(index), matrix.ih(index)); endif endfunction function matrix = set_entry (matrix, i, j, value) if (isscalar (matrix.rl)) matrix.rl = value.rl; matrix.rh = value.rh; matrix.il = value.il; matrix.ih = value.ih; else matrix.rl(i,j) = value.rl; matrix.rh(i,j) = value.rh; matrix.il(i,j) = value.il; matrix.ih(i,j) = value.ih; endif endfunction function matrix = set_linear_entry (matrix, index, value) if (isscalar (matrix.rl)) matrix.rl = value.rl; matrix.rh = value.rh; matrix.il = value.il; matrix.ih = value.ih; else matrix.rl(index) = value.rl; matrix.rh(index) = value.rh; matrix.il(index) = value.il; matrix.ih(index) = value.ih; endif endfunction function matrix = set_column (matrix, index, column) if (isscalar (matrix.rl)) matrix.rl = column.rl; matrix.rh = column.rh; matrix.il = column.il; matrix.ih = column.ih; else matrix.rl(:,index) = column.rl; matrix.rh(:,index) = column.rh; matrix.il(:,index) = column.il; matrix.ih(:,index) = column.ih; endif endfunction function result = failure (Q, R, diagonal_lower, diagonal_upper, index) result = struct ("method", "neigt_interval_qr_v1", ... "status", "INCONCLUSIVE_QR_NORMALIZATION", "pass", false, ... "Q_box", Q, "R_box", R, "diagonal_lower", diagonal_lower, ... "diagonal_upper", diagonal_upper, "failed_column", index, ... "all_normalizations_positive", false, "paper_algorithm_reproduction", false); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_real_neg.m0000644000230300031750000000040415274353472025157 0ustar rafaelrafaelfunction result = net_iv_real_neg (a) if (! isstruct (a) || ! strcmp (a.kind, "real") || ! isfinite (a.lo) || ! isfinite (a.hi)) error ("mplapack:neigt:Interval", "invalid real interval"); endif result = net_iv_real (-a.hi, -a.lo); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_exact_product_dyadic.m0000644000230300031750000000464715274353472027103 0ustar rafaelrafael% Independent exact dyadic matrix product checker. % Each term is placed on a common power-of-two denominator before summation. function [product, metadata] = net_exact_product_dyadic (left, right, bits) if (nargin != 3 || ! isa (left, "mp") || ! isa (right, "mp") ... || columns (left) != rows (right) || ! isnumeric (bits) ... || ! isscalar (bits) || bits != fix (bits) || bits < 1) error ("mplapack:neigt:ExactProduct", "invalid exact product arguments"); endif m = rows (left); n = columns (right); terms = columns (left); left_parts = cell (rows (left), columns (left)); right_parts = cell (rows (right), columns (right)); minimum_exponent = 0; have_term = false; for i = 1:rows (left) for k = 1:columns (left) part = net_dyadic_decompose (left(i, k), bits); left_parts{i, k} = part; endfor endfor for k = 1:rows (right) for j = 1:columns (right) part = net_dyadic_decompose (right(k, j), bits); right_parts{k, j} = part; endfor endfor for i = 1:m for j = 1:n for k = 1:terms lp = left_parts{i, k}; rp = right_parts{k, j}; if (! lp.zero && ! rp.zero) e = lp.exponent + rp.exponent; if (! have_term || e < minimum_exponent) minimum_exponent = e; have_term = true; endif endif endfor endfor endfor if (! have_term) check_bits = max (64, bits); else check_bits = max (64, 2 * bits + net_ceil_log2_integer (max (1, terms)) + 8); endif saved_bits = mpbits (); unwind_protect mpbits (check_bits); product = mp (zeros (m, n)); for i = 1:m for j = 1:n accumulator = mp (0); for k = 1:terms lp = left_parts{i, k}; rp = right_parts{k, j}; if (! lp.zero && ! rp.zero) coefficient = lp.coefficient * rp.coefficient; shift = lp.exponent + rp.exponent - minimum_exponent; accumulator = accumulator + coefficient * net_pow2 (shift, check_bits); endif endfor product(i, j) = accumulator * net_pow2 (minimum_exponent, check_bits); endfor endfor unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect metadata = struct ("exact", true, "minimum_exponent", minimum_exponent, ... "check_bits", check_bits, "terms", terms, ... "method", "common_dyadic_denominator_v1"); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_q.m0000644000230300031750000000056315274353472023651 0ustar rafaelrafael% Validate the fixed precision contract used by every interval primitive. function net_iv_q (q) if (nargin != 1 || ! isnumeric (q) || ! isscalar (q) || ! isreal (q) ... || ! isfinite (q) || q != fix (q) || q < 64 || q > 4096) error ("mplapack:neigt:IntervalPrecision", ... "interval precision must be an integer in [64,4096]"); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_widen.m0000644000230300031750000000154415274353472024021 0ustar rafaelrafael% Exact widening of an existing represented value without text conversion. function value = net_widen (source, target_bits, source_bits) if (nargin != 3 || ! (isa (source, "mp") || isa (source, "double")) ... || ! isnumeric (target_bits) || ! isscalar (target_bits) ... || target_bits != fix (target_bits) || target_bits < 1 ... || ! isnumeric (source_bits) || ! isscalar (source_bits) ... || source_bits != fix (source_bits) || source_bits < 1 ... || target_bits < source_bits) error ("mplapack:neigt:Widen", "invalid exact-widening arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (target_bits); if (isa (source, "mp")) value = source + mp (zeros (size (source))); else value = mp (source); endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_mks_model.m0000644000230300031750000000256115274353472024665 0ustar rafaelrafael% Exact Morimoto--Katori--Shirai model 1 and reduced polynomial. function result = net_mks_model (n, m, delta, bits) if (nargin != 4 || n != fix (n) || m != fix (m) || n < 1 || m < 1 || m > n ... || ! isa (delta, "mp") || ! isscalar (delta) || delta <= mp (0) ... || bits != fix (bits) || bits < 64) error ("mplapack:neigt:MKS", "invalid MKS arguments"); endif ell = floor ((n - 1) / m) + 1; saved_bits = mpbits (); unwind_protect mpbits (bits); Npower = mp (zeros (n, n)); for i = 1:(n - m) Npower(i, i + m) = mp (1); endfor A = Npower + delta * (mp (ones (n, 1)) * mp (ones (1, n))); q = mp (zeros (1, ell + 1)); q(1) = mp (1); for j = 0:(ell - 1) q(j + 2) = -delta * mp (n - m * j); endfor q_companion = mp (zeros (ell, ell)); q_companion(1, :) = -q(2:end); for i = 2:ell q_companion(i, i - 1) = mp (1); endfor result = struct ("family", "mks", "n", n, "m", m, "ell", ell, ... "delta", delta, "A_model", A, "A_frozen", A, "native_A", double (A), ... "q_coefficients", q, "q_companion", q_companion, ... "zero_algebraic_multiplicity", n - ell, ... "zero_geometric_multiplicity", min (m - 1, n - ell), ... "input_status", "exact_model", "source", "A5_MKS_EXACT_RANK_ONE_SHIFT"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_cmatrix_fro_upper.m0000644000230300031750000000234515274353472027141 0ustar rafaelrafael% Verified Frobenius upper norm for a rectangle matrix. function result = net_iv_cmatrix_fro_upper (matrix, q) net_iv_q (q); if (! valid_matrix_norm (matrix)) error ("mplapack:neigt:MatrixInterval", "invalid rectangle matrix"); endif sum_box = net_iv_real (mp (0), mp (0)); if (isscalar (matrix.rl)) re = net_iv_real (matrix.rl, matrix.rh); im = net_iv_real (matrix.il, matrix.ih); sum_box = net_iv_real_add (sum_box, net_iv_real_square (re, q), q); sum_box = net_iv_real_add (sum_box, net_iv_real_square (im, q), q); result = net_iv_real_sqrt (sum_box, q).hi; return; endif for index = 1:numel (matrix.rl) re = net_iv_real (matrix.rl(index), matrix.rh(index)); im = net_iv_real (matrix.il(index), matrix.ih(index)); sum_box = net_iv_real_add (sum_box, net_iv_real_square (re, q), q); sum_box = net_iv_real_add (sum_box, net_iv_real_square (im, q), q); endfor result = net_iv_real_sqrt (sum_box, q).hi; endfunction function value = valid_matrix_norm (matrix) value = isstruct (matrix) && isfield (matrix, "kind") ... && strcmp (matrix.kind, "complex_matrix") && isfield (matrix, "rl") ... && isfield (matrix, "rh") && isfield (matrix, "il") && isfield (matrix, "ih"); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_dyadic_read_json.m0000644000230300031750000001175615274353472026202 0ustar rafaelrafael% Read and verify a canonical dyadic witness; status fields are never trusted. function result = net_dyadic_read_json (filename) if (nargin != 1 || ! ischar (filename) || isempty (filename)) error ("mplapack:neigt:Deserialize", "invalid witness path"); endif text = fileread (filename); while (! isempty (text) && any (text(end) == char ([9, 10, 13, 32]))) text(end) = []; endwhile [result, position] = net_json_value (text, 1); position = net_json_skip (text, position); if (position <= numel (text)) error ("mplapack:neigt:Deserialize", "trailing JSON content"); endif if (! isstruct (result) || ! isfield (result, "sha256")) error ("mplapack:neigt:Deserialize", "witness hash is missing"); endif supplied_hash = result.sha256; result = normalize_record (result); expected_hash = hash ("sha256", net_dyadic_canonical (result, false)); if (! strcmp (supplied_hash, expected_hash)) error ("mplapack:neigt:Deserialize", "witness content hash mismatch"); endif result.sha256 = supplied_hash; endfunction function result = normalize_record (result) if (iscell (result.shape)) shape = zeros (1, numel (result.shape)); for index = 1:numel (shape) shape(index) = result.shape{index}; endfor result.shape = shape; endif if (! iscell (result.values)) error ("mplapack:neigt:Deserialize", "values must be a JSON array"); endif endfunction function [value, position] = net_json_value (text, position) position = net_json_skip (text, position); if (position > numel (text)) error ("mplapack:neigt:Deserialize", "unexpected JSON end"); endif token = text(position); if (token == '{') [value, position] = net_json_object (text, position + 1); elseif (token == '[') [value, position] = net_json_array (text, position + 1); elseif (token == '"') [value, position] = net_json_string (text, position + 1); elseif (token == '-' || (token >= '0' && token <= '9')) [value, position] = net_json_number (text, position); else error ("mplapack:neigt:Deserialize", "unsupported JSON token"); endif endfunction function position = net_json_skip (text, position) while (position <= numel (text) && any (text(position) == char ([9,10,13,32]))) position += 1; endwhile endfunction function [value, position] = net_json_object (text, position) value = struct (); position = net_json_skip (text, position); if (position <= numel (text) && text(position) == '}') position += 1; return; endif while (true) if (position > numel (text) || text(position) != '"') error ("mplapack:neigt:Deserialize", "object key expected"); endif [key, position] = net_json_string (text, position + 1); position = net_json_skip (text, position); if (position > numel (text) || text(position) != ':') error ("mplapack:neigt:Deserialize", "object colon expected"); endif [item, position] = net_json_value (text, position + 1); value.(key) = item; position = net_json_skip (text, position); if (text(position) == '}') position += 1; return; elseif (text(position) != ',') error ("mplapack:neigt:Deserialize", "object separator expected"); endif position = net_json_skip (text, position + 1); endwhile endfunction function [value, position] = net_json_array (text, position) value = {}; position = net_json_skip (text, position); if (position <= numel (text) && text(position) == ']') position += 1; return; endif while (true) [item, position] = net_json_value (text, position); value{end + 1} = item; position = net_json_skip (text, position); if (text(position) == ']') position += 1; return; elseif (text(position) != ',') error ("mplapack:neigt:Deserialize", "array separator expected"); endif position = net_json_skip (text, position + 1); endwhile endfunction function [value, position] = net_json_string (text, position) value = ""; while (position <= numel (text)) token = text(position); if (token == '"') position += 1; return; elseif (token == '\\') if (position + 1 > numel (text)) error ("mplapack:neigt:Deserialize", "unterminated JSON escape"); endif escaped = text(position + 1); if (escaped == '"' || escaped == '\\' || escaped == '/') value = [value, escaped]; elseif (escaped == 'n') value = [value, char (10)]; else error ("mplapack:neigt:Deserialize", "unsupported JSON escape"); endif position += 2; else value = [value, token]; position += 1; endif endwhile error ("mplapack:neigt:Deserialize", "unterminated JSON string"); endfunction function [value, position] = net_json_number (text, position) first = position; while (position <= numel (text) && any (text(position) == "-+0123456789.eE")) position += 1; endwhile value = str2double (text(first:position - 1)); if (! isfinite (value)) error ("mplapack:neigt:Deserialize", "invalid JSON number"); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_dyadic_decode_scalar.m0000644000230300031750000000456615274353472027007 0ustar rafaelrafael% Decode one exact dyadic scalar at a destination precision. function result = net_dyadic_decode_scalar (encoded, destination_bits) if (nargin != 2 || ! isstruct (encoded) || ! isfield (encoded, "kind") ... || ! isnumeric (destination_bits) || ! isscalar (destination_bits) ... || destination_bits != fix (destination_bits) || destination_bits < 1) error ("mplapack:neigt:Deserialize", "invalid scalar record"); endif if (strcmp (encoded.kind, "real")) result = decode_real (encoded, destination_bits); elseif (strcmp (encoded.kind, "complex")) if (! isfield (encoded, "real") || ! isfield (encoded, "imag")) error ("mplapack:neigt:Deserialize", "complex record lacks components"); endif result = net_mp_complex (decode_real (encoded.real, destination_bits), ... decode_real (encoded.imag, destination_bits)); else error ("mplapack:neigt:Deserialize", "unknown scalar kind"); endif endfunction function result = decode_real (encoded, destination_bits) required = {"sign", "mantissa_hex", "exponent2"}; for index = 1:numel (required) if (! isfield (encoded, required{index})) error ("mplapack:neigt:Deserialize", "incomplete real record"); endif endfor sign = encoded.sign; hexadecimal = encoded.mantissa_hex; exponent = encoded.exponent2; if (sign == 0) if (! strcmp (hexadecimal, "0") || exponent != 0) error ("mplapack:neigt:Deserialize", "invalid zero encoding"); endif result = mp (0); return; endif if (! any (sign == [-1, 1]) || ! ischar (hexadecimal) ... || isempty (hexadecimal) || hexadecimal(1) == "0" ... || hexadecimal(end) == "0" || isempty (regexp (hexadecimal, ... "^[0-9a-f]+$", "once")) || ! isnumeric (exponent) ... || ! isscalar (exponent) || exponent != fix (exponent)) error ("mplapack:neigt:Deserialize", "invalid nonzero dyadic encoding"); endif if (net_hex_bit_length (hexadecimal) > destination_bits) error ("mplapack:neigt:Deserialize", ... "destination precision cannot represent mantissa"); endif coefficient = mp (0); for index = 1:numel (hexadecimal) digit = find ("0123456789abcdef" == hexadecimal(index)) - 1; coefficient = coefficient * mp (16) + mp (digit); endfor result = coefficient * net_pow2 (exponent, destination_bits); if (sign < 0) result = -result; endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_forsythe_model.m0000644000230300031750000000411315274353472025731 0ustar rafaelrafael% S4 Forsythe original, explicitly scaled, and zero-limit models. function result = net_forsythe_model (n, a, representation, bits) if (nargin != 4 || ! isnumeric (n) || ! isscalar (n) || n != fix (n) ... || n < 3 || ! isnumeric (a) || ! isscalar (a) || a != fix (a) ... || a < 1 || ! ischar (representation) ... || ! any (strcmp (representation, {"original", "explicitly_scaled", ... "zero_limit"}))) error ("mplapack:neigt:Forsythe", "invalid Forsythe arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); radius = net_pow2 (-a, bits); epsilon = net_pow2 (-a * n, bits); N = mp (zeros (n, n)); for i = 1:(n - 1) N(i, i + 1) = mp (1); endfor P = N; P(n, 1) = mp (1); original = mp (eye (n)) + N; original(n, 1) = epsilon; scaled = mp (eye (n)) + radius * P; scaling = mp (zeros (n, n)); for i = 1:n scaling(i, i) = net_pow2 (-a * (i - 1), bits); endfor [left_relation, left_metadata] = ... net_exact_product_dyadic (original, scaling, bits); [right_relation, right_metadata] = ... net_exact_product_dyadic (scaling, scaled, bits); relation_exact = (left_relation == right_relation); if (! relation_exact) error ("mplapack:neigt:Forsythe", "F*D=D*F_scaled exact relation failed"); endif if (strcmp (representation, "original")) A = original; elseif (strcmp (representation, "explicitly_scaled")) A = scaled; else A = mp (eye (n)) + N; epsilon = mp (0); endif result = struct (... "family", "forsythe", "representation", representation, "n", n, ... "a", a, "bits", bits, "radius", radius, "epsilon", epsilon, ... "N", N, "P", P, "original", original, "scaled", scaled, ... "scaling", scaling, "A", A, "relation_exact", relation_exact, ... "relation_metadata", {{left_metadata, right_metadata}}, ... "source", "S4_FORSYTHE_SPLIT_SCALED_ZERO", "status", "MEASURED"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_perron_model.m0000644000230300031750000000204115274353472025371 0ustar rafaelrafael% Exact positive non-unitary diagonal similarity of the Markov model. function result = net_perron_model (n, epsilon_exponent, bits) markov = net_markov_model (n, epsilon_exponent, bits); saved_bits = mpbits (); unwind_protect mpbits (bits); D = mp (zeros (n, n)); D_inverse = mp (zeros (n, n)); for i = 1:n D(i, i) = net_pow2 (i - 1, bits); D_inverse(i, i) = net_pow2 (-(i - 1), bits); endfor A = mp (zeros (n, n)); for i = 1:n for j = 1:n A(i, j) = mp (3) / mp (2) * D(i, i) * markov.P_model(i, j) ... * D_inverse(j, j); endfor endfor result = struct ("family", "perron_positive", "n", n, ... "epsilon_exponent", epsilon_exponent, "markov", markov, ... "D", D, "D_inverse", D_inverse, "A_model", A, "A_frozen", A, ... "native_A", double (A), "perron_scale", mp (3) / mp (2), ... "input_status", "exact_model", "source", "A6_POSITIVE_DIAGONAL_SIMILARITY"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_complex_mul.m0000644000230300031750000000073315274353472025734 0ustar rafaelrafaelfunction result = net_iv_complex_mul (a, b, q) ar = net_iv_real (a.rl, a.rh); ai = net_iv_real (a.il, a.ih); br = net_iv_real (b.rl, b.rh); bi = net_iv_real (b.il, b.ih); re = net_iv_real_sub (net_iv_real_mul (ar, br, q), ... net_iv_real_mul (ai, bi, q), q); im = net_iv_real_add (net_iv_real_mul (ar, bi, q), ... net_iv_real_mul (ai, br, q), q); result = net_iv_complex (re.lo, re.hi, im.lo, im.hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_real.m0000644000230300031750000000061415274353472024331 0ustar rafaelrafael% Construct a closed finite real interval [lo,hi]. function result = net_iv_real (lo, hi) if (nargin != 2 || ! isa (lo, "mp") || ! isa (hi, "mp") ... || ! isscalar (lo) || ! isscalar (hi) ... || ! isfinite (lo) || ! isfinite (hi) || lo > hi) error ("mplapack:neigt:Interval", "invalid real interval"); endif result = struct ("kind", "real", "lo", lo, "hi", hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_cmatrix_add.m0000644000230300031750000000266715274353472025677 0ustar rafaelrafaelfunction result = net_iv_cmatrix_add (left, right, q) net_iv_q (q); if (! valid_matrix_local (left) || ! valid_matrix_local (right) ... || ! isequal (size (left.rl), size (right.rl))) error ("mplapack:neigt:MatrixInterval", "incompatible interval matrices"); endif result = left; if (isscalar (left.rl)) box = net_iv_complex_add (entry_box_local (left, 1), ... entry_box_local (right, 1), q); result.rl = box.rl; result.rh = box.rh; result.il = box.il; result.ih = box.ih; return; endif for index = 1:numel (left.rl) box = net_iv_complex_add (entry_box_local (left, index), ... entry_box_local (right, index), q); result.rl(index) = box.rl; result.rh(index) = box.rh; result.il(index) = box.il; result.ih(index) = box.ih; endfor endfunction function value = valid_matrix_local (matrix) value = isstruct (matrix) && isfield (matrix, "kind") ... && strcmp (matrix.kind, "complex_matrix") && isfield (matrix, "rl") ... && isfield (matrix, "rh") && isfield (matrix, "il") && isfield (matrix, "ih"); endfunction function result = entry_box_local (matrix, index) if (isscalar (matrix.rl)) result = net_iv_complex (matrix.rl, matrix.rh, matrix.il, matrix.ih); else result = net_iv_complex (matrix.rl(index), matrix.rh(index), ... matrix.il(index), matrix.ih(index)); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_toeplitz_model.m0000644000230300031750000000377715274353472025757 0ustar rafaelrafael% S3 tridiagonal Toeplitz and directly constructed symmetric control. function result = net_toeplitz_model (n, b, representation, bits) if (nargin != 4 || ! isnumeric (n) || ! isscalar (n) || n != fix (n) ... || n < 2 || ! isnumeric (b) || ! isscalar (b) || b != fix (b) ... || b < 1 || ! ischar (representation) ... || ! any (strcmp (representation, {"original", "explicitly_symmetric"}))) error ("mplapack:neigt:Toeplitz", "invalid Toeplitz arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); A_original = mp (zeros (n, n)); B_symmetric = mp (zeros (n, n)); upper_A = net_pow2 (-2 * b, bits); offdiag_B = net_pow2 (-b, bits); for i = 1:n A_original(i, i) = mp (3); B_symmetric(i, i) = mp (3); if (i < n) A_original(i, i + 1) = upper_A; A_original(i + 1, i) = mp (1); B_symmetric(i, i + 1) = offdiag_B; B_symmetric(i + 1, i) = offdiag_B; endif endfor D = mp (zeros (n, n)); for i = 1:n D(i, i) = net_pow2 (b * (i - 1), bits); endfor [left_relation, left_metadata] = ... net_exact_product_dyadic (A_original, D, bits); [right_relation, right_metadata] = ... net_exact_product_dyadic (D, B_symmetric, bits); relation_exact = (left_relation == right_relation); if (! relation_exact) error ("mplapack:neigt:Toeplitz", "A*D=D*B exact relation failed"); endif if (strcmp (representation, "original")) A = A_original; else A = B_symmetric; endif result = struct (... "family", "toeplitz", "representation", representation, "n", n, ... "b", b, "bits", bits, "A", A, "A_original", A_original, ... "B_symmetric", B_symmetric, "D", D, ... "relation_exact", relation_exact, ... "relation_metadata", {{left_metadata, right_metadata}}, ... "source", "S3_DIRECT_TRIDIAGONAL_AND_SYMMETRIC", ... "status", "MEASURED"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_polynomial_backward_error.m0000644000230300031750000000215215274353472030141 0ustar rafaelrafael% Complex coefficientwise polynomial backward-error indicator. function result = net_polynomial_backward_error (z, coefficients, bits) if (nargin != 3 || ! isa (z, "mp") || ! isa (coefficients, "mp") ... || ! isscalar (z) || rows (coefficients) != 1 || bits != fix (bits) ... || bits < 64) error ("mplapack:neigt:Polynomial", "invalid polynomial error arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); value = mp (0); denominator = mp (0); modulus = abs (z); for index = 1:numel (coefficients) value = value * z + coefficients(index); denominator = denominator * modulus + abs (coefficients(index)); endfor if (denominator == mp (0)) eta = mp (0); status = "denominator_zero_exact_zero"; else eta = abs (value) / denominator; status = "finite"; endif result = struct ("z", z, "value", value, ... "denominator", denominator, "eta", eta, "status", status, ... "convention", "nonmonic_complex_coefficientwise_v1"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_markov_model.m0000644000230300031750000000260115274353472025365 0ustar rafaelrafael% Exact lazy-cyclic teleportation model. function result = net_markov_model (n, epsilon_exponent, bits) if (nargin != 3 || n != fix (n) || n < 4 || mod (n, 2) != 0 ... || epsilon_exponent != fix (epsilon_exponent) || epsilon_exponent < 1 ... || bits != fix (bits) || bits < 64) error ("mplapack:neigt:Markov", "invalid Markov arguments"); endif h = n / 2; saved_bits = mpbits (); unwind_protect mpbits (bits); C = mp (zeros (h, h)); for i = 1:(h - 1) C(i, i + 1) = mp (1); endfor C(h, 1) = mp (1); I_h = mp (eye (h)); Q = mp (zeros (n, n)); Q(1:h, 1:h) = (mp (3) / mp (4)) * I_h + (mp (1) / mp (4)) * C; Q((h + 1):n, (h + 1):n) = (mp (7) / mp (8)) * I_h ... + (mp (1) / mp (8)) * C; r = mp (zeros (n, 1)); for i = 1:(n - 1) r(i) = net_pow2 (-i, bits); endfor r(n) = net_pow2 (-(n - 1), bits); epsilon = net_pow2 (-epsilon_exponent, bits); P = (mp (1) - epsilon) * Q ... + epsilon * (mp (ones (n, 1)) * transpose (r)); result = struct ("family", "markov", "n", n, "h", h, ... "epsilon_exponent", epsilon_exponent, "epsilon", epsilon, ... "Q", Q, "r", r, "P_model", P, "P_frozen", P, ... "native_P", double (P), "input_status", "exact_model", ... "source", "A6_LAZY_CYCLIC_TELEPORTATION"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_hadamard.m0000644000230300031750000000136515274353472024455 0ustar rafaelrafael% Construct the Sylvester Hadamard matrix exactly. function H = net_hadamard (n, bits) if (nargin != 2 || ! isnumeric (n) || ! isscalar (n) ... || n != fix (n) || n < 1 || ! isnumeric (bits) ... || bits != fix (bits) || bits < 1) error ("mplapack:neigt:Hadamard", "invalid Hadamard arguments"); endif power = 1; while (power < n) power *= 2; endwhile if (power != n) error ("mplapack:neigt:Hadamard", "n must be a power of two"); endif H_native = 1; while (rows (H_native) < n) H_native = [H_native, H_native; H_native, -H_native]; endwhile saved_bits = mpbits (); unwind_protect mpbits (bits); H = mp (H_native); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_neigt_capture_s1.m0000644000230300031750000000551115274353472026145 0ustar rafaelrafael% Capture one measured V-S1 job with exact replay inputs. % Capture may call eig; the separate replay path must not. function result = net_neigt_capture_s1 (profile, job_id) bundle = net_manifest (); case_profile = bundle.cases.profiles.(profile); profile_data = bundle.jobs.profiles.(profile); jobs = bundle.jobs.profiles.(profile).jobs; job = []; for index = 1:numel (jobs) if (strcmp (jobs{index}.id, job_id)) job = jobs{index}; break; endif endfor if (isempty (job) || ! strncmp (job_id, "VS1-", 4)) error ("mplapack:neigt:Capture", "only a V-S1 job can be captured"); endif case_entry = []; for index = 1:numel (case_profile.cases) if (strcmp (case_profile.cases(index).id, job.core_case)) case_entry = case_profile.cases(index); break; endif endfor if (isempty (case_entry)) error ("mplapack:neigt:Capture", "capture case is absent from manifest"); endif source_bits = profile_data.source_bits; q = profile_data.evaluation_bits; saved_bits = mpbits (); unwind_protect mpbits (source_bits); model = net_case_model (case_entry, source_bits); [V, D, unused_W] = eig (model.A_frozen, "nobalance"); %#ok mpbits (q); A = net_widen (model.A_frozen, q, source_bits); X = net_widen (V, q, source_bits); T = net_widen (D, q, source_bits); R = X \ mp (eye (rows (X))); useful_exponent = -40; if (strcmp (profile, "demo")) useful_exponent = -64; endif certificate = net_v_s1_gershgorin (A, X, T, R, q, useful_exponent); if (! strcmp (certificate.status, "CERTIFIED_ALL") ... || ! certificate.all_roots || certificate.counted_roots != rows (A) ... || ! certificate.singleton_useful || ! certificate.useful) error ("mplapack:neigt:Capture", "capture job did not pass its fixed gate"); endif payload = struct (); payload.profile = profile; payload.job_id = job_id; payload.source_bits = source_bits; payload.evaluation_bits = q; payload.usefulness_exponent = useful_exponent; payload.input_hash = net_raw_hash (model.A_frozen, [job_id, "_A_frozen"]); payload.A = A; payload.X = X; payload.T = T; payload.R = R; payload.certificate = certificate; payload.certificate_status = certificate.status; payload.certificate_method = certificate.method; payload.raw_V_hash = net_raw_hash (V, [job_id, "_raw_V"]); payload.raw_D_hash = net_raw_hash (D, [job_id, "_raw_D"]); encoded_payload = net_neigt_encode_value (payload, q); result = struct ("schema", "neigt-proof-v1", ... "method_version", "neigt-s1-replay-v1", ... "profile", profile, "job_id", job_id, ... "stored_precision", q, "payload", encoded_payload); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a1_model.m0000644000230300031750000000360715274353472024723 0ustar rafaelrafael% Build the fixed NEIGT VA1 source models without using a trusted factor. function result = net_v_a1_model (regime, n, bits) regime = char (regime); if (n != 4 || bits != fix (bits) || bits < 64) error ("mplapack:neigt:VA1", "invalid fixed VA1 model dimensions"); endif pair = net_exact_similarity (n, bits); J = mp (zeros (n, n)); if (strcmp (regime, "real_simple") || strcmp (regime, "complex_simple")) diagonal = [1, 2, 4, 8]; for index = 1:n J(index,index) = mp (diagonal(index)); endfor elseif (strcmp (regime, "defective_block")) J(1,1) = mp (1); J(1,2) = mp (1); J(2,2) = mp (1); J(3,3) = mp (4); J(4,4) = mp (8); else error ("mplapack:neigt:VA1", "unsupported fixed VA1 regime %s", regime); endif A_real = pair.Y * J * pair.X; if (strcmp (regime, "real_simple") || strcmp (regime, "defective_block")) A = A_real; elseif (strcmp (regime, "complex_simple")) Z = mp (eye (n)); Z(1,1) = net_mp_complex (mp (1), mp (0)); Z(2,2) = net_mp_complex (mp (0), mp (1)); Z(3,3) = net_mp_complex (mp (-1), mp (0)); Z(4,4) = net_mp_complex (mp (0), mp (-1)); A = Z * A_real * ctranspose (Z); endif if (strcmp (regime, "real_simple")) result = struct ("family", "exact_similarity", "n", n, ... "A_model", A, "A_frozen", A, "source", ... "VA1_REAL_SIMPLE_EXACT_SIMILARITY", "input_status", "exact_model"); elseif (strcmp (regime, "complex_simple")) result = struct ("family", "exact_similarity", "n", n, ... "A_model", A, "A_frozen", A, "source", ... "VA1_COMPLEX_PHASED_REAL_SIMPLE_EXACT_SIMILARITY", ... "input_status", "exact_model"); elseif (strcmp (regime, "defective_block")) result = struct ("family", "exact_similarity", "n", n, ... "A_model", A, "A_frozen", A, "source", ... "VA1_DEFECTIVE_BLOCK_EXACT_SIMILARITY", "input_status", "exact_model"); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_case_reference.m0000644000230300031750000001035515274353472025644 0ustar rafaelrafael% Construct the declared ordinary reference without replacing measured outputs. function result = net_case_reference (entry, bits1, bits2) if (nargin != 3 || ! isstruct (entry) || bits1 != fix (bits1) ... || bits2 != fix (bits2) || bits1 < 64 || bits2 < bits1) error ("mplapack:neigt:Reference", "invalid ordinary reference arguments"); endif id = entry.id; p = entry.parameters; if (any (strcmp (id, {"OO53_REAL", "OO53_PAIR", "OO128_CLOSE"}))) generator = net_oo_generator (id, p.n); values = generator.realized_spectrum; result = struct ("status", "exact_realized_generation", ... "values", values, "source", generator.source, ... "reference_bits", generator.generation_bits); elseif (strncmp (id, "SIM_", 4)) gap = 0; if (isfield (p, "gap_exponent")) gap = p.gap_exponent; endif fixture = net_similarity_model (lower (p.regime), p.n, gap, bits2); result = struct ("status", "exact_J_diagonal", "values", diag (fixture.J), ... "source", fixture.source, "reference_bits", bits2); elseif (strcmp (id, "TOEPLITZ") || strcmp (id, "TOEPLITZ_SYM")) ref = net_toeplitz_reference (p.n, p.b, bits2); result = struct ("status", ref.reference_status, "values", ref.eigenvalues, ... "source", ref.source, "reference_bits", bits2, ... "condition_numbers", ref.condition_numbers); elseif (strncmp (id, "FORSYTHE", 8)) if (strcmp (p.representation, "zero_limit")) values = mp (ones (p.n, 1)); result = struct ("status", "exact_defective_zero_limit", ... "values", values, "source", "S4_ZERO_LIMIT_REFERENCE", ... "reference_bits", bits2); else ref = net_forsythe_reference (p.n, p.a, bits2); result = struct ("status", ref.reference_status, "values", ref.eigenvalues, ... "source", ref.source, "reference_bits", bits2, ... "unit_roots", ref.unit_roots, "radius", ref.radius); endif elseif (strcmp (id, "HAD_BIDIAG") || strcmp (id, "HAD_COMPLEX")) ref = net_hadamard_reference (p.n, p.s, bits2); result = struct ("status", ref.reference_status, "values", ref.eigenvalues, ... "source", ref.source, "reference_bits", bits2, ... "condition_numbers", ref.condition_numbers); elseif (strcmp (id, "FRANK0") || strcmp (id, "FRANK1")) ref = net_frank_reference (p.n, bits2); result = struct ("status", ref.reference_status, "values", ref.eigenvalues, ... "source", ref.source, "reference_bits", bits2, ... "reference_auxiliary_bits", bits1); elseif (strcmp (id, "WILKINSON")) ref = net_wilkinson_reference (p.n, bits2); result = struct ("status", ref.reference_status, "values", ref.roots, ... "source", ref.source, "reference_bits", ref.reference_bits, ... "horner_exact_zero", ref.horner_exact_zero); elseif (strcmp (id, "GRCAR")) model = net_grcar_model (p.n, p.upper_bandwidth, bits2); ref = net_grcar_reference (model, bits1, bits2); result = struct ("status", ref.reference_status, "values", ref.values2, ... "source", ref.source, "reference_bits", bits2, ... "reference_agreement", ref.agreement); elseif (strcmp (id, "MKS")) model = net_mks_model (p.n, p.m, net_dyadic_parameter (p.delta, bits2), bits2); ref = net_mks_reference (model, bits1, bits2); result = struct ("status", ref.reference_status, "values", ref.values2, ... "source", ref.source, "reference_bits", bits2, "gcd", ref.gcd, ... "reference_agreement", ref.nonzero_agreement); elseif (strcmp (id, "MARKOV")) model = net_markov_model (p.n, p.epsilon_exponent, bits2); ref = net_markov_reference (model, bits1, bits2, false); result = struct ("status", ref.reference_status, "values", ref.values2, ... "source", ref.source, "reference_bits", bits2, ... "stationary_formula", ref.stationary_formula, ... "stationary_independent", ref.stationary_independent); elseif (strcmp (id, "PERRON_POS")) model = net_perron_model (p.n, p.epsilon_exponent, bits2); ref = net_markov_reference (model.markov, bits1, bits2, true); result = struct ("status", ref.reference_status, "values", ref.values2, ... "source", ref.source, "reference_bits", bits2); else error ("mplapack:neigt:Reference", "unsupported ordinary case %s", id); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_frank_audit.m0000644000230300031750000000343615274353472025204 0ustar rafaelrafael% A2 spectrum, recurrence, and reflected-orientation audit. function result = net_frank_audit (n, bits, reference_bits) f0 = net_frank_model (n, 0, bits); f1 = net_frank_model (n, 1, bits); reference = net_frank_reference (n, reference_bits); polynomial = net_frank_polynomial (n, bits); saved_bits = mpbits (); unwind_protect mpbits (max (saved_bits, bits)); [unused0, diagonal0] = eig (f0.A, "nobalance"); [unused1, diagonal1] = eig (f1.A, "nobalance"); values0 = diag (diagonal0); values1 = diag (diagonal1); match0 = net_match (values0, reference.eigenvalues, "relative"); match1 = net_match (values1, reference.eigenvalues, "relative"); reflected_exact = (f1.A == f1.reversal * ctranspose (f0.A) * f1.reversal); reflected_transpose_spectrum = net_match (values0, values1, "relative"); characteristic_checks = false (numel (polynomial.points), 1); for j = 1:numel (polynomial.points) point = mp (polynomial.points(j)); [matrix_value, unused_metadata] = ... net_exact_det_permutation (point * mp (eye (n)) - f0.A, bits); characteristic_checks(j) = (matrix_value == polynomial.values(j)); endfor positive = all (reference.eigenvalues > mp (0)); reciprocal_error = max (abs (reference.reciprocal_products - mp (1))); result = struct ("status", "MEASURED", "F0", f0, "F1", f1, ... "reference", reference, "polynomial", polynomial, ... "match_F0", match0, "match_F1", match1, ... "reflected_exact", reflected_exact, ... "reflected_transpose_match", reflected_transpose_spectrum, ... "characteristic_checks", characteristic_checks, ... "positive_reference", positive, "reciprocal_error", reciprocal_error); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a1_schur_job.m0000644000230300031750000001742415274353472025603 0ustar rafaelrafael% Run NEIGT19 genuine triangular and defective block-Schur certificates. function result = net_v_a1_schur_job (job, profile_data, profile) result = status_template (); regime = char (job.fixture.regime); bits = profile_data.source_bits; q = profile_data.evaluation_bits; saved_bits = mpbits (); unwind_protect try model = net_v_a1_model (regime, job.fixture.n, bits); A = net_widen (model.A_frozen, q, bits); mpbits (q); if (strcmp (regime, "real_simple") || strcmp (regime, "complex_simple")) base = net_v_a1_job (job, profile_data, profile); result = base; if (! base.pass) return; endif factors = base.certificate; qr = net_v_a1_interval_qr (factors.E_box, q); if (! qr.pass) result.status = qr.status; result.claim_status = "INCONCLUSIVE"; result.pass = false; result.milestone_pass = false; result.certificate = qr; result.details = qr; return; endif schur = direct_schur (A, qr, 0, q); schur.factor_certificate = factors; result.certificate = schur; result.details = schur; result.status = schur.status; result.claim_status = schur.claim_status; result.claim_quality = schur.claim_quality; result.pass = schur.pass; result.milestone_pass = schur.pass; elseif (strcmp (regime, "defective_block")) [graph, X] = defective_graph (model, bits, q); if (! graph.pass || ! graph.nontrivial) result.status = "INCONCLUSIVE_DEFECTIVE_GRAPH"; result.claim_status = "INCONCLUSIVE"; result.error_message = "defective invariant graph did not pass"; return; endif H = concatenate_columns (graph.Y1_box, ... column_range (net_iv_cmatrix_point (X, q), 3, 4)); qr = net_v_a1_interval_qr (H, q); if (! qr.pass) result.status = qr.status; result.claim_status = "INCONCLUSIVE"; result.certificate = qr; result.details = qr; return; endif schur = direct_schur (A, qr, 2, q); schur.graph = graph; schur.claim_status = "CERTIFIED_BLOCK_SCHUR"; schur.status = "CERTIFIED_BLOCK_SCHUR"; schur.pass = graph.pass && qr.pass && schur.lower_left_zero_proof; schur.milestone_pass = schur.pass; result.id = job.id; result.tier = job.tier; result.kind = job.kind; result.candidate_source = job.candidate_source; result.candidate_bits = bits; result.evaluation_bits = q; result.certificate = schur; result.details = schur; result.status = schur.status; result.claim_status = schur.claim_status; result.claim_quality = "invariant_block_existence"; result.pass = schur.pass; result.milestone_pass = schur.pass; result.input_hash = net_raw_hash (model.A_frozen, [job.id, "_A_frozen"]); result.source = model.source; result.input_status = model.input_status; else error ("mplapack:neigt:VA1", "unsupported VA1 Schur regime %s", regime); endif catch exception result.status = "FAILED_VERIFIER"; result.claim_status = "ERROR"; result.claim_quality = "not_identified"; result.error_identifier = exception.identifier; result.error_message = exception.message; end_try_catch unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function [graph, X] = defective_graph (model, bits, q) preparation = net_v_s2_candidate (model.A_frozen, mp (1), net_pow2 (-2, bits), 2, bits); X = net_widen (preparation.candidates{1}, q, bits); graph = net_v_s2_graph (net_widen (model.A_frozen, q, bits), X, 2, q); endfunction function result = direct_schur (A, qr, block_dimension, q) Q = qr.Q_box; T_direct = net_iv_cmatrix_mul (net_iv_cmatrix_mul ... (net_iv_cmatrix_conjtrans (Q), net_iv_cmatrix_point (A, q), q), Q, q); T = T_direct; n = rows (T.rl); lower_zero = false; for i = 1:n for j = 1:(i - 1) if (block_dimension == 0) T = set_entry (T, i, j, net_iv_complex (mp (0), mp (0), mp (0), mp (0))); elseif (i > block_dimension && j <= block_dimension) T = set_entry (T, i, j, net_iv_complex (mp (0), mp (0), mp (0), mp (0))); endif endfor endfor if (block_dimension == 0) lower_zero = all_lower_zero (T); else lower_zero = lower_left_zero (T, block_dimension); endif if (block_dimension == 0) status = "CERTIFIED_SCHUR_TRIANGULAR"; claim = status; quality = "algebraic_lower_zero_from_compatible_E"; else status = "CERTIFIED_BLOCK_SCHUR"; claim = status; quality = "algebraic_lower_left_zero_from_invariant_graph"; endif result = struct ("method", "neigt_interval_qr_schur_v1", ... "paper_algorithm_reproduction", false, "status", status, ... "claim_status", claim, "claim_quality", quality, "pass", ... qr.pass && lower_zero, "milestone_pass", qr.pass && lower_zero, ... "Q_box", Q, "R_box", qr.R_box, "T_box", T, ... "T_direct", T_direct, "block_dimension", block_dimension, ... "lower_left_zero_proof", lower_zero, ... "lower_triangle_algebraically_forced", block_dimension == 0, ... "normalization_lower", qr.diagonal_lower, ... "normalization_upper", qr.diagonal_upper, ... "all_normalizations_positive", qr.all_normalizations_positive); endfunction function result = all_lower_zero (matrix) result = true; for i = 1:rows (matrix.rl) for j = 1:(i - 1) box = entry_box (matrix, i, j); result = result && box.rl == mp (0) && box.rh == mp (0) ... && box.il == mp (0) && box.ih == mp (0); endfor endfor endfunction function result = lower_left_zero (matrix, k) result = true; for i = (k + 1):rows (matrix.rl) for j = 1:k box = entry_box (matrix, i, j); result = result && box.rl == mp (0) && box.rh == mp (0) ... && box.il == mp (0) && box.ih == mp (0); endfor endfor endfunction function result = concatenate_columns (left, right) result = left; result.rl = [left.rl, right.rl]; result.rh = [left.rh, right.rh]; result.il = [left.il, right.il]; result.ih = [left.ih, right.ih]; endfunction function result = column_range (matrix, first, last) result = matrix; result.rl = matrix.rl(:, first:last); result.rh = matrix.rh(:, first:last); result.il = matrix.il(:, first:last); result.ih = matrix.ih(:, first:last); endfunction function result = set_entry (matrix, i, j, value) if (isscalar (matrix.rl)) matrix.rl = value.rl; matrix.rh = value.rh; matrix.il = value.il; matrix.ih = value.ih; else matrix.rl(i,j) = value.rl; matrix.rh(i,j) = value.rh; matrix.il(i,j) = value.il; matrix.ih(i,j) = value.ih; endif result = matrix; endfunction function result = entry_box (matrix, i, j) if (isscalar (matrix.rl)) result = net_iv_complex (matrix.rl, matrix.rh, matrix.il, matrix.ih); else result = net_iv_complex (matrix.rl(i,j), matrix.rh(i,j), ... matrix.il(i,j), matrix.ih(i,j)); endif endfunction function result = status_template () result = struct ("id", "", "tier", "", "kind", "", "status", ... "NOT_IMPLEMENTED", "pass", false, "milestone_pass", false, ... "claim_status", "", "claim_quality", "", "details", [], ... "candidate_source", "", "candidate_bits", NaN, "evaluation_bits", NaN, ... "raw_V_hash", "", "raw_D_hash", "", "raw_W_hash", "", ... "raw_B_hash", "", "raw_U_hash", "", "raw_s_hash", "", ... "raw_lambda_hash", "", "certificate", [], "input_hash", "", ... "source", "", "input_status", "", "target", "", "raw_V", [], ... "raw_D", [], "raw_W", [], "error_identifier", "", "error_message", ""); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_dyadic_decompose.m0000644000230300031750000000265515274353472026212 0ustar rafaelrafael% Exact dyadic decomposition: value = coefficient * 2^exponent. % coefficient is an odd integer for a nonzero value. function result = net_dyadic_decompose (value, bits) if (nargin != 2 || ! isa (value, "mp") || ! isscalar (value) ... || ! isfinite (value) || ! isnumeric (bits) || ! isscalar (bits) ... || bits != fix (bits) || bits < 1) error ("mplapack:neigt:Dyadic", "invalid dyadic decomposition arguments"); endif if (value == mp (0)) result = struct ("coefficient", mp (0), "exponent", 0, ... "zero", true, "exact", true); return; endif magnitude = abs (value); leading = net_ufp (magnitude); scale = net_pow2 (leading, bits); quotient = magnitude / scale; found = false; % A bits-bit MP dyadic has its odd coefficient within this range. for exponent = leading:-1:(leading - bits - 2) if (floor (quotient) == quotient) coefficient = quotient; if (floor (coefficient / mp (2)) * mp (2) != coefficient) if (value < mp (0)) coefficient = -coefficient; endif result = struct ("coefficient", coefficient, ... "exponent", exponent, "zero", false, "exact", true); found = true; break; endif endif quotient = quotient * mp (2); endfor if (! found) error ("mplapack:neigt:Dyadic", ... "value is not an exact dyadic at the supplied precision"); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_minmax.m0000644000230300031750000000073515274353472024703 0ustar rafaelrafael% Min/max for a finite MP scalar list without binary64 conversion. function [lo, hi] = net_iv_minmax (values) if (! isa (values, "mp") || isempty (values) || ! all (isfinite (values))) error ("mplapack:neigt:Interval", "invalid MP extrema list"); endif lo = values(1); hi = values(1); for index = 2:numel (values) if (values(index) < lo) lo = values(index); endif if (values(index) > hi) hi = values(index); endif endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_options.m0000644000230300031750000000404215274353472024402 0ustar rafaelrafael% Parse strict NEIGT facade options. function options = net_options (profile, supplied) if (nargin < 1 || nargin > 2 || ! (ischar (profile) || isstring (profile))) error ("mplapack:neigt:Options", "profile must be smoke, demo, or stress"); endif profile = char (profile); if (! any (strcmp (profile, {"smoke", "demo", "stress"}))) error ("mplapack:neigt:Options", ... "profile must be smoke, demo, or stress"); endif defaults = struct ("tier", "all", "output_dir", "", "plot", false, "case_id", ""); if (nargin == 1 || isempty (supplied)) supplied = struct (); endif if (! isstruct (supplied) || ! isscalar (supplied)) error ("mplapack:neigt:Options", "options must be a scalar struct"); endif fields = fieldnames (supplied); for index = 1:numel (fields) if (! any (strcmp (fields{index}, fieldnames (defaults)))) error ("mplapack:neigt:Options", ... "unknown NEIGT option: %s", fields{index}); endif endfor options = defaults; for index = 1:numel (fields) options.(fields{index}) = supplied.(fields{index}); endfor if (! (ischar (options.tier) || isstring (options.tier))) error ("mplapack:neigt:Options", "tier must be a character value"); endif options.tier = char (options.tier); if (! any (strcmp (options.tier, {"all", "S", "A", "V-S", "V-A", "V"}))) error ("mplapack:neigt:Options", ... "tier must be all, S, A, V-S, V-A, or V"); endif if (! (ischar (options.output_dir) || isstring (options.output_dir))) error ("mplapack:neigt:Options", ... "output_dir must be a character value"); endif options.output_dir = char (options.output_dir); if (! islogical (options.plot) || ! isscalar (options.plot)) error ("mplapack:neigt:Options", "plot must be a logical scalar"); endif if (! (ischar (options.case_id) || isstring (options.case_id))) error ("mplapack:neigt:Options", "case_id must be a character value"); endif options.case_id = char (options.case_id); options.profile = profile; endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_metrics.m0000644000230300031750000000735715274353472024371 0ustar rafaelrafael% MP diagnostics for raw nonsymmetric eigentriples. function result = net_metrics (A, V, D, W, reference, options) if (nargin < 5 || nargin > 6 || ! isa (A, "mp") || ! isa (V, "mp") ... || ! isa (D, "mp") || ! isa (W, "mp") || ! isa (reference, "mp")) error ("mplapack:neigt:Metrics", "invalid eigentriple metric arguments"); endif if (nargin == 5 || isempty (options)) options = struct (); endif n = rows (A); if (columns (A) != n || rows (V) != n || columns (V) != n ... || rows (W) != n || columns (W) != n ... || rows (D) != n || columns (D) != n || numel (reference) != n) error ("mplapack:neigt:Metrics", "incompatible eigentriple dimensions"); endif if (! all (isfinite (A)) || ! all (isfinite (V)) ... || ! all (isfinite (D)) || ! all (isfinite (W)) ... || ! all (isfinite (reference))) error ("mplapack:neigt:Metrics", "metrics require finite MP values"); endif if (isfield (options, "simple_mask")) simple_mask = logical (options.simple_mask(:)); if (numel (simple_mask) != n) error ("mplapack:neigt:Metrics", "simple_mask has the wrong size"); endif else simple_mask = true (n, 1); endif values = diag (D); a_norm = norm (A, "fro"); v_norm = norm (V, "fro"); w_norm = norm (W, "fro"); right_numerator = norm (A * V - V * D, "fro"); left_numerator = norm (ctranspose (W) * A - D * ctranspose (W), "fro"); if (a_norm == mp (0)) right_residual = right_numerator; left_residual = left_numerator; else right_residual = right_numerator / (a_norm * v_norm); left_residual = left_numerator / (a_norm * w_norm); endif right_column = mp (zeros (n, 1)); left_column = mp (zeros (n, 1)); condition = mp (zeros (n, 1)); condition_status = repmat ({"not_applicable_simple_root"}, n, 1); for index = 1:n v = V(:, index); w = W(:, index); nv = norm (v); nw = norm (w); if (nv == mp (0) || nw == mp (0)) error ("mplapack:neigt:Metrics", "zero eigvector column"); endif scale = a_norm + abs (values(index)); if (scale == mp (0)) right_column(index) = norm (A * v - values(index) * v) / nv; left_column(index) = norm (ctranspose (A) * w ... - conj (values(index)) * w) / nw; else right_column(index) = norm (A * v - values(index) * v) / (scale * nv); left_column(index) = norm (ctranspose (A) * w ... - conj (values(index)) * w) / (scale * nw); endif if (simple_mask(index)) overlap = abs (ctranspose (w) * v); if (overlap == mp (0)) condition(index) = mp ("Inf"); condition_status{index} = "unresolved_zero_overlap"; else condition(index) = nv * nw / overlap; condition_status{index} = "resolved_simple_root"; endif endif endfor absolute = net_match (values, reference, "absolute"); has_zero = any (reference == mp (0)); if (has_zero) relative = struct ("status", "undefined_zero_reference", ... "method", "minimum_bottleneck_bijective_v1"); else relative = net_match (values, reference, "relative"); endif result = struct ("values", values, "absolute_match", absolute, ... "relative_match", relative, ... "right_residual", right_residual, ... "left_residual", left_residual, ... "right_column_residual", max (right_column), ... "left_column_residual", max (left_column), ... "eta_right", right_column, "eta_left", left_column, ... "condition_estimates", condition, ... "condition_status", {condition_status}, ... "simple_mask", simple_mask, "status", "MEASURED"); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_s2_cluster.m0000644000230300031750000004326315274353472025331 0ustar rafaelrafael% Identify a separated V-S2 cluster and bound the raw-basis projector error. % This checker is independent of candidate preparation. It consumes only the % outward graph boxes and the point candidate supplied to the graph proof. function result = net_v_s2_cluster (graph, X, center, job, profile, q) if (nargin != 6) error ("mplapack:neigt:VS2Cluster", ... "graph, X, center, job, profile, and q are required"); endif result = cluster_template (); if (! isstruct (graph) || ! isfield (graph, "pass") || ! graph.pass ... || ! isfield (graph, "M_box") || ! isfield (graph, "D2_box") ... || ! isa (X, "mp") || ! isstruct (job) ... || ! isfield (job, "cluster_dimension") || ! isscalar (center) ... || ! isa (center, "mp") || ! isfinite (center) || q < 64 || q > 4096) result.status = "ERROR_INVALID_INPUT"; result.claim_status = "ERROR"; return; endif saved_bits = mpbits (); unwind_protect mpbits (q); k = job.cluster_dimension; n = rows (X); h = n - k; result.k = k; result.h = h; result.n = n; result.query_center = center; result.query_radius = net_dyadic_parameter (job.fixture.query_radius, q); result.power_order = power_order (job); if (strcmp (char (job.fixture.regime), "two_jordan")) result.refined_power_order = 4 * k; else result.refined_power_order = result.power_order; endif result.profile = profile; result.raw_X_hash = net_raw_hash (X, "VS2_raw_candidate_X"); if (k < 1 || k >= n || columns (X) != n) result.status = "INCONCLUSIVE_FULL_SPACE_OR_DIMENSION"; result.claim_status = "INCONCLUSIVE"; return; endif M = graph.M_box; D2 = graph.D2_box; result.M_gershgorin = gershgorin_disks (M, q); result.D2_gershgorin = gershgorin_disks (D2, q); % The Gershgorin data are retained for a direct disk enclosure. The % centered power disk is the required sharp region for defective blocks; % its center is the requested query center, not an assumed root. shifted = net_iv_cmatrix_sub (M, scalar_eye (center, k, q), q); required_power_box = scalar_power (shifted, result.power_order, q); required_power_norm = net_iv_cmatrix_inf_upper (required_power_box, q); required_power_radius = root_radius (required_power_norm, ... result.power_order, q); refined_power_box = scalar_power (shifted, result.refined_power_order, q); refined_power_norm = net_iv_cmatrix_inf_upper (refined_power_box, q); refined_power_radius = root_radius (refined_power_norm, ... result.refined_power_order, q); power_box = refined_power_box; power_norm = refined_power_norm; power_radius = refined_power_radius; gersh_radius = centered_gersh_radius (result.M_gershgorin, center, q); result.centered_power_box = power_box; result.centered_power_norm = power_norm; result.centered_power_radius = power_radius; result.required_centered_power_box = required_power_box; result.required_centered_power_norm = required_power_norm; result.required_centered_power_radius = required_power_radius; result.refined_centered_power_box = refined_power_box; result.refined_centered_power_norm = refined_power_norm; result.refined_centered_power_radius = refined_power_radius; result.M_gershgorin_centered_radius = gersh_radius; result.centered_power_required = strcmp (char (job.fixture.regime), ... "jordan") ... || strcmp (char (job.fixture.regime), ... "two_jordan") ... || strcmp (char (job.fixture.regime), ... "mks_zero"); result.merged_polynomial = []; result.spectral_region_method = "centered_power"; cluster_target = cluster_radius_target (job, profile, q); % A power disk contains every M eigenvalue. For the complement use the % union of its interval Gershgorin disks, which is safe even when D2 is % nonnormal. The selected query radius is only a quality target; it is % never used as a proof of the spectrum. region_radius = power_radius; if (strcmp (char (job.fixture.regime), "two_jordan")) % A centered raw power is deliberately retained above. For two % distinct size-two defective groups it can be dominated by the % nilpotent term (M-cI)^16 even when the spectrum is much tighter. % The following independently proves a sharper disk from a polynomial % power of the computed M box; it does not consume known roots or a % generator basis. merged = merged_polynomial_certificate (M, center, cluster_target, q); result.merged_polynomial = merged; if (merged.pass) region_radius = cluster_target; result.spectral_region_method = "centered_polynomial_power"; endif endif if (isfield (job, "adversarial_claimed_radius")) region_radius = job.adversarial_claimed_radius; result.adversarial_override = true; else result.adversarial_override = false; endif d2_separation = true; d2_disks = result.D2_gershgorin.disks; for index = 1:numel (d2_disks) disk = d2_disks(index); distance = net_iv_complex_abs (net_iv_complex_point (... center - disk.center, q), q).lo; sum_radius = net_iv_primitive ("add", region_radius, ... disk.radius, q).hi; disk.separation_distance = distance; disk.separation_limit = sum_radius; disk.separated = distance > sum_radius; d2_separation = d2_separation && disk.separated; d2_disks(index) = disk; endfor result.D2_gershgorin.disks = d2_disks; result.region_radius = region_radius; result.strict_separation = d2_separation; result.counted_M_roots = k; result.counted_D2_roots = h; result.counted_total_roots = k + h; result.counting_argument = "exact_graph_block_sizes_plus_strict_M_D2_separation"; result.projector = raw_projector_bound (X, graph, k, q, profile); result.cluster_radius_target = cluster_target; result.projector_target = projector_target (profile, q); result.cluster_radius_pass = region_radius <= result.cluster_radius_target; result.projector_pass = result.projector.pass ... && result.projector.bound <= result.projector_target; result.centered_power_pass = (! result.centered_power_required ... || power_radius <= result.cluster_radius_target ... || (isstruct (result.merged_polynomial) ... && result.merged_polynomial.pass)); result.root_count_pass = d2_separation && result.counted_total_roots == n; result.cluster_pass = result.root_count_pass ... && result.cluster_radius_pass ... && result.centered_power_pass ... && result.projector_pass ... && ! result.adversarial_override; if (result.cluster_pass) result.status = "CERTIFIED_CLUSTER"; result.claim_status = "CERTIFIED_CLUSTER"; result.claim_quality = "resolved"; result.pass = true; result.nontrivial = true; elseif (! d2_separation) result.status = "INCONCLUSIVE_CLUSTER_SEPARATION"; result.claim_status = "CERTIFIED_INVARIANT_BASIS"; result.claim_quality = "not_identified"; elseif (! result.projector_pass) result.status = "INCONCLUSIVE_PROJECTOR"; result.claim_status = "CERTIFIED_INVARIANT_BASIS"; result.claim_quality = "not_identified"; else result.status = "INCONCLUSIVE_CLUSTER_RADIUS"; result.claim_status = "CERTIFIED_INVARIANT_BASIS"; result.claim_quality = "not_identified"; endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function value = power_order (job) regime = char (job.fixture.regime); if (strcmp (regime, "jordan") || strcmp (regime, "two_jordan") ... || strcmp (regime, "mks_zero")) % The required defective fixtures have nilpotent block length two. For % the merged job this is deliberately the block dimension, not the total % selected cluster dimension four. value = 2; else value = job.cluster_dimension; endif endfunction function result = cluster_template () result = struct ("method", "neigt_cluster_power_projector_v1", ... "paper_algorithm_reproduction", false, "status", "INCONCLUSIVE", ... "pass", false, "claim_status", "INCONCLUSIVE", ... "claim_quality", "not_identified", "nontrivial", false, ... "strict_separation", false, "root_count_pass", false, ... "centered_power_required", false, "centered_power_pass", false, ... "cluster_radius_pass", false, "projector_pass", false, ... "adversarial_override", false, "counted_M_roots", 0, ... "counted_D2_roots", 0, "counted_total_roots", 0); endfunction function result = scalar_eye (center, n, q) result = net_iv_cmatrix_point (center * mp (eye (n)), q); endfunction function result = scalar_power (base, exponent, q) result = net_iv_cmatrix_eye (rows (base.rl), q); for index = 1:exponent result = net_iv_cmatrix_mul (result, base, q); endfor endfunction function value = root_radius (bound, exponent, q) if (bound == mp (0)) value = mp (0); return; endif exponent2 = floor (net_ufp (bound) / exponent); value = net_pow2 (exponent2, q); while (point_power_upper (value, exponent, q) < bound) exponent2 += 1; value = net_pow2 (exponent2, q); endwhile endfunction function value = point_power_upper (base, exponent, q) value = mp (1); for index = 1:exponent value = net_iv_primitive ("mul", value, base, q).hi; endfor endfunction function result = gershgorin_disks (matrix, q) n = rows (matrix.rl); disks = repmat (struct ("center", mp (0), "radius", mp (0), ... "diagonal_uncertainty", mp (0), ... "offdiagonal_radius", mp (0), ... "separation_distance", mp (0), ... "separation_limit", mp (0), "separated", false), n, 1); for i = 1:n diagonal = entry (matrix, i, i); center = midpoint (diagonal, q); deviation = net_iv_complex_sub (diagonal, ... net_iv_complex_point (center, q), q); diagonal_uncertainty = net_iv_complex_abs (deviation, q).hi; offdiag = mp (0); for j = 1:n if (i != j) offdiag = net_iv_primitive ("add", offdiag, ... net_iv_complex_abs (entry (matrix, i, j), q).hi, q).hi; endif endfor disks(i).center = center; disks(i).diagonal_uncertainty = diagonal_uncertainty; disks(i).offdiagonal_radius = offdiag; disks(i).radius = net_iv_primitive ("add", diagonal_uncertainty, ... offdiag, q).hi; endfor result = struct ("method", "neigt_interval_gershgorin_v1", ... "disks", disks, "count", n); endfunction function value = centered_gersh_radius (record, center, q) value = mp (0); for index = 1:numel (record.disks) distance = net_iv_complex_abs (net_iv_complex_point (... record.disks(index).center - center, q), q).hi; total = net_iv_primitive ("add", distance, record.disks(index).radius, q).hi; if (total > value) value = total; endif endfor endfunction function result = raw_projector_bound (X, graph, k, q, profile) n = rows (X); h = n - k; X1 = net_iv_cmatrix_point (X(:, 1:k), q); X2 = net_iv_cmatrix_point (X(:, (k + 1):n), q); gram_error = net_iv_cmatrix_sub (... net_iv_cmatrix_mul (net_iv_cmatrix_conjtrans (X1), X1, q), ... net_iv_cmatrix_eye (k, q), q); g1 = net_iv_cmatrix_fro_upper (gram_error, q); result = struct ("method", "neigt_raw_basis_projector_bound_v1", ... "g1", g1, "alo", mp (0), "b", mp (0), ... "sine_bound", mp (0), "subspace_projector_bound", mp (0), ... "raw_projector_bound", mp (0), "bound", mp (0), ... "pass", false, ... "gram_error", gram_error, "X1_hash", ... net_raw_hash (X(:, 1:k), "VS2_raw_X1")); if (g1 >= mp (1)) result.status = "INCONCLUSIVE_RAW_BASIS_GRAM"; return; endif one_minus = net_iv_primitive ("sub", mp (1), g1, q).lo; alo = net_iv_real_sqrt (net_iv_real (one_minus, one_minus), q).lo; result.alo = alo; x2_norm = net_iv_cmatrix_fro_upper (X2, q); factor = net_iv_real_sqrt (net_iv_real (mp (h * k), mp (h * k)), q).hi; t = graph.Z_radius; b = net_iv_primitive ("mul", x2_norm, factor, q).hi; b = net_iv_primitive ("mul", b, t, q).hi; result.b = b; if (b >= alo) result.status = "INCONCLUSIVE_PROJECTOR_DENOMINATOR"; return; endif denominator = net_iv_primitive ("sub", alo, b, q).lo; sine = net_iv_primitive ("div", b, denominator, q).hi; result.sine_bound = sine; factor_projector = net_iv_real_sqrt (... net_iv_real (mp (2 * k), mp (2 * k)), q).hi; subspace = net_iv_primitive ("mul", factor_projector, sine, q).hi; total = net_iv_primitive ("add", subspace, g1, q).hi; result.subspace_projector_bound = subspace; result.raw_projector_bound = total; result.bound = total; result.status = "COMPUTED"; result.pass = true; endfunction function value = cluster_radius_target (job, profile, q) if (isfield (job, "cluster_radius_target_exponent")) value = net_pow2 (job.cluster_radius_target_exponent, q); return; endif if (strcmp (profile, "demo")) target = net_pow2 (-48, q); else target = net_pow2 (-24, q); endif if (strcmp (char (job.fixture.regime), "two_jordan")) gap = net_pow2 (-job.fixture.gap_exponent, q); target = net_iv_primitive ("mul", mp (2), gap, q).hi + target; endif value = target; endfunction function value = projector_target (profile, q) if (strcmp (profile, "demo")) value = net_pow2 (-64, q); else value = net_pow2 (-40, q); endif endfunction function result = merged_polynomial_certificate (M, center, target, q) result = struct ("method", "neigt_centered_polynomial_power_v1", ... "paper_algorithm_reproduction", false, "pass", false, ... "status", "INCONCLUSIVE", "center", [], "second_moment", [], ... "polynomial_norm", mp ("NaN"), "local_radius", mp ("NaN"), ... "polynomial_lower_bound", mp ("NaN")); n = rows (M.rl); trace_M = net_iv_complex (mp (0), mp (0), mp (0), mp (0)); for index = 1:n trace_M = net_iv_complex_add (trace_M, entry (M, index, index), q); endfor mean_box = divide_complex_box (trace_M, n, q); centered = net_iv_cmatrix_sub (M, scalar_interval_eye (mean_box, n, q), q); centered_square = net_iv_cmatrix_mul (centered, centered, q); trace_square = net_iv_complex (mp (0), mp (0), mp (0), mp (0)); for index = 1:n trace_square = net_iv_complex_add (trace_square, ... entry (centered_square, index, index), q); endfor second_moment = divide_complex_box (trace_square, n, q); polynomial_base = net_iv_cmatrix_sub ... (centered_square, scalar_interval_eye (second_moment, n, q), q); polynomial_box = net_iv_cmatrix_mul (polynomial_base, polynomial_base, q); polynomial_norm = net_iv_cmatrix_inf_upper (polynomial_box, q); center_offset = net_iv_complex_abs (net_iv_complex_sub (mean_box, ... net_iv_complex_point (center, q), q), q).hi; local_radius_box = net_iv_primitive ("sub", target, center_offset, q); result.center = mean_box; result.second_moment = second_moment; result.polynomial_box = polynomial_box; result.polynomial_norm = polynomial_norm; result.center_offset_upper = center_offset; result.local_radius = local_radius_box.lo; if (local_radius_box.lo <= mp (0)) result.status = "INCONCLUSIVE_CENTER_OFFSET"; return; endif second_moment_abs = net_iv_complex_abs (second_moment, q).hi; local_square = net_iv_primitive ("mul", local_radius_box.lo, ... local_radius_box.lo, q).lo; radial_gap = net_iv_primitive ("sub", local_square, ... second_moment_abs, q).lo; if (radial_gap <= mp (0)) result.status = "INCONCLUSIVE_POLYNOMIAL_SEPARATION"; result.second_moment_abs_upper = second_moment_abs; return; endif lower_bound = net_iv_primitive ("mul", radial_gap, radial_gap, q).lo; result.second_moment_abs_upper = second_moment_abs; result.radial_gap = radial_gap; result.polynomial_lower_bound = lower_bound; result.pass = polynomial_norm < lower_bound; if (result.pass) result.status = "CERTIFIED_MERGED_DISK"; else result.status = "INCONCLUSIVE_POLYNOMIAL_RESIDUAL"; endif endfunction function result = divide_complex_box (box, denominator, q) denominator_box = net_iv_real (mp (denominator), mp (denominator)); real_part = net_iv_real_div (net_iv_real (box.rl, box.rh), ... denominator_box, q); imag_part = net_iv_real_div (net_iv_real (box.il, box.ih), ... denominator_box, q); result = net_iv_complex (real_part.lo, real_part.hi, ... imag_part.lo, imag_part.hi); endfunction function result = scalar_interval_eye (box, n, q) result = net_iv_cmatrix_point (mp (zeros (n, n)), q); for index = 1:n result.rl(index,index) = box.rl; result.rh(index,index) = box.rh; result.il(index,index) = box.il; result.ih(index,index) = box.ih; endfor endfunction function value = entry (matrix, i, j) value = net_iv_complex (matrix.rl(i,j), matrix.rh(i,j), ... matrix.il(i,j), matrix.ih(i,j)); endfunction function value = midpoint (box, q) re = (box.rl + box.rh) * mp ("0.5"); im = (box.il + box.ih) * mp ("0.5"); value = net_mp_complex (re, im); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_hex_bit_length.m0000644000230300031750000000075215274353472025676 0ustar rafaelrafaelfunction result = net_hex_bit_length (hex) if (! ischar (hex) || isempty (hex) || hex(1) == "0") error ("mplapack:neigt:DyadicHex", "invalid normalized hexadecimal integer"); endif digit = find ("0123456789abcdef" == lower (hex(1))) - 1; if (isempty (digit)) error ("mplapack:neigt:DyadicHex", "invalid hexadecimal digit"); endif bits = 0; while (digit > 0) bits += 1; digit = floor (digit / 2); endwhile result = 4 * (numel (hex) - 1) + bits; endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_mp_complex.m0000644000230300031750000000065215274353472025055 0ustar rafaelrafael% Construct one complex MP scalar from MP real and imaginary components. function value = net_mp_complex (real_part, imaginary_part) if (nargin != 2 || ! isa (real_part, "mp") || ! isa (imaginary_part, "mp") ... || ! isscalar (real_part) || ! isscalar (imaginary_part)) error ("mplapack:neigt:Complex", "expected two MP scalar components"); endif value = real_part + imaginary_part * mp ("(0,1)"); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_raw_hash.m0000644000230300031750000000211215274353472024477 0ustar rafaelrafael% Deterministic raw-value binding hash for measured profile records. function digest = net_raw_hash (value, label) if (nargin != 2 || ! ischar (label)) error ("mplapack:neigt:Hash", "invalid raw hash arguments"); endif if (isa (value, "mp")) tokens = cell (1, numel (value)); for index = 1:numel (value) tokens{index} = char (value(index)); endfor joined = tokens{1}; for index = 2:numel (tokens) joined = [joined, ";", tokens{index}]; endfor text = sprintf ("%s|mp|%dx%d|%s", label, rows (value), columns (value), joined); elseif (isa (value, "double")) text = sprintf ("%s|double|%dx%d|", label, rows (value), columns (value)); tokens = cell (1, numel (value)); for index = 1:numel (value) tokens{index} = sprintf ("%.17g", value(index)); endfor joined = tokens{1}; for index = 2:numel (tokens) joined = [joined, ";", tokens{index}]; endfor text = [text, joined]; else error ("mplapack:neigt:Hash", "raw hash accepts MP or double values"); endif digest = hash ("sha256", text); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_wilkinson_audit.m0000644000230300031750000000314415274353472026114 0ustar rafaelrafael% A3 numerical/reference audit with separate model and frozen-input labels. function result = net_wilkinson_audit (n, bits, reference_bits) model = net_wilkinson_model (n, bits); reference = net_wilkinson_reference (n, reference_bits); saved_bits = mpbits (); unwind_protect mpbits (max ([saved_bits, bits, reference_bits])); [V, D, W] = eig (model.A_frozen, "nobalance"); metrics = net_metrics (model.A_frozen, V, D, W, reference.roots); values = diag (D); model_eta = mp (zeros (n, 1)); frozen_coefficients = model.coefficients; for index = 1:n model_eta(index) = net_polynomial_backward_error ... (values(index), model.coefficients, reference_bits).eta; endfor frozen_eta = mp (zeros (n, 1)); if (bits >= model.guard_bits) frozen_coefficients = model.coefficients; else frozen_coefficients = mp (zeros (1, n + 1)) + model.coefficients; endif for index = 1:n frozen_eta(index) = net_polynomial_backward_error ... (values(index), frozen_coefficients, reference_bits).eta; endfor result = struct ("status", "MEASURED", "model", model, ... "reference", reference, "values", values, "metrics", metrics, ... "model_coefficients", model.coefficients, ... "frozen_coefficients", frozen_coefficients, ... "model_eta_poly", model_eta, "frozen_eta_poly", frozen_eta, ... "model_matrix_residual", metrics.right_residual, ... "frozen_matrix_residual", metrics.right_residual, ... "source", "A3_WILKINSON_AUDIT"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_forsythe_audit.m0000644000230300031750000000411715274353472025743 0ustar rafaelrafael% Forward circle and zero-limit audit for S4. function result = net_forsythe_audit (fixture, reference_bits) if (nargin != 2 || ! isstruct (fixture) || ! isfield (fixture, "A")) error ("mplapack:neigt:Forsythe", "invalid Forsythe audit fixture"); endif saved_bits = mpbits (); unwind_protect mpbits (max (saved_bits, fixture.bits)); if (strcmp (fixture.representation, "zero_limit")) nilpotent = fixture.A - mp (eye (fixture.n)); powers = cell (fixture.n, 1); current = mp (eye (fixture.n)); for order = 1:fixture.n [current, metadata] = net_exact_product_dyadic (current, nilpotent, fixture.bits); powers{order} = struct ("value", current, "metadata", metadata); endfor result = struct (... "status", "MEASURED", "zero_limit", true, ... "first_n_minus_one_nonzero", norm (powers{fixture.n - 1}.value, "fro") ... != mp (0), ... "nth_power_zero", all (all (powers{fixture.n}.value ... == mp (zeros (fixture.n)))), ... "powers", {powers}, "unique_eigenvector_target", "NOT_APPLICABLE", ... "nontrivial_cluster_target", "DEFERRED_TO_SIM_JORDAN"); else reference = net_forsythe_reference (fixture.n, fixture.a, reference_bits); [V, D, W] = eig (fixture.A, "nobalance"); values = diag (D); [Vb, Db, Wb] = eig (fixture.A, "balance"); circle = net_match (values, reference.unit_roots, "circle", ... mp (1), fixture.radius); metrics = net_metrics (fixture.A, V, D, W, reference.eigenvalues); balance_metrics = net_metrics (fixture.A, Vb, Db, Wb, ... reference.eigenvalues); result = struct (... "status", "MEASURED", "zero_limit", false, "reference", reference, ... "circle_match", circle, "metrics", metrics, ... "balance_metrics", balance_metrics, "original_coordinate_label", ... fixture.representation); endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_s3_job.m0000644000230300031750000001205615274353472024417 0ustar rafaelrafael% Run one V-S3 verified pseudospectrum point or positive-area cell job. function result = net_v_s3_job (job, profile_data, profile) result = status_template (); if (nargin != 3 || ! isstruct (job) || ! isfield (job, "id") ... || ! isfield (job, "kind") || ! isfield (job, "fixture") ... || ! isfield (profile_data, "source_bits") ... || ! isfield (profile_data, "evaluation_bits") ... || ! any (strcmp (profile, {"smoke", "demo"}))) error ("mplapack:neigt:VS3", "invalid V-S3 job arguments"); endif result.id = job.id; result.tier = job.tier; result.kind = job.kind; result.candidate_source = job.candidate_source; result.candidate_bits = profile_data.source_bits; result.evaluation_bits = profile_data.evaluation_bits; source_bits = profile_data.source_bits; q = profile_data.evaluation_bits; saved_bits = mpbits (); unwind_protect try mpbits (source_bits); entry = make_case_entry (job.fixture); model = net_case_model (entry, source_bits); z = net_mp_complex (parse_scalar (job.center.real, source_bits), ... parse_scalar (job.center.imag, source_bits)); epsilon = parse_scalar (job.epsilon, source_bits); cell_box = []; if (strcmp (job.kind, "pseudospectrum_cell")) cell_box = struct ("real_halfwidth", ... parse_scalar (job.halfwidths.real, source_bits), ... "imag_halfwidth", ... parse_scalar (job.halfwidths.imag, source_bits)); endif certificate = net_v_s3_svd (model.A_frozen, z, epsilon, cell_box, ... source_bits, q); result.certificate = certificate; result.details = certificate; result.status = certificate.status; result.claim_status = certificate.status; result.claim_quality = "resolved"; result.pass = strcmp (certificate.status, job.expected); result.milestone_pass = result.pass; result.raw_B_hash = certificate.raw.B_hash; result.raw_U_hash = certificate.raw.U_hash; result.raw_s_hash = certificate.raw.s_hash; result.raw_V_hash = certificate.raw.V_hash; result.input_hash = net_raw_hash (model.A_frozen, [job.id, "_A_frozen"]); result.source = model.source; result.input_status = model.input_status; result.target = job.target; if (result.pass) result.status = "PASS"; endif catch exception result.status = "FAILED_VERIFIER"; result.claim_status = "ERROR"; result.claim_quality = "not_identified"; result.error_identifier = exception.identifier; result.error_message = exception.message; end_try_catch unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function entry = make_case_entry (fixture) family = char (fixture.family); if (strcmp (family, "exact_similarity")) regime = char (fixture.regime); if (strcmp (regime, "jordan")) case_id = "SIM_JORDAN"; elseif (strcmp (regime, "semisimple")) case_id = "SIM_SEMISIMPLE"; elseif (strcmp (regime, "simple")) case_id = "SIM_SIMPLE"; else error ("mplapack:neigt:VS3", "unsupported exact-similarity regime %s", regime); endif entry = struct ("id", case_id, ... "tier", "V", "parameters", struct ("n", fixture.n, ... "regime", regime, "gap_exponent", 0)); elseif (strcmp (family, "grcar")) entry = struct ("id", "GRCAR", "tier", "V", ... "parameters", struct ("n", fixture.n, ... "upper_bandwidth", fixture.upper_bandwidth)); else error ("mplapack:neigt:VS3", "unsupported V-S3 fixture family %s", family); endif endfunction function value = parse_scalar (token, bits) token = char (token); if (! isempty (regexp (token, "^[+-]?[0-9]+$", "once"))) value = mp (str2num (token)); %#ok return; endif match = regexp (token, "^2\\^(-[0-9]+)$", "tokens", "once"); if (! isempty (match)) value = net_pow2 (str2num (match{1}), bits); %#ok return; endif pieces = strsplit (token, "/"); if (numel (pieces) == 2 ... && ! isempty (regexp (pieces{1}, "^[0-9]+$", "once")) ... && ! isempty (regexp (pieces{2}, "^[0-9]+$", "once"))) value = net_dyadic_parameter (token, bits); return; endif error ("mplapack:neigt:VS3", "unsupported exact scalar token %s", token); endfunction function result = status_template () result = struct ("id", "", "tier", "", "kind", "", "status", ... "NOT_IMPLEMENTED", "pass", false, "milestone_pass", false, ... "claim_status", "", "claim_quality", "", "details", [], ... "candidate_source", "", "candidate_bits", NaN, "evaluation_bits", NaN, ... "raw_V_hash", "", "raw_D_hash", "", "raw_W_hash", "", ... "raw_B_hash", "", "raw_U_hash", "", "raw_s_hash", "", ... "raw_lambda_hash", "", ... "certificate", [], "input_hash", "", "source", "", ... "input_status", "", "target", "", "error_identifier", "", ... "raw_V", [], "raw_D", [], "raw_W", [], "error_message", ""); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_dyadic_encode_scalar.m0000644000230300031750000000275715274353472027021 0ustar rafaelrafael% Encode one represented MP real or complex scalar without decimal conversion. function result = net_dyadic_encode_scalar (value, stored_bits) if (nargin != 2 || ! isa (value, "mp") || ! isscalar (value) ... || ! isnumeric (stored_bits) || ! isscalar (stored_bits) ... || stored_bits != fix (stored_bits) || stored_bits < 1 ... || ! isfinite (real (value)) || ! isfinite (imag (value))) error ("mplapack:neigt:Serialize", "invalid scalar serialization input"); endif if (isreal (value)) result = encode_real (value, stored_bits); result.kind = "real"; else result = struct ("kind", "complex", "real", ... encode_real (real (value), stored_bits), "imag", ... encode_real (imag (value), stored_bits)); endif endfunction function result = encode_real (value, stored_bits) if (value == mp (0)) result = struct ("sign", 0, "mantissa_hex", "0", "exponent2", 0); return; endif decomposition = net_dyadic_decompose (value, stored_bits); coefficient = abs (decomposition.coefficient); hexadecimal = net_mp_integer_hex (coefficient); if (hexadecimal(end) == "0" || hexadecimal(1) == "0") error ("mplapack:neigt:Serialize", "mantissa was not normalized"); endif result = struct ("sign", ternary_sign (value), ... "mantissa_hex", hexadecimal, ... "exponent2", decomposition.exponent); endfunction function value = ternary_sign (x) if (x < mp (0)) value = -1; else value = 1; endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a3_pair.m0000644000230300031750000001213715274353472024556 0ustar rafaelrafael% Outward contraction certificate for a normalized positive Perron pair. function result = net_v_a3_pair (A, x0, lambda0, q, options) if (nargin < 4 || nargin > 5) error ("mplapack:neigt:VA3", "A, x0, lambda0, and q are required"); endif if (nargin == 4) options = struct (); endif net_iv_q (q); n = rows (A); result = struct ("method", "neigt_positive_pair_contraction_v1", ... "paper_algorithm_reproduction", false, "status", "INCONCLUSIVE", ... "pass", false, "n", n, "candidate_source", "computed_eig_candidate", ... "c", mp ("NaN"), "e", mp ("NaN"), "trials", struct ([]), ... "radius_trial_count", 0, "contraction_pass", false, ... "positivity_pass", false, "x0", x0, "lambda0", lambda0, ... "R", [], "F0", [], "J0", [], "Y_box", [], ... "normalization_equation", "sum(x)-1=0"); if (! isa (A, "mp") || ! isa (x0, "mp") || ! isa (lambda0, "mp") ... || rows (A) != columns (A) || ! isequal (size (x0), [n, 1]) ... || ! isscalar (lambda0) || ! all (isfinite (A(:))) ... || ! all (isfinite (x0(:))) || ! isfinite (lambda0) ... || q < 64 || q > 4096) result.status = "ERROR_INVALID_INPUT"; return; endif if (any (imag (A(:)) != mp (0)) || any (imag (x0(:)) != mp (0)) ... || imag (lambda0) != mp (0)) result.status = "UNSUPPORTED_COMPLEX_DOMAIN"; return; endif x0_sum = mp (0); for i = 1:numel (x0) x0_sum = x0_sum + real (x0(i)); endfor if (any (x0(:) <= mp (0)) || x0_sum <= mp (0)) result.status = "INCONCLUSIVE_NONPOSITIVE_TRIAL"; return; endif I = mp (eye (n + 1)); x0 = real (x0); lambda0 = real (lambda0); F0 = mp (zeros (n + 1, 1)); F0(1:n) = A * x0 - lambda0 * x0; F0(n + 1) = x0_sum - mp (1); J0 = mp (zeros (n + 1, n + 1)); J0(1:n, 1:n) = A - lambda0 * mp (eye (n)); J0(1:n, n + 1) = -x0; J0(n + 1, 1:n) = mp (ones (1, n)); if (isfield (options, "R")) R = options.R; if (! isa (R, "mp") || ! isequal (size (R), size (J0)) ... || ! all (isfinite (R(:)))) result.status = "ERROR_INVALID_INVERSE_CANDIDATE"; return; endif else R = J0 \ I; endif F_box = net_iv_cmatrix_point (F0, q); R_box = net_iv_cmatrix_point (R, q); c = net_iv_cmatrix_inf_upper (net_iv_cmatrix_mul (R_box, F_box, q), q); result.c = c; result.R = R; result.F0 = F0; result.J0 = J0; if (c == mp (0)) exponent = -floor (q / 2); else exponent = net_ufp (c) + 1; while (net_pow2 (exponent, q) <= mp (2) * c) exponent += 1; endwhile endif trials = struct ([]); accepted = false; accepted_t = mp (0); accepted_J = []; for index = 1:4 t = net_pow2 (exponent + index - 1, q); J_box = jacobian_box (A, x0, lambda0, t, q); E_box = net_iv_cmatrix_sub (net_iv_cmatrix_point (I, q), ... net_iv_cmatrix_mul (R_box, J_box, q), q); e = net_iv_cmatrix_inf_upper (E_box, q); et = net_iv_primitive ("mul", e, t, q).hi; self_bound = net_iv_primitive ("add", c, et, q).hi; positive = all (x0 - t > mp (0)); trial = struct ("index", index, "t", t, "e", e, ... "self_bound", self_bound, "self_map", self_bound < t, ... "contraction", e < mp (1), "positive", positive, ... "pass", self_bound < t && e < mp (1) && positive); if (isempty (trials)) trials = trial; else trials(end + 1) = trial; endif if (trial.pass) accepted = true; accepted_t = t; accepted_J = J_box; break; endif endfor result.trials = trials; result.radius_trial_count = numel (trials); result.contraction_pass = accepted; result.positivity_pass = accepted && all (x0 - accepted_t > mp (0)); if (! accepted) result.status = "INCONCLUSIVE_PAIR_CONTRACTION"; return; endif result.t = accepted_t; result.e = trials(end).e; result.Y_box = struct ("x_lower", x0 - accepted_t, ... "x_upper", x0 + accepted_t, ... "lambda_lower", lambda0 - accepted_t, ... "lambda_upper", lambda0 + accepted_t); result.J_box = accepted_J; result.status = "CERTIFIED_PERRON_PAIR"; result.claim_status = "CERTIFIED_PERRON_PAIR"; result.claim_quality = "positive_normalized_unique_fixed_point"; result.pass = true; endfunction function result = jacobian_box (A, x0, lambda0, t, q) n = rows (A); result = net_iv_cmatrix_point (mp (zeros (n + 1, n + 1)), q); for i = 1:n for j = 1:n value = A(i,j); if (i == j) center_box = net_iv_primitive ("sub", value, lambda0, q); result.rl(i,j) = net_iv_primitive ("sub", center_box.lo, t, q).lo; result.rh(i,j) = net_iv_primitive ("add", center_box.hi, t, q).hi; else result.rl(i,j) = value; result.rh(i,j) = value; endif endfor result.rl(i,n + 1) = net_iv_primitive ("sub", -x0(i), t, q).lo; result.rh(i,n + 1) = net_iv_primitive ("add", -x0(i), t, q).hi; result.il(i,n + 1) = mp (0); result.ih(i,n + 1) = mp (0); endfor for j = 1:n result.rl(n + 1,j) = mp (1); result.rh(n + 1,j) = mp (1); endfor result.rl(n + 1,n + 1) = mp (0); result.rh(n + 1,n + 1) = mp (0); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_reference.m0000644000230300031750000000223615274353472024650 0ustar rafaelrafael% Independent reference-role dispatcher for fixed exact S2 models. function result = net_reference (fixture, reference_bits) if (nargin != 2 || ! isstruct (fixture) || ! isscalar (fixture) ... || ! isnumeric (reference_bits) || ! isscalar (reference_bits) ... || reference_bits != fix (reference_bits) || reference_bits < 1) error ("mplapack:neigt:Reference", "invalid reference arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (reference_bits); if (! isfield (fixture, "J") || ! isfield (fixture, "generation_bits")) error ("mplapack:neigt:Reference", ... "exact algebraic reference requires a fixed S2 model"); endif values = net_widen (diag (fixture.J), reference_bits, fixture.generation_bits); result = struct ("values", values, "reference_bits", reference_bits, ... "reference_status", "exact_algebraic", ... "role", "INDEPENDENT_MODEL_REFERENCE", ... "source", "SIM_EXACT_INTEGER", ... "model_hash", "pending_exact_serializer"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_manifest.m0000644000230300031750000001111415274353472024513 0ustar rafaelrafael% Load and validate the NEIGT JSON manifests without executing parameters. function bundle = net_manifest () here = fileparts (mfilename ("fullpath")); example_root = fileparts (here); repo_root = fileparts (fileparts (example_root)); manifest_root = fullfile (repo_root, "docs", "codex", "neigt"); cases_path = fullfile (manifest_root, "cases.json"); jobs_path = fullfile (manifest_root, "verification-jobs.json"); if (exist (cases_path, "file") != 2 || exist (jobs_path, "file") != 2) error ("mplapack:neigt:Manifest", ... "NEIGT cases.json and verification-jobs.json are required"); endif cases_text = fileread (cases_path); jobs_text = fileread (jobs_path); cases = jsondecode (cases_text); jobs = jsondecode (jobs_text); if (! isstruct (cases) || ! isstruct (jobs) ... || ! strcmp (cases.schema, "neigt-cases-v1") ... || ! strcmp (jobs.schema, "neigt-verification-jobs-v1")) error ("mplapack:neigt:Manifest", "unsupported NEIGT manifest schema"); endif if (! strcmp (cases.version, "1.0") || ! strcmp (jobs.version, "1.0")) error ("mplapack:neigt:Manifest", "unsupported NEIGT manifest version"); endif profiles = {"smoke", "demo", "stress"}; for index = 1:numel (profiles) profile = profiles{index}; if (! isfield (cases.profiles, profile)) error ("mplapack:neigt:Manifest", "cases manifest lacks profile %s", profile); endif data = cases.profiles.(profile); if (! isfield (data, "cases") || ! isfield (data, "work_bits") ... || ! isfield (data, "expected_case_count") ... || ! isfield (data, "expected_measured_eig_rows")) error ("mplapack:neigt:Manifest", "incomplete cases profile %s", profile); endif case_count = numel (data.cases); if (case_count != data.expected_case_count) error ("mplapack:neigt:Manifest", ... "%s case count mismatch: %d != %d", profile, case_count, ... data.expected_case_count); endif if (! isscalar (data.native_baseline) || ! data.native_baseline) error ("mplapack:neigt:Manifest", ... "%s must declare the native baseline", profile); endif expected_rows = 2 * case_count * (numel (data.work_bits) + 1); if (expected_rows != data.expected_measured_eig_rows) error ("mplapack:neigt:Manifest", ... "%s measured-row count mismatch: %d != %d", profile, ... expected_rows, data.expected_measured_eig_rows); endif ids = cell (case_count, 1); for case_index = 1:case_count entry = data.cases(case_index); if (! isfield (entry, "id") || ! isfield (entry, "tier") ... || ! isfield (entry, "parameters")) error ("mplapack:neigt:Manifest", ... "malformed %s case %d", profile, case_index); endif ids{case_index} = entry.id; if (! any (strcmp (entry.tier, {"S", "A"}))) error ("mplapack:neigt:Manifest", ... "ordinary case %s has invalid tier", entry.id); endif endfor if (numel (unique (ids)) != case_count) error ("mplapack:neigt:Manifest", "%s case IDs are not unique", profile); endif endfor job_profiles = {"smoke", "demo"}; for index = 1:numel (job_profiles) profile = job_profiles{index}; if (! isfield (jobs.profiles, profile)) error ("mplapack:neigt:Manifest", "jobs manifest lacks profile %s", profile); endif data = jobs.profiles.(profile); if (! isfield (data, "jobs") || data.expected_job_count != 26 ... || numel (data.jobs) != data.expected_job_count) error ("mplapack:neigt:Manifest", ... "%s must contain exactly 26 verification jobs", profile); endif ids = cell (numel (data.jobs), 1); for job_index = 1:numel (data.jobs) job = data.jobs{job_index}; if (! isfield (job, "id") || ! isfield (job, "tier") ... || ! isfield (job, "kind")) error ("mplapack:neigt:Manifest", ... "malformed %s verification job %d", profile, job_index); endif ids{job_index} = job.id; if (! any (strcmp (job.tier, {"V-S", "V-A"}))) error ("mplapack:neigt:Manifest", ... "verification job %s has invalid tier", job.id); endif endfor if (numel (unique (ids)) != numel (data.jobs)) error ("mplapack:neigt:Manifest", ... "%s verification IDs are not unique", profile); endif endfor bundle = struct ("root", manifest_root, "cases_path", cases_path, ... "jobs_path", jobs_path, "cases_text", cases_text, ... "jobs_text", jobs_text, "cases", cases, "jobs", jobs); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_cmatrix_inf_upper.m0000644000230300031750000000224215274353472027123 0ustar rafaelrafael% Verified induced infinity upper norm for a rectangle matrix. function result = net_iv_cmatrix_inf_upper (matrix, q) net_iv_q (q); if (! valid_matrix_norm (matrix)) error ("mplapack:neigt:MatrixInterval", "invalid rectangle matrix"); endif result = mp (0); for i = 1:rows (matrix.rl) row_sum = net_iv_real (mp (0), mp (0)); for j = 1:columns (matrix.rl) magnitude = net_iv_complex_abs (entry_box_norm (matrix, i, j), q); row_sum = net_iv_real_add (row_sum, magnitude, q); endfor if (row_sum.hi > result) result = row_sum.hi; endif endfor endfunction function value = valid_matrix_norm (matrix) value = isstruct (matrix) && isfield (matrix, "kind") ... && strcmp (matrix.kind, "complex_matrix") && isfield (matrix, "rl") ... && isfield (matrix, "rh") && isfield (matrix, "il") && isfield (matrix, "ih"); endfunction function result = entry_box_norm (matrix, i, j) if (isscalar (matrix.rl)) result = net_iv_complex (matrix.rl, matrix.rh, matrix.il, matrix.ih); else result = net_iv_complex (matrix.rl(i,j), matrix.rh(i,j), ... matrix.il(i,j), matrix.ih(i,j)); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_s2_graph.m0000644000230300031750000003257315274353472024753 0ustar rafaelrafael% Conservative verified invariant-graph checker from CERTIFICATES.md. % Candidate preparation and this proof are deliberately separate: the proof % only trusts the supplied point A/X and checks every required nonsingularity % and contraction inequality with outward rectangles. function result = net_v_s2_graph (A, X, k, q, options) if (nargin < 4 || nargin > 5) error ("mplapack:neigt:VS2", "expected A, X, k, q, and optional options"); endif if (nargin == 4) options = struct (); endif saved_bits = mpbits (); unwind_protect mpbits (q); result = graph_failure_template ("INCONCLUSIVE"); if (! valid_inputs (A, X, k, q)) result.status = "ERROR_INVALID_INPUT"; return; endif transpose_mode = "nonconjugating"; if (isfield (options, "transpose_mode")) transpose_mode = options.transpose_mode; endif if (! ischar (transpose_mode) || ! strcmp (transpose_mode, "nonconjugating")) result.status = "UNSUPPORTED_WRONG_KRONECKER_TRANSPOSE"; result.claim_status = "UNSUPPORTED_DOMAIN"; return; endif n = rows (A); h = n - k; I = mp (eye (n)); % These are auxiliary point operations. They are retained separately % from the outward proof below and never replace it. R_candidate = X \ I; C0 = X \ (A * X); result.candidate_inverse = R_candidate; result.candidate_C0 = C0; result.candidate_C0_hash = net_raw_hash (C0, "VS2_candidate_C0"); similarity = certified_similarity (A, X, R_candidate, C0, q, options); result.similarity = similarity; if (! similarity.basis_nonsingular) result.status = "INCONCLUSIVE_BASIS_INVERSE"; result.claim_status = "INCONCLUSIVE"; return; endif C = similarity.C_box; C11 = matrix_block (C, 1:k, 1:k); C12 = matrix_block (C, 1:k, (k + 1):n); C21 = matrix_block (C, (k + 1):n, 1:k); C22 = matrix_block (C, (k + 1):n, (k + 1):n); K = net_iv_cmatrix_sub ... (net_iv_cmatrix_kron (net_iv_cmatrix_eye (k, q), C22, q), ... net_iv_cmatrix_kron (nonconjugating_transpose (C11), ... net_iv_cmatrix_eye (h, q), q), q); K_mid = midpoint_matrix (K, q); if (isfield (options, "preconditioner")) R_s = options.preconditioner; if (! isa (R_s, "mp") || ! isequal (size (R_s), [h * k, h * k])) result.status = "INCONCLUSIVE_BAD_PRECONDITIONER"; result.claim_status = "INCONCLUSIVE"; return; endif else R_s = K_mid \ mp (eye (h * k)); endif result.preconditioner = R_s; K_residual = net_iv_cmatrix_sub ... (net_iv_cmatrix_eye (h * k, q), ... net_iv_cmatrix_mul (net_iv_cmatrix_point (R_s, q), K, q), q); e = net_iv_cmatrix_inf_upper (K_residual, q); c_vector = net_iv_cmatrix_mul (net_iv_cmatrix_point (R_s, q), ... vector_box (C21, q), q); c = net_iv_cmatrix_inf_upper (c_vector, q); r_norm = net_iv_cmatrix_inf_upper (net_iv_cmatrix_point (R_s, q), q); c12_max = max_entry_modulus (C12, q); kh = mp (k * h); g = net_iv_primitive ("mul", r_norm, kh, q).hi; g = net_iv_primitive ("mul", g, c12_max, q).hi; result.e = e; result.c = c; result.g = g; result.K = K; result.K_mid = K_mid; result.preconditioner_residual_pass = e < mp (1); if (! result.preconditioner_residual_pass) result.status = "INCONCLUSIVE_PRECONDITIONER_RESIDUAL"; result.claim_status = "INCONCLUSIVE"; return; endif [initial_exponent, initial_bound] = initial_radius (c, e, q); result.initial_radius_bound = initial_bound; result.initial_radius_exponent = initial_exponent; trials = struct ([]); accepted = false; accepted_t = mp (0); for trial_index = 0:7 t = net_pow2 (initial_exponent + trial_index, q); trial = radius_trial (c, e, g, t, q, trial_index + 1); if (isempty (trials)) trials = trial; else trials(end + 1) = trial; endif if (trial.self_map && trial.contraction) accepted = true; accepted_t = t; break; endif if (! trial.contraction_possible) break; endif endfor result.trials = trials; result.radius_trial_count = numel (trials); result.contraction_pass = accepted; if (! accepted) result.status = "INCONCLUSIVE_CONTRACTION"; result.claim_status = "INCONCLUSIVE"; return; endif % The polydisk proof is complete before the larger rectangle is formed. % The rectangle below is only the returned enclosure of the fixed point. Z_box = constant_rectangle (h, k, -accepted_t, accepted_t, ... -accepted_t, accepted_t); X1 = matrix_block (net_iv_cmatrix_point (X, q), 1:n, 1:k); X2 = matrix_block (net_iv_cmatrix_point (X, q), 1:n, (k + 1):n); Y1_box = net_iv_cmatrix_add (X1, net_iv_cmatrix_mul (X2, Z_box, q), q); M_box = net_iv_cmatrix_add (C11, net_iv_cmatrix_mul (C12, Z_box, q), q); result.Z_box = Z_box; result.Z_radius = accepted_t; result.Y1_box = Y1_box; result.M_box = M_box; % The lower-left block of the exact graph similarity is zero and the % complementary diagonal block is D2=C22-Z*C12. Keep this enclosure % separate so NEIGT16 can prove spectral separation without treating a % graph-existence result as an isolated-cluster result. result.D2_box = net_iv_cmatrix_sub (C22, ... net_iv_cmatrix_mul (Z_box, C12, q), q); result.k = k; result.h = h; result.n = n; result.method = "neigt_riccati_graph_v1"; result.paper_algorithm_reproduction = false; result.claim_status = "CERTIFIED_INVARIANT_BASIS"; result.claim_quality = "not_identified"; result.status = "CERTIFIED_INVARIANT_BASIS"; result.pass = true; result.nontrivial = (k > 0 && k < n); result.full_space_triviality = false; result.candidate_source = "computed_candidate_basis_bounded_schedule"; unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function value = valid_inputs (A, X, k, q) value = isa (A, "mp") && isa (X, "mp") && rows (A) == columns (A) ... && isequal (size (A), size (X)) && isscalar (k) && k == fix (k) ... && k >= 1 && k < rows (A) && q >= 64 && q <= 4096; endfunction function result = graph_failure_template (status) result = struct ("method", "neigt_riccati_graph_v1", ... "paper_algorithm_reproduction", false, "status", status, "pass", false, ... "claim_status", "INCONCLUSIVE", "claim_quality", "not_identified", ... "nontrivial", false, "full_space_triviality", false, ... "basis_nonsingular", false, "preconditioner_residual_pass", false, ... "contraction_pass", false, "candidate_source", "", ... "candidate_C0_hash", "", "trials", struct ([])); endfunction function result = certified_similarity (A, X, R, C0, q, options) n = rows (A); A_box = net_iv_cmatrix_point (A, q); if (isfield (options, "A_box")) if (! isstruct (options.A_box) || ! isequal (size (options.A_box.rl), size (A))) result = struct ("E_box", [], "e", mp ("NaN"), "basis_nonsingular", false, ... "C0", C0, "C_box", [], "RF_box", [], "c", mp ("NaN"), ... "eta", mp ("NaN")); return; endif A_box = options.A_box; endif X_box = net_iv_cmatrix_point (X, q); R_box = net_iv_cmatrix_point (R, q); E_box = net_iv_cmatrix_sub (net_iv_cmatrix_eye (n, q), ... net_iv_cmatrix_mul (R_box, X_box, q), q); e = net_iv_cmatrix_inf_upper (E_box, q); result = struct ("E_box", E_box, "e", e, "basis_nonsingular", e < mp (1), ... "C0", C0, "C_box", [], "RF_box", [], "c", mp ("NaN"), ... "eta", mp ("NaN")); if (e >= mp (1)) return; endif F_box = net_iv_cmatrix_sub ... (net_iv_cmatrix_mul (A_box, X_box, q), ... net_iv_cmatrix_mul (X_box, net_iv_cmatrix_point (C0, q), q), q); RF_box = net_iv_cmatrix_mul (R_box, F_box, q); c = net_iv_cmatrix_inf_upper (RF_box, q); denominator = net_iv_primitive ("sub", mp (1), e, q); eta = net_iv_primitive ("div", c, denominator.lo, q).hi; C_box = expand_modulus (net_iv_cmatrix_point (C0, q), eta, q); result.F_box = F_box; result.RF_box = RF_box; result.c = c; result.eta = eta; result.C_box = C_box; endfunction function [exponent, bound] = initial_radius (c, e, q) if (c == mp (0)) exponent = -floor (q / 2); bound = mp (0); return; endif numerator = net_iv_primitive ("mul", mp (2), c, q).hi; denominator = net_iv_primitive ("sub", mp (1), e, q).lo; bound = net_iv_primitive ("div", numerator, denominator, q).hi; exponent = net_ufp (bound); t = net_pow2 (exponent, q); if (t <= bound) exponent += 1; endif endfunction function result = radius_trial (c, e, g, t, q, index) t2 = net_iv_primitive ("mul", t, t, q).hi; et = net_iv_primitive ("mul", e, t, q).hi; gt2 = net_iv_primitive ("mul", g, t2, q).hi; first = net_iv_primitive ("add", c, et, q).hi; self_bound = net_iv_primitive ("add", first, gt2, q).hi; two_g = net_iv_primitive ("mul", mp (2), g, q).hi; two_gt = net_iv_primitive ("mul", two_g, t, q).hi; contraction_bound = net_iv_primitive ("add", e, two_gt, q).hi; result = struct ("index", index, "t", t, "self_bound", self_bound, ... "contraction_bound", contraction_bound, ... "self_map", self_bound < t, "contraction", contraction_bound < mp (1), ... "contraction_possible", contraction_bound < mp (1)); endfunction function result = matrix_block (matrix, rows_selected, cols_selected) result = matrix; result.rl = matrix.rl(rows_selected, cols_selected); result.rh = matrix.rh(rows_selected, cols_selected); result.il = matrix.il(rows_selected, cols_selected); result.ih = matrix.ih(rows_selected, cols_selected); endfunction function result = vector_box (matrix, q) result = matrix; result.rl = matrix.rl(:); result.rh = matrix.rh(:); result.il = matrix.il(:); result.ih = matrix.ih(:); endfunction function result = nonconjugating_transpose (matrix) result = matrix; result.rl = transpose (matrix.rl); result.rh = transpose (matrix.rh); result.il = transpose (matrix.il); result.ih = transpose (matrix.ih); endfunction function result = expand_modulus (matrix, eta, q) result = matrix; for index = 1:numel (matrix.rl) result.rl(index) = net_iv_primitive ("sub", matrix.rl(index), eta, q).lo; result.rh(index) = net_iv_primitive ("add", matrix.rh(index), eta, q).hi; result.il(index) = net_iv_primitive ("sub", matrix.il(index), eta, q).lo; result.ih(index) = net_iv_primitive ("add", matrix.ih(index), eta, q).hi; endfor endfunction function result = midpoint_matrix (matrix, q) result = mp (zeros (size (matrix.rl))); half = mp ("0.5"); for index = 1:numel (result) re = (matrix.rl(index) + matrix.rh(index)) * half; im = (matrix.il(index) + matrix.ih(index)) * half; result(index) = net_mp_complex (re, im); endfor endfunction function result = max_entry_modulus (matrix, q) result = mp (0); for index = 1:numel (matrix.rl) value = net_iv_complex_abs (entry_box (matrix, index), q).hi; if (value > result) result = value; endif endfor endfunction function result = entry_box (matrix, index) if (isscalar (matrix.rl)) result = net_iv_complex (matrix.rl, matrix.rh, matrix.il, matrix.ih); else result = net_iv_complex (matrix.rl(index), matrix.rh(index), ... matrix.il(index), matrix.ih(index)); endif endfunction function result = constant_rectangle (m, n, rl, rh, il, ih) result = struct ("kind", "complex_matrix", ... "rl", rl * mp (ones (m, n)), "rh", rh * mp (ones (m, n)), ... "il", il * mp (ones (m, n)), "ih", ih * mp (ones (m, n))); endfunction % Explicit interval Kronecker product. The nonconjugating transpose is % supplied by the caller; no public matrix kron is used on proof data. function result = net_iv_cmatrix_kron (left, right, q) net_iv_q (q); if (! valid_matrix_local (left) || ! valid_matrix_local (right)) error ("mplapack:neigt:MatrixInterval", "invalid Kronecker operands"); endif m = rows (left.rl) * rows (right.rl); n = columns (left.rl) * columns (right.rl); result = struct ("kind", "complex_matrix", "rl", mp (zeros (m,n)), ... "rh", mp (zeros (m,n)), "il", mp (zeros (m,n)), ... "ih", mp (zeros (m,n))); for i = 1:rows (left.rl) for j = 1:columns (left.rl) for u = 1:rows (right.rl) for v = 1:columns (right.rl) value = net_iv_complex_mul (entry_box (left, sub2ind (size (left.rl), i, j)), ... entry_box (right, sub2ind (size (right.rl), u, v)), q); row = (i - 1) * rows (right.rl) + u; col = (j - 1) * columns (right.rl) + v; result.rl(row,col) = value.rl; result.rh(row,col) = value.rh; result.il(row,col) = value.il; result.ih(row,col) = value.ih; endfor endfor endfor endfor endfunction function value = valid_matrix_local (matrix) value = isstruct (matrix) && isfield (matrix, "kind") ... && strcmp (matrix.kind, "complex_matrix") && isfield (matrix, "rl") ... && isfield (matrix, "rh") && isfield (matrix, "il") && isfield (matrix, "ih") ... && isequal (size (matrix.rl), size (matrix.rh)) ... && isequal (size (matrix.rl), size (matrix.il)) ... && isequal (size (matrix.rl), size (matrix.ih)); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a2_reduction.m0000644000230300031750000000427015274353472025615 0ustar rafaelrafael% Prove the finite solve reduction C=B^(-1)A by the stated Neumann bound. % A, B, RB and C0 are all point MP values at the current evaluation precision; % RB and C0 remain candidate calculations, never exact substitutions. function result = net_v_a2_reduction (A, B, RB, C0, q) net_iv_q (q); if (nargin != 5 || ! isa (A, "mp") || ! isa (B, "mp") ... || ! isa (RB, "mp") || ! isa (C0, "mp") || rows (A) != columns (A) ... || ! isequal (size (A), size (B)) || ! isequal (size (A), size (RB)) ... || ! isequal (size (A), size (C0)) || ! all (isfinite (A(:))) ... || ! all (isfinite (B(:))) || ! all (isfinite (RB(:))) ... || ! all (isfinite (C0(:)))) error ("mplapack:neigt:VA2", "invalid finite-pencil reduction inputs"); endif n = rows (A); A_box = net_iv_cmatrix_point (A, q); B_box = net_iv_cmatrix_point (B, q); RB_box = net_iv_cmatrix_point (RB, q); C0_box = net_iv_cmatrix_point (C0, q); e_box = net_iv_cmatrix_sub (net_iv_cmatrix_eye (n, q), ... net_iv_cmatrix_mul (RB_box, B_box, q), q); e = net_iv_cmatrix_inf_upper (e_box, q); residual_box = net_iv_cmatrix_sub (A_box, ... net_iv_cmatrix_mul (B_box, C0_box, q), q); f_box = net_iv_cmatrix_mul (RB_box, residual_box, q); f = net_iv_cmatrix_inf_upper (f_box, q); denominator = net_iv_primitive ("sub", mp (1), e, q); result = struct ("method", "neigt_verified_finite_pencil_v1", ... "paper_algorithm_reproduction", false, "status", "INCONCLUSIVE", ... "pass", false, "B_nonsingular", false, "eB", e, "fB", f, ... "denominator", denominator.lo, "B_inverse_residual", e_box, ... "A_minus_BC0", residual_box, "RB_A_minus_BC0", f_box, ... "etaB", mp ("NaN"), "A_box", A_box, "B_box", B_box, ... "C0_box", C0_box, "C_box", [], "candidate_RB", RB, ... "candidate_C0", C0); if (e >= mp (1) || denominator.lo <= mp (0)) result.status = "INCONCLUSIVE_B_NONSINGULARITY"; return; endif eta = net_iv_primitive ("div", f, denominator.lo, q).hi; result.etaB = eta; result.C_box = net_v_a2_expand_modulus (C0_box, eta, q); result.B_nonsingular = true; result.pass = true; result.status = "CERTIFIED_B_NONSINGULAR_AND_REDUCTION"; endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_complex_add.m0000644000230300031750000000057315274353472025671 0ustar rafaelrafaelfunction result = net_iv_complex_add (a, b, q) real_sum = net_iv_real_add (net_iv_real (a.rl, a.rh), ... net_iv_real (b.rl, b.rh), q); imag_sum = net_iv_real_add (net_iv_real (a.il, a.ih), ... net_iv_real (b.il, b.ih), q); result = net_iv_complex (real_sum.lo, real_sum.hi, imag_sum.lo, imag_sum.hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_neigt_json_encode.m0000644000230300031750000000675215274353472026375 0ustar rafaelrafael% Canonical JSON encoder for NEIGT proof records and tagged values. function result = net_neigt_json_encode (value) if (ischar (value)) result = json_quote (value); elseif (islogical (value) && isscalar (value)) result = ternary (value, "true", "false"); elseif (isa (value, "double") && isscalar (value)) if (! isfinite (value)) error ("mplapack:neigt:Serialize", "nonfinite JSON number"); endif result = sprintf ("%.17g", value); elseif (iscell (value)) % jsondecode collapses a one-element JSON array to a scalar. Keep an % explicit array wrapper so canonical bytes survive a process restart. result = strcat ("{\"kind\":\"json_array\",\"items\":", ... encode_array_items (value), "}"); elseif (isstruct (value) && isscalar (value) ... && isfield (value, "kind") && strcmp (value.kind, "json_array")) % Preserve the explicit array-wrapper order across jsondecode/re-encode. result = strcat ("{\"kind\":\"json_array\",\"items\":", ... encode_array_items (value.items), "}"); elseif (isstruct (value) && isscalar (value)) names = sort (fieldnames (value)); result = "{"; for index = 1:numel (names) if (index > 1), result = strcat (result, ","); endif name = names{index}; result = strcat (result, json_quote (name), ":", ... net_neigt_json_encode (value.(name))); endfor result = strcat (result, "}"); elseif (isstruct (value)) result = "["; for index = 1:numel (value) if (index > 1), result = strcat (result, ","); endif result = strcat (result, net_neigt_json_encode (value(index))); endfor result = strcat (result, "]"); elseif (isnumeric (value) && isvector (value)) result = "["; for index = 1:numel (value) if (index > 1), result = strcat (result, ","); endif result = strcat (result, net_neigt_json_encode (double (value(index)))); endfor result = strcat (result, "]"); elseif (isnumeric (value) && isempty (value)) result = "[]"; else error ("mplapack:neigt:Serialize", ... "unsupported canonical JSON class %s", class (value)); endif endfunction function result = encode_array_items (items) result = "["; if (iscell (items)) count = numel (items); for index = 1:count if (index > 1), result = strcat (result, ","); endif result = strcat (result, net_neigt_json_encode (items{index})); endfor elseif (isstruct (items) && numel (items) > 1) count = numel (items); for index = 1:count if (index > 1), result = strcat (result, ","); endif result = strcat (result, net_neigt_json_encode (items(index))); endfor elseif ((isnumeric (items) || islogical (items)) && numel (items) > 1) count = numel (items); for index = 1:count if (index > 1), result = strcat (result, ","); endif result = strcat (result, net_neigt_json_encode (items(index))); endfor elseif (! isempty (items)) result = strcat (result, net_neigt_json_encode (items)); endif result = strcat (result, "]"); endfunction function result = json_quote (value) value = strrep (value, "\\", "\\\\"); value = strrep (value, '"', '\\"'); value = strrep (value, char (10), "\\n"); value = strrep (value, char (13), "\\r"); value = strrep (value, char (9), "\\t"); result = ['"', value, '"']; endfunction function result = ternary (condition, if_true, if_false) if (condition), result = if_true; else, result = if_false; endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_cmatrix_conjtrans.m0000644000230300031750000000035515274353472027140 0ustar rafaelrafaelfunction result = net_iv_cmatrix_conjtrans (matrix) result = matrix; result.rl = ctranspose (matrix.rl); result.rh = ctranspose (matrix.rh); result.il = -ctranspose (matrix.ih); result.ih = -ctranspose (matrix.il); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_oo_validate_pair.m0000644000230300031750000000173115274353472026212 0ustar rafaelrafael% Reject an inverse pair unless both exact products equal identity. function metadata = net_oo_validate_pair (X, Y, bits) if (nargin != 3 || ! isa (X, "mp") || ! isa (Y, "mp") ... || rows (X) != columns (X) || any (size (X) != size (Y))) error ("mplapack:neigt:OO", "invalid inverse-pair arguments"); endif [xy, xy_metadata] = net_exact_product_dyadic (X, Y, bits); [yx, yx_metadata] = net_exact_product_dyadic (Y, X, bits); saved_bits = mpbits (); unwind_protect mpbits (max ([bits, xy_metadata.check_bits, yx_metadata.check_bits])); identity = mp (eye (rows (X))); if (! all (xy(:) == identity(:)) || ! all (yx(:) == identity(:))) error ("mplapack:neigt:OO", "inverse-pair exact identity check failed"); endif metadata = struct ("valid", true, "xy", xy_metadata, "yx", yx_metadata, ... "method", "common_dyadic_denominator_v1"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_oo_standard.m0000644000230300031750000000353215274353472025207 0ustar rafaelrafael% Ozaki--Ogita requested standard forms at their fixed generation precision. function S = net_oo_standard (kind, n, bits) if (nargin != 3 || ! ischar (kind) || ! isnumeric (n) ... || ! isscalar (n) || n != fix (n) || n < 2) error ("mplapack:neigt:OO", "invalid standard-form arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); S = mp (zeros (n, n)); if (strcmp (kind, "OO53_REAL")) delta = net_pow2 (-45, bits); for i = 1:n S(i, i) = mp (i) + delta; if (i < n) S(i, i + 1) = mp (32); endif endfor elseif (strcmp (kind, "OO53_PAIR")) if (mod (n, 2) != 0) error ("mplapack:neigt:OO", "OO53_PAIR requires even n"); endif delta = net_pow2 (-45, bits); for block = 0:(n / 2 - 1) first = 2 * block + 1; a = mp (2 * block + 1) + delta; b = mp (2 * block + 1) / mp (8) + delta; S(first, first) = a; S(first + 1, first + 1) = a; S(first, first + 1) = b; S(first + 1, first) = -b; if (first + 2 <= n) S(first, first + 2) = mp (8); S(first + 1, first + 3) = mp (8); endif endfor elseif (strcmp (kind, "OO128_CLOSE")) if (bits != 128) error ("mplapack:neigt:OO", "OO128_CLOSE has fixed generation precision 128"); endif delta = net_pow2 (-80, bits); tiny = net_pow2 (-120, bits); for i = 1:n if (i == 1) S(i, i) = mp (1); elseif (i == 2) S(i, i) = mp (1) + delta + tiny; else S(i, i) = mp (i); endif if (i < n) S(i, i + 1) = mp (1); endif endfor else error ("mplapack:neigt:OO", "unknown Ozaki--Ogita standard form"); endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_s3_svd.m0000644000230300031750000002043615274353472024442 0ustar rafaelrafael% Verified V-S3 point/cell pseudospectrum baseline. % This is the finite polar/Weyl enclosure specified by CERTIFICATES.md; % it is not a reproduction of a full pseudospectrum algorithm. function result = net_v_s3_svd (A, z, epsilon, cell_box, source_bits, q) if (nargin != 6 || ! isa (A, "mp") || rows (A) != columns (A) ... || ! isa (z, "mp") || ! isscalar (z) || ! isfinite (real (z)) ... || ! isfinite (imag (z)) || ! isa (epsilon, "mp") ... || ! isscalar (epsilon) || ! isfinite (epsilon) || epsilon <= mp (0) ... || source_bits != fix (source_bits) || source_bits < 64 ... || q != fix (q) || q < source_bits) error ("mplapack:neigt:VS3", "invalid verified SVD arguments"); endif if (! isempty (cell_box) && (! isstruct (cell_box) ... || ! isfield (cell_box, "real_halfwidth") ... || ! isfield (cell_box, "imag_halfwidth") ... || cell_box.real_halfwidth <= mp (0) ... || cell_box.imag_halfwidth <= mp (0))) error ("mplapack:neigt:VS3", "cell must have positive halfwidths"); endif saved_bits = mpbits (); unwind_protect % Freeze the solver input and candidate outputs at source_bits. The % proof below only widens these returned values; it never substitutes a % higher-precision solve or a known singular value. mpbits (source_bits); n = rows (A); B_candidate = z * mp (eye (n)) - A; [U, S, V] = svd (B_candidate); s = diag (S); if (rows (U) != n || columns (U) != n || rows (V) != n ... || columns (V) != n || numel (s) != n) error ("mplapack:neigt:VS3", "full square SVD output was not returned"); endif if (! all (isfinite (real (U))) || ! all (isfinite (imag (U))) ... || ! all (isfinite (real (V))) || ! all (isfinite (imag (V))) ... || ! all (isfinite (s)) || any (s < mp (0)) ... || any (s(1:(n - 1)) < s(2:n))) error ("mplapack:neigt:VS3", ... "SVD candidate is not finite, nonnegative, and descending"); endif raw = struct ("B_candidate", B_candidate, "U", U, "s", s, "V", V, ... "B_hash", net_raw_hash (B_candidate, "VS3_B_candidate"), ... "U_hash", net_raw_hash (U, "VS3_U_candidate"), ... "s_hash", net_raw_hash (s, "VS3_s_candidate"), ... "V_hash", net_raw_hash (V, "VS3_V_candidate")); % The exact target is the separate expression z*I-A. Constructing this % as rectangle arithmetic retains the expression enclosure even when % z*I-A was rounded while forming the solver input above. mpbits (q); B_exact = net_iv_cmatrix_sub (net_iv_cmatrix_point (z * mp (eye (n)), q), ... net_iv_cmatrix_point (A, q), q); Ub = net_iv_cmatrix_point (net_widen (U, q, source_bits), q); Vb = net_iv_cmatrix_point (net_widen (V, q, source_bits), q); sb = net_iv_cmatrix_point (net_widen (s, q, source_bits), q); Sbox = diagonal_box (sb, n, q); gram_u = net_iv_cmatrix_sub (net_iv_cmatrix_mul ... (net_iv_cmatrix_conjtrans (Ub), Ub, q), net_iv_cmatrix_eye (n, q), q); gram_v = net_iv_cmatrix_sub (net_iv_cmatrix_mul ... (net_iv_cmatrix_conjtrans (Vb), Vb, q), net_iv_cmatrix_eye (n, q), q); gU = net_iv_cmatrix_fro_upper (gram_u, q); gV = net_iv_cmatrix_fro_upper (gram_v, q); if (gU >= mp (1) || gV >= mp (1)) error ("mplapack:neigt:VS3", "candidate singular vectors are not certifiably close to unitary"); endif reconstruction = net_iv_cmatrix_mul (net_iv_cmatrix_mul (Ub, Sbox, q), ... net_iv_cmatrix_conjtrans (Vb), q); residual_box = net_iv_cmatrix_sub (B_exact, reconstruction, q); r = net_iv_cmatrix_fro_upper (residual_box, q); fU = scalar_f (gU, q); fV = scalar_f (gV, q); one_plus_gv = net_iv_real (net_iv_primitive ("add", mp (1), gV, q).lo, ... net_iv_primitive ("add", mp (1), gV, q).hi); term_u = net_iv_primitive ("mul", fU, ... net_iv_real_sqrt (net_iv_real (net_iv_primitive ("add", mp (1), gV, q).lo, ... net_iv_primitive ("add", mp (1), gV, q).hi), q).hi, q).hi; term_v = fV; % The formula uses fU*sqrt(1+gV)+fV. Keep every scalar operation in % the audited outward primitive path; one_plus_gv is retained in the % record to make the proof data explicit. unused = one_plus_gv; %#ok bracket = net_iv_primitive ("add", term_u, term_v, q).hi; s1_upper = sb.rh(1); sn_lower = sb.rl(numel (s)); sn_upper = sb.rh(numel (s)); delta = net_iv_primitive ("add", r, ... net_iv_primitive ("mul", s1_upper, bracket, q).hi, q).hi; lower_s = net_iv_primitive ("sub", sn_lower, delta, q).lo; upper_s = net_iv_primitive ("add", sn_upper, delta, q).hi; lower = max (mp (0), lower_s); upper = upper_s; point_status = net_v_s3_classify (lower, upper, epsilon); A_norm = net_iv_cmatrix_fro_upper (net_iv_cmatrix_point (A, q), q); z_abs = net_iv_complex_abs (net_iv_complex_point (z, q), q); norm_margin = net_iv_primitive ("sub", z_abs.lo, A_norm, q).lo; norm_outside = norm_margin > epsilon; if (strcmp (point_status, "CERTIFIED_OUTSIDE") && norm_outside) % The norm witness can only strengthen an outside classification. It % is never used to turn a straddling SVD enclosure into a claim. point_status = "CERTIFIED_OUTSIDE"; endif result = struct ("method", "neigt_svd_pseudospectrum_point_v1", ... "paper_algorithm_reproduction", false, "status", point_status, ... "claim_status", point_status, "pass", true, "epsilon", epsilon, ... "source_bits", source_bits, "evaluation_bits", q, "raw", raw, ... "B_exact", B_exact, "candidate_singular_values", sb, ... "gU", gU, "gV", gV, "fU", fU, "fV", fV, "residual", r, ... "delta", delta, "lower", lower, "upper", upper, ... "A_fro_upper", A_norm, "z_abs_lower", z_abs.lo, ... "norm_margin_lower", norm_margin, ... "norm_outside_witness", norm_outside, ... "target", "exact_expression_zI_minus_A", "cell", []); if (! isempty (cell_box)) hx = cell_box.real_halfwidth; hy = cell_box.imag_halfwidth; d = net_iv_primitive ("add", hx, hy, q).hi; cell_lower = max (mp (0), net_iv_primitive ("sub", lower, d, q).lo); cell_upper = net_iv_primitive ("add", upper, d, q).hi; cell_box_iv = net_iv_complex (real (z) - hx, real (z) + hx, ... imag (z) - hy, imag (z) + hy); cell_abs = net_iv_complex_abs (cell_box_iv, q); cell_norm_margin = net_iv_primitive ("sub", cell_abs.lo, A_norm, q).lo; cell_norm_outside = cell_norm_margin > epsilon; cell_status = net_v_s3_classify (cell_lower, cell_upper, epsilon); if (strcmp (cell_status, "CERTIFIED_OUTSIDE") && cell_norm_outside) cell_status = "CERTIFIED_OUTSIDE"; endif cell_area = net_iv_primitive ("mul", ... net_iv_primitive ("mul", hx, hy, q).hi, mp (4), q).hi; result.cell = struct ("status", cell_status, "lower", cell_lower, ... "upper", cell_upper, "distance", d, "halfwidth_real", hx, ... "halfwidth_imag", hy, "area", cell_area, ... "positive_area", cell_area > mp (0), ... "norm_margin_lower", cell_norm_margin, ... "norm_outside_witness", cell_norm_outside, ... "lipschitz", "sigma_min is 1-Lipschitz in z under the 2-norm"); result.method = "neigt_svd_pseudospectrum_cell_v1"; result.status = cell_status; result.claim_status = cell_status; endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = scalar_f (g, q) root_arg = net_iv_real (net_iv_primitive ("sub", mp (1), g, q).lo, ... net_iv_primitive ("sub", mp (1), g, q).hi); root = net_iv_real_sqrt (root_arg, q); denominator = net_iv_real (net_iv_primitive ("add", mp (1), root.lo, q).lo, ... net_iv_primitive ("add", mp (1), root.hi, q).hi); result = net_iv_real_div (net_iv_real (g, g), denominator, q).hi; endfunction function result = diagonal_box (diagonal, n, q) result = net_iv_cmatrix_point (mp (zeros (n, n)), q); for index = 1:n result.rl(index,index) = diagonal.rl(index); result.rh(index,index) = diagonal.rh(index); result.il(index,index) = diagonal.il(index); result.ih(index,index) = diagonal.ih(index); endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_neigt_decode_value.m0000644000230300031750000001170215274353472026515 0ustar rafaelrafael% Decode the tagged exact result values written by net_neigt_encode_value. function result = net_neigt_decode_value (encoded, destination_bits) if (nargin != 2 || ! isstruct (encoded) || ! isfield (encoded, "kind") ... || destination_bits != fix (destination_bits) || destination_bits < 1) error ("mplapack:neigt:Deserialize", "invalid tagged value"); endif kind = char (encoded.kind); if (strcmp (kind, "mp_matrix")) shape = checked_shape (encoded.shape); values = items_as_cell (encoded.values); if (numel (values) != prod (shape) ... || ! isfield (encoded, "stored_precision") ... || destination_bits < encoded.stored_precision) error ("mplapack:neigt:Deserialize", "invalid MP matrix payload"); endif saved_bits = mpbits (); unwind_protect mpbits (destination_bits); decoded = cell (numel (values), 1); complex_value = false; for index = 1:numel (values) item = values{index}; decoded{index} = net_dyadic_decode_scalar (item, destination_bits); complex_value = complex_value || ! isreal (decoded{index}); endfor if (complex_value) result = mp (zeros (shape)) + net_mp_complex (mp (0), mp (0)); else result = mp (zeros (shape)); endif if (numel (decoded) == 1) result = decoded{1}; else for index = 1:numel (decoded) result(index) = decoded{index}; endfor endif unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect return; endif if (strcmp (kind, "logical_array")) shape = checked_shape (encoded.shape); values = items_as_cell (encoded.values); if (numel (values) != prod (shape)) error ("mplapack:neigt:Deserialize", "logical value count mismatch"); endif result = false (shape); for index = 1:numel (values) result(index) = logical (values{index}); endfor return; endif if (strcmp (kind, "double_array")) shape = checked_shape (encoded.shape); values = items_as_cell (encoded.values); if (numel (values) != prod (shape)) error ("mplapack:neigt:Deserialize", "double value count mismatch"); endif result = zeros (shape); for index = 1:numel (values) if (! isnumeric (values{index}) || ! isscalar (values{index}) ... || ! isfinite (values{index})) error ("mplapack:neigt:Deserialize", "invalid double value"); endif result(index) = values{index}; endfor return; endif if (strcmp (kind, "char")) if (! isfield (encoded, "value") || ! ischar (encoded.value)) error ("mplapack:neigt:Deserialize", "invalid character value"); endif result = encoded.value; return; endif if (strcmp (kind, "cell_array")) shape = checked_shape (encoded.shape); items = items_as_cell (encoded.items); if (numel (items) != prod (shape)) error ("mplapack:neigt:Deserialize", "cell value count mismatch"); endif result = cell (shape); for index = 1:numel (items) result{index} = net_neigt_decode_value (items{index}, destination_bits); endfor return; endif if (strcmp (kind, "struct")) if (! isfield (encoded, "fields") || ! isstruct (encoded.fields)) error ("mplapack:neigt:Deserialize", "invalid struct value"); endif result = struct (); names = fieldnames (encoded.fields); for index = 1:numel (names) name = names{index}; result.(name) = net_neigt_decode_value ... (encoded.fields.(name), destination_bits); endfor return; endif if (strcmp (kind, "struct_array")) shape = checked_shape (encoded.shape); items = items_as_cell (encoded.items); if (numel (items) != prod (shape)) error ("mplapack:neigt:Deserialize", "struct value count mismatch"); endif if (isempty (items)) result = struct ([]); return; endif first = net_neigt_decode_value (items{1}, destination_bits); result = repmat (first, shape); for index = 2:numel (items) result(index) = net_neigt_decode_value (items{index}, destination_bits); endfor return; endif error ("mplapack:neigt:Deserialize", "unknown tagged value kind %s", kind); endfunction function shape = checked_shape (shape) if (! isnumeric (shape) || numel (shape) != 2 || any (shape != fix (shape)) ... || any (shape < 0)) error ("mplapack:neigt:Deserialize", "invalid tagged value shape"); endif shape = double (shape(:).'); endfunction function result = items_as_cell (items) if (isstruct (items) && isscalar (items) && isfield (items, "kind") ... && strcmp (items.kind, "json_array")) result = items_as_cell (items.items); return; endif if (iscell (items)) result = items; elseif (isstruct (items)) result = cell (numel (items), 1); for index = 1:numel (items) result{index} = items(index); endfor elseif (isempty (items)) result = cell (0, 1); else result = num2cell (items(:)); endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_real_sub.m0000644000230300031750000000032515274353472025201 0ustar rafaelrafaelfunction result = net_iv_real_sub (a, b, q) net_iv_q (q); result = net_iv_real (net_iv_primitive ("sub", a.lo, b.hi, q).lo, ... net_iv_primitive ("sub", a.hi, b.lo, q).hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_neigt_json_write.m0000644000230300031750000000140215274353472026255 0ustar rafaelrafael% Write a canonical hash-bound NEIGT proof record. function digest = net_neigt_json_write (record, filename) if (nargin != 2 || ! isstruct (record) || ! isscalar (record) ... || ! ischar (filename) || isempty (filename) || isfield (record, "sha256")) error ("mplapack:neigt:Serialize", "invalid proof-record write request"); endif body = net_neigt_json_encode (record); digest = hash ("sha256", body); record.sha256 = digest; text = net_neigt_json_encode (record); handle = fopen (filename, "w"); if (handle < 0) error ("mplapack:neigt:Serialize", "cannot open proof record"); endif unwind_protect fwrite (handle, text); fwrite (handle, char (10)); unwind_protect_cleanup fclose (handle); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_match.m0000644000230300031750000000234515274353472024007 0ustar rafaelrafael% Example-local facade over the previously tested MP bottleneck matcher. function result = net_match (computed, reference, kind, varargin) here = fileparts (mfilename ("fullpath")); repo_root = fileparts (fileparts (fileparts (here))); old_private = fullfile (repo_root, "examples", "nonsymmetric_eig", ... "private"); if (exist (fullfile (old_private, "nes_match.m"), "file") != 2) error ("mplapack:neigt:Matching", "existing NEIG matcher is unavailable"); endif added = false; if (! any (strcmp (strsplit (path (), pathsep), old_private))) addpath (old_private); added = true; endif unwind_protect if (nargin == 3) result = nes_match (computed, reference, kind); elseif (nargin == 5) result = nes_match (computed, reference, kind, varargin{1}, varargin{2}); else error ("mplapack:neigt:Matching", "invalid matching arguments"); endif result.method = "minimum_bottleneck_bijective_v1"; result.paper_algorithm_reproduction = false; if (added) rmpath (old_private); endif unwind_protect_cleanup if (added && any (strcmp (strsplit (path (), pathsep), old_private))) rmpath (old_private); endif end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_frank_model.m0000644000230300031750000000204115274353472025165 0ustar rafaelrafael% A2 explicit Frank orientations from their defining formulas. function result = net_frank_model (n, orientation, bits) if (nargin != 3 || n != fix (n) || n < 2 ... || ! any (orientation == [0, 1])) error ("mplapack:neigt:Frank", "invalid Frank model arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); F0 = mp (zeros (n, n)); for i = 1:n for j = 1:n if (j >= i - 1) F0(i, j) = mp (n + 1 - max (i, j)); endif endfor endfor reversal = mp (zeros (n, n)); for i = 1:n reversal(i, n - i + 1) = mp (1); endfor F1 = reversal * ctranspose (F0) * reversal; if (orientation == 0) A = F0; else A = F1; endif result = struct ("family", "frank", "orientation", orientation, ... "n", n, "bits", bits, "A", A, "F0", F0, "F1", F1, ... "reversal", reversal, "source", "A2_EXPLICIT_FRANK_ORIENTATIONS", ... "status", "MEASURED"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a1_job.m0000644000230300031750000001064115274353472024371 0ustar rafaelrafael% Run one NEIGT18 compatible-factor job. function result = net_v_a1_job (job, profile_data, profile) result = status_template (); result.id = job.id; result.tier = job.tier; result.kind = job.kind; result.candidate_source = job.candidate_source; result.candidate_bits = profile_data.source_bits; result.evaluation_bits = profile_data.evaluation_bits; source_bits = profile_data.source_bits; q = profile_data.evaluation_bits; saved_bits = mpbits (); unwind_protect try regime = char (job.fixture.regime); if (strcmp (regime, "real_simple")) model = net_v_a1_model (regime, job.fixture.n, source_bits); elseif (strcmp (regime, "complex_simple")) model = net_v_a1_model (regime, job.fixture.n, source_bits); elseif (strcmp (regime, "defective_block")) result = defective_guard (job, profile_data, profile); return; else error ("mplapack:neigt:VA1", "unsupported VA1 regime %s", regime); endif mpbits (source_bits); [V, D, W] = eig (model.A_frozen, "nobalance"); result.raw_V = V; result.raw_D = D; result.raw_W = W; mpbits (q); A = net_widen (model.A_frozen, q, source_bits); Vq = net_widen (V, q, source_bits); Dq = net_widen (D, q, source_bits); exponent = -40; if (strcmp (profile, "demo")) exponent = -64; endif factors = net_v_a1_factors (A, Vq, Dq, q, exponent); result.certificate = factors; result.details = factors; result.status = factors.status; result.claim_status = factors.claim_status; result.claim_quality = factors.claim_quality; result.pass = factors.pass; result.milestone_pass = result.pass; result.raw_V_hash = factors.raw_V_hash; result.raw_D_hash = factors.raw_D_hash; result.raw_W_hash = net_raw_hash (W, [job.id, "_raw_W"]); result.raw_lambda_hash = factors.raw_lambda_hash; result.input_hash = net_raw_hash (model.A_frozen, [job.id, "_A_frozen"]); result.source = model.source; result.input_status = model.input_status; catch exception result.status = "FAILED_VERIFIER"; result.claim_status = "ERROR"; result.claim_quality = "not_identified"; result.error_identifier = exception.identifier; result.error_message = exception.message; end_try_catch unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = defective_guard (job, profile_data, profile) bits = profile_data.source_bits; q = profile_data.evaluation_bits; saved_bits = mpbits (); unwind_protect mpbits (bits); model = net_v_a1_model ("defective_block", job.fixture.n, bits); A = net_widen (model.A_frozen, q, bits); preparation = net_v_s2_candidate (model.A_frozen, mp (1), net_pow2 (-2, bits), 2, bits); X = net_widen (preparation.candidates{1}, q, bits); graph = net_v_s2_graph (A, X, 2, q); result = status_template (); result.id = job.id; result.tier = job.tier; result.kind = job.kind; result.candidate_source = job.candidate_source; result.candidate_bits = bits; result.evaluation_bits = q; result.certificate = graph; result.details = graph; result.claim_status = "INDIVIDUAL_FACTORS_REFUSED_DEFECTIVE_BLOCK"; result.claim_quality = "fail_closed"; result.status = "INCONCLUSIVE_DEFECTIVE_INDIVIDUAL"; result.pass = false; result.milestone_pass = graph.pass && graph.nontrivial; result.input_hash = net_raw_hash (model.A_frozen, [job.id, "_A_frozen"]); result.source = model.source; result.input_status = model.input_status; result.error_message = "A true Jordan block is not diagonalizable; block Schur is NEIGT19."; unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = status_template () result = struct ("id", "", "tier", "", "kind", "", "status", ... "NOT_IMPLEMENTED", "pass", false, "milestone_pass", false, ... "claim_status", "", "claim_quality", "", "details", [], ... "candidate_source", "", "candidate_bits", NaN, "evaluation_bits", NaN, ... "raw_V_hash", "", "raw_D_hash", "", "raw_W_hash", "", ... "raw_B_hash", "", "raw_U_hash", "", "raw_s_hash", "", ... "raw_lambda_hash", "", "certificate", [], "input_hash", "", ... "source", "", "input_status", "", "target", "", "raw_V", [], ... "raw_D", [], "raw_W", [], "error_identifier", "", "error_message", ""); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_cmatrix_neg.m0000644000230300031750000000026515274353472025710 0ustar rafaelrafaelfunction result = net_iv_cmatrix_neg (matrix) result = matrix; result.rl = -matrix.rh; result.rh = -matrix.rl; result.il = -matrix.ih; result.ih = -matrix.il; endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a3_job.m0000644000230300031750000002172015274353472024373 0ustar rafaelrafael% Run one verified positive Perron root/vector job. function result = net_v_a3_job (job, profile_data, profile) result = status_template (job, profile_data); bits = profile_data.source_bits; q = profile_data.evaluation_bits; saved_bits = mpbits (); unwind_protect try stage = "model"; fixture = job.fixture; if (strcmp (char (fixture.representation), "stochastic")) markov = net_markov_model (fixture.n, fixture.epsilon_exponent, bits); A_model = markov.P_frozen; source = markov.source; input_status = markov.input_status; base_markov = markov; elseif (strcmp (char (fixture.representation), "positive_similarity")) perron = net_perron_model (fixture.n, fixture.epsilon_exponent, bits); A_model = perron.A_frozen; source = perron.source; input_status = perron.input_status; base_markov = perron.markov; else error ("mplapack:neigt:VA3", "unsupported Perron representation"); endif if (fixture.transpose) A_model = ctranspose (A_model); source = [source, "_TRANSPOSE"]; endif result.source = source; result.input_status = input_status; result.input_hash = net_raw_hash (A_model, [job.id, "_A_frozen"]); result.base_input_hash = net_raw_hash (base_markov.P_frozen, [job.id, "_P_frozen"]); mpbits (bits); stage = "right-eig"; [V, D, W_unused] = eig (A_model, "nobalance"); values = diag (D); index = select_perron (values); x0 = real (V(:, index)); x0 = orient_positive (x0); x0_sum = mp (0); for x_index = 1:numel (x0) x0_sum = x0_sum + real (x0(x_index)); endfor x0 = x0 / x0_sum; lambda0 = real (values(index)); result.raw_V = V; result.raw_D = D; result.raw_W = W_unused; result.raw_V_hash = net_raw_hash (V, [job.id, "_raw_V"]); result.raw_D_hash = net_raw_hash (D, [job.id, "_raw_D"]); result.raw_W_hash = net_raw_hash (W_unused, [job.id, "_raw_W"]); result.candidate_index = index; result.candidate_lambda = lambda0; result.candidate_source = "computed_normalized_positive_pair"; result.candidate_bits = bits; result.evaluation_bits = q; mpbits (q); stage = "collatz"; A = net_widen (A_model, q, bits); xq = net_widen (x0, q, bits); lq = net_widen (lambda0, q, bits); collatz = net_v_a3_collatz (A, xq, q); stage = "pair"; pair = net_v_a3_pair (A, xq, lq, q); result.collatz = collatz; result.pair = pair; result.root_status = collatz.status; result.root_interval = net_iv_real (collatz.cw_lower, collatz.cw_upper); if (pair.pass) pair_interval = net_iv_real (pair.Y_box.lambda_lower, ... pair.Y_box.lambda_upper); result.lambda_pair_interval = pair_interval; result.lambda_intersection = interval_intersection (collatz, pair_interval); else result.lambda_pair_interval = net_iv_real (mp (0), mp (0)); result.lambda_intersection = struct ("nonempty", false); endif % An independently prepared left candidate is retained separately from % the right-pair contraction. It is normalized by w'*x=1 and checked % against the original A, including the nontrivial stationary case. stage = "left-eig"; [VL, DL] = eig (ctranspose (A_model), "nobalance"); left_values = diag (DL); left_index = select_perron (left_values); w0 = orient_positive (real (VL(:, left_index))); w0 = w0 / (ctranspose (w0) * x0); stage = "left-residual"; Wq = net_widen (w0, q, bits); left_lambda = net_widen (real (left_values(left_index)), q, bits); stage = "left-mul"; left_row = net_iv_cmatrix_conjtrans (net_iv_cmatrix_point (Wq, q)); left_matrix = net_iv_cmatrix_point (A, q); left_A = net_iv_cmatrix_mul (left_row, left_matrix, q); stage = "left-scale"; left_rhs = row_scale (left_row, left_lambda, q); stage = "left-sub"; left_residual = net_iv_cmatrix_sub ... (left_A, left_rhs, q); result.raw_left_V = VL; result.raw_left_D = DL; result.raw_left_V_hash = net_raw_hash (VL, [job.id, "_raw_left_V"]); result.left_candidate = Wq; result.left_residual_box = left_residual; result.left_residual_norm_upper = net_iv_cmatrix_fro_upper (left_residual, q); result.left_strictly_positive = all (real (Wq(:)) > mp (0)) ... && all (imag (Wq(:)) == mp (0)); result.left_normalization = ctranspose (Wq) * net_widen (x0, q, bits); result.stationary = []; if (strcmp (char (fixture.representation), "stochastic")) result.stationary = independent_stationary (base_markov.P_frozen, bits); endif result.root_width_target = net_pow2 (-64, q); result.root_width_pass = collatz.pass ... && collatz.width <= result.root_width_target; result.pass = collatz.pass && result.root_width_pass && pair.pass ... && result.lambda_intersection.nonempty ... && result.left_strictly_positive ... && result.left_residual_norm_upper <= result.root_width_target ... && (isempty (result.stationary) || result.stationary.pass); if (result.pass) result.status = "CERTIFIED_PERRON_PAIR"; result.claim_status = "CERTIFIED_PERRON_ROOT_AND_PAIR"; result.claim_quality = "strict_positive_graph_collatz_contraction"; result.milestone_pass = true; else result.status = "INCONCLUSIVE_PERRON_PAIR"; result.claim_status = "INCONCLUSIVE"; result.milestone_pass = false; endif catch exception result.status = "FAILED_VERIFIER"; result.claim_status = "ERROR"; result.error_identifier = exception.identifier; result.error_message = exception.message; result.failure_stage = stage; end_try_catch unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = row_scale (row, scalar, q) result = net_iv_cmatrix_point (mp (zeros (1, columns (row.rl))), q); scalar_box = net_iv_complex_point (scalar, q); for j = 1:columns (row.rl) value = net_iv_complex (row.rl(1,j), row.rh(1,j), ... row.il(1,j), row.ih(1,j)); product = net_iv_complex_mul (scalar_box, value, q); result.rl(1,j) = product.rl; result.rh(1,j) = product.rh; result.il(1,j) = product.il; result.ih(1,j) = product.ih; endfor endfunction function index = select_perron (values) index = 1; for i = 2:numel (values) if (real (values(i)) > real (values(index))) index = i; endif endfor endfunction function result = orient_positive (value) result = value; [~, index] = max (abs (result)); if (result(index) < mp (0)) result = -result; endif endfunction function result = interval_intersection (collatz, pair_interval) lower = collatz.cw_lower; if (pair_interval.lo > lower) lower = pair_interval.lo; endif upper = collatz.cw_upper; if (pair_interval.hi < upper) upper = pair_interval.hi; endif result = struct ("lower", lower, "upper", upper, "nonempty", lower <= upper); endfunction function result = independent_stationary (P, bits) saved_bits = mpbits (); unwind_protect mpbits (bits); n = rows (P); M = ctranspose (P) - mp (eye (n)); rhs = mp (zeros (n, 1)); M(n,:) = mp (ones (1, n)); rhs(n) = mp (1); pi = M \ rhs; pi_sum = sum_real_vector (pi); pi = pi / pi_sum; pi_sum = sum_real_vector (pi); equation = ctranspose (P) * pi - pi; normalization_error = abs (pi_sum - mp (1)); result = struct ("method", "independent_stationary_normalized_solve", ... "vector", pi, "sum", pi_sum, "normalization_error", normalization_error, ... "positive", all (pi > mp (0)), ... "residual", equation, "residual_norm", norm (equation), ... "pass", all (pi > mp (0)) && normalization_error <= net_pow2 (-64, bits) ... && norm (equation) <= net_pow2 (-64, bits)); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = sum_real_vector (items) result = mp (0); for i = 1:numel (items) result = result + real (items(i)); endfor endfunction function result = status_template (job, profile_data) result = struct ("id", job.id, "tier", job.tier, "kind", job.kind, ... "status", "NOT_IMPLEMENTED", "pass", false, "milestone_pass", false, ... "claim_status", "", "claim_quality", "", "candidate_source", "", ... "candidate_bits", profile_data.source_bits, ... "evaluation_bits", profile_data.evaluation_bits, "source", "", ... "input_status", "", "input_hash", "", "base_input_hash", "", ... "raw_V_hash", "", "raw_D_hash", "", "raw_W_hash", "", ... "raw_V", [], "raw_D", [], "raw_W", [], "error_identifier", "", ... "error_message", "", "failure_stage", ""); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_toeplitz_reference.m0000644000230300031750000000334415274353472026603 0ustar rafaelrafael% Stable MP analytic reference for S3 Toeplitz eigenvalues and vectors. function result = net_toeplitz_reference (n, b, reference_bits) if (nargin != 3 || ! isnumeric (n) || ! isscalar (n) || n != fix (n) ... || n < 2 || ! isnumeric (b) || ! isscalar (b) || b != fix (b) ... || b < 1) error ("mplapack:neigt:Toeplitz", "invalid Toeplitz reference arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (reference_bits); pi_value = acos (mp ("-1")); scale = net_pow2 (1 - b, reference_bits); eigenvalues = mp (zeros (n, 1)); right_vectors = mp (zeros (n, n)); left_vectors = mp (zeros (n, n)); condition_numbers = mp (zeros (n, 1)); overlaps = mp (zeros (n, 1)); for k = 1:n theta = pi_value * mp (k) / mp (n + 1); eigenvalues(k) = mp (3) + scale * cos (theta); for j = 1:n sine = sin (mp (j) * theta); right_vectors(j, k) = net_pow2 (b * (j - 1), reference_bits) * sine; left_vectors(j, k) = net_pow2 (-b * (j - 1), reference_bits) * sine; endfor overlaps(k) = ctranspose (left_vectors(:, k)) * right_vectors(:, k); condition_numbers(k) = norm (right_vectors(:, k)) ... * norm (left_vectors(:, k)) / abs (overlaps(k)); endfor result = struct (... "reference_status", "analytic_MP_sine_cosine", ... "reference_bits", reference_bits, "eigenvalues", eigenvalues, ... "right_vectors", right_vectors, "left_vectors", left_vectors, ... "condition_numbers", condition_numbers, "overlaps", overlaps, ... "overlap_target", mp (n + 1) / mp (2), ... "source", "S3_CLOSED_FORM_REFERENCE"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_exact_det_permutation.m0000644000230300031750000000361015274353472027276 0ustar rafaelrafael% Exact small determinant by fraction-free MP elimination. % This is an independent checker for integer/dyadic fixture identities. function [value, metadata] = net_exact_det_permutation (matrix, bits) if (nargin != 2 || ! isa (matrix, "mp") || rows (matrix) != columns (matrix) ... || rows (matrix) < 1 || rows (matrix) > 8) error ("mplapack:neigt:Determinant", ... "permutation determinant is restricted to 1-by-1 through 8-by-8"); endif n = rows (matrix); check_bits = max (64, bits + net_ceil_log2_integer (factorial (n)) + 8); saved_bits = mpbits (); unwind_protect mpbits (check_bits); work = matrix; sign = mp (1); previous_pivot = mp (1); for k = 1:(n - 1) pivot_row = k; while (pivot_row <= n && work(pivot_row, k) == mp (0)) pivot_row += 1; endwhile if (pivot_row > n) value = mp (0); metadata = struct ("method", "fraction_free_bareiss_v1", ... "permutations", factorial (n), ... "check_bits", check_bits, "exact", true, ... "singular", true); return; endif if (pivot_row != k) temporary = work(k, :); work(k, :) = work(pivot_row, :); work(pivot_row, :) = temporary; sign = -sign; endif pivot = work(k, k); for i = (k + 1):n for j = (k + 1):n work(i, j) = (pivot * work(i, j) - work(i, k) * work(k, j)) ... / previous_pivot; endfor endfor previous_pivot = pivot; work((k + 1):n, k) = mp (0); endfor value = sign * work(n, n); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect metadata = struct ("method", "fraction_free_bareiss_v1", ... "permutations", factorial (n), "check_bits", check_bits, ... "exact", true); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_frank_reference.m0000644000230300031750000000275115274353472026033 0ustar rafaelrafael% Independent Hermite--Jacobi reference for Frank eigenvalues. function result = net_frank_reference (n, bits) if (nargin != 2 || n != fix (n) || n < 2) error ("mplapack:neigt:Frank", "invalid Frank reference arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); K = mp (zeros (n, n)); for j = 1:(n - 1) value = sqrt (mp (j)); K(j, j + 1) = value; K(j + 1, j) = value; endfor [unused, diagonal] = eig (K, "nobalance"); z = sort (diag (diagonal)); eigenvalues = mp (zeros (n, 1)); for j = 1:n radical = sqrt (z(j) * z(j) + mp (4)); if (z(j) >= mp (0)) root = ((z(j) + radical) / mp (2))^2; else root = (mp (2) / (radical - z(j)))^2; endif eigenvalues(j) = root; endfor central_index = (n + 1) / 2; central_exact = false; if (mod (n, 2) == 1) eigenvalues(central_index) = mp (1); central_exact = true; endif reciprocal_products = mp (zeros (floor (n / 2), 1)); for j = 1:floor (n / 2) reciprocal_products(j) = eigenvalues(j) * eigenvalues(n - j + 1); endfor result = struct ("reference_status", "hermite_jacobi_independent", ... "reference_bits", bits, "K", K, "z", z, ... "eigenvalues", eigenvalues, "central_exact", central_exact, ... "reciprocal_products", reciprocal_products, ... "source", "A2_HERMITE_JACOBI_REFERENCE"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_markov_reference.m0000644000230300031750000000633215274353472026230 0ustar rafaelrafael% Analytic Markov/Perron spectrum and two independent stationary solves. function result = net_markov_reference (model, bits1, bits2, is_perron) if (nargin != 4 || ! isstruct (model) || ! isfield (model, "P_model") ... || bits1 != fix (bits1) || bits2 != fix (bits2) || bits1 < 64 ... || bits2 < bits1 || ! islogical (is_perron)) error ("mplapack:neigt:Markov", "invalid Markov reference arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits1); epsilon = net_pow2 (-model.epsilon_exponent, bits1); h = model.h; pi_value = acos (mp (-1)); values1 = mp (zeros (model.n, 1)); values1(1) = mp (1); values1(2) = mp (1) - epsilon; next = 3; for block = 1:2 if (block == 1) alpha = mp (1) / mp (4); else alpha = mp (1) / mp (8); endif for k = 1:(h - 1) angle = mp (2) * pi_value * mp (k) / mp (h); root = net_mp_complex (cos (angle), sin (angle)); values1(next) = (mp (1) - epsilon) ... * (mp (1) - alpha + alpha * root); next += 1; endfor endfor if (is_perron) values1 = (mp (3) / mp (2)) * values1; endif mpbits (bits2); epsilon = net_pow2 (-model.epsilon_exponent, bits2); pi_value = acos (mp (-1)); values2 = mp (zeros (model.n, 1)); values2(1) = mp (1); values2(2) = mp (1) - epsilon; next = 3; for block = 1:2 if (block == 1) alpha = mp (1) / mp (4); else alpha = mp (1) / mp (8); endif for k = 1:(h - 1) angle = mp (2) * pi_value * mp (k) / mp (h); root = net_mp_complex (cos (angle), sin (angle)); values2(next) = (mp (1) - epsilon) ... * (mp (1) - alpha + alpha * root); next += 1; endfor endfor if (is_perron) values2 = (mp (3) / mp (2)) * values2; endif mpbits (bits2); P = model.P_model; identity = mp (eye (model.n)); rhs = epsilon * transpose (model.r); stationary_matrix = identity - (mp (1) - epsilon) * model.Q; stationary_column = transpose (stationary_matrix) \ transpose (rhs); normalized_matrix = transpose (P) - identity; normalized_rhs = mp (zeros (model.n, 1)); normalized_matrix(end, :) = mp (ones (1, model.n)); normalized_rhs(end) = mp (1); independent_column = normalized_matrix \ normalized_rhs; stationary_formula = transpose (stationary_column); independent_row = transpose (independent_column); stationary_equation = stationary_formula * P - stationary_formula; independent_equation = independent_row * P - independent_row; stationary_difference = stationary_formula - independent_row; result = struct ("reference_status", "analytic_spectrum_two_stationary_solves", ... "bits1", bits1, "bits2", bits2, "values1", values1, "values2", values2, ... "stationary_formula", stationary_formula, ... "stationary_independent", independent_row, ... "stationary_equation", stationary_equation, ... "independent_equation", independent_equation, ... "stationary_difference", stationary_difference, ... "source", "A6_ANALYTIC_FOURIER_AND_LINEAR_SOLVE_REFERENCE"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_mks_audit.m0000644000230300031750000000330715274353472024672 0ustar rafaelrafael% MKS exact characteristic, zero multiplicity, and reduced-root audit. function result = net_mks_audit (n, m, delta, bits, reference_bits) model = net_mks_model (n, m, delta, bits); reference = net_mks_reference (model, reference_bits, reference_bits + 64); points = [0, 1, 2, 3]; determinant_checks = false (numel (points), 1); polynomial_values = mp (zeros (numel (points), 1)); saved_bits = mpbits (); unwind_protect mpbits (reference_bits + 64); for index = 1:numel (points) x = mp (points(index)); accumulator = mp (0); for j = 1:numel (model.q_coefficients) accumulator = accumulator * x + model.q_coefficients(j); endfor polynomial_values(index) = accumulator; if (n <= 8) [determinant, unused] = net_exact_det_permutation ... (x * mp (eye (n)) - model.A_model, reference_bits); determinant_checks(index) = (determinant == ... x ^ (n - model.ell) * accumulator); endif endfor [V, D, W] = eig (model.A_frozen, "nobalance"); simple_mask = false (model.n, 1); simple_mask((model.n - model.ell + 1):model.n) = true; metrics = net_metrics (model.A_frozen, V, D, W, reference.values2, ... struct ("simple_mask", simple_mask)); result = struct ("status", "MEASURED", "model", model, ... "reference", reference, "determinant_points", points, ... "q_values", polynomial_values, "determinant_checks", determinant_checks, ... "zero_multiplicity", model.zero_algebraic_multiplicity, ... "nonzero_simple_guard", reference.gcd.square_free, "metrics", metrics, ... "source", "A5_MKS_AUDIT"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_cmatrix_point.m0000644000230300031750000000165115274353472026270 0ustar rafaelrafael% Convert an MP matrix to a point rectangle matrix. function result = net_iv_cmatrix_point (value, q) net_iv_q (q); if (nargin != 2 || ! isa (value, "mp") || ndims (value) > 2 ... || ! all (isfinite (real (value))) || ! all (isfinite (imag (value)))) error ("mplapack:neigt:MatrixInterval", "invalid MP matrix"); endif result = struct ("kind", "complex_matrix", ... "rl", mp (zeros (size (value))), "rh", mp (zeros (size (value))), ... "il", mp (zeros (size (value))), "ih", mp (zeros (size (value)))); if (isscalar (value)) box = net_iv_complex_point (value, q); result.rl = box.rl; result.rh = box.rh; result.il = box.il; result.ih = box.ih; return; endif for index = 1:numel (value) box = net_iv_complex_point (value(index), q); result.rl(index) = box.rl; result.rh(index) = box.rh; result.il(index) = box.il; result.ih(index) = box.ih; endfor endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_exact_similarity.m0000644000230300031750000000332615274353472026265 0ustar rafaelrafael% Build and independently verify the common exact integer similarity pair. function result = net_exact_similarity (n, bits) if (nargin != 2 || ! isnumeric (n) || n != fix (n) ... || n < 2 || ! isnumeric (bits) || bits != fix (bits) || bits < 1) error ("mplapack:neigt:Similarity", "invalid similarity arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); N = mp (zeros (n, n)); for index = 1:(n - 1) N(index, index + 1) = mp (1); endfor identity = mp (eye (n)); L = identity + ctranspose (N); U = identity + N; X = L * U; Uinv = net_triangular_inverse (U, bits); Linv = net_triangular_inverse (L, bits); Y = Uinv * Linv; product_guard = max (net_product_guard (L, U, bits), ... net_product_guard (Uinv, Linv, bits)); check_bits = max ([bits, product_guard]); old_check_bits = mpbits (); mpbits (check_bits); identity_check = mp (eye (n)); xy = X * Y; yx = Y * X; xy_error = norm (xy - identity_check, "fro"); yx_error = norm (yx - identity_check, "fro"); exact = (xy_error == mp (0) && yx_error == mp (0)); mpbits (old_check_bits); if (! exact) error ("mplapack:neigt:Exactness", ... "integer similarity inverse products were not exact"); endif result = struct ("n", n, "bits", bits, "N", N, "L", L, "U", U, ... "X", X, "Y", Y, "Uinv", Uinv, "Linv", Linv, ... "product_guard_bits", product_guard, ... "xy_error", xy_error, "yx_error", yx_error, ... "exact", true, "source", "SIM_EXACT_INTEGER"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_dyadic_decode_matrix.m0000644000230300031750000000320015274353472027026 0ustar rafaelrafael% Decode a serialized MP matrix at sufficient destination precision. function result = net_dyadic_decode_matrix (record, destination_bits) if (nargin != 2 || ! isstruct (record) || ! isfield (record, "schema") ... || ! strcmp (record.schema, "neigt-dyadic-v1") ... || ! isnumeric (destination_bits) || ! isscalar (destination_bits) ... || destination_bits != fix (destination_bits) || destination_bits < 1) error ("mplapack:neigt:Deserialize", "invalid matrix record"); endif if (! isfield (record, "shape") || ! isfield (record, "stored_precision") ... || ! isfield (record, "values") || destination_bits < record.stored_precision) error ("mplapack:neigt:Deserialize", "incomplete or insufficient matrix record"); endif shape = record.shape; if (numel (shape) != 2 || any (shape != fix (shape)) || any (shape < 0) ... || numel (record.values) != prod (shape)) error ("mplapack:neigt:Deserialize", "invalid matrix shape/value count"); endif saved_bits = mpbits (); unwind_protect mpbits (destination_bits); decoded = cell (numel (record.values), 1); complex_value = false; for index = 1:numel (record.values) decoded{index} = net_dyadic_decode_scalar (record.values{index}, destination_bits); complex_value = complex_value || ! isreal (decoded{index}); endfor if (complex_value) result = mp (zeros (shape)) + net_mp_complex (mp (0), mp (0)); else result = mp (zeros (shape)); endif for index = 1:numel (decoded) result(index) = decoded{index}; endfor unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_similarity_model.m0000644000230300031750000000520515274353472026257 0ustar rafaelrafael% Construct one fixed exact S2 similarity model and its frozen work input. function result = net_similarity_model (regime, n, gap_exponent, bits) if (nargin < 4) error ("mplapack:neigt:Similarity", "regime, n, gap, and bits are required"); endif if (! ischar (regime) || ! any (strcmp (regime, ... {"simple", "semisimple", ... "jordan", "two_jordan"}))) error ("mplapack:neigt:Similarity", "unsupported S2 regime"); endif if (n < 4 || n != fix (n) || bits != fix (bits) || bits < 64) error ("mplapack:neigt:Similarity", "invalid S2 dimensions or precision"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); pair = net_exact_similarity (n, bits); J = mp (zeros (n, n)); gap = mp (0); if (strcmp (regime, "simple") || strcmp (regime, "two_jordan")) gap = net_pow2 (-gap_exponent, bits); endif if (strcmp (regime, "simple") || strcmp (regime, "jordan") ... || strcmp (regime, "two_jordan")) J(1, 2) = mp (1); endif J(1, 1) = mp (1); if (strcmp (regime, "simple")) J(2, 2) = mp (1); else J(2, 2) = mp (1) + gap; endif start = 3; if (strcmp (regime, "two_jordan")) J(2, 2) = mp (1); J(2, 1) = mp (0); J(2, 3) = mp (0); J(3, 3) = mp (1) + gap; J(3, 4) = mp (1); J(4, 4) = mp (1) + gap; start = 5; endif for index = start:n J(index, index) = mp (index - start + 4); endfor if (strcmp (regime, "semisimple")) J(1, 2) = mp (0); endif A_model = pair.Y * J * pair.X; guard_yj = net_product_guard (pair.Y, J, bits); guard_jx = net_product_guard (pair.Y * J, pair.X, bits); guard = max ([pair.product_guard_bits, guard_yj, guard_jx]); if (bits < guard) error ("mplapack:neigt:Guard", ... "S2 model precision is below its exact product guard"); endif % This is one rounding of the already constructed exact model. native_A = double (A_model); frozen = A_model; result = struct ("family", "similarity", "regime", regime, "n", n, ... "gap_exponent", gap_exponent, "gap", gap, ... "similarity", pair, "J", J, "A_model", A_model, ... "A_frozen", frozen, "native_A", native_A, ... "generation_bits", bits, "model_guard_bits", guard, ... "input_status", "exact_model", ... "source", "SIM_EXACT_INTEGER", ... "model_products_exact", true); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_s2_job.m0000644000230300031750000002235115274353472024415 0ustar rafaelrafael% Run one bounded computed V-S2 candidate schedule and full cluster proof. function result = net_v_s2_job (job, profile_data, profile) if (nargin != 3 || ! isstruct (job) || ! isfield (job, "fixture") ... || ! isfield (job, "cluster_dimension")) error ("mplapack:neigt:VS2", "invalid V-S2 job"); endif candidate_bits = profile_data.work_bits(end); q = profile_data.evaluation_bits; fixture = job.fixture; model = make_fixture (fixture, candidate_bits); center = parse_center (fixture.query_center, candidate_bits); radius = net_dyadic_parameter (fixture.query_radius, candidate_bits); preparation = net_v_s2_candidate (model.A_frozen, center, radius, ... job.cluster_dimension, candidate_bits); if (strcmp (char (fixture.regime), "mks_zero")) [mks_candidate, mks_record] = mks_eigen_complement (... model.A_frozen, center, radius, preparation, job.cluster_dimension, ... candidate_bits); preparation.candidates = {mks_candidate, preparation.candidates{1}}; preparation.candidate_source = "computed_subspace_plus_mks_eigen_complement"; preparation.mks_complement = mks_record; endif attempts = struct ([]); graph = []; cluster = []; selected_strategy = 0; selected_X = []; selected_newton = []; A = net_widen (model.A_frozen, q, candidate_bits); for strategy = 1:min (2, numel (preparation.candidates)) candidate_X = net_widen (preparation.candidates{strategy}, q, candidate_bits); mpbits (q); newton = candidate_newton_for_basis (A, candidate_X, ... job.cluster_dimension, q); corrected_X = candidate_X; if (newton.success) corrected_X = transform_basis (candidate_X, newton.final_Z, ... job.cluster_dimension, q); endif cluster_try = []; try graph_try = net_v_s2_graph (A, corrected_X, ... job.cluster_dimension, q); if (graph_try.pass) cluster_try = net_v_s2_cluster (graph_try, corrected_X, center, ... job, profile, q); endif catch exception graph_try = graph_exception (exception, rows (A), job.cluster_dimension); end_try_catch attempt = struct ("strategy", strategy, ... "candidate_source", preparation.candidate_source, ... "candidate_bits", candidate_bits, "evaluation_bits", q, ... "raw_candidate", candidate_X, "newton", newton, ... "corrected_candidate", corrected_X, "graph", graph_try, ... "cluster", cluster_try, "status", graph_try.status, ... "pass", ! isempty (cluster_try) && cluster_try.pass); if (isempty (attempts)) attempts = attempt; else attempts(end + 1) = attempt; endif if (! isempty (cluster_try) && cluster_try.pass) graph = graph_try; cluster = cluster_try; selected_strategy = strategy; selected_X = corrected_X; selected_newton = newton; break; endif graph = graph_try; cluster = cluster_try; endfor if (selected_strategy == 0) selected_strategy = 1; endif % Assign fields incrementally. This avoids Octave's struct constructor % expansion rules when a nested candidate record contains a struct array. result = struct (); result.id = job.id; result.tier = job.tier; result.kind = job.kind; if (! isempty (cluster) && isfield (cluster, "status") && cluster.pass) result.status = cluster.status; result.claim_status = cluster.claim_status; result.claim_quality = cluster.claim_quality; result.pass = true; else result.status = graph.status; result.claim_status = graph.claim_status; result.claim_quality = graph.claim_quality; if (! isempty (cluster) && isfield (cluster, "status")) result.status = cluster.status; result.claim_status = cluster.claim_status; result.claim_quality = cluster.claim_quality; endif result.pass = false; endif result.milestone_pass = result.pass && graph.nontrivial; result.expected_claim = job.expected; result.candidate_source = preparation.candidate_source; result.candidate_bits = candidate_bits; result.evaluation_bits = q; result.fixture = fixture; result.model_source = model.source; result.model_input_status = model.input_status; result.query_center = center; result.query_radius = radius; result.candidate_preparation = preparation; result.candidate_attempts = attempts; result.selected_strategy = selected_strategy; result.selected_candidate = selected_X; result.selected_newton = selected_newton; result.graph = graph; result.cluster = cluster; result.error_identifier = ""; result.error_message = ""; endfunction function result = graph_exception (exception, n, k) result = struct ("method", "neigt_riccati_graph_v1", ... "paper_algorithm_reproduction", false, "status", "FAILED_VERIFIER", ... "pass", false, "claim_status", "ERROR", "claim_quality", "not_identified", ... "nontrivial", k > 0 && k < n, "full_space_triviality", false, ... "basis_nonsingular", false, "preconditioner_residual_pass", false, ... "contraction_pass", false, "candidate_source", "", ... "candidate_C0_hash", "", "trials", struct ([]), ... "error_identifier", exception.identifier, "error_message", exception.message); endfunction function [candidate, result] = mks_eigen_complement (A, center, radius, ... preparation, k, bits) saved_bits = mpbits (); unwind_protect mpbits (bits); [V, D] = eig (A, "nobalance"); values = diag (D); h = rows (A) - k; selected = false (1, columns (V)); selected_indices = zeros (1, h); for target = 1:h best = 0; best_modulus = mp (0); for index = 1:numel (values) if (! selected(index) && abs (values(index) - center) > radius ... && (best == 0 || abs (values(index) - center) > best_modulus)) best = index; best_modulus = abs (values(index) - center); endif endfor if (best == 0) error ("mplapack:neigt:VS2", ... "MKS computed eig complement did not find enough separated roots"); endif selected(best) = true; selected_indices(target) = best; endfor q1 = preparation.selected_bases{end}; candidate = [q1, V(:, selected_indices)]; result = struct ("method", "computed_mks_nonzero_eigen_complement_v1", ... "candidate_only", true, "candidate_bits", bits, ... "selected_indices", selected_indices, "selected_values", values(selected_indices), ... "source", "public_eig_nobalance_outside_query_region", ... "query_center", center, "query_radius", radius, ... "raw_eigenvalue_hash", net_raw_hash (values, "VS2_MKS_complement_D")); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function result = make_fixture (fixture, bits) regime = char (fixture.regime); n = fixture.n; if (strcmp (regime, "semisimple") || strcmp (regime, "jordan")) result = net_similarity_model (regime, n, 0, bits); elseif (strcmp (regime, "two_jordan")) result = net_similarity_model (regime, n, fixture.gap_exponent, bits); elseif (strcmp (regime, "mks_zero")) delta = net_dyadic_parameter (fixture.delta, bits); result = net_mks_model (n, fixture.m, delta, bits); else error ("mplapack:neigt:VS2", "unsupported V-S2 fixture %s", regime); endif endfunction function value = parse_center (text, bits) if (! ischar (text)) error ("mplapack:neigt:VS2", "center must be a bounded string"); endif if (! isempty (regexp (text, "^[0-9]+$", "once"))) value = integer_mp (text, bits); return; endif token = regexp (text, "^1\\+2\\^(-[0-9]+)$", "tokens", "once"); if (! isempty (token)) exponent = integer_signed (token{1}); value = mp (1) + net_pow2 (exponent, bits); return; endif error ("mplapack:neigt:VS2", "unsupported bounded center %s", text); endfunction function value = integer_mp (text, bits) value = mp (0); for index = 1:numel (text) value = value * mp (10) + mp (text(index) - "0"); endfor endfunction function value = integer_signed (text) if (isempty (regexp (text, "^-[0-9]+$", "once"))) error ("mplapack:neigt:VS2", "invalid signed bounded exponent"); endif value = 0; for index = 2:numel (text) value = value * 10 - (text(index) - "0"); endfor endfunction function result = candidate_newton_for_basis (A, X, k, q) result = struct ("method", "neigt_candidate_graph_newton_v1", ... "candidate_only", true, "success", false, "status", "NOT_RUN", ... "initial_Z", [], "final_Z", [], "steps", struct ([]), "steps_used", 0); try C0 = X \ (A * X); h = rows (A) - k; Z0 = -(C0((k + 1):rows(A), (k + 1):rows(A)) \ ... C0((k + 1):rows(A), 1:k)); result = net_v_s2_newton (C0, k, Z0, q); catch exception result.status = "FAILED_PREPARATION"; result.error_identifier = exception.identifier; result.error_message = exception.message; end_try_catch endfunction function result = transform_basis (X, Z, k, q) n = rows (X); h = n - k; transform = mp (zeros (n, n)); transform(1:k, 1:k) = mp (eye (k)); transform((k + 1):n, 1:k) = Z; transform((k + 1):n, (k + 1):n) = mp (eye (h)); result = X * transform; endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_case_model.m0000644000230300031750000001046215274353472025005 0ustar rafaelrafael% Build one ordinary NEIGT case at the requested mathematical work precision. function result = net_case_model (entry, bits) if (nargin != 2 || ! isstruct (entry) || ! isfield (entry, "id") ... || ! isfield (entry, "parameters") || bits != fix (bits) || bits < 64) error ("mplapack:neigt:Case", "invalid ordinary case entry"); endif id = entry.id; p = entry.parameters; saved_bits = mpbits (); unwind_protect mpbits (bits); if (any (strcmp (id, {"OO53_REAL", "OO53_PAIR", "OO128_CLOSE"}))) generator = net_oo_generator (id, p.n); A_model = generator.A; A_frozen = net_widen (A_model, bits, generator.generation_bits); source = generator.source; input_status = "fixed_generation_then_exact_widening"; elseif (strncmp (id, "SIM_", 4)) gap = 0; if (isfield (p, "gap_exponent")) gap = p.gap_exponent; endif fixture = net_similarity_model (lower (p.regime), p.n, gap, bits); A_model = fixture.A_model; A_frozen = fixture.A_frozen; source = fixture.source; input_status = fixture.input_status; elseif (strcmp (id, "TOEPLITZ") || strcmp (id, "TOEPLITZ_SYM")) fixture = net_toeplitz_model (p.n, p.b, p.representation, bits); A_model = fixture.A; A_frozen = fixture.A; source = fixture.source; input_status = "exact_model"; elseif (strncmp (id, "FORSYTHE", 8)) fixture = net_forsythe_model (p.n, p.a, p.representation, bits); A_model = fixture.A; A_frozen = fixture.A; source = fixture.source; input_status = "exact_model"; elseif (strcmp (id, "HAD_BIDIAG")) fixture = net_hadamard_model (p.n, p.s, bits); A_model = fixture.A; A_frozen = fixture.A; source = fixture.source; input_status = "exact_model"; elseif (strcmp (id, "FRANK0") || strcmp (id, "FRANK1")) orientation = p.orientation; fixture = net_frank_model (p.n, orientation, bits); A_model = fixture.A; A_frozen = fixture.A; source = fixture.source; input_status = "exact_model"; elseif (strcmp (id, "WILKINSON")) fixture = net_wilkinson_model (p.n, bits); A_model = fixture.A_model; A_frozen = fixture.A_frozen; source = fixture.source; input_status = fixture.input_status; elseif (strcmp (id, "GRCAR")) fixture = net_grcar_model (p.n, p.upper_bandwidth, bits); A_model = fixture.A_model; A_frozen = fixture.A_frozen; source = fixture.source; input_status = fixture.input_status; elseif (strcmp (id, "MKS")) delta = net_dyadic_parameter (p.delta, bits); fixture = net_mks_model (p.n, p.m, delta, bits); A_model = fixture.A_model; A_frozen = fixture.A_frozen; source = fixture.source; input_status = fixture.input_status; elseif (strcmp (id, "MARKOV")) fixture = net_markov_model (p.n, p.epsilon_exponent, bits); A_model = fixture.P_model; A_frozen = fixture.P_frozen; source = fixture.source; input_status = fixture.input_status; elseif (strcmp (id, "PERRON_POS")) fixture = net_perron_model (p.n, p.epsilon_exponent, bits); A_model = fixture.A_model; A_frozen = fixture.A_frozen; source = fixture.source; input_status = fixture.input_status; elseif (strcmp (id, "HAD_COMPLEX")) base = net_hadamard_model (p.n, p.s, bits); Z = mp (zeros (p.n, p.n)); for index = 1:p.n phase = mod (index - 1, 4); if (phase == 0) Z(index, index) = net_mp_complex (mp (1), mp (0)); elseif (phase == 1) Z(index, index) = net_mp_complex (mp (0), mp (1)); elseif (phase == 2) Z(index, index) = net_mp_complex (mp (-1), mp (0)); else Z(index, index) = net_mp_complex (mp (0), mp (-1)); endif endfor A_model = Z * base.A * ctranspose (Z); A_frozen = A_model; source = "A1_COMPLEX_QUARTER_TURN_SIMILARITY"; input_status = "exact_model"; else error ("mplapack:neigt:Case", "unsupported ordinary case %s", id); endif result = struct ("id", id, "bits", bits, "A_model", A_model, ... "A_frozen", A_frozen, "native_A", double (A_model), ... "input_status", input_status, "source", source); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_s1_gershgorin.m0000644000230300031750000001344015274353472026010 0ustar rafaelrafael% Conservative counted all-spectrum inclusion from CERTIFICATES.md section 1. function result = net_v_s1_gershgorin (A, X, T, R, q, usefulness_exponent, options) net_iv_q (q); if (nargin < 6 || nargin > 7 || ! isa (A, "mp") || ! isa (X, "mp") ... || ! isa (T, "mp") || ! isa (R, "mp") || rows (A) != columns (A) ... || ! isequal (size (A), size (X)) || ! isequal (size (A), size (T)) ... || ! isequal (size (A), size (R))) error ("mplapack:neigt:VS1", "invalid similarity certificate inputs"); endif if (nargin == 6) options = struct (); endif n = rows (A); A_box = net_iv_cmatrix_point (A, q); if (isfield (options, "A_box")) if (! isstruct (options.A_box) || ! isequal (size (options.A_box.rl), size (A))) error ("mplapack:neigt:VS1", "invalid supplied A enclosure"); endif A_box = options.A_box; endif X_box = net_iv_cmatrix_point (X, q); T_box = net_iv_cmatrix_point (T, q); R_box = net_iv_cmatrix_point (R, q); stage = tic (); E_box = net_iv_cmatrix_sub (net_iv_cmatrix_eye (n, q), ... net_iv_cmatrix_mul (R_box, X_box, q), q); fprintf (2, "NEIGT14: certificate RX %.3fs\n", toc (stage)); stage = tic (); F_box = net_iv_cmatrix_sub (net_iv_cmatrix_mul (A_box, X_box, q), ... net_iv_cmatrix_mul (X_box, T_box, q), q); fprintf (2, "NEIGT14: certificate residual %.3fs\n", toc (stage)); stage = tic (); RF_box = net_iv_cmatrix_mul (R_box, F_box, q); fprintf (2, "NEIGT14: certificate RF %.3fs\n", toc (stage)); stage = tic (); e = net_iv_cmatrix_inf_upper (E_box, q); c = net_iv_cmatrix_inf_upper (RF_box, q); fprintf (2, "NEIGT14: certificate norms %.3fs\n", toc (stage)); denominator = net_iv_primitive ("sub", mp (1), e, q); if (denominator.lo <= mp (0)) result = failed_result ("INCONCLUSIVE_INVERSE_RESIDUAL", n, e, c); return; endif eta = net_iv_primitive ("div", c, denominator.lo, q).hi; stage = tic (); centers = diag (T); radii = mp (zeros (n, 1)); for i = 1:n radius = net_iv_real (eta, eta); for j = 1:n if (j != i) radius_term = net_iv_complex_abs ... (net_iv_complex_point (T(i,j), q), q); radius = net_iv_real_add (radius, ... net_iv_real (radius_term.hi, radius_term.hi), q); endif endfor radii(i) = radius.hi; endfor fprintf (2, "NEIGT14: certificate disks %.3fs\n", toc (stage)); stage = tic (); parent = 1:n; for i = 1:n for j = i+1:n center_difference = net_iv_complex_sub ... (net_iv_complex_point (centers(i), q), ... net_iv_complex_point (centers(j), q), q); separation = net_iv_complex_abs (center_difference, q); radius_sum = net_iv_real_add (net_iv_real (radii(i), radii(i)), ... net_iv_real (radii(j), radii(j)), q); if (! (separation.lo > radius_sum.hi)) parent = union_sets (parent, i, j); endif endfor endfor fprintf (2, "NEIGT14: certificate overlap %.3fs\n", toc (stage)); stage = tic (); roots = cell (n, 1); for i = 1:n root = find_root (parent, i); roots{root}(end + 1) = i; endfor component_count = 0; singleton_count = 0; component_sizes = []; for i = 1:n if (! isempty (roots{i})) component_count += 1; component_sizes(end + 1) = numel (roots{i}); singleton_count += (numel (roots{i}) == 1); endif endfor stage = tic (); norm_upper = net_iv_cmatrix_fro_upper (A_box, q); if (norm_upper < mp (1)) norm_upper = mp (1); endif radius_upper = mp (0); for i = 1:n if (radii(i) > radius_upper) radius_upper = radii(i); endif endfor fprintf (2, "NEIGT14: certificate Frobenius %.3fs\n", toc (stage)); usefulness_target = net_pow2 (usefulness_exponent, q); useful = radius_upper / norm_upper <= usefulness_target; coverage = (component_count > 0 && sum (component_sizes) == n); result = struct ("method", "neigt_similarity_gershgorin_v1", ... "paper_algorithm_reproduction", false, "status", "CERTIFIED_ALL", ... "all_roots", coverage, ... "counted_roots", sum (component_sizes), "n", n, ... "component_count", component_count, "component_sizes", component_sizes, ... "singleton_count", singleton_count, "require_singletons", true, ... "singleton_useful", singleton_count == n, "centers", centers, ... "radii", radii, "max_radius", radius_upper, ... "verified_frobenius_upper", norm_upper, "usefulness_target", usefulness_target, ... "useful", useful, "e", e, "c", c, "eta", eta, ... "inverse_residual_pass", e < mp (1), "coverage", coverage, "parent", parent); if (! result.coverage || ! result.inverse_residual_pass) result.status = "INCONCLUSIVE"; elseif (! result.singleton_useful || ! result.useful) result.status = "CERTIFIED_ALL_NOT_USEFUL"; endif endfunction function result = failed_result (status, n, e, c) result = struct ("method", "neigt_similarity_gershgorin_v1", ... "paper_algorithm_reproduction", false, "status", status, ... "all_roots", false, "counted_roots", 0, "n", n, ... "component_count", 0, "component_sizes", [], "singleton_count", 0, ... "require_singletons", true, "singleton_useful", false, "centers", [], ... "radii", [], "max_radius", mp ("NaN"), ... "verified_frobenius_upper", mp ("NaN"), "usefulness_target", mp ("NaN"), ... "useful", false, "e", e, "c", c, "eta", mp ("NaN"), ... "inverse_residual_pass", false, "coverage", false, "parent", []); endfunction function root = find_root (parent, index) root = index; while (parent(root) != root) root = parent(root); endwhile endfunction function parent = union_sets (parent, left, right) left_root = find_root (parent, left); right_root = find_root (parent, right); if (left_root != right_root) parent(right_root) = left_root; endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_round.m0000644000230300031750000000352015274353472024534 0ustar rafaelrafael% Enclose one MPFR round-to-nearest primitive by the ARITHMETIC.md margin. function result = net_iv_round (rounded, q, zero_witness, operation) if (nargin < 3 || nargin > 4) error ("mplapack:neigt:IntervalPrimitive", "invalid primitive arguments"); endif net_iv_q (q); if (mpbits () != q) error ("mplapack:neigt:IntervalPrecision", ... "primitive must execute at its declared current precision"); endif if (! isa (rounded, "mp") || ! isscalar (rounded) || ! isfinite (rounded)) error ("mplapack:neigt:IntervalRange", ... "primitive result is not finite"); endif if (nargin < 4) operation = "unknown"; endif if (rounded == mp (0)) if (! islogical (zero_witness) || ! isscalar (zero_witness) ... || ! zero_witness) error ("mplapack:neigt:UnexpectedZero", ... "zero primitive result lacks an exact-zero witness for %s", operation); endif result = net_iv_real (mp (0), mp (0)); return; endif persistent cached_q cached_lower_limit cached_upper_limit cached_unit; if (isempty (cached_q) || cached_q != q) cached_q = q; cached_lower_limit = net_pow2 (-8192, q); cached_upper_limit = net_pow2 (8192, q); cached_unit = net_pow2 (-q, q); endif lower_limit = cached_lower_limit; upper_limit = cached_upper_limit; magnitude = abs (rounded); if (magnitude < lower_limit || magnitude > upper_limit) error ("mplapack:neigt:IntervalRange", ... "primitive result is outside the verified range for %s", operation); endif margin = mp (8) * cached_unit * magnitude; lo = rounded - margin; hi = rounded + margin; if (! isfinite (lo) || ! isfinite (hi) || lo > hi) error ("mplapack:neigt:IntervalRange", ... "outward endpoint construction failed for %s", operation); endif result = net_iv_real (lo, hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_grcar_audit.m0000644000230300031750000000126315274353472025175 0ustar rafaelrafael% Grcar exact-input and two-reference audit. function result = net_grcar_audit (n, upper_bandwidth, bits, reference_bits) model = net_grcar_model (n, upper_bandwidth, bits); reference = net_grcar_reference (model, reference_bits, reference_bits + 64); saved_bits = mpbits (); unwind_protect mpbits (reference_bits + 64); [V, D, W] = eig (model.A_frozen, "nobalance"); metrics = net_metrics (model.A_frozen, V, D, W, reference.values2); result = struct ("status", "MEASURED", "model", model, ... "reference", reference, "metrics", metrics, ... "source", "A4_GRCAR_AUDIT"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_dyadic_canonical.m0000644000230300031750000000566615274353472026170 0ustar rafaelrafael% Produce canonical JSON bytes, optionally including the content hash. function result = net_dyadic_canonical (record, include_hash) if (nargin < 1 || nargin > 2 || ! isstruct (record)) error ("mplapack:neigt:Serialize", "invalid dyadic record"); endif if (nargin < 2) include_hash = false; endif required = {"schema", "method_version", "shape", "stored_precision", "values"}; for index = 1:numel (required) if (! isfield (record, required{index})) error ("mplapack:neigt:Serialize", "record lacks %s", required{index}); endif endfor result = "{\"schema\":"; result = strcat (result, json_quote (record.schema), ",\"method_version\":"); result = strcat (result, json_quote (record.method_version), ",\"shape\":["); result = strcat (result, json_shape (record.shape), "],\"stored_precision\":"); result = strcat (result, sprintf ("%d", record.stored_precision), ",\"values\":["); for index = 1:numel (record.values) if (index > 1) result = strcat (result, ","); endif result = strcat (result, json_scalar (record.values{index})); endfor result = strcat (result, "]"); if (include_hash) if (! isfield (record, "sha256") || ! ischar (record.sha256)) error ("mplapack:neigt:Serialize", "record lacks sha256"); endif result = strcat (result, ",\"sha256\":", json_quote (record.sha256)); endif result = strcat (result, "}"); endfunction function result = json_shape (shape) if (! isnumeric (shape) || numel (shape) != 2 || any (shape != fix (shape)) ... || any (shape < 0)) error ("mplapack:neigt:Serialize", "invalid record shape"); endif result = sprintf ("%d,%d", shape(1), shape(2)); endfunction function result = json_scalar (value) if (! isstruct (value) || ! isfield (value, "kind")) error ("mplapack:neigt:Serialize", "invalid serialized scalar"); endif if (strcmp (value.kind, "real")) result = strcat ("{\"kind\":\"real\",", json_real (value), "}"); elseif (strcmp (value.kind, "complex")) result = strcat ("{\"kind\":\"complex\",\"real\":{", ... json_real (value.real), "},\"imag\":{", ... json_real (value.imag), "}}"); else error ("mplapack:neigt:Serialize", "unknown serialized kind"); endif endfunction function result = json_real (value) if (! isfield (value, "sign") || ! isfield (value, "mantissa_hex") ... || ! isfield (value, "exponent2")) error ("mplapack:neigt:Serialize", "invalid real encoding"); endif result = strcat ("\"sign\":", sprintf ("%d", value.sign), ... ",\"mantissa_hex\":", json_quote (value.mantissa_hex), ... ",\"exponent2\":", sprintf ("%d", value.exponent2)); endfunction function result = json_quote (value) if (! ischar (value)) error ("mplapack:neigt:Serialize", "JSON string expected"); endif value = strrep (value, "\\", "\\\\"); value = strrep (value, '"', '\\"'); result = ['"', value, '"']; endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_primitive.m0000644000230300031750000000313715274353472025421 0ustar rafaelrafael% Evaluate one real scalar operation and enclose its rounded result. function result = net_iv_primitive (operation, x, y, q) if (nargin != 4 || ! (ischar (operation) || isstring (operation))) error ("mplapack:neigt:IntervalPrimitive", "invalid primitive operation"); endif net_iv_q (q); if (mpbits () != q) error ("mplapack:neigt:IntervalPrecision", ... "primitive must execute at its declared current precision"); endif operation = char (operation); if (! isa (x, "mp") || ! isscalar (x) || ! isfinite (x)) error ("mplapack:neigt:IntervalPrimitive", "invalid first operand"); endif if (! strcmp (operation, "sqrt") ... && (! isa (y, "mp") || ! isscalar (y) || ! isfinite (y))) error ("mplapack:neigt:IntervalPrimitive", "invalid second operand"); endif switch (operation) case "add" rounded = x + y; witness = (x == -y); case "sub" rounded = x - y; witness = (x == y); case "mul" rounded = x * y; witness = (x == mp (0) || y == mp (0)); case "div" if (y == mp (0)) error ("mplapack:neigt:IntervalDomain", "division by zero"); endif rounded = x / y; witness = (x == mp (0)); case "sqrt" if (x < mp (0)) error ("mplapack:neigt:IntervalDomain", ... "square root has a negative argument"); endif rounded = sqrt (x); witness = (x == mp (0)); otherwise error ("mplapack:neigt:IntervalPrimitive", ... "unknown real primitive %s", operation); endswitch result = net_iv_round (rounded, q, witness, operation); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_complex_div.m0000644000230300031750000000156715274353472025727 0ustar rafaelrafaelfunction result = net_iv_complex_div (a, b, q) ar = net_iv_real (a.rl, a.rh); ai = net_iv_real (a.il, a.ih); br = net_iv_real (b.rl, b.rh); bi = net_iv_real (b.il, b.ih); denominator = net_iv_real_add (net_iv_real_mul (br, br, q), ... net_iv_real_mul (bi, bi, q), q); if (denominator.lo <= mp (0)) error ("mplapack:neigt:IntervalDomain", "complex denominator contains zero"); endif re = net_iv_real_div (net_iv_real_add (net_iv_real_mul (ar, br, q), ... net_iv_real_mul (ai, bi, q), q), ... denominator, q); im = net_iv_real_div (net_iv_real_sub (net_iv_real_mul (ai, br, q), ... net_iv_real_mul (ar, bi, q), q), ... denominator, q); result = net_iv_complex (re.lo, re.hi, im.lo, im.hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_polynomial_gcd.m0000644000230300031750000001221715274353472025712 0ustar rafaelrafael% Exact rational polynomial gcd for dyadic MP coefficients. % Coefficients are scaled to bounded integers before pseudo-division, so a % theoretically zero remainder cannot become a tiny MP residue and loop. function result = net_polynomial_gcd (p, q, bits) if (nargin != 3 || ! isa (p, "mp") || ! isa (q, "mp") ... || rows (p) != 1 || rows (q) != 1 || bits != fix (bits) || bits < 64) error ("mplapack:neigt:Polynomial", "invalid polynomial gcd arguments"); endif saved_bits = mpbits (); unwind_protect mpbits (bits); [p_integer, p_scale] = dyadic_integer_polynomial (p, bits); [q_integer, q_scale] = dyadic_integer_polynomial (q, bits); first = trim_integer (p_integer); second = trim_integer (q_integer); while (!is_zero_integer_poly (second)) remainder = pseudo_remainder (first, second); first = second; second = trim_integer (remainder); endwhile first = primitive_integer (trim_integer (first)); gcd_mp = mp (zeros (1, numel (first))); for index = 1:numel (first) gcd_mp(index) = integer_to_mp (first(index)); endfor % A rational gcd is defined only up to a nonzero scalar. The integer % primitive representative is the replayable exact witness. result = struct ("gcd", gcd_mp, "degree", numel (first) - 1, ... "square_free", numel (first) == 1, ... "method", "dyadic_integer_pseudo_remainder_v1", ... "p_scale_exponent2", p_scale, "q_scale_exponent2", q_scale, ... "exact", true); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function [integer_poly, common_exponent] = dyadic_integer_polynomial (poly, bits) nonzero_exponents = []; for index = 1:numel (poly) if (poly(index) != mp (0)) decomposition = net_dyadic_decompose (poly(index), bits); nonzero_exponents(end + 1) = decomposition.exponent; endif endfor if (isempty (nonzero_exponents)) integer_poly = int64 (zeros (1, numel (poly))); common_exponent = 0; return; endif common_exponent = min (nonzero_exponents); scale = net_pow2 (common_exponent, bits); integer_poly = int64 (zeros (1, numel (poly))); for index = 1:numel (poly) scaled = poly(index) / scale; if (scaled != mp (0)) rounded = floor (abs (scaled)); if (rounded != abs (scaled)) error ("mplapack:neigt:Polynomial", ... "non-dyadic coefficient in exact gcd input"); endif integer_poly(index) = mp_integer (scaled); endif endfor endfunction function value = mp_integer (input) negative = (input < 0); if (isa (input, "mp")) magnitude = floor (abs (input)); else magnitude = abs (input); endif value = int64 (0); two = int64 (2); while (magnitude != 0) if (isa (magnitude, "mp")) half = floor (magnitude / mp (2)); remainder_bit = magnitude - mp (2) * half; bit = int64 (0); if (remainder_bit == mp (1)) bit = int64 (1); elseif (remainder_bit != mp (0)) error ("mplapack:neigt:Polynomial", "non-integer MP coefficient"); endif magnitude = half; else bit = mod (magnitude, two); magnitude = idivide (magnitude, two, "floor"); endif value = value * two + bit; endwhile if (negative) value = -value; endif endfunction function value = integer_to_mp (input) negative = (input < int64 (0)); magnitude = abs (input); value = mp (0); power = mp (1); two = int64 (2); while (magnitude != int64 (0)) if (mod (magnitude, two) != int64 (0)) value = value + power; endif magnitude = idivide (magnitude, two, "floor"); power = power * mp (2); endwhile if (negative) value = -value; endif endfunction function value = trim_integer (value) while (numel (value) > 1 && value(1) == int64 (0)) value = value(2:end); endwhile endfunction function result = is_zero_integer_poly (value) result = (numel (value) == 1 && value == int64 (0)); endfunction function remainder = pseudo_remainder (dividend, divisor) dividend = trim_integer (dividend); divisor = trim_integer (divisor); if (is_zero_integer_poly (divisor)) error ("mplapack:neigt:Polynomial", "division by zero polynomial"); endif remainder = dividend; divisor_degree = numel (divisor) - 1; while (!is_zero_integer_poly (remainder) ... && numel (remainder) - 1 >= divisor_degree) leading = remainder(1); shifted = int64 (zeros (1, numel (remainder))); shifted(1:numel (divisor)) = leading * divisor; remainder = int64 (divisor(1) * remainder - shifted); remainder = trim_integer (remainder); endwhile endfunction function value = primitive_integer (value) value = trim_integer (value); if (is_zero_integer_poly (value)) return; endif common = abs (value(1)); for index = 2:numel (value) common = integer_gcd (common, abs (value(index))); endfor if (common > int64 (1)) value = idivide (value, common, "floor"); endif if (value(1) < int64 (0)) value = -value; endif endfunction function result = integer_gcd (a, b) a = abs (a); b = abs (b); while (b != int64 (0)) remainder = mod (a, b); a = b; b = remainder; endwhile result = a; endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_real_sqrt.m0000644000230300031750000000052215274353472025400 0ustar rafaelrafaelfunction result = net_iv_real_sqrt (a, q) net_iv_q (q); if (a.lo < mp (0)) error ("mplapack:neigt:IntervalDomain", "sqrt interval crosses negative values"); endif lower = net_iv_primitive ("sqrt", a.lo, mp (0), q); upper = net_iv_primitive ("sqrt", a.hi, mp (0), q); result = net_iv_real (lower.lo, upper.hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_v_a3_collatz.m0000644000230300031750000000476015274353472025276 0ustar rafaelrafael% Positive-graph and Collatz--Wielandt root enclosure baseline. function result = net_v_a3_collatz (A, x, q) net_iv_q (q); result = struct ("method", "neigt_collatz_wielandt_v1", ... "paper_algorithm_reproduction", false, "status", "INCONCLUSIVE", ... "pass", false, "irreducible", false, "strictly_positive", false, ... "cw_lower", mp ("NaN"), "cw_upper", mp ("NaN"), ... "width", mp ("NaN"), "trial_vector", x, "reachable", false); if (nargin != 3 || ! isa (A, "mp") || ! isa (x, "mp") ... || rows (A) != columns (A) || columns (x) != 1 ... || rows (x) != rows (A) || ! all (isfinite (A(:))) ... || ! all (isfinite (x(:)))) result.status = "ERROR_INVALID_INPUT"; return; endif n = rows (A); if (any (imag (A(:)) != mp (0))) result.status = "UNSUPPORTED_COMPLEX_DOMAIN"; return; endif if (any (A(:) < mp (0))) result.status = "UNSUPPORTED_NEGATIVE_ENTRY"; return; endif if (any (x(:) <= mp (0))) result.status = "INCONCLUSIVE_NONPOSITIVE_TRIAL"; return; endif adjacency = false (n, n); for i = 1:n for j = 1:n adjacency(i,j) = A(i,j) > mp (0); endfor endfor reachable = adjacency | eye (n); for k = 1:n reachable = reachable | (reachable * reachable > 0); endfor strongly_connected = all (reachable(:)); strictly_positive = all (A(:) > mp (0)); result.reachable = strongly_connected; result.irreducible = strongly_connected; result.strictly_positive = strictly_positive; if (! strongly_connected) result.status = "INCONCLUSIVE_NOT_IRREDUCIBLE"; return; endif A_box = net_iv_cmatrix_point (A, q); x_box = net_iv_cmatrix_point (x, q); ax_box = net_iv_cmatrix_mul (A_box, x_box, q); ratios = mp (zeros (n, 1)); ratio_lower = mp (zeros (n, 1)); ratio_upper = mp (zeros (n, 1)); for i = 1:n numerator = net_iv_real (ax_box.rl(i), ax_box.rh(i)); denominator = net_iv_real (x_box.rl(i), x_box.rh(i)); ratio = net_iv_real_div (numerator, denominator, q); ratio_lower(i) = ratio.lo; ratio_upper(i) = ratio.hi; ratios(i) = (ratio.lo + ratio.hi) * mp ("0.5"); endfor [lower, ~] = net_iv_minmax (ratio_lower); [~, upper] = net_iv_minmax (ratio_upper); result.ratios = ratios; result.ratio_lower = ratio_lower; result.ratio_upper = ratio_upper; result.cw_lower = lower; result.cw_upper = upper; result.width = upper - lower; result.pass = lower <= upper && lower >= mp (0); if (result.pass) result.status = "CERTIFIED_PERRON_ROOT"; endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_real_div.m0000644000230300031750000000117115274353472025172 0ustar rafaelrafaelfunction result = net_iv_real_div (a, b, q) net_iv_q (q); if (b.lo <= mp (0) && b.hi >= mp (0)) error ("mplapack:neigt:IntervalDomain", "real interval denominator contains zero"); endif p11 = net_iv_primitive ("div", a.lo, b.lo, q); p12 = net_iv_primitive ("div", a.lo, b.hi, q); p21 = net_iv_primitive ("div", a.hi, b.lo, q); p22 = net_iv_primitive ("div", a.hi, b.hi, q); lower_values = mp ([p11.lo; p12.lo; p21.lo; p22.lo]); upper_values = mp ([p11.hi; p12.hi; p21.hi; p22.hi]); [lo, ~] = net_iv_minmax (lower_values); [~, hi] = net_iv_minmax (upper_values); result = net_iv_real (lo, hi); endfunction mplapack-interop-0.5.1/examples/neig_tiers/private/net_iv_complex_point.m0000644000230300031750000000055715274353472026274 0ustar rafaelrafaelfunction result = net_iv_complex_point (value, q) net_iv_q (q); if (nargin != 2 || ! isa (value, "mp") || ! isscalar (value) ... || ! isfinite (real (value)) || ! isfinite (imag (value))) error ("mplapack:neigt:Rectangle", "invalid complex point"); endif result = net_iv_complex (real (value), real (value), imag (value), imag (value)); endfunction mplapack-interop-0.5.1/examples/neig_tiers/mp_neig_write_outputs.m0000644000230300031750000001735015274353472025030 0ustar rafaelrafael## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mp_neig_write_outputs (@var{profile}, @var{output_dir}) ## @deftypefnx {} {@var{result} =} mp_neig_write_outputs (@var{profile}, @var{output_dir}, @var{options}) ## Write a new, non-overwriting NEIGT result directory. ## ## The directory contains an ordinary measured-row TSV, execution metadata, ## a Markdown report, and a hash-bound exact MP V-S1 proof record. The proof ## record stores the measured inputs and certificate data separately from the ## result summary and can be checked with @code{mp_neig_replay}. No binary64 ## conversion is used for the proof artifact. @var{options} accepts the ## ordinary @code{tier} and @code{plot} fields; plotting is presentation-only ## and is recorded as not run when false. ## @end deftypefn function result = mp_neig_write_outputs (profile, output_dir, options) if (nargin < 2 || nargin > 3 || ! ischar (output_dir) ... || isempty (output_dir) || rows (output_dir) != 1) error ("mplapack:neigt:Output", "a new output directory is required"); endif if (exist (output_dir, "file") || exist (output_dir, "dir")) error ("mplapack:neigt:OutputExists", ... "refusing to write an existing output path: %s", output_dir); endif if (nargin < 3 || isempty (options)) options = struct ("tier", "all", "plot", false); endif if (! isstruct (options) || ! isscalar (options)) error ("mplapack:neigt:Output", "options must be a scalar struct"); endif if (! isfield (options, "tier")), options.tier = "all"; endif if (! isfield (options, "plot")), options.plot = false; endif if (! ischar (options.tier) || ! islogical (options.plot) ... || ! isscalar (options.plot)) error ("mplapack:neigt:Output", "invalid output options"); endif if (! any (strcmp (options.tier, {"all", "S", "A"}))) error ("mplapack:neigt:Output", "output tier must be all, S, or A"); endif helper_root = fileparts (mfilename ("fullpath")); private_root = fullfile (helper_root, "private"); added = false; if (! any (strcmp (strsplit (path (), pathsep), private_root))) addpath (private_root); added = true; endif [created, message] = mkdir (output_dir); if (! created) error ("mplapack:neigt:Output", "cannot create output directory: %s", message); endif saved_bits = mpbits (); unwind_protect ordinary = mp_neig_tiers (profile, struct ("tier", options.tier)); proof = net_neigt_capture_s1 (profile, "VS1-01"); proof_file = fullfile (output_dir, "proof-vs1-01.json"); proof_hash = net_neigt_json_write (proof, proof_file); rows_file = fullfile (output_dir, "rows.tsv"); write_rows (rows_file, ordinary); environment_file = fullfile (output_dir, "environment.txt"); write_environment (environment_file, ordinary, proof_hash, options); report_file = fullfile (output_dir, "report.md"); write_report (report_file, ordinary, proof, proof_hash, options); manifest_file = fullfile (output_dir, "manifest.tsv"); write_manifest (manifest_file, rows_file, environment_file, report_file, ... proof_file, proof_hash); result = struct ("schema", "neigt-output-v1", "profile", profile, ... "tier", options.tier, "status", "COMPLETE", "ok", ordinary.coverage.ordinary_complete, ... "ordinary", ordinary, "proof", proof, "proof_hash", proof_hash, ... "replay", mp_neig_replay (proof_file), ... "output", struct ("rows", rows_file, "environment", environment_file, ... "report", report_file, "manifest", manifest_file, ... "proof", proof_file)); if (! result.replay.ok) error ("mplapack:neigt:Output", "fresh proof replay did not pass"); endif if (added) rmpath (private_root); endif unwind_protect_cleanup mpbits (saved_bits); if (added && any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect endfunction function write_rows (filename, result) handle = fopen (filename, "w"); if (handle < 0), error ("mplapack:neigt:Output", "cannot open rows TSV"); endif unwind_protect fprintf (handle, "case_id\tmode\twork_role\twork_bits\tstatus\tgate_pass\telapsed_seconds\tinput_hash\tmodel_hash\traw_V_hash\traw_D_hash\traw_W_hash\n"); for index = 1:numel (result.rows) row = result.rows{index}; fprintf (handle, "%s\t%s\t%s\t%d\t%s\t%d\t%.17g\t%s\t%s\t%s\t%s\t%s\n", ... row.case_id, row.mode, row.work_role, row.work_bits, row.status, ... row.gate_pass, row.elapsed_seconds, row.input_hash, row.model_hash, ... row.raw_V_hash, row.raw_D_hash, row.raw_W_hash); endfor unwind_protect_cleanup fclose (handle); end_unwind_protect endfunction function write_environment (filename, ordinary, proof_hash, options) handle = fopen (filename, "w"); if (handle < 0), error ("mplapack:neigt:Output", "cannot open environment"); endif unwind_protect fprintf (handle, "schema=neigt-output-v1\nprofile=%s\ntier=%s\n", ... ordinary.profile, options.tier); fprintf (handle, "ordinary_status=%s\nordinary_rows=%d\n", ... ordinary.status, numel (ordinary.rows)); fprintf (handle, "octave_version=%s\narchitecture=%s\nworking_directory=%s\n", ... version (), computer (), pwd ()); fprintf (handle, "evaluation_default_bits=%d\nproof_sha256=%s\n", ... mpbits (), proof_hash); fprintf (handle, "plot=%s\nplot_status=NOT_RUN\n", ... ternary (options.plot, "true", "false")); unwind_protect_cleanup fclose (handle); end_unwind_protect endfunction function write_report (filename, ordinary, proof, proof_hash, options) handle = fopen (filename, "w"); if (handle < 0), error ("mplapack:neigt:Output", "cannot open output report"); endif unwind_protect fprintf (handle, "# NEIGT output bundle\n\n"); fprintf (handle, "- Schema: `neigt-output-v1`\n- Profile: `%s`\n", ordinary.profile); fprintf (handle, "- Tier: `%s`\n- Status: **%s**\n", options.tier, ordinary.status); fprintf (handle, "- Ordinary measured rows: `%d`\n", numel (ordinary.rows)); fprintf (handle, "- Exact proof: `proof-vs1-01.json`\n"); fprintf (handle, "- Proof SHA256: `%s`\n", proof_hash); fprintf (handle, "- Proof method: `%s`\n", proof.method_version); fprintf (handle, "- Replay command: `mp_neig_replay (""proof-vs1-01.json"")`\n"); fprintf (handle, "- Replay policy: no `eig`, no ideal-model reconstruction, MP-only proof inputs.\n"); fprintf (handle, "- Plot status: **NOT_RUN** (plot=false; display conversion is not numerical evidence).\n\n"); fprintf (handle, "Files:\n\n- `rows.tsv`\n- `manifest.tsv`\n- `environment.txt`\n- `proof-vs1-01.json`\n- `report.md`\n"); unwind_protect_cleanup fclose (handle); end_unwind_protect endfunction function write_manifest (filename, rows_file, environment_file, report_file, proof_file, proof_hash) handle = fopen (filename, "w"); if (handle < 0), error ("mplapack:neigt:Output", "cannot open output manifest"); endif unwind_protect fprintf (handle, "schema\tfile\tsha256\tsize_bytes\n"); entries = {rows_file, environment_file, report_file, proof_file}; labels = {"rows", "environment", "report", "proof"}; for index = 1:numel (entries) data = fileread (entries{index}); digest = hash ("sha256", data); if (strcmp (labels{index}, "proof")), digest = proof_hash; endif info = dir (entries{index}); fprintf (handle, "neigt-output-v1\t%s\t%s\t%d\n", ... labels{index}, digest, info.bytes); endfor unwind_protect_cleanup fclose (handle); end_unwind_protect endfunction function result = ternary (condition, if_true, if_false) if (condition), result = if_true; else, result = if_false; endif endfunction mplapack-interop-0.5.1/examples/neig_tiers/mp_neig_tiers_selftest.m0000644000230300031750000000500315274353472025122 0ustar rafaelrafael% NEIGT01 manifest/options/path-restoration self-test. function report = mp_neig_tiers_selftest () helper_root = fileparts (mfilename ("fullpath")); private_root = fullfile (helper_root, "private"); addpath (private_root); saved_path = path (); have_mpbits = (exist ("mpbits", "file") == 2); if (have_mpbits) saved_bits = mpbits (); endif unwind_protect bundle = net_manifest (); assert (bundle.cases.profiles.smoke.expected_case_count == 20); assert (bundle.cases.profiles.demo.expected_case_count == 21); assert (bundle.cases.profiles.stress.expected_case_count == 8); assert (bundle.cases.profiles.smoke.expected_measured_eig_rows == 120); assert (bundle.cases.profiles.demo.expected_measured_eig_rows == 168); assert (bundle.cases.profiles.stress.expected_measured_eig_rows == 64); assert (numel (bundle.jobs.profiles.smoke.jobs) == 26); assert (numel (bundle.jobs.profiles.demo.jobs) == 26); smoke = mp_neig_tiers ("smoke", struct ("tier", "V")); assert (smoke.scope_ok && ! smoke.ok && strcmp (smoke.status, "NOT_APPLICABLE")); s = mp_neig_tiers ("smoke", struct ("tier", "S")); a = mp_neig_tiers ("smoke", struct ("tier", "A")); vs = mp_neig_verify_examples ("smoke", struct ("tier", "V-S")); va = mp_neig_verify_examples ("smoke", struct ("tier", "V-A")); assert (s.coverage.case_count == 12 && s.coverage.measured_eig_rows == 72); assert (a.coverage.case_count == 8 && a.coverage.measured_eig_rows == 48); assert (numel (vs.jobs) == 16 && numel (va.jobs) == 10); assert (! any (strcmp ({vs.jobs.status}, "PASS"))); caught = false; try mp_neig_tiers ("smoke", struct ("unknown", true)); catch caught = true; end_try_catch assert (caught); caught = false; try mp_neig_tiers ("smoke", struct ("tier", "bad")); catch caught = true; end_try_catch assert (caught); if (have_mpbits) mpbits (256); mp_neig_tiers ("smoke", struct ("tier", "S")); assert (mpbits () == 256); endif report = struct ("ok", true, "manifest", "PASS", "options", "PASS", ... "state_restoration", "PASS", "implemented", true); fprintf ("PASS: NEIGT01 manifest, strict options, filtered coverage, and restoration selftest\n"); unwind_protect_cleanup path (saved_path); if (have_mpbits) mpbits (saved_bits); endif if (any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect endfunction mplapack-interop-0.5.1/examples/17_neig_verified_va.m0000644000230300031750000000100315274353472022025 0ustar rafaelrafael% NEIGT verified application (V-A) entry point. if (exist ("mp_neig_verify_examples", "file") != 2) example_root = fileparts (mfilename ("fullpath")); addpath (fullfile (example_root, "neig_tiers")); endif result = mp_neig_verify_examples ("smoke", struct ("tier", "V-A", ... "plot", false)); assert (result.scope_ok); fprintf ("NEIGT V-A scope parsed: %d verification jobs; status=%s\n", ... result.coverage.verification_job_count, result.status); mplapack-interop-0.5.1/examples/03_linear_solve.m0000644000230300031750000000027115274353472021223 0ustar rafaelrafael% Square and rectangular real multiprecision solves. A = mp ([2, 1; 1, 3]); b = mp ([1; 2]); x = A \ b; disp (x); T = mp ([1, 0; 0, 1; 1, 1]); r = mp ([0; 1; 4]); y = T \ r; disp (y); mplapack-interop-0.5.1/examples/06_grcar_eig.m0000644000230300031750000000140115274353472020462 0ustar rafaelrafael% High-precision eigenvalue residual for the standard Grcar matrix. % % gallery("grcar", 32) is intentionally used as the documented Octave matrix % fixture. The resulting binary64 entries are transferred once into native % MPFR storage; all eig and residual arithmetic after that is multiprecision. if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif previous_bits = mpbits (); unwind_protect mpbits (1024); G = mp (gallery ("grcar", 32)); [V, D] = eig (G, "nobalance"); residual = norm (G * V - V * D, "fro"); fprintf ("Grcar(32) eig residual at %d bits: %s\n", mpbits (), char (residual)); disp ("The residual is computed by native MPFR/MPC operations."); unwind_protect_cleanup mpbits (previous_bits); end_unwind_protect mplapack-interop-0.5.1/examples/09_serialization_rng.m0000644000230300031750000000172315274353472022275 0ustar rafaelrafael% Exact persistence and deterministic arbitrary-precision random values. if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif saved_bits = mpbits (); saved_state = mprng ("state"); path = "/tmp/mplapack-interop-example.mat"; unwind_protect mpbits (512); mprng ("seed", uint64 (7)); A = mp ({"1.234567890123456789", "-0"; "Inf", "NaN"}); first = mprand (2, 1); checkpoint = mprng ("state"); save ("-binary", path, "A"); clear A; load (path, "A"); assert (strcmp (class (A), "mp")); assert (char (A(1, 1)) == char (mp ("1.234567890123456789"))); mprng ("state", checkpoint); repeat = mprand (2, 1); assert (isequal (first, repeat) == false); mprng ("seed", uint64 (7)); assert (isequal (first, mprand (2, 1))); fprintf ("serialization/RNG PASS: exact state and value round trip\n"); unwind_protect_cleanup mprng ("state", saved_state); mpbits (saved_bits); if (exist (path, "file")), unlink (path); endif end_unwind_protect mplapack-interop-0.5.1/examples/04_factorizations.m0000644000230300031750000000042215274353472021577 0ustar rafaelrafael% Dense real Cholesky, QR, pivoted QR, and LU. A = mp ([4, 2; 2, 10]); Rchol = chol (A); disp (Rchol); [Q, Rqr] = qr (A); disp (Q * Rqr); Ap = mp ([1, 0, 0; 0, 4, 0; 0, 0, 2]); [Qp, Rp, P] = qr (Ap); disp (Qp * Rp - Ap * P); [L, U, PLU] = lu (A); disp (PLU * A - L * U); mplapack-interop-0.5.1/examples/svd_tiers/0000755000230300031750000000000015274353472020063 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/svd_tiers/mp_svd_tiers_selftest.m0000644000230300031750000000644015274353472024654 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = mp_svd_tiers_selftest () ## Focused SVT01 contract tests. This helper intentionally does not run ## numerical suite rows; those are enabled only after their milestone. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_path (suite_dir, added)); svt_expect_error (@() mp_svd_tiers ("unknown"), ... "mplapack:svt:InvalidProfile"); svt_expect_error (@() mp_svd_tiers ("smoke", struct ("bad", true)), ... "mplapack:svt:InvalidOptions"); svt_expect_error (@() mp_svd_tiers ("smoke", struct ("tier", "bad")), ... "mplapack:svt:InvalidTier"); svt_expect_error (@() mp_svd_tiers ("smoke", struct ("plot", 1)), ... "mplapack:svt:InvalidPlotOption"); saved_bits = mpbits (); precision_cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (128); source = mp ("0.1"); widened = svt_widen (source, 256); source_info = __mplapack_core__ ("value_shape_info", source); widened_info = __mplapack_core__ ("value_shape_info", widened); assert (source_info.precision_bits == 128); assert (widened_info.precision_bits == 256); assert (source == widened); assert (mpbits () == 128); clear precision_cleanup; assert (mpbits () == saved_bits); svt_expect_error (@() svt_widen (source, 64), ... "mplapack:svt:InsufficientWidening"); assert (mpbits () == saved_bits); ## The facade now executes a selected profile immediately. Keep this ## contract selftest structural so the ordinary test runner does not launch ## the multi-minute smoke/demo measurement wall. manifest = svt_load_manifest (); smoke_profile = svt_manifest_profile (manifest, "smoke"); demo_profile = svt_manifest_profile (manifest, "demo"); assert (numel (smoke_profile.cases) == 20); assert (smoke_profile.expected_svd_rows == 120); assert (numel (demo_profile.cases) == 23); assert (demo_profile.expected_svd_rows == 184); assert (numel (smoke_profile.cases(strcmp ({smoke_profile.cases.tier}, "S"))) == 7); assert (numel (demo_profile.cases(strcmp ({demo_profile.cases.tier}, "S"))) == 9); output_dir = tempname (); mkdir (output_dir); svt_expect_error (@() mp_svd_tiers ("smoke", ... struct ("output_dir", output_dir)), ... "mplapack:svt:OutputDirectoryExists"); rmdir (output_dir, "s"); report = struct ("ok", true, "manifest", "smoke=20/120,demo=23/184", ... "precision_cleanup", true, "output_safety", true, ... "status", "PASS"); clear cleanup_path; endfunction function svt_expect_error (thunk, expected_id) caught = false; try thunk (); catch exception caught = true; ## Octave releases represent caught identifiers differently in a few ## execution modes; the focused contract is rejection, while callers may ## inspect the identifier in the ordinary error struct. end_try_catch assert (caught, ["expected error was not raised: ", expected_id]); endfunction function svt_restore_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/mp_svd_tiers.m0000644000230300031750000001264015274353472022742 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function results = mp_svd_tiers (profile, options) ## -*- texinfo -*- ## @deftypefn {} {@var{results} =} mp_svd_tiers (@var{profile}) ## @deftypefnx {} {@var{results} =} mp_svd_tiers (@var{profile}, @var{options}) ## Run the Tier S/A/V SVD example suite for a named profile. ## ## This facade owns option validation, manifest accounting, precision cleanup, ## and result-directory safety. Numerical constructors and verifiers are ## private example helpers; the public package API is not changed by this ## example suite. `options.case_id` optionally selects one manifest case for ## a short worked example; the unfiltered profile remains the QA wall. ## @end deftypefn if (nargin < 1 || nargin > 2) error ("mplapack:svt:InvalidArguments", ... "mp_svd_tiers expects a profile and optional options struct"); endif if ((! ischar (profile) && ! isstring (profile)) ... || (ischar (profile) && rows (profile) != 1) ... || (isstring (profile) && numel (profile) != 1)) error ("mplapack:svt:InvalidProfile", ... "profile must be \"smoke\", \"demo\", or \"stress\""); endif profile = char (profile); if (! any (strcmp (profile, {"smoke", "demo", "stress"}))) error ("mplapack:svt:InvalidProfile", ... "unknown SVD tier profile: %s", profile); endif if (nargin == 1) options = struct (); endif if (! isstruct (options) || numel (options) != 1) error ("mplapack:svt:InvalidOptions", ... "options must be a scalar struct"); endif fields = fieldnames (options); allowed = {"tier", "output_dir", "plot", "case_id"}; for index = 1:numel (fields) if (! any (strcmp (fields{index}, allowed))) error ("mplapack:svt:InvalidOptions", ... "unknown mp_svd_tiers option: %s", fields{index}); endif endfor tier = "all"; if (isfield (options, "tier")) tier = options.tier; if ((! ischar (tier) && ! isstring (tier)) ... || (ischar (tier) && rows (tier) != 1) ... || (isstring (tier) && numel (tier) != 1)) error ("mplapack:svt:InvalidTier", ... "tier must be \"all\", \"S\", \"A\", or \"V\""); endif tier = char (tier); endif if (! any (strcmp (tier, {"all", "S", "A", "V"}))) error ("mplapack:svt:InvalidTier", ... "tier must be \"all\", \"S\", \"A\", or \"V\""); endif output_dir = ""; if (isfield (options, "output_dir")) output_dir = options.output_dir; if ((! ischar (output_dir) && ! isstring (output_dir)) ... || (ischar (output_dir) && rows (output_dir) != 1) ... || (isstring (output_dir) && numel (output_dir) != 1)) error ("mplapack:svt:InvalidOutputDirectory", ... "output_dir must be a character vector or string scalar"); endif output_dir = char (output_dir); if (! isempty (output_dir) && (exist (output_dir, "file") || exist (output_dir, "dir"))) error ("mplapack:svt:OutputDirectoryExists", ... "refusing to overwrite existing output directory: %s", output_dir); endif if (! isempty (output_dir) && ! mkdir (output_dir)) error ("mplapack:svt:OutputDirectoryCreate", ... "could not create output directory: %s", output_dir); endif endif plot_enabled = false; if (isfield (options, "plot")) plot_enabled = options.plot; if (! islogical (plot_enabled) || ! isscalar (plot_enabled)) error ("mplapack:svt:InvalidPlotOption", "plot must be a logical scalar"); endif endif case_id = ""; if (isfield (options, "case_id")) if ((! ischar (options.case_id) && ! isstring (options.case_id)) ... || (ischar (options.case_id) && rows (options.case_id) != 1) ... || (isstring (options.case_id) && numel (options.case_id) != 1)) error ("mplapack:svt:InvalidCase", ... "case_id must be a character vector or string scalar"); endif case_id = char (options.case_id); endif manifest = svt_load_manifest (); profile_data = svt_manifest_profile (manifest, profile); manifest_case_count = numel (profile_data.cases); if (strcmp (tier, "all")) selected_cases = profile_data.cases; else selected_cases = profile_data.cases(strcmp ({profile_data.cases.tier}, tier)); endif if (! isempty (case_id)) selected_cases = selected_cases(strcmp ({selected_cases.id}, case_id)); if (isempty (selected_cases)) error ("mplapack:svt:UnknownCase", ... "case_id %s is not in the selected profile/tier", case_id); endif profile_data.cases = selected_cases; endif saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); results = svt_run_profile (profile_data, profile, tier, plot_enabled); results.output_dir = output_dir; results.manifest_schema = manifest.schema; results.case_count = numel (selected_cases); results.manifest_case_count = manifest_case_count; results.cases = selected_cases; results.v_jobs = struct ("count", results.v_job_count, ... "status", ternary_status (results.v_job_count > 0)); results.environment.mpbits_at_entry = saved_bits; if (! isempty (output_dir)) results.artifacts = svt_write_profile_artifacts (results, profile_data, output_dir); else results.artifacts = {}; endif clear cleanup_precision; endfunction function value = ternary_status (condition) if (condition), value = "EXECUTED"; else, value = "NOT_RUN"; endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_v1_values_selftest.m0000644000230300031750000000461615274353472024762 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_v1_values_selftest () ## SVT13 all-singular-value enclosure gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_v1_values_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); diagonal = mp (diag ([3, 1])); [u, s, v] = svd (diagonal, "econ"); exact = svt_certify_values (diagonal, u, s, v, 256); assert (strcmp (exact.status, "CERTIFIED")); assert (all (exact.values_lower <= svd (diagonal))); assert (all (exact.values_upper >= svd (diagonal))); assert (exact.epsilon.hi < mp ('1e-60')); tall = mp ([3, 0; 0, 1; 0, 0]); [ut, st, vt] = svd (tall, "econ"); tall_certificate = svt_certify_values (tall, ut, st, vt, 256); assert (strcmp (tall_certificate.status, "CERTIFIED")); assert (tall_certificate.input_shape(1) == 3); complex_input = mp ({'(1,2)', '(0,0)'; '(0,0)', '(2,-1)'}); [uc, sc, vc] = svd (complex_input, "econ"); complex_certificate = svt_certify_values (complex_input, uc, sc, vc, 256); assert (strcmp (complex_certificate.status, "CERTIFIED")); assert (! isreal (uc) && isreal (sc) && ! isreal (vc)); zero_input = mp (zeros (2, 3)); [uz, sz, vz] = svd (zero_input, "econ"); zero_certificate = svt_certify_values (zero_input, uz, sz, vz, 256); assert (strcmp (zero_certificate.status, "CERTIFIED")); assert (all (zero_certificate.values_lower == mp (0))); assert (all (zero_certificate.values_upper >= mp (0))); bad_gram = mp (ones (2, 2)); bad_certificate = svt_certify_values (diagonal, bad_gram, s, v, 256); assert (strcmp (bad_certificate.status, "INCONCLUSIVE")); malformed = false; try svt_certify_values (diagonal, u, mp ([-1, 0; 0, 1]), v, 256); catch malformed = true; end_try_catch assert (malformed); assert (mpbits () == 256); report = struct ("ok", true, "exact_diagonal", true, "tall", true, ... "complex", true, "zero", true, "bad_gram_inconclusive", true, ... "malformed_rejected", true, "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_v1_values_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_jacobi_stirling_selftest.m0000644000230300031750000000523615274353472026216 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_jacobi_stirling_selftest () ## SVT05 constructor and measured-row gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_js_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); leading = svt_make_jacobi_stirling ("S2-JS-5", struct ("n", 5, "z", 1), 256); expected = mp ([1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 2, 1, 0, 0; ... 0, 4, 8, 1, 0; 0, 8, 52, 20, 1]); assert (all (all (leading.A == expected))); assert (all (all (tril (leading.A) == leading.A))); assert (all (all (diag (leading.A) == mp (ones (5, 1))))); assert (leading.det_model == mp (1) && leading.full_rank); one = svt_make_jacobi_stirling ("S2-JS-1", struct ("n", 1, "z", 1), 128); assert (one.A == mp (1) && one.construction_guard_bits == 3); rejected = false; try svt_make_jacobi_stirling ("bad", struct ("n", 5, "z", 2), 256); catch rejected = true; end_try_catch assert (rejected); manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "jacobi_stirling")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_jacobi_stirling (entry.id, entry.parameters, ... profile.work_bits(bits_index)); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (mp_row.metrics.status, "PASS")); endif measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 8 + 12); assert (mpbits () == 256); report = struct ("ok", true, "known_fixture", true, "n1", true, ... "guard", true, "measured_rows", measured_rows, "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_js_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_dd_selftest.m0000644000230300031750000000672715274353472023451 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_dd_selftest () ## SVT07 constructor, analytic symmetric reference, and measured-row gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_dd_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); symmetric = svt_make_dd_path ("S4-DD-SYM", ... struct ("n", 8, "b", 32, "rho_num", 1, ... "rho_den", 1, "allow_below_guard", true), 256); assert (symmetric.symmetric && symmetric.tau == svt_pow2 (-32)); assert (symmetric.analytic_values(1) == symmetric.tau); assert (all (all (symmetric.model == symmetric.model'))); assert (all (all (symmetric.tau0_leading_principal_determinants == mp (1)))); assert (symmetric.tau0_full_determinant == mp (0)); nonsymmetric = svt_make_dd_path ("S4-DD-NONSYM", ... struct ("n", 8, "b", 32, "rho_num", 1, ... "rho_den", 2, "allow_below_guard", true), 256); assert (! nonsymmetric.symmetric && isempty (nonsymmetric.analytic_values)); assert (nonsymmetric.tau0_full_determinant == mp (0)); rounded = svt_make_dd_path ("S4-DD-ROUNDED", ... struct ("n", 24, "b", 160, "rho_num", 1, ... "rho_den", 2, "allow_below_guard", true), 128); assert (rounded.below_guard && rounded.represented_tau_lost); assert (rounded.rank == 24 && rounded.tau0_full_determinant == mp (0)); rejected = false; try svt_make_dd_path ("bad", struct ("n", 8, "b", 160, "rho_num", 1, ... "rho_den", 1), 128); catch rejected = true; end_try_catch assert (rejected); manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "dd_path")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_dd_path (entry.id, entry.parameters, ... profile.work_bits(bits_index)); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (mp_row.metrics.status, "PASS")); endif measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 16 + 24); assert (mpbits () == 256); report = struct ("ok", true, "symmetric_formula", true, ... "nonsymmetric_not_tau_claim", true, "rounded_tau_control", true, ... "rank_proof", true, "measured_rows", measured_rows, "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_dd_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_v3_inverse_selftest.m0000644000230300031750000000452615274353472025140 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_v3_inverse_selftest () ## SVT16 inverse residual/norm gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_v3_inverse_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); diagonal = mp (diag ([3, 1])); inverse = diagonal \ mp (eye (2)); good = svt_certify_inverse (diagonal, inverse, 256); assert (strcmp (good.status, "CERTIFIED")); assert (good.residual.hi < mp ('1e-50')); assert (good.sigma_min_lower > mp (0)); assert (good.inverse_norm_upper_status == "FINITE"); fixture = svt_make_nro_companion ("A6-INVERSE", struct ("n", 8, "nu", 16), 256); inverse_fixture = fixture.A \ mp (eye (8)); fixture_certificate = svt_certify_inverse (fixture.A, inverse_fixture, 256); assert (strcmp (fixture_certificate.status, "CERTIFIED")); assert (fixture_certificate.sigma_min_lower > mp (0)); published = svt_make_nro_companion ("A6-PUBLISHED", struct ("n", 8, "nu", 16), 256); published_certificate = svt_certify_inverse (published.published_C, ... published.published_X, 256); assert (strcmp (published_certificate.status, "CERTIFIED")); poor = svt_certify_inverse (diagonal, mp (zeros (2, 2)), 256); assert (strcmp (poor.status, "INCONCLUSIVE")); singular = mp (diag ([1, 0])); singular_control = svt_certify_inverse (singular, mp (eye (2)), 256); assert (strcmp (singular_control.status, "INCONCLUSIVE")); rectangular = svt_certify_inverse (mp ([1, 0; 0, 1; 0, 0]), ... mp ([1, 0; 0, 1]), 256); assert (strcmp (rectangular.status, "UNSUPPORTED_RECTANGULAR")); assert (mpbits () == 256); report = struct ("ok", true, "good_inverse", true, "nro_inverse", true, ... "published_inverse", true, "poor_inconclusive", true, ... "singular_inconclusive", true, "rectangular_unsupported", true, ... "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_v3_inverse_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_hadamard_spectrum_selftest.m0000644000230300031750000001112415274353472026530 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_hadamard_spectrum_selftest () ## SVT10 A5 constructor and measured-row gate. Lauchli rows are executed ## here as well because A4/A5 share this milestone in MILESTONES.md. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_hadamard_spectrum_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); small = svt_make_hadamard_spectrum ("A5-SMALL", ... struct ("n", 8, "mode", "close", "b", 32), 256); assert (small.values(1) == mp (4)); assert (small.values(3) == mp (1) + svt_pow2 (-32)); assert (small.model_rank == 8 && small.full_rank); assert (all (all (small.left_projector * small.left_projector ... - small.left_projector == mp (0)))); repeat = svt_make_hadamard_spectrum ("A5-REPEAT-SMALL", ... struct ("n", 8, "mode", "repeat"), 256); assert (repeat.values(3) == repeat.values(4)); rank4 = svt_make_hadamard_spectrum ("A5-RANK4-SMALL", ... struct ("n", 8, "mode", "rank4"), 256); rank5 = svt_make_hadamard_spectrum ("A5-RANK5-SMALL", ... struct ("n", 8, "mode", "rank5", "b", 32), 256); assert (rank4.model_rank == 4 && rank5.model_rank == 5); assert (numel (rank4.null_indices) == 4 && numel (rank5.null_indices) == 3); ## The mixed and raw diagonal forms are orthogonally equivalent. This is a ## high-precision cross-check; it is not yet a Tier V certificate. geometric = svt_make_hadamard_spectrum ("A5-GEO-SMALL", ... struct ("n", 8, "mode", "geometric", "a", 4), 256); mpbits (512); mixed_values = svd (svt_widen (geometric.A, 512)); raw_values = svd (svt_widen (geometric.model, 512)); assert (norm (mixed_values - raw_values, "fro") < mp ('1e-100')); manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "hadamard_spectrum")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_hadamard_spectrum (entry.id, entry.parameters, ... profile.work_bits(bits_index)); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (mp_row.metrics.status, "PASS")); endif measured_rows = measured_rows + 2; endfor endfor endfor endfor ## Lauchli is the A4 half of SVT10. for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "lauchli")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_lauchli (entry.id, entry.parameters, ... profile.work_bits(bits_index)); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 100 + 16 + 36); assert (mpbits () == 512); report = struct ("ok", true, "hadamard_cases", 5, "lauchli_cases", 5, ... "rank_metadata", true, "projectors", true, ... "mixed_raw_crosscheck", true, "measured_rows", measured_rows, ... "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_hadamard_spectrum_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_bidiagonal_selftest.m0000644000230300031750000000562215274353472025144 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_bidiagonal_selftest () ## SVT10 bidiagonal constructor and measured-row gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_bidiagonal_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); small_raw = svt_make_bidiagonal ("A3-BDI-RAW-SMALL", ... struct ("n", 4, "a", 2, "representation", "raw"), 256); small_mixed = svt_make_bidiagonal ("A3-BDI-MIXED-SMALL", ... struct ("n", 4, "a", 2, "representation", "mixed"), 256); assert (small_raw.raw(1, 1) == mp (1)); assert (small_raw.raw(1, 2) == svt_pow2 (-1)); assert (small_raw.raw(4, 4) == svt_pow2 (-6)); assert (all (all (small_raw.raw == small_mixed.raw))); assert (small_raw.full_rank && small_mixed.full_rank); ## The two-sided Hadamard factors preserve singular values. This is a ## numerical cross-check at high precision, not a Tier V certificate. mpbits (512); raw_values = svd (svt_widen (small_raw.raw, 512)); mixed_values = svd (svt_widen (small_raw.mixed, 512)); assert (norm (raw_values - mixed_values, "fro") < mp ('1e-100')); manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "bidiagonal")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_bidiagonal (entry.id, entry.parameters, ... profile.work_bits(bits_index)); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (mp_row.metrics.status, "PASS")); endif measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 16 + 24); assert (mpbits () == 512); report = struct ("ok", true, "raw_construction", true, "mixed_construction", true, ... "spectrum_crosscheck", true, "measured_rows", measured_rows, ... "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_bidiagonal_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_vandermonde_selftest.m0000644000230300031750000000476515274353472025364 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_vandermonde_selftest () ## SVT09 dyadic Vandermonde and measured-row gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_vandermonde_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); small = svt_make_vandermonde ("A2-VAND-SMALL", ... struct ("n", 3, "node_den_bits", 3), 128); assert (small.nodes(1) == mp (1) / mp (8)); assert (small.nodes(1) < small.nodes(2) && small.nodes(2) < small.nodes(3)); assert (small.A(1, 2) == small.nodes(1)); assert (small.A(1, 3) == small.nodes(1) * small.nodes(1)); assert (small.full_rank && small.determinant_positive); manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "vandermonde")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_vandermonde (entry.id, entry.parameters, ... profile.work_bits(bits_index)); assert (fixture.full_rank && fixture.determinant_sign_proof); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (mp_row.metrics.status, "PASS")); endif measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 8 + 12); assert (mpbits () == 256); report = struct ("ok", true, "dyadic_nodes", true, "successive_powers", true, ... "positive_determinant_proof", true, "measured_rows", measured_rows, ... "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_vandermonde_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_lah_selftest.m0000644000230300031750000000441015274353472023611 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_lah_selftest () ## SVT06 constructor and measured-row gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_lah_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); leading = svt_make_lah ("S3-LAH-4", struct ("n", 4), 256); expected = mp ([1, 0, 0, 0; 2, 1, 0, 0; 6, 6, 1, 0; 24, 36, 12, 1]); assert (all (all (leading.A == expected))); assert (all (all (tril (leading.A) == leading.A))); assert (all (all (diag (leading.A) == mp (ones (4, 1))))); assert (leading.det_model == mp (1) && leading.full_rank); manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "lah")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_lah (entry.id, entry.parameters, ... profile.work_bits(bits_index)); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (mp_row.metrics.status, "PASS")); endif measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 8 + 12); assert (mpbits () == 256); report = struct ("ok", true, "known_fixture", true, "unit_lower", true, ... "guard", true, "measured_rows", measured_rows, "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_lah_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/0000755000230300031750000000000015274353472021535 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/svd_tiers/private/svt_case_identity.m0000644000230300031750000000212315274353472025431 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function identity = svt_case_identity (case_id, family, model, represented, ... construction_bits, exactness, notes) if (! isa (model, "mp") || ! isa (represented, "mp")) error ("mplapack:svt:InvalidIdentity", "identity inputs must be mp values"); endif model_info = __mplapack_core__ ("value_shape_info", model); represented_info = __mplapack_core__ ("value_shape_info", represented); identity = struct (); identity.schema = "svt-input-v1"; identity.case_id = case_id; identity.family = family; identity.model_shape = [model_info.rows, model_info.columns]; identity.represented_shape = [represented_info.rows, represented_info.columns]; identity.model_precision_bits = model_info.precision_bits; identity.represented_precision_bits = represented_info.precision_bits; identity.construction_precision_bits = construction_bits; identity.exactness = exactness; identity.notes = notes; identity.model_is_real = isreal (model); identity.represented_is_real = isreal (represented); endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_lah.m0000644000230300031750000000363415274353472024356 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_lah (case_id, parameters, work_bits) ## Construct the unsigned Lah matrix with its integer recurrence. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters) ... || ! isfield (parameters, "n")) error ("mplapack:svt:InvalidLahRequest", "invalid Lah request"); endif n = parameters.n; if (! isnumeric (n) || ! isscalar (n) || ! isfinite (n) ... || n != fix (n) || n < 1 || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidLahParameters", ... "Lah n must be a positive integer and precision integral"); endif required_bits = 3; for i = 2:n required_bits = required_bits + svt_ceil_log2_integer (2 * i); endfor svt_require_guard (required_bits, work_bits, "Lah exact recurrence"); saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); matrix = mp (zeros (n, n)); matrix(1, 1) = mp (1); for i = 2:n for j = 1:i term_shift = mp (0); if (j >= 2) term_shift = matrix(i - 1, j - 1); endif term_recur = mp (0); if (j <= i - 1) term_recur = mp (i + j - 1) * matrix(i - 1, j); endif matrix(i, j) = term_shift + term_recur; endfor endfor identity = svt_case_identity (case_id, "lah", matrix, matrix, work_bits, ... "exact_integer_recurrence", ... "unsigned Lah recurrence; unit lower triangular"); result = struct ("id", case_id, "tier", "S", "family", "lah", ... "parameters", parameters, "n", n, "model", matrix, ... "A", matrix, "analytic_values", [], "rank", n, ... "full_rank", true, "det_model", mp (1), ... "construction_guard_bits", required_bits, "identity", identity, ... "status", "CONSTRUCTED"); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_nro.m0000644000230300031750000001242715274353472024410 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_nro (case_id, parameters, work_bits) ## Construct the Section-5 NRO block fixture used by the SVT S1 tier. ## The returned inverse is an invariant/check object; measured solves still ## go through the public SVD/solve paths. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters)) error ("mplapack:svt:InvalidNroRequest", ... "svt_make_nro expects an ID, parameter struct, and work precision"); endif required = {"m", "mode"}; for index = 1:numel (required) if (! isfield (parameters, required{index})) error ("mplapack:svt:InvalidNroParameters", ... "NRO parameters lack field %s", required{index}); endif endfor m = parameters.m; mode = char (parameters.mode); if (! isnumeric (m) || ! isscalar (m) || ! isreal (m) ... || ! isfinite (m) || m != fix (m) || m < 4 ... || 2 ^ svt_ceil_log2_integer (m) != m ... || svt_ceil_log2_integer (m) != 2 * fix (svt_ceil_log2_integer (m) / 2)) error ("mplapack:svt:InvalidNroParameters", ... "NRO m must be a power of four of at least four"); endif if (! any (strcmp (mode, {"two", "three", "graded"}))) error ("mplapack:svt:InvalidNroParameters", "unknown NRO mode"); endif if (! isnumeric (work_bits) || ! isscalar (work_bits) ... || ! isfinite (work_bits) || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidNroPrecision", "work precision must be integral"); endif if (strcmp (mode, "graded")) if (! isfield (parameters, "g") || parameters.g != fix (parameters.g) ... || parameters.g < 1) error ("mplapack:svt:InvalidNroParameters", ... "graded NRO mode requires a positive integer g"); endif max_exponent = parameters.g * (m - 1); else if (! isfield (parameters, "b") || parameters.b != fix (parameters.b) ... || parameters.b < 0) error ("mplapack:svt:InvalidNroParameters", ... "two/three-level NRO mode requires a nonnegative integer b"); endif max_exponent = parameters.b; endif scale_bits = 0; if (isfield (parameters, "scale_bits")) scale_bits = parameters.scale_bits; if (! isnumeric (scale_bits) || ! isscalar (scale_bits) ... || ! isfinite (scale_bits) || scale_bits != fix (scale_bits)) error ("mplapack:svt:InvalidNroParameters", ... "scale_bits must be an integer"); endif endif required_bits = 8 + svt_ceil_log2_integer (m); svt_require_guard (required_bits, work_bits, "NRO exact block construction"); saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); [h, unused_g] = svt_hadamard (m); weights = mp (zeros (m, 1)); if (strcmp (mode, "two")) for index = 1:m weights(index) = svt_pow2 (parameters.b); endfor elseif (strcmp (mode, "three")) for index = 1:floor (m / 2) weights(index) = svt_pow2 (parameters.b); endfor else for index = 1:m weights(index) = svt_pow2 (parameters.g * (index - 1)); endfor endif B = h * diag (weights); identity = mp (eye (m)); zero = mp (zeros (m, m)); model = [identity, B; zero, identity]; inverse_model = [identity, -B; zero, identity]; scale = svt_pow2 (scale_bits); represented = model * scale; inverse_formula = inverse_model / scale; sqrt_m_exponent = svt_ceil_log2_integer (m) / 2; beta = mp (zeros (m, 1)); unscaled_values = mp (zeros (2 * m, 1)); cursor = 1; for index = 1:m if (weights(index) == mp (0)) beta(index) = mp (0); large = mp (1); small = mp (1); else weight_exponent = max_exponent; if (strcmp (mode, "two") || strcmp (mode, "three")) weight_exponent = parameters.b; elseif (strcmp (mode, "graded")) weight_exponent = parameters.g * (index - 1); endif beta(index) = svt_pow2 (weight_exponent + sqrt_m_exponent); root = sqrt (beta(index) * beta(index) + mp (4)); denominator = root + beta(index); large = denominator / mp (2); ## Stable reciprocal formula; do not subtract nearly equal roots. small = mp (2) / denominator; endif unscaled_values(cursor) = large; unscaled_values(cursor + 1) = small; cursor = cursor + 2; endfor analytic_values = sort (unscaled_values, "descend") * scale; notes = "NRO Section-5 block; stable reciprocal singular-value formula"; if (scale_bits != 0) notes = [notes, "; global exact dyadic scale applied"]; endif result = struct (); result.id = case_id; result.tier = "S"; result.family = "nro_block"; result.mode = mode; result.parameters = parameters; result.m = m; result.H = h; result.G = unused_g; result.weights = weights; result.B = B; result.model = model; result.A = represented; result.inverse_formula = inverse_formula; result.beta = beta * scale; result.analytic_values = analytic_values; result.unscaled_analytic_values = unscaled_values; result.scale = scale; result.rank = 2 * m; result.full_rank = true; result.det_model = mp (1); result.construction_guard_bits = required_bits; result.identity = svt_case_identity (case_id, "nro_block", model, represented, ... work_bits, "exact_dyadic", notes); result.status = "CONSTRUCTED"; clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_dyadic_complex_decode.m0000644000230300031750000000073415274353472027102 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function value = svt_dyadic_complex_decode (encoded, target_bits) if (! isstruct (encoded) || ! isfield (encoded, "real") ... || ! isfield (encoded, "imag")) error ("mplapack:svt:DyadicRecord", "incomplete complex dyadic record"); endif real_part = svt_dyadic_decode (encoded.real, target_bits); imag_part = svt_dyadic_decode (encoded.imag, target_bits); value = real_part + imag_part * mp ('0', '1'); endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_bidiagonal.m0000644000230300031750000000430215274353472025674 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_bidiagonal (case_id, parameters, work_bits) ## Construct the graded bidiagonal raw/mixed pair from A3. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters) ... || ! isfield (parameters, "n") || ! isfield (parameters, "a") ... || ! isfield (parameters, "representation")) error ("mplapack:svt:InvalidBidiagonalRequest", ... "invalid bidiagonal request"); endif n = parameters.n; a = parameters.a; representation = char (parameters.representation); if (! isnumeric (n) || ! isscalar (n) || n != fix (n) || n < 1 ... || ! isnumeric (a) || ! isscalar (a) || a != fix (a) || a < 1 ... || ! any (strcmp (representation, {"raw", "mixed"})) ... || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidBidiagonalParameters", ... "bidiagonal requires positive integer n/a and raw/mixed representation"); endif required_bits = a * (n - 1) + 4; svt_require_guard (required_bits, work_bits, "bidiagonal exact mixing"); saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); raw = mp (zeros (n, n)); for i = 1:n raw(i, i) = svt_pow2 (-a * (i - 1)); if (i < n) raw(i, i + 1) = svt_pow2 (-a * (i - 1) - 1); endif endfor mixed = svt_mix (raw); if (strcmp (representation, "raw")) matrix = raw; else matrix = mixed; endif identity = svt_case_identity (case_id, "bidiagonal", raw, matrix, ... work_bits, "exact_dyadic", ... "graded one-bit bidiagonal; raw/mixed singular spectra agree"); result = struct ("id", case_id, "tier", "A", "family", "bidiagonal", ... "parameters", parameters, "n", n, "a", a, ... "representation", representation, "raw", raw, "mixed", mixed, ... "model", raw, "A", matrix, "analytic_values", [], "rank", n, ... "full_rank", true, "det_model", svt_pow2 (-a * n * (n - 1) / 2), ... "construction_guard_bits", required_bits, "identity", identity, ... "status", "CONSTRUCTED"); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_pow2.m0000644000230300031750000000071515274353472023501 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_pow2 (exponent) ## Return the exact MPFR value 2^exponent at the current project precision. if (! isnumeric (exponent) || ! isreal (exponent) || ! isscalar (exponent) ... || ! isfinite (exponent) || exponent != fix (exponent)) error ("mplapack:svt:InvalidExponent", ... "power-of-two exponent must be an integer scalar"); endif result = mp (2) ^ exponent; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_load_manifest.m0000644000230300031750000000167315274353472025423 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function manifest = svt_load_manifest () helper_dir = fileparts (mfilename ("fullpath")); suite_dir = fileparts (helper_dir); repo_root = fileparts (fileparts (suite_dir)); manifest_path = fullfile (repo_root, "docs", "codex", "svt", "cases.json"); if (! exist (manifest_path, "file")) error ("mplapack:svt:ManifestMissing", ... "normative SVT manifest is missing: %s", manifest_path); endif try manifest = jsondecode (fileread (manifest_path)); catch exception error ("mplapack:svt:ManifestInvalid", ... "could not decode normative SVT manifest: %s", exception.message); end_try_catch if (! isfield (manifest, "schema") || ... ! strcmp (manifest.schema, "svt-case-manifest-v1") || ... ! isfield (manifest, "profiles")) error ("mplapack:svt:ManifestInvalid", ... "normative SVT manifest has an invalid schema"); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_dyadic_decode.m0000644000230300031750000000503615274353472025353 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function value = svt_dyadic_decode (encoded, target_bits) ## Decode a canonical exact dyadic into an MPFR value at target_bits. if (! isstruct (encoded) || ! isfield (encoded, "sign") ... || ! isfield (encoded, "mantissa_hex") || ! isfield (encoded, "exponent2")) error ("mplapack:svt:DyadicRecord", "incomplete dyadic record"); endif sign = encoded.sign; mantissa_hex = encoded.mantissa_hex; exponent2 = encoded.exponent2; if (! ischar (mantissa_hex) || isempty (mantissa_hex) ... || any (mantissa_hex != lower (mantissa_hex)) ... || any (! ismember (mantissa_hex, '0123456789abcdef')) ... || ! isnumeric (exponent2) || ! isscalar (exponent2) ... || exponent2 != fix (exponent2) || ! any (sign == [-1, 0, 1])) error ("mplapack:svt:DyadicRecord", "invalid dyadic fields"); endif if (sign == 0) if (! strcmp (mantissa_hex, "0") || exponent2 != 0) error ("mplapack:svt:DyadicRecord", "zero dyadic has noncanonical fields"); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (target_bits); if (isfield (encoded, "zero_signbit") && encoded.zero_signbit) value = mp ("-0"); else value = mp (0); endif clear cleanup; return; endif if (mantissa_hex(1) == '0' || mod (hex_digit (mantissa_hex(end)), 2) == 0) error ("mplapack:svt:DyadicRecord", "nonzero mantissa is not positive odd"); endif first_digit = hex_digit (mantissa_hex(1)); leading_bits = 0; while first_digit > 0 leading_bits = leading_bits + 1; first_digit = fix (first_digit / 2); endwhile required_bits = 4 * (numel (mantissa_hex) - 1) + leading_bits; if (! isnumeric (target_bits) || ! isscalar (target_bits) ... || target_bits != fix (target_bits) || target_bits < required_bits) error ("mplapack:svt:DyadicInsufficientPrecision", ... "target precision cannot represent dyadic mantissa"); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (target_bits); accumulator = mp (0); for index = 1:numel (mantissa_hex) accumulator = accumulator * mp (16) + mp (hex_digit (mantissa_hex(index))); endfor value = accumulator * svt_pow2 (exponent2); if (sign < 0) value = -value; endif clear cleanup; endfunction function value = hex_digit(character) index = find ('0123456789abcdef' == character, 1); if (isempty (index)) error ("mplapack:svt:DyadicRecord", "invalid hexadecimal digit"); endif value = index - 1; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_ceil_log2_integer.m0000644000230300031750000000115315274353472026163 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_ceil_log2_integer (value) ## Exact ceil(log2(value)) for a positive small integer. The loop uses only ## integer comparisons and therefore has no power-of-two boundary rounding. if (! isnumeric (value) || ! isreal (value) || ! isscalar (value) ... || ! isfinite (value) || value != fix (value) || value < 1) error ("mplapack:svt:InvalidInteger", ... "ceil-log2 input must be a positive integer"); endif result = 0; power = 1; while (power < value) power = power * 2; result = result + 1; endwhile endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_jacobi_stirling.m0000644000230300031750000000427415274353472026755 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_jacobi_stirling (case_id, parameters, work_bits) ## Construct the z=1 Jacobi--Stirling second-kind matrix by MP integer ## recurrence. Indices in the recurrence are zero-based mathematically. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters) ... || ! isfield (parameters, "n") || ! isfield (parameters, "z")) error ("mplapack:svt:InvalidJsRequest", "invalid Jacobi--Stirling request"); endif n = parameters.n; z = parameters.z; if (! isnumeric (n) || ! isscalar (n) || ! isfinite (n) ... || n != fix (n) || n < 1 || ! isnumeric (z) || ! isscalar (z) ... || z != 1 || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidJsParameters", ... "Jacobi--Stirling requires n>=1, z=1, and integral precision"); endif required_bits = 3; for r = 1:(n - 1) required_bits = required_bits + svt_ceil_log2_integer (1 + r * (r + 1)); endfor svt_require_guard (required_bits, work_bits, "Jacobi--Stirling exact recurrence"); saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); matrix = mp (zeros (n, n)); matrix(1, 1) = mp (1); for i = 1:(n - 1) for j = 1:i term_shift = mp (0); if (j <= i) term_shift = matrix(i, j); endif term_recur = mp (0); if (j <= i - 1) term_recur = mp (j * (j + 1)) * matrix(i, j + 1); endif matrix(i + 1, j + 1) = term_shift + term_recur; endfor endfor identity = svt_case_identity (case_id, "jacobi_stirling", matrix, matrix, ... work_bits, "exact_integer_recurrence", ... "z=1; unit lower triangular Jacobi--Stirling matrix"); result = struct ("id", case_id, "tier", "S", "family", "jacobi_stirling", ... "parameters", parameters, "n", n, "z", z, "model", matrix, ... "A", matrix, "analytic_values", [], "rank", n, ... "full_rank", true, "det_model", mp (1), ... "construction_guard_bits", required_bits, "identity", identity, ... "status", "CONSTRUCTED"); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_lauchli.m0000644000230300031750000000712715274353472025234 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_lauchli (case_id, parameters, work_bits) ## Construct the Lauchli tall/wide pair and optional quarter-turn phase. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters) ... || ! isfield (parameters, "n") || ! isfield (parameters, "b") ... || ! isfield (parameters, "representation")) error ("mplapack:svt:InvalidLauchliRequest", "invalid Lauchli request"); endif n = parameters.n; b = parameters.b; representation = char (parameters.representation); if (! isnumeric (n) || ! isscalar (n) || n != fix (n) || n < 1 ... || ! isnumeric (b) || ! isscalar (b) || b != fix (b) || b < 1 ... || ! any (strcmp (representation, {"tall", "wide"})) ... || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidLauchliParameters", ... "Lauchli requires positive integer n/b and tall/wide representation"); endif required_bits = b + svt_ceil_log2_integer (n) + 3; svt_require_guard (required_bits, work_bits, "Lauchli exact dyadic construction"); phase_requested = isfield (parameters, "quarter_turn_phases") ... && parameters.quarter_turn_phases; if (phase_requested && strcmp (representation, "wide")) error ("mplapack:svt:InvalidLauchliParameters", ... "quarter-turn Lauchli control is defined for the tall form"); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); mu = svt_pow2 (-b); ones_row = mp (ones (1, n)); eye_n = mp (eye (n)); tall = [ones_row; mu * eye_n]; phase_left = mp (eye (n + 1)); phase_right = mp (eye (n)); matrix = tall; if (phase_requested) phase_left = svt_phase_diagonal (n + 1); phase_right = svt_phase_diagonal (n); matrix = phase_left * tall * phase_right'; elseif (strcmp (representation, "wide")) matrix = tall'; endif spectrum = mp (zeros (n, 1)); spectrum(1) = sqrt (mp (n) + mu * mu); for index = 2:n spectrum(index) = mu; endfor base_right = mp (eye (n)) - ... (mp (ones (n, 1)) * mp (ones (1, n))) / mp (n); base_left = mp (zeros (n + 1, n + 1)); base_left(2:end, 2:end) = base_right; if (phase_requested) right_projector = phase_right * base_right * phase_right'; left_projector = phase_left * base_left * phase_left'; elseif (strcmp (representation, "tall")) right_projector = base_right; left_projector = base_left; else right_projector = base_left; left_projector = base_right; endif normal_model = mp (ones (n, n)) + (mu * mu) * mp (eye (n)); identity = svt_case_identity (case_id, "lauchli", tall, matrix, work_bits, ... "exact_dyadic", ... "Lauchli repeated-small-group projector; normal equations are negative control"); result = struct ("id", case_id, "tier", "A", "family", "lauchli", ... "parameters", parameters, "n", n, "b", b, ... "representation", representation, "mu", mu, "tall", tall, ... "A", matrix, "model", tall, "analytic_values", spectrum, ... "right_projector", right_projector, "left_projector", left_projector, ... "normal_equations_model", normal_model, ... "normal_equations_negative_control", true, "phase_left", phase_left, ... "phase_right", phase_right, "rank", n, "full_rank", true, ... "det_model", [], "construction_guard_bits", required_bits, ... "identity", identity, "status", "CONSTRUCTED"); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_replay_snapshots.m0000644000230300031750000000364715274353472026217 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_replay_snapshots (path_name) ## Decode every exact input/factor snapshot and verify its canonical hash. data = jsondecode (fileread (path_name)); if (! isfield (data, "records")), error ("mplapack:svt:Replay", "records missing"); endif checked = 0; for index = 1:numel (data.records) record = data.records(index); names = {"input", "U", "S", "V"}; for name_index = 1:numel (names) snapshot = record.(names{name_index}); value = decode_snapshot (snapshot); reencoded = svt_serialize_mp_array (value, snapshot.storage_bits); if (! strcmp (reencoded.canonical_byte_hash, snapshot.canonical_byte_hash)) error ("mplapack:svt:ReplayHash", ... "canonical snapshot hash mismatch at record %d (%s)", index, names{name_index}); endif checked = checked + 1; endfor endfor report = struct ("status", "PASS", "records", numel (data.records), ... "snapshots", checked, "path", path_name); endfunction function value = decode_snapshot (snapshot) if (! isstruct (snapshot) || ! isfield (snapshot, "kind") ... || ! isfield (snapshot, "shape") || ! isfield (snapshot, "values") ... || ! isfield (snapshot, "storage_bits")) error ("mplapack:svt:Replay", "malformed exact snapshot"); endif shape = snapshot.shape; q = snapshot.storage_bits; saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (q); if (strcmp (snapshot.kind, "complex")) value = mp (complex (zeros (shape), zeros (shape))); else value = mp (zeros (shape)); endif entries = snapshot.values; for index = 1:numel (entries) if (strcmp (snapshot.kind, "complex")) element = svt_dyadic_complex_decode (entries(index), q); else element = svt_dyadic_decode (entries(index), q); endif value(index) = element; endfor clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_widen.m0000644000230300031750000000244415274353472023721 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_widen (value, target_bits) ## Widen an existing mp value by adding an exact zero created at target_bits. ## This is intentionally not a text or binary64 round trip. The existing ## core metadata query is used only to reject a target below source storage; ## no new public precision-inspection API is introduced. if (! isa (value, "mp") || ! isscalar (target_bits) ... || ! isfinite (target_bits) || target_bits != fix (target_bits) ... || target_bits < 64) error ("mplapack:svt:InvalidWidening", ... "svt_widen requires an mp value and an integer target of at least 64 bits"); endif info = __mplapack_core__ ("value_shape_info", value); if (target_bits < info.precision_bits) error ("mplapack:svt:InsufficientWidening", ... "cannot narrow an mp value while widening: source=%d target=%d", ... info.precision_bits, target_bits); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (target_bits); if (isfield (info, "rows") && isfield (info, "columns") ... && (info.rows != 1 || info.columns != 1)) zero = mp (zeros (info.rows, info.columns)); else zero = mp (0); endif result = value + zero; clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_serialize_mp_array.m0000644000230300031750000000354715274353472026501 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function snapshot = svt_serialize_mp_array (value, q, method) ## Serialize represented MPFR/MPC values without reading a private payload. ## The hash covers the exact JSON bytes of the metadata and encoded values. if (nargin < 3), method = "svt_exact_dyadic_v1"; endif if (! isa (value, "mp") || ndims (value) > 2) error ("mplapack:svt:SnapshotType", "snapshot requires a scalar or 2-D mp value"); endif if (! isnumeric (q) || ! isscalar (q) || q != fix (q) || q < 64 || q > 4096) error ("mplapack:svt:SnapshotPrecision", "invalid snapshot precision"); endif info = __mplapack_core__ ("value_shape_info", value); if (q < info.precision_bits) error ("mplapack:svt:SnapshotPrecision", ... "snapshot precision is below source precision"); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (q); shape = size (value); complex_value = ! isreal (value); if (complex_value) kind = "complex"; else kind = "real"; endif encoded_values = cell (numel (value), 1); if (numel (value) == 1) flat = value; else flat = value(:); endif for index = 1:numel (flat) if (numel (flat) == 1) element = flat; else element = flat(index); endif if (complex_value) encoded_values{index} = svt_dyadic_complex_encode (element, q); else encoded_values{index} = svt_dyadic_encode (element, q); endif endfor snapshot = struct ("schema", "svt-exact-snapshot-v1", "kind", kind, ... "storage_bits", info.precision_bits, "shape", shape, ... "order", "column-major", "method", method, ... "values", {encoded_values}); canonical_bytes = jsonencode (snapshot); snapshot.canonical_byte_hash = hash ("sha256", canonical_bytes); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_check_coverage.m0000644000230300031750000000133215274353472025536 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function ok = svt_check_coverage (rows, expected_rows) ## Reject missing and duplicate measured rows before a profile is complete. ok = iscell (rows) && numel (rows) == expected_rows; if (! ok), return; endif keys = cell (numel (rows), 1); for index = 1:numel (rows) row = rows{index}; required = {"case_id", "mode", "native", "work_bits", "status"}; if (! isstruct (row) || any (! cellfun (@(name) isfield (row, name), required))) ok = false; return; endif keys{index} = sprintf ("%s|%s|%d|%d", row.case_id, row.mode, ... row.native, row.work_bits); endfor ok = numel (unique (keys)) == expected_rows; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_known_projector.m0000644000230300031750000000145715274353472026041 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function projector = svt_known_projector (basis, indices) ## Form a model projector from exact columns of a Hadamard factor. if (! isa (basis, "mp") || rows (basis) != columns (basis)) error ("mplapack:svt:InvalidProjectorBasis", ... "projector basis must be a square mp matrix"); endif indices = indices(:).'; if (isempty (indices)) projector = mp (zeros (rows (basis), rows (basis))); return; endif if (any (indices < 1) || any (indices > columns (basis)) ... || any (indices != fix (indices))) error ("mplapack:svt:InvalidProjectorIndices", ... "projector indices are outside the basis"); endif projector = basis(:, indices) * basis(:, indices)' ... * (mp (1) / mp (rows (basis))); endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_compare_references.m0000644000230300031750000000314015274353472026434 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function comparison = svt_compare_references (low, high) ## Compare two frozen-input reference solves observationally. This routine ## never labels agreement as a certificate. if (! isstruct (low) || ! isstruct (high) ... || ! isfield (low, "values") || ! isfield (high, "values")) error ("mplapack:svt:InvalidReference", "reference records are incomplete"); endif q = max ([low.input_precision_bits, high.input_precision_bits]); low_values = svt_widen (low.values, q); high_values = svt_widen (high.values, q); a = svt_widen (low.input, q); norm_a = norm (a, "fro"); threshold = norm_a * svt_pow2 (-floor (low.input_precision_bits / 2)); k = numel (low_values); resolved = false (k, 1); relative = mp (zeros (k, 1)); absolute = mp (zeros (k, 1)); for index = 1:k absolute(index) = abs (low_values(index) - high_values(index)); resolved(index) = low_values(index) > threshold ... && high_values(index) > threshold; low_abs = abs (low_values(index)); high_abs = abs (high_values(index)); denominator = max ([low_abs, high_abs]); if (denominator == mp (0)) relative(index) = mp (0); else relative(index) = absolute(index) / denominator; endif endfor comparison = struct ("status", "consistent_reference", ... "reference_bits", [low.input_precision_bits, high.input_precision_bits], ... "resolution_floor", threshold, "resolved", resolved, ... "absolute_error", absolute, "relative_error", relative); endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_iv.m0000644000230300031750000003611415274353472023232 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_iv (operation, varargin) ## Private real-interval/complex-rectangle arithmetic for Tier V. ## Every nonzero real primitive is enclosed before it is propagated. switch (operation) case "point" result = iv_point (varargin{1}, varargin{2}); case "primitive" result = iv_primitive (varargin{1}, varargin{2}, varargin{3}); case "add" result = iv_add (varargin{1}, varargin{2}); case "sub" result = iv_sub (varargin{1}, varargin{2}); case "mul" result = iv_mul (varargin{1}, varargin{2}); case "div" result = iv_div (varargin{1}, varargin{2}); case "square" result = iv_square (varargin{1}); case "sqrt" result = iv_sqrt (varargin{1}); case "neg" result = iv_neg (varargin{1}); case "conj" result = iv_conj (varargin{1}); case "matrix_point" result = matrix_point (varargin{1}, varargin{2}); case "matrix_get" result = matrix_get (varargin{1}, varargin{2}, varargin{3}); case "matrix_set" result = matrix_set (varargin{1}, varargin{2}, varargin{3}, varargin{4}); case "matrix_add" result = matrix_binary (varargin{1}, varargin{2}, "add"); case "matrix_sub" result = matrix_binary (varargin{1}, varargin{2}, "sub"); case "matrix_mul" result = matrix_mul (varargin{1}, varargin{2}); case "matrix_transpose" result = matrix_transpose (varargin{1}); case "matrix_ctranspose" result = matrix_ctranspose (varargin{1}); case "matrix_fro_upper" result = matrix_fro_upper (varargin{1}); case "matrix_column_lower" result = matrix_column_lower (varargin{1}); otherwise error ("mplapack:svt:IntervalOperation", "unknown interval operation: %s", operation); endswitch endfunction function result = iv_point (value, q) require_q (q); if (! isa (value, "mp") || ! isscalar (value)) error ("mplapack:svt:IntervalPoint", "interval points require mp scalars"); endif value = svt_widen (value, q); if (isreal (value)) result = real_interval (value, value, q); else result = complex_interval (real_interval (real (value), real (value), q), ... real_interval (imag (value), imag (value), q)); endif endfunction function result = iv_primitive (value, exact_zero, q) require_q (q); if (! isa (value, "mp") || ! isscalar (value) || ! isreal (value) ... || ! islogical (exact_zero) || ! isscalar (exact_zero)) error ("mplapack:svt:IntervalPrimitive", "invalid audited real primitive"); endif if (! isfinite (value)) error ("mplapack:svt:ContractNonfinite", "audited primitive produced nonfinite data"); endif zero = mp (0); if (value == zero) if (! exact_zero) error ("mplapack:svt:ContractUnexpectedZero", ... "nonzero exact primitive rounded to an unexplained zero"); endif result = real_interval (zero, zero, q); return; endif magnitude = abs (value); if (magnitude < svt_pow2 (-8192) || magnitude > svt_pow2 (8192)) error ("mplapack:svt:ContractPrimitiveRange", ... "audited primitive is outside the declared range"); endif ## 8*2^-q is one exact power-of-two scaling of the stored MPFR result. padding = magnitude * svt_pow2 (3 - q); if (padding == zero) error ("mplapack:svt:ContractZeroPadding", "outward padding became zero"); endif lower = value - padding; upper = value + padding; if (lower > upper || ! isfinite (lower) || ! isfinite (upper)) error ("mplapack:svt:ContractEndpoint", "invalid outward primitive endpoints"); endif result = real_interval (lower, upper, q); endfunction function result = iv_add(a, b) if (strcmp (a.kind, "complex") || strcmp (b.kind, "complex")) a = complexify (a); b = complexify (b); result = complex_interval (svt_iv ("add", a.real, b.real), ... svt_iv ("add", a.imag, b.imag)); return; endif require_same_kind(a, b); q = a.q; lower = a.lo + b.lo; upper = a.hi + b.hi; result = real_interval_bounds (svt_iv ("primitive", lower, ... a.lo == -b.lo, q), ... svt_iv ("primitive", upper, ... a.hi == -b.hi, q)); endfunction function result = iv_sub(a, b) if (strcmp (a.kind, "complex") || strcmp (b.kind, "complex")) a = complexify (a); b = complexify (b); result = complex_interval (svt_iv ("sub", a.real, b.real), ... svt_iv ("sub", a.imag, b.imag)); return; endif require_same_kind(a, b); q = a.q; lower = a.lo - b.hi; upper = a.hi - b.lo; result = real_interval_bounds (svt_iv ("primitive", lower, ... a.lo == b.hi, q), ... svt_iv ("primitive", upper, ... a.hi == b.lo, q)); endfunction function result = iv_mul(a, b) if (strcmp (a.kind, "complex") || strcmp (b.kind, "complex")) a = complexify (a); b = complexify (b); rr = svt_iv ("sub", svt_iv ("mul", a.real, b.real), ... svt_iv ("mul", a.imag, b.imag)); ii = svt_iv ("add", svt_iv ("mul", a.real, b.imag), ... svt_iv ("mul", a.imag, b.real)); result = complex_interval (rr, ii); return; endif require_same_kind(a, b); q = a.q; values = {a.lo * b.lo, a.lo * b.hi, a.hi * b.lo, a.hi * b.hi}; exact = {a.lo == 0 || b.lo == 0, a.lo == 0 || b.hi == 0, ... a.hi == 0 || b.lo == 0, a.hi == 0 || b.hi == 0}; candidates = cell (1, 4); for index = 1:4 candidates{index} = svt_iv ("primitive", values{index}, exact{index}, q); endfor lower = candidates{1}.lo; upper = candidates{1}.hi; for index = 2:4 if (candidates{index}.lo < lower), lower = candidates{index}.lo; endif if (candidates{index}.hi > upper), upper = candidates{index}.hi; endif endfor result = real_interval (lower, upper, q); endfunction function result = iv_div(a, b) if (strcmp (a.kind, "complex") || strcmp (b.kind, "complex")) error ("mplapack:svt:IntervalComplexDivision", ... "complex division is outside the rectangle baseline"); endif require_same_kind(a, b); if (! (b.lo > mp (0) || b.hi < mp (0))) error ("mplapack:svt:IntervalZeroDenominator", ... "interval denominator crosses zero"); endif q = a.q; values = {a.lo / b.lo, a.lo / b.hi, a.hi / b.lo, a.hi / b.hi}; exact = {a.lo == 0, a.lo == 0, a.hi == 0, a.hi == 0}; candidates = cell (1, 4); for index = 1:4 candidates{index} = svt_iv ("primitive", values{index}, exact{index}, q); endfor lower = candidates{1}.lo; upper = candidates{1}.hi; for index = 2:4 if (candidates{index}.lo < lower), lower = candidates{index}.lo; endif if (candidates{index}.hi > upper), upper = candidates{index}.hi; endif endfor result = real_interval (lower, upper, q); endfunction function result = iv_square(a) if (strcmp (a.kind, "complex")) error ("mplapack:svt:IntervalComplexSquare", "square expects a real interval"); endif q = a.q; if (a.lo <= mp (0) && a.hi >= mp (0)) lower = mp (0); else left = svt_iv ("mul", a, a); lower = left.lo; endif left = svt_iv ("mul", a, a); result = real_interval (lower, left.hi, q); endfunction function result = iv_sqrt(a) if (strcmp (a.kind, "complex") || a.lo < mp (0)) error ("mplapack:svt:IntervalSqrtDomain", "sqrt interval is not nonnegative"); endif q = a.q; lo_value = sqrt (a.lo); hi_value = sqrt (a.hi); result = real_interval_bounds (svt_iv ("primitive", lo_value, a.lo == 0, q), ... svt_iv ("primitive", hi_value, a.hi == 0, q)); endfunction function result = iv_neg(a) if (strcmp (a.kind, "complex")) result = complex_interval (svt_iv ("neg", a.real), svt_iv ("neg", a.imag)); else result = real_interval (-a.hi, -a.lo, a.q); endif endfunction function result = iv_conj(a) if (strcmp (a.kind, "complex")) result = complex_interval (a.real, svt_iv ("neg", a.imag)); else result = a; endif endfunction function result = matrix_point(value, q) if (! isa (value, "mp") || ndims (value) != 2) error ("mplapack:svt:IntervalMatrixPoint", "matrix point requires a 2-D mp matrix"); endif value = svt_widen (value, q); if (isreal (value)) result = struct ("schema", "svt-interval-matrix-v1", "kind", "real", "q", q, ... "lo", value, "hi", value); else result = struct ("schema", "svt-interval-matrix-v1", "kind", "complex", "q", q, ... "real_lo", real (value), "real_hi", real (value), ... "imag_lo", imag (value), "imag_hi", imag (value)); endif endfunction function result = matrix_get(matrix, row, column) if (strcmp (matrix.kind, "real")) result = real_interval (matrix.lo(row, column), matrix.hi(row, column), matrix.q); else result = complex_interval (real_interval (matrix.real_lo(row, column), ... matrix.real_hi(row, column), matrix.q), ... real_interval (matrix.imag_lo(row, column), ... matrix.imag_hi(row, column), matrix.q)); endif endfunction function matrix = matrix_set(matrix, row, column, value) if (strcmp (matrix.kind, "real") && strcmp (value.kind, "real")) matrix.lo(row, column) = value.lo; matrix.hi(row, column) = value.hi; else if (strcmp (matrix.kind, "real")) matrix = promote_matrix_complex (matrix); endif value = complexify (value); matrix.real_lo(row, column) = value.real.lo; matrix.real_hi(row, column) = value.real.hi; matrix.imag_lo(row, column) = value.imag.lo; matrix.imag_hi(row, column) = value.imag.hi; endif endfunction function result = matrix_binary(a, b, operation) if (a.q != b.q), error ("mplapack:svt:IntervalPrecision", "matrix precisions differ"); endif [m, n] = matrix_shape(a); [mb, nb] = matrix_shape(b); if (m != mb || n != nb), error ("mplapack:svt:IntervalShape", "matrix shapes differ"); endif result = matrix_zero (a.q, m, n, strcmp (a.kind, "complex") || strcmp (b.kind, "complex")); for row = 1:m for column = 1:n result = matrix_set (result, row, column, svt_iv (operation, ... svt_iv ("matrix_get", a, row, column), svt_iv ("matrix_get", b, row, column))); endfor endfor endfunction function result = matrix_mul(a, b) [m, k] = matrix_shape(a); [kb, n] = matrix_shape(b); if (k != kb), error ("mplapack:svt:IntervalShape", "matrix product shapes differ"); endif is_complex = strcmp (a.kind, "complex") || strcmp (b.kind, "complex"); result = matrix_zero (a.q, m, n, is_complex); for row = 1:m for column = 1:n if (is_complex) sum_value = svt_iv ("point", mp ('0', '0'), a.q); else sum_value = svt_iv ("point", mp (0), a.q); endif for inner = 1:k sum_value = svt_iv ("add", sum_value, svt_iv ("mul", ... svt_iv ("matrix_get", a, row, inner), ... svt_iv ("matrix_get", b, inner, column))); endfor result = matrix_set (result, row, column, sum_value); endfor endfor endfunction function result = matrix_ctranspose(matrix) [m, n] = matrix_shape(matrix); result = matrix_zero (matrix.q, n, m, strcmp (matrix.kind, "complex")); for row = 1:m for column = 1:n result = matrix_set (result, column, row, svt_iv ("conj", ... svt_iv ("matrix_get", matrix, row, column))); endfor endfor endfunction function result = matrix_transpose(matrix) [m, n] = matrix_shape(matrix); result = matrix_zero (matrix.q, n, m, strcmp (matrix.kind, "complex")); for row = 1:m for column = 1:n result = matrix_set (result, column, row, ... svt_iv ("matrix_get", matrix, row, column)); endfor endfor endfunction function result = matrix_fro_upper(matrix) [m, n] = matrix_shape(matrix); sum_value = svt_iv ("point", mp (0), matrix.q); for row = 1:m for column = 1:n value = svt_iv ("matrix_get", matrix, row, column); if (strcmp (value.kind, "complex")) sum_value = svt_iv ("add", sum_value, svt_iv ("square", value.real)); sum_value = svt_iv ("add", sum_value, svt_iv ("square", value.imag)); else sum_value = svt_iv ("add", sum_value, svt_iv ("square", value)); endif endfor endfor result = svt_iv ("sqrt", sum_value); endfunction function result = matrix_column_lower(matrix) [m, n] = matrix_shape(matrix); result = mp (zeros (1, n)); for column = 1:n sum_value = svt_iv ("point", mp (0), matrix.q); for row = 1:m value = svt_iv ("matrix_get", matrix, row, column); if (strcmp (value.kind, "complex")) sum_value = svt_iv ("add", sum_value, svt_iv ("square", value.real)); sum_value = svt_iv ("add", sum_value, svt_iv ("square", value.imag)); else sum_value = svt_iv ("add", sum_value, svt_iv ("square", value)); endif endfor norm_interval = svt_iv ("sqrt", sum_value); result(column) = norm_interval.lo; endfor endfunction function result = real_interval(lo, hi, q) if (lo > hi), error ("mplapack:svt:IntervalOrder", "lower endpoint exceeds upper endpoint"); endif result = struct ("schema", "svt-interval-real-v1", "kind", "real", ... "q", q, "lo", lo, "hi", hi); endfunction function result = real_interval_bounds(lower, upper) result = real_interval (lower.lo, upper.hi, lower.q); endfunction function result = complex_interval(real_part, imag_part) result = struct ("schema", "svt-interval-complex-v1", "kind", "complex", ... "q", real_part.q, "real", real_part, "imag", imag_part); endfunction function result = complexify(value) if (strcmp (value.kind, "complex")) result = value; else result = complex_interval (value, real_interval (mp (0), mp (0), value.q)); endif endfunction function require_same_kind(a, b) if (a.q != b.q || ! strcmp (a.kind, b.kind)) error ("mplapack:svt:IntervalKind", "interval kinds or precisions differ"); endif endfunction function require_q(q) if (mpbits () != q), error ("mplapack:svt:IntervalPrecision", ... "ambient precision does not match interval q"); endif endfunction function [m, n] = matrix_shape(matrix) if (strcmp (matrix.kind, "real")) [m, n] = size (matrix.lo); else [m, n] = size (matrix.real_lo); endif endfunction function result = matrix_zero(q, m, n, is_complex) if (! is_complex) result = struct ("schema", "svt-interval-matrix-v1", "kind", "real", "q", q, ... "lo", mp (zeros (m, n)), "hi", mp (zeros (m, n))); else result = struct ("schema", "svt-interval-matrix-v1", "kind", "complex", "q", q, ... "real_lo", mp (zeros (m, n)), "real_hi", mp (zeros (m, n)), ... "imag_lo", mp (zeros (m, n)), "imag_hi", mp (zeros (m, n))); endif endfunction function result = promote_matrix_complex(matrix) result = matrix_zero (matrix.q, size (matrix.lo, 1), size (matrix.lo, 2), true); result.real_lo = matrix.lo; result.real_hi = matrix.hi; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_dyadic_complex_encode.m0000644000230300031750000000076115274353472027114 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function encoded = svt_dyadic_complex_encode (value, q) if (! isa (value, "mp") || ! isscalar (value) || isreal (value)) error ("mplapack:svt:DyadicType", "complex encoder expects a complex mp scalar"); endif value = svt_widen (value, q); encoded = struct ("schema", "svt-dyadic-complex-v1", ... "real", svt_dyadic_encode (real (value), q), ... "imag", svt_dyadic_encode (imag (value), q)); endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_run_svd.m0000644000230300031750000000516315274353472024274 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function row = svt_run_svd (input, mode, evaluation_bits) ## Execute exactly one measured values-only or economy-factor SVD call. if (! isa (input, "mp") || ! any (strcmp (mode, {"values", "econ"}))) error ("mplapack:svt:InvalidSvdRequest", ... "svt_run_svd requires an mp input and values/econ mode"); endif if (nargin < 3) evaluation_bits = []; endif input_info = __mplapack_core__ ("value_shape_info", input); before = input; row = struct (); row.schema = "svt-row-v1"; row.mode = mode; row.input_shape = [input_info.rows, input_info.columns]; row.input_precision_bits = input_info.precision_bits; row.evaluation_bits = evaluation_bits; row.api = "mp.svd -> MPLAPACK Rgesvd/Cgesvd"; row.status = "PASS"; timer = tic (); if (strcmp (mode, "values")) row.values = svd (input); row.has_factors = false; else [row.U, row.S, row.V] = svd (input, "econ"); row.values = diag (row.S); row.has_factors = true; endif row.svd_seconds = toc (timer); row.input_unchanged = all (all (input == before)); if (! row.input_unchanged) error ("mplapack:svt:InputMutation", "SVD changed its public input"); endif row.value_info = svt_validate_values (row.values, input_info); if (row.has_factors) row.metrics = svt_metrics (input, row.U, row.S, row.V, evaluation_bits); else row.metrics = struct ("status", "VALUES_ONLY", ... "reconstruction", [], "rho_rec", [], ... "rho_R", [], "rho_L", [], ... "orthogonality_U", [], "orthogonality_V", []); endif endfunction function info = svt_validate_values (values, input_info) if (! isa (values, "mp")) error ("mplapack:svt:SvdContract", "SVD did not return an mp value vector"); endif shape = size (values); k = min (input_info.rows, input_info.columns); if (shape(1) != k || shape(2) != 1) error ("mplapack:svt:SvdContract", "SVD value output has an invalid shape"); endif if (! isreal (values) || ! all (all (isfinite (values)))) error ("mplapack:svt:SvdContract", "SVD values are not finite real mp data"); endif previous = mp (0); for index = 1:k current = values(index); if (current < mp (0)) error ("mplapack:svt:SvdContract", "SVD returned a negative singular value"); endif if (index > 1 && current > previous) error ("mplapack:svt:SvdContract", "SVD values are not descending"); endif previous = current; endfor info = struct ("count", k, "real", true, "finite", true, ... "descending", true, "nonnegative", true); endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_vandermonde.m0000644000230300031750000000433215274353472026110 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_vandermonde (case_id, parameters, work_bits) ## Construct the dyadic-node Vandermonde matrix by successive MP powers. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters) ... || ! isfield (parameters, "n") || ! isfield (parameters, "node_den_bits")) error ("mplapack:svt:InvalidVandermondeRequest", ... "invalid Vandermonde request"); endif n = parameters.n; d = parameters.node_den_bits; if (! isnumeric (n) || ! isscalar (n) || n != fix (n) || n < 1 ... || ! isnumeric (d) || ! isscalar (d) || d != fix (d) || d < 1 ... || n >= 2 ^ d || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidVandermondeParameters", ... "Vandermonde requires n<2^d and integral parameters"); endif required_bits = 2 + (n - 1) * svt_ceil_log2_integer (n); svt_require_guard (required_bits, work_bits, "Vandermonde exact dyadic construction"); saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); denominator = svt_pow2 (d); nodes = mp (zeros (n, 1)); matrix = mp (zeros (n, n)); for i = 1:n nodes(i) = mp (i) / denominator; matrix(i, 1) = mp (1); for j = 2:n matrix(i, j) = matrix(i, j - 1) * nodes(i); endfor endfor distinct = true; for i = 1:(n - 1) for j = (i + 1):n if (nodes(i) == nodes(j)) distinct = false; endif endfor endfor identity = svt_case_identity (case_id, "vandermonde", matrix, matrix, ... work_bits, "exact_dyadic", ... "nodes i/2^d; successive powers; distinct positive nodes"); result = struct ("id", case_id, "tier", "A", "family", "vandermonde", ... "parameters", parameters, "n", n, "node_den_bits", d, ... "nodes", nodes, "model", matrix, "A", matrix, ... "analytic_values", [], "rank", n, "full_rank", distinct, ... "determinant_sign_proof", distinct, "determinant_positive", distinct, ... "construction_guard_bits", required_bits, "identity", identity, ... "status", "CONSTRUCTED"); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_pascal.m0000644000230300031750000000440615274353472025053 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_pascal (case_id, parameters, work_bits) ## Construct either the lower Pascal factor Q or symmetric Pascal P. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters) ... || ! isfield (parameters, "n") || ! isfield (parameters, "representation")) error ("mplapack:svt:InvalidPascalRequest", "invalid Pascal request"); endif n = parameters.n; representation = char (parameters.representation); if (! isnumeric (n) || ! isscalar (n) || n != fix (n) || n < 1 ... || ! any (strcmp (representation, {"lower", "symmetric"})) ... || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidPascalParameters", ... "Pascal requires a positive n, valid representation, and integral precision"); endif q_guard = n + 2; p_guard = 2 * n + 2; required_bits = max ([q_guard, p_guard]); svt_require_guard (required_bits, work_bits, "Pascal exact recurrence"); saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); q = mp (zeros (n, n)); for i = 1:n q(i, 1) = mp (1); q(i, i) = mp (1); for j = 2:(i - 1) q(i, j) = q(i - 1, j - 1) + q(i - 1, j); endfor endfor p = mp (zeros (n, n)); for i = 1:n p(i, 1) = mp (1); p(1, i) = mp (1); endfor for i = 2:n for j = 2:n p(i, j) = p(i, j - 1) + p(i - 1, j); endfor endfor if (strcmp (representation, "lower")) matrix = q; else matrix = p; endif relation = p - q * q'; identity = svt_case_identity (case_id, "pascal", q, matrix, work_bits, ... "exact_integer_recurrence", ... "Pascal Q/P generated by Pascal addition"); result = struct ("id", case_id, "tier", "A", "family", "pascal", ... "parameters", parameters, "n", n, "representation", representation, ... "Q", q, "P", p, "model", q, "A", matrix, ... "q_times_q_transpose_error", relation, "analytic_values", [], ... "rank", n, "full_rank", true, "det_model", mp (1), ... "construction_guard_bits", required_bits, "identity", identity, ... "status", "CONSTRUCTED"); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_nro_companion.m0000644000230300031750000000616715274353472026457 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_nro_companion (case_id, parameters, work_bits) ## Construct the deterministic bounded-integer NRO companion-like matrix. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters) ... || ! isfield (parameters, "n") || ! isfield (parameters, "nu")) error ("mplapack:svt:InvalidNroCompanionRequest", ... "invalid NRO companion request"); endif n = parameters.n; nu = parameters.nu; if (! isnumeric (n) || ! isscalar (n) || n != fix (n) || n < 1 ... || ! isnumeric (nu) || ! isscalar (nu) || nu != fix (nu) || nu < 2 ... || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidNroCompanionParameters", ... "NRO companion requires integer n>=1, nu>=2, and integral precision"); endif required_bits = svt_ceil_log2_integer (nu + 1) + 3; svt_require_guard (required_bits, work_bits, "NRO companion exact construction"); saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); k = mp (zeros (n, 1)); for index = 1:(n - 1) if (mod (index, 2) == 1) k(index) = mp (1); else k(index) = mp (-1); endif endfor k(n) = mp (1); coefficients = mp (zeros (n, 1)); coefficients(1) = k(1); for index = 2:n coefficients(index) = k(index) - mp (nu) * k(index - 1); endfor matrix = mp (zeros (n, n)); matrix(1, :) = coefficients'; for index = 2:n matrix(index, index - 1) = mp (1); matrix(index, index) = -mp (nu); endfor horner = mp (zeros (n, 1)); horner(1) = coefficients(1); for index = 2:n horner(index) = horner(index - 1) * mp (nu) + coefficients(index); endfor det_sign = (-1) ^ (n - 1); published_c = mp ([1, -6, 7, -9; 1, -5, 0, 0; 0, 1, -5, 0; 0, 0, 1, -5]); published_x = mp ([125, -124, 130, -225; 25, -25, 26, -45; ... 5, -5, 5, -9; 1, -1, 1, -2]); published_left_error = published_c * published_x - mp (eye (4)); published_right_error = published_x * published_c - mp (eye (4)); identity = svt_case_identity (case_id, "nro_companion", matrix, matrix, ... work_bits, "exact_integer_recurrence", ... "bounded-integer NRO companion; Horner unimodularity proof"); result = struct ("id", case_id, "tier", "A", "family", "nro_companion", ... "parameters", parameters, "n", n, "nu", nu, "k", k, ... "coefficients", coefficients, "model", matrix, "A", matrix, ... "analytic_values", [], "rank", n, "full_rank", true, ... "det_model", mp (det_sign), "det_sign", det_sign, ... "horner_states", horner, "horner_matches_k", all (all (horner == k)), ... "entry_bound", nu + 1, "construction_guard_bits", required_bits, ... "published_C", published_c, "published_X", published_x, ... "published_left_error", published_left_error, ... "published_right_error", published_right_error, "identity", identity, ... "status", "CONSTRUCTED"); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_certify_factor_boxes.m0000644000230300031750000001355115274353472027017 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function certificate = svt_certify_factor_boxes (a, u, s, v, q, indices) ## V2 conservative compatible factor boxes for positive simple values. value_certificate = svt_certify_values (a, u, s, v, q); certificate = value_certificate; certificate.schema = "svt-v2-factor-box-certificate-v1"; certificate.method = "svt_dilation_factor_boxes_v1"; if (nargin < 6 || isempty (indices)) indices = 1:min (size (a)); endif indices = indices(:).'; certificate.indices = indices; certificate.individual_status = cell (1, numel (indices)); if (! strcmp (value_certificate.status, "CERTIFIED")) certificate.status = value_certificate.status; certificate.factor_status = "INCONCLUSIVE"; return; endif k = min (size (a)); if (isempty (indices) || any (indices < 1) || any (indices > k) ... || any (indices != fix (indices)) || numel (unique (indices)) != numel (indices)) error ("mplapack:svt:FactorBoxIndices", "factor-box indices are invalid"); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (q); uq = svt_widen (u, q); vq = svt_widen (v, q); boxes_u = struct ("real_lower", mp (zeros (size (u))), ... "real_upper", mp (zeros (size (u))), ... "imag_lower", mp (zeros (size (u))), ... "imag_upper", mp (zeros (size (u)))); boxes_v = struct ("real_lower", mp (zeros (size (v))), ... "real_upper", mp (zeros (size (v))), ... "imag_lower", mp (zeros (size (v))), ... "imag_upper", mp (zeros (size (v)))); all_certified = true; unsupported = false; for position = 1:numel (indices) index = indices(position); repeated = false; for other = 1:k if (other != index && s(other, other) == s(index, index)) repeated = true; endif endfor if (repeated) certificate.individual_status{position} = "UNSUPPORTED_MULTIPLICITY"; all_certified = false; unsupported = true; continue; endif if (value_certificate.values_lower(index) <= mp (0)) certificate.individual_status{position} = "INCONCLUSIVE_NONPOSITIVE"; all_certified = false; continue; endif target = svt_iv ("point", s(index, index), q); delta_lower = []; for other = 1:k if (other != index) difference = svt_iv ("sub", target, svt_iv ("point", s(other, other), q)); delta_lower = append_factor_min (delta_lower, factor_abs_lower (difference)); endif negative_sum = svt_iv ("add", target, svt_iv ("point", s(other, other), q)); delta_lower = append_factor_min (delta_lower, negative_sum.lo); endfor if (size (a, 1) != size (a, 2)) delta_lower = append_factor_min (delta_lower, target.lo); endif epsilon = value_certificate.epsilon; if (isempty (delta_lower) || delta_lower <= mp (2) * epsilon.hi) certificate.individual_status{position} = "INCONCLUSIVE_GAP"; all_certified = false; continue; endif delta = svt_iv ("point", delta_lower, q); denominator = svt_iv ("sub", delta, epsilon); z = svt_iv ("div", svt_iv ("mul", svt_iv ("point", mp (2), q), epsilon), denominator); radius_u = svt_iv ("add", value_certificate.dU, z); radius_v = svt_iv ("add", value_certificate.dV, z); if (isreal (uq)) [boxes_u, unused] = set_real_box (boxes_u, real (uq), index, ... radius_u.hi, q); [boxes_v, unused] = set_real_box (boxes_v, real (vq), index, ... radius_v.hi, q); else [boxes_u, unused] = set_complex_box (boxes_u, uq, index, radius_u.hi, q); [boxes_v, unused] = set_complex_box (boxes_v, vq, index, radius_v.hi, q); endif certificate.individual_status{position} = "CERTIFIED"; endfor certificate.boxes_U = boxes_u; certificate.boxes_V = boxes_v; certificate.common_phase = true; certificate.compatibility_claim = "one common phase per simple pair; boxes are conservative norm-derived rectangles"; if (unsupported) certificate.status = "UNSUPPORTED_MULTIPLICITY"; certificate.factor_status = "UNSUPPORTED_MULTIPLICITY"; elseif (all_certified) certificate.status = "CERTIFIED"; certificate.factor_status = "CERTIFIED"; else certificate.status = "INCONCLUSIVE"; certificate.factor_status = "INCONCLUSIVE"; endif clear cleanup; endfunction function [boxes, unused] = set_real_box(boxes, centers, position, radius, q) unused = false; for row = 1:size (centers, 1) lower = svt_iv ("sub", svt_iv ("point", centers(row, position), q), ... svt_iv ("point", radius, q)); upper = svt_iv ("add", svt_iv ("point", centers(row, position), q), ... svt_iv ("point", radius, q)); boxes.real_lower(row, position) = lower.lo; boxes.real_upper(row, position) = upper.hi; endfor endfunction function [boxes, unused] = set_complex_box(boxes, centers, position, radius, q) unused = false; [boxes, unused] = set_real_box (boxes, real (centers), position, radius, q); for row = 1:size (centers, 1) lower = svt_iv ("sub", svt_iv ("point", imag (centers(row, position)), q), ... svt_iv ("point", radius, q)); upper = svt_iv ("add", svt_iv ("point", imag (centers(row, position)), q), ... svt_iv ("point", radius, q)); boxes.imag_lower(row, position) = lower.lo; boxes.imag_upper(row, position) = upper.hi; endfor endfunction function lower = factor_abs_lower(interval) if (interval.lo <= mp (0) && interval.hi >= mp (0)) lower = mp (0); else lower = abs (interval.lo); if (abs (interval.hi) < lower), lower = abs (interval.hi); endif endif endfunction function current = append_factor_min(current, candidate) if (isempty (current) || candidate < current), current = candidate; endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_require_guard.m0000644000230300031750000000074715274353472025455 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function svt_require_guard (required_bits, actual_bits, label) if (! isnumeric (required_bits) || ! isnumeric (actual_bits) ... || required_bits != fix (required_bits) ... || actual_bits != fix (actual_bits) || actual_bits < required_bits) error ("mplapack:svt:InsufficientConstructionPrecision", ... "%s needs at least %d bits (requested %d)", label, ... required_bits, actual_bits); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_reference.m0000644000230300031750000000136015274353472024545 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function reference = svt_reference (input, reference_bits) ## Compute a non-timed frozen-input reference. Agreement is provisional ## until SVT13 supplies an independent enclosure. if (! isa (input, "mp") || ! isscalar (reference_bits) ... || reference_bits != fix (reference_bits)) error ("mplapack:svt:InvalidReference", "invalid reference request"); endif frozen = svt_widen (input, reference_bits); reference = struct (); reference.schema = "svt-reference-v1"; reference.input = frozen; reference.input_precision_bits = reference_bits; reference.values = svd (frozen); reference.status = "consistent_reference"; reference.api = "mp.svd one-output reference"; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_certify_inverse.m0000644000230300031750000000564215274353472026016 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function certificate = svt_certify_inverse (a, x, q) ## V3 verified inverse residual and inverse-norm/sigma-min bounds. certificate = struct ("schema", "svt-v3-inverse-certificate-v1", ... "method", "svt_neumann_inverse_v1", "status", "ERROR", ... "paper_algorithm_reproduction", false, "q", q); if (! isa (a, "mp") || ! isa (x, "mp") || ndims (a) != 2 || ndims (x) != 2) error ("mplapack:svt:InverseInput", "V3 requires 2-D mp matrices"); endif [m, n] = size (a); if (m != n) certificate.status = "UNSUPPORTED_RECTANGULAR"; certificate.reason = "Neumann inverse route requires a square matrix"; return; endif if (size (x, 1) != n || size (x, 2) != n) error ("mplapack:svt:InverseShape", "approximate inverse has the wrong shape"); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (q); svt_v0_contract (q); aq = svt_iv ("matrix_point", a, q); xq = svt_iv ("matrix_point", x, q); identity = svt_iv ("matrix_point", mp (eye (n)), q); residual = svt_iv ("matrix_sub", identity, svt_iv ("matrix_mul", aq, xq)); r = svt_iv ("matrix_fro_upper", residual); certificate.residual = r; certificate.input_shape = [m, n]; certificate.inverse_source_precision = __mplapack_core__ ("value_shape_info", x).precision_bits; if (r.hi >= mp (1)) certificate.status = "INCONCLUSIVE"; certificate.reason = "verified residual does not satisfy r<1"; clear cleanup; return; endif x_norm = svt_iv ("matrix_fro_upper", xq); column_lower = svt_iv ("matrix_column_lower", xq); x_lower = column_lower(1); for index = 2:numel (column_lower) if (column_lower(index) > x_lower), x_lower = column_lower(index); endif endfor certificate.x_norm_upper = x_norm; certificate.x_column_lower = column_lower; certificate.x_norm_lower = x_lower; if (x_norm.hi == mp (0)) certificate.status = "INCONCLUSIVE"; certificate.reason = "inverse norm upper bound is zero"; clear cleanup; return; endif one = svt_iv ("point", mp (1), q); one_minus_r = svt_iv ("sub", one, r); one_plus_r = svt_iv ("add", one, r); sigma_lower = svt_iv ("div", one_minus_r, x_norm).lo; certificate.sigma_min_lower = sigma_lower; certificate.inverse_norm_lower = svt_iv ("div", ... svt_iv ("point", x_lower, q), one_plus_r).lo; if (x_lower > mp (0)) certificate.inverse_norm_upper = svt_iv ("div", one_plus_r, ... svt_iv ("point", x_lower, q)).hi; certificate.inverse_norm_upper_status = "FINITE"; else certificate.inverse_norm_upper = []; certificate.inverse_norm_upper_status = "UNAVAILABLE_ZERO_COLUMN_LOWER"; endif certificate.status = "CERTIFIED"; certificate.claim = "A is nonsingular and sigma_min(A) has a positive verified lower bound"; clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_phase_diagonal.m0000644000230300031750000000111615274353472025544 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function diagonal = svt_phase_diagonal (n) ## Exact quarter-turn diagonal phases [1,i,-1,-i,...]. if (! isnumeric (n) || ! isscalar (n) || n != fix (n) || n < 1) error ("mplapack:svt:InvalidPhaseSize", "phase size must be positive"); endif diagonal = mp (complex (zeros (n, n), zeros (n, n))); phases = cell (1, 4); phases{1} = mp ('1', '0'); phases{2} = mp ('0', '1'); phases{3} = mp ('-1', '0'); phases{4} = mp ('0', '-1'); for index = 1:n diagonal(index, index) = phases{mod (index - 1, 4) + 1}; endfor endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_write_profile_artifacts.m0000644000230300031750000002375715274353472027537 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function artifacts = svt_write_profile_artifacts (results, profile_data, output_dir) ## Write the versioned, exact-evidence result bundle. Numeric display columns ## are conveniences; certificates and factor snapshots remain exact V4 data. if (exist (output_dir, "file") == 2 || exist (output_dir, "dir") != 7) error ("mplapack:svt:OutputDirectoryExists", ... "artifact writer requires a newly created output directory"); endif directory_entries = dir (output_dir); entry_names = {directory_entries.name}; entry_names = entry_names(! strcmp (entry_names, ".") ... & ! strcmp (entry_names, "..")); if (! isempty (entry_names)) error ("mplapack:svt:OutputDirectoryExists", ... "artifact writer refuses a nonempty output directory"); endif q = profile_data.evaluation_bits; if (results.plot) plots_dir = fullfile (output_dir, "plots"); if (! mkdir (plots_dir)) error ("mplapack:svt:PlotDirectory", "could not create plots directory"); endif svt_write_plots (results.rows, plots_dir); endif write_summary_tsv (fullfile (output_dir, "summary.tsv"), results); write_values_tsv (fullfile (output_dir, "singular-values.tsv"), results.rows); write_verification_tsv (fullfile (output_dir, "verification.tsv"), results.certificates); safe_certificates = cell (numel (results.certificates), 1); for index = 1:numel (results.certificates) safe_certificates{index} = svt_json_safe (results.certificates{index}, q); endfor write_json (fullfile (output_dir, "certificates.json"), ... struct ("schema", "svt-v1", "profile", results.profile, ... "certificates", {safe_certificates})); safe_rows = cell (numel (results.rows), 1); for index = 1:numel (results.rows) row = results.rows{index}; summary = struct ("schema", row.schema, "case_id", row.case_id, ... "tier", row.tier, "family", row.family, ... "mode", row.mode, "native", row.native, ... "precision_role", row.precision_role, ... "work_bits", row.work_bits, ... "input_shape", row.input_shape, ... "input_precision_bits", row.input_precision_bits, ... "evaluation_bits", row.evaluation_bits, ... "status", row.status, "svd_seconds", row.svd_seconds, ... "values", svt_json_safe (row.values, row.input_precision_bits)); if (isfield (row, "metrics")) summary.metrics = svt_json_safe (row.metrics, q); endif if (isfield (row, "reference_absolute_max")) summary.reference_absolute_max = svt_json_safe (... row.reference_absolute_max, q); endif safe_rows{index} = summary; endfor write_json (fullfile (output_dir, "summary.json"), ... struct ("schema", "svt-v1", "profile", results.profile, ... "rows", {safe_rows})); snapshots = {}; for index = 1:numel (results.rows) row = results.rows{index}; if (! row.native && strcmp (row.mode, "econ") ... && row.work_bits == profile_data.work_bits(end)) snapshots{end + 1} = struct ("schema", "svt-input-factor-record-v1", ... "case_id", row.case_id, "tier", row.tier, ... "family", row.family, "work_bits", row.work_bits, ... "evaluation_bits", q, ... "input", svt_serialize_mp_array (row.input_snapshot, row.work_bits), ... "U", svt_serialize_mp_array (row.U, row.work_bits), ... "S", svt_serialize_mp_array (row.S, row.work_bits), ... "V", svt_serialize_mp_array (row.V, row.work_bits)); endif endfor write_json (fullfile (output_dir, "inputs-and-factors.json"), ... struct ("schema", "svt-v1", "profile", results.profile, ... "records", {snapshots}, "replay", ... "replay exact snapshots with the V4 decoder before checking certificates")); environment_path = fullfile (output_dir, "environment.txt"); write_environment (environment_path, results, profile_data); report_path = fullfile (output_dir, "report.md"); write_report (report_path, results); names = {"summary.tsv", "singular-values.tsv", "verification.tsv", ... "certificates.json", "summary.json", "inputs-and-factors.json", ... "environment.txt", "report.md"}; if (results.plot), names{end + 1} = "plots"; endif artifacts = cell (numel (names), 1); for index = 1:numel (names) path_name = fullfile (output_dir, names{index}); artifacts{index} = struct ("name", names{index}, "path", path_name, ... "sha256", path_hash (path_name), ... "bytes", path_bytes (path_name)); endfor endfunction function write_summary_tsv (path_name, results) fid = fopen (path_name, "w"); require_file (fid, path_name); fprintf (fid, "case_id\ttier\tfamily\tmode\tnative\twork_bits\tshape\tinput_bits\tstatus\tseconds\n"); for index = 1:numel (results.rows) row = results.rows{index}; shape = sprintf ("%dx%d", row.input_shape(1), row.input_shape(2)); fprintf (fid, "%s\t%s\t%s\t%s\t%d\t%d\t%s\t%d\t%s\t%.9g\n", ... row.case_id, row.tier, row.family, row.mode, row.native, ... row.work_bits, shape, row.input_precision_bits, row.status, ... row.svd_seconds); endfor fclose (fid); endfunction function write_values_tsv (path_name, rows) fid = fopen (path_name, "w"); require_file (fid, path_name); fprintf (fid, "case_id\tmode\tnative\twork_bits\tindex\tvalue\n"); for row_index = 1:numel (rows) row = rows{row_index}; for value_index = 1:numel (row.values) fprintf (fid, "%s\t%s\t%d\t%d\t%d\t%s\n", row.case_id, row.mode, ... row.native, row.work_bits, value_index, display_value (row.values(value_index))); endfor endfor fclose (fid); endfunction function write_verification_tsv (path_name, jobs) fid = fopen (path_name, "w"); require_file (fid, path_name); fprintf (fid, "case_id\ttier\tmethod\tstatus\tgate_ok\tmeets_accuracy_target\tnotes\n"); for index = 1:numel (jobs) job = jobs{index}; fprintf (fid, "%s\t%s\t%s\t%s\t%d\t%d\t%s\n", job.case_id, job.tier, ... job.method, job.status, job.gate_ok, ... job.certificate.meets_accuracy_target, job.notes); endfor fclose (fid); endfunction function write_json (path_name, value) fid = fopen (path_name, "w"); require_file (fid, path_name); fwrite (fid, jsonencode (value)); fwrite (fid, "\n"); fclose (fid); endfunction function write_environment (path_name, results, profile_data) fid = fopen (path_name, "w"); require_file (fid, path_name); fprintf (fid, "schema=svt-v1\nprofile=%s\ntier=%s\noctave=%s\n", ... results.profile, results.tier, version ()); fprintf (fid, "work_bits=%s\nreference_bits=%s\nevaluation_bits=%d\n", ... vector_text (profile_data.work_bits), vector_text (profile_data.reference_bits), ... profile_data.evaluation_bits); fprintf (fid, "native_rows_are_explicit=true\nmp_numeric_evidence=exact_v4_snapshots\n"); fprintf (fid, "paper_algorithm_reproduction=false\nmodule_resolution=source-tree src/__mplapack_core__.oct plus inst\n"); fclose (fid); endfunction function write_report (path_name, results) fid = fopen (path_name, "w"); require_file (fid, path_name); fprintf (fid, "# SVT %s artifact report\n\n", results.profile); fprintf (fid, "- schema: `svt-v1`\n- tier: `%s`\n- status: `%s`\n", ... results.tier, results.status); fprintf (fid, "- measured SVD rows: `%d/%d`\n- references: `%d`\n- V jobs: `%d`\n", ... results.measured_svd_rows, results.expected_svd_rows, ... results.reference_job_count, results.v_job_count); fprintf (fid, "- `plot=false` execution is headless and produces no plots.\n\n"); fprintf (fid, "All values in `certificates.json` and `inputs-and-factors.json` are exact MPFR/MPC V4 snapshots; TSV values are display fields.\n\n"); fprintf (fid, "## Verification jobs\n\n| Case | Tier | Method | Status | Gate | Target |\n|---|---|---|---|---:|---:|\n"); for index = 1:numel (results.certificates) job = results.certificates{index}; fprintf (fid, "| %s | %s | `%s` | `%s` | %d | %d |\n", job.case_id, ... job.tier, job.method, job.status, job.gate_ok, ... job.certificate.meets_accuracy_target); endfor fclose (fid); endfunction function svt_write_plots (rows, plots_dir) ## Presentation-only conversion; no plotted value is fed back to a gate. try figure ("visible", "off"); hold on; for index = 1:numel (rows) row = rows{index}; if (! row.native && strcmp (row.mode, "values")) semilogy (1:numel (row.values), double (row.values), ".-"); endif endfor hold off; print (fullfile (plots_dir, "singular-values.png"), "-dpng"); close all; catch exception close all; error ("mplapack:svt:PlotFailure", "presentation plot failed: %s", exception.message); end_try_catch endfunction function text = display_value (value) if (isa (value, "mp")), text = char (value); else, text = sprintf ("%.17g", value); endif endfunction function text = vector_text (value) text = ""; for index = 1:numel (value) if (index > 1) text = [text, ","]; endif entry = value(index); entry = double (entry); formatted = sprintf ("%d", entry); text = [text, formatted]; endfor endfunction function require_file (fid, path_name) if (fid < 0), error ("mplapack:svt:ArtifactWrite", "cannot write %s", path_name); endif endfunction function digest = path_hash (path_name) digest = hash ("sha256", fileread (path_name)); endfunction function bytes = path_bytes (path_name) info = dir (path_name); if (isempty (info)), bytes = 0; else, bytes = info.bytes; endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_metrics.m0000644000230300031750000000433415274353472024261 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function metrics = svt_metrics (input, u, s, v, evaluation_bits) ## Reevaluate ordinary residual/orthogonality diagnostics at q from widened ## returned values. These are diagnostics, not Tier V certificates. if (isempty (evaluation_bits)) input_info = __mplapack_core__ ("value_shape_info", input); evaluation_bits = max ([input_info.precision_bits, 64]); endif aq = svt_widen (input, evaluation_bits); uq = svt_widen (u, evaluation_bits); sq = svt_widen (s, evaluation_bits); vq = svt_widen (v, evaluation_bits); saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (evaluation_bits); [m, n] = size (aq); k = min (m, n); identity_u = mp (eye (k)); identity_v = mp (eye (k)); reconstruction = aq - uq * sq * vq'; right_triplet = aq * vq - uq * sq; left_triplet = aq' * uq - vq * sq; orth_u = uq' * uq - identity_u; orth_v = vq' * vq - identity_v; norm_a = norm (aq, "fro"); reconstruction_abs = norm (reconstruction, "fro"); right_abs = norm (right_triplet, "fro"); left_abs = norm (left_triplet, "fro"); orth_u_abs = norm (orth_u, "fro"); orth_v_abs = norm (orth_v, "fro"); metrics = struct (); metrics.evaluation_bits = evaluation_bits; metrics.norm_A = norm_a; metrics.reconstruction = reconstruction_abs; metrics.triplet_R = right_abs; metrics.triplet_L = left_abs; metrics.orthogonality_U = orth_u_abs; metrics.orthogonality_V = orth_v_abs; metrics.sigma_max = sq(1, 1); metrics.sigma_min = sq(k, k); metrics.zero_norm_branch = (norm_a == mp (0)); if (metrics.zero_norm_branch) metrics.rho_rec = mp (0); metrics.rho_R = mp (0); metrics.rho_L = mp (0); metrics.status = "ZERO_NORM_ABSOLUTE_DIAGNOSTICS"; else metrics.rho_rec = reconstruction_abs / norm_a; metrics.rho_R = right_abs / (norm_a * norm (vq, "fro")); metrics.rho_L = left_abs / (norm_a * norm (uq, "fro")); metrics.status = "PASS"; endif u_shape = size (uq); s_shape = size (sq); v_shape = size (vq); metrics.factor_shapes = [u_shape; s_shape; v_shape]; u_real = isreal (uq); s_real = isreal (sq); v_real = isreal (vq); metrics.factor_real = [u_real, s_real, v_real]; clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_certify_projector.m0000644000230300031750000001130015274353472026336 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function certificate = svt_certify_projector (a, u, s, v, q, indices) ## V1b signed-dilation positive-cluster projector certificate. value_certificate = svt_certify_values (a, u, s, v, q); certificate = value_certificate; certificate.schema = "svt-v1b-projector-certificate-v1"; certificate.method = "svt_dilation_projector_v1"; certificate.cluster_indices = indices(:).'; certificate.projector_status = "INCONCLUSIVE"; if (! strcmp (value_certificate.status, "CERTIFIED")) certificate.reason = "V1a value certificate is unavailable"; return; endif k = min (size (a)); indices = indices(:).'; if (isempty (indices) || any (indices < 1) || any (indices > k) ... || any (indices != fix (indices)) || numel (unique (indices)) != numel (indices)) error ("mplapack:svt:ProjectorIndices", "cluster indices are invalid"); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (q); target_positive = true; for index = indices if (value_certificate.values_lower(index) <= mp (0)) target_positive = false; endif endfor certificate.target_positive = target_positive; if (! target_positive) certificate.reason = "target cluster has no certified positive lower endpoint"; certificate.status = "INCONCLUSIVE"; clear cleanup; return; endif ## Build the separation of target +/-s_j from every complementary dilation ## eigenvalue. All differences and sums are interval operations. delta_lower = []; complement_count = 0; for target = indices target_point = svt_iv ("point", s(target, target), q); for other = 1:k if (! any (indices == other) && s(other, other) >= mp (0)) other_point = svt_iv ("point", s(other, other), q); difference = svt_iv ("sub", target_point, other_point); candidate = interval_abs_lower (difference); delta_lower = append_minimum (delta_lower, candidate); complement_count = complement_count + 1; endif ## The negative branch contains -s_other, including the target itself. other_point = svt_iv ("point", s(other, other), q); sum_value = svt_iv ("add", target_point, other_point); delta_lower = append_minimum (delta_lower, sum_value.lo); complement_count = complement_count + 1; endfor if (size (a, 1) != size (a, 2)) delta_lower = append_minimum (delta_lower, target_point.lo); complement_count = complement_count + 1; endif endfor certificate.complement_count = complement_count; certificate.delta_lower = delta_lower; certificate.cluster_size = numel (indices); epsilon_upper = value_certificate.epsilon.hi; certificate.epsilon_upper = epsilon_upper; if (isempty (delta_lower)) ## The full square dilation is exhausted by the selected +/- cluster. b_sub = svt_iv ("point", mp (0), q); certificate.delta_trivial = true; else certificate.delta_trivial = false; if (delta_lower <= mp (2) * epsilon_upper) certificate.reason = "external dilation gap is not greater than 2*epsilon"; certificate.status = "INCONCLUSIVE"; clear cleanup; return; endif delta = svt_iv ("point", delta_lower, q); rank_interval = svt_iv ("point", mp (numel (indices)), q); numerator = svt_iv ("mul", svt_iv ("point", mp (2), q), ... svt_iv ("sqrt", rank_interval)); denominator = svt_iv ("sub", delta, value_certificate.epsilon); b_sub = svt_iv ("div", svt_iv ("mul", numerator, value_certificate.epsilon), denominator); endif one = svt_iv ("point", mp (1), q); correction_u = svt_iv ("mul", svt_iv ("add", ... svt_iv ("sqrt", svt_iv ("add", one, value_certificate.gU)), one), ... value_certificate.dU); correction_v = svt_iv ("mul", svt_iv ("add", ... svt_iv ("sqrt", svt_iv ("add", one, value_certificate.gV)), one), ... value_certificate.dV); certificate.b_sub = b_sub; certificate.bU = svt_iv ("add", b_sub, correction_u); certificate.bV = svt_iv ("add", b_sub, correction_v); certificate.projector_status = "CERTIFIED"; certificate.status = "CERTIFIED"; certificate.claim = "raw-factor cluster projectors are enclosed by bU/bV"; clear cleanup; endfunction function lower = interval_abs_lower(interval) if (interval.lo <= mp (0) && interval.hi >= mp (0)) lower = mp (0); else left = abs (interval.lo); right = abs (interval.hi); lower = left; if (right < lower), lower = right; endif endif endfunction function current = append_minimum(current, candidate) if (isempty (current) || candidate < current) current = candidate; endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_dd_path.m0000644000230300031750000001046515274353472025215 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_dd_path (case_id, parameters, work_bits) ## Construct the symmetric or nonsymmetric diagonally-dominant path pair. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters)) error ("mplapack:svt:InvalidDdRequest", "invalid DD path request"); endif required_fields = {"n", "b", "rho_num", "rho_den"}; for index = 1:numel (required_fields) if (! isfield (parameters, required_fields{index})) error ("mplapack:svt:InvalidDdParameters", ... "DD parameters lack field %s", required_fields{index}); endif endfor n = parameters.n; b = parameters.b; rho_num = parameters.rho_num; rho_den = parameters.rho_den; if (! isnumeric (n) || ! isscalar (n) || n != fix (n) || n < 2 ... || ! isnumeric (b) || ! isscalar (b) || b != fix (b) || b < 1 ... || ! isnumeric (rho_num) || ! isscalar (rho_num) || rho_num <= 0 ... || ! isnumeric (rho_den) || ! isscalar (rho_den) || rho_den <= 0 ... || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidDdParameters", "invalid DD integer parameters"); endif required_bits = b + 2; below_guard = work_bits < required_bits; allow_below_guard = isfield (parameters, "allow_below_guard") ... && parameters.allow_below_guard; if (below_guard && ! allow_below_guard) error ("mplapack:svt:InsufficientConstructionPrecision", ... "DD path is below its exact tau guard"); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); tau = svt_pow2 (-b); rho = mp (rho_num) / mp (rho_den); represented = svt_dd_matrix (n, tau, rho); represented_tau = represented(1, 1) - mp (1); represented_tau_lost = (represented_tau == mp (0)); model_bits = max ([work_bits, required_bits]); mpbits (model_bits); exact_tau = svt_pow2 (-b); exact_rho = mp (rho_num) / mp (rho_den); model = svt_dd_matrix (n, exact_tau, exact_rho); symmetric = rho_num == rho_den; analytic_values = []; if (symmetric) pi_value = acos (mp (-1)); analytic_values = mp (zeros (n, 1)); for index = 1:n k = index - 1; if (k == 0) analytic_values(index) = exact_tau; else angle = mp (k) * pi_value / (mp (2) * mp (n)); sine = sin (angle); analytic_values(index) = exact_tau + mp (4) * sine * sine; endif endfor endif tau0_leading = mp (ones (n - 1, 1)); tau0_full = mp (0); if (symmetric) kind = "symmetric"; else kind = "nonsymmetric"; endif exactness = "exact_dyadic"; if (below_guard) exactness = "rounded_tau_loss_at_declared_guard"; endif notes = ["DD path ", kind, "; nonsymmetric path does not identify tau as sigma_min"]; identity = svt_case_identity (case_id, "dd_path", model, represented, ... work_bits, exactness, notes); result = struct ("id", case_id, "tier", "S", "family", "dd_path", ... "parameters", parameters, "n", n, "b", b, ... "rho", rho, "tau", exact_tau, "represented_tau", represented_tau, ... "model", model, "A", represented, "analytic_values", analytic_values, ... "rank", n, "full_rank", true, "det_model", [], ... "symmetric", symmetric, "construction_guard_bits", required_bits, ... "below_guard", below_guard, "allow_below_guard", allow_below_guard, ... "represented_tau_lost", represented_tau_lost, ... "tau0_leading_principal_determinants", tau0_leading, ... "tau0_full_determinant", tau0_full, "identity", identity, ... "status", "CONSTRUCTED"); if (below_guard && represented_tau_lost) result.represented_rank_proof = "tau=0 tridiagonal recurrence: leading minors 1, full determinant 0"; else result.represented_rank_proof = "not applicable: represented tau retained"; endif clear cleanup; endfunction function matrix = svt_dd_matrix (n, tau, rho) one = mp (1); matrix = mp (zeros (n, n)); matrix(1, 1) = one + tau; matrix(1, 2) = -one; for index = 2:(n - 1) matrix(index, index - 1) = -rho; matrix(index, index) = one + rho + tau; matrix(index, index + 1) = -one; endfor matrix(n, n - 1) = -rho; matrix(n, n) = rho + tau; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_run_profile.m0000644000230300031750000003775215274353472025151 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function results = svt_run_profile (profile_data, profile_name, tier, plot_enabled) ## Execute the complete measured profile and its separate reference/V jobs. ## Native rows are explicit comparison rows; they never feed an MP solve. saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); selected = profile_data.cases; if (! strcmp (tier, "all")) selected = selected(strcmp ({selected.tier}, tier)); endif work_bits = profile_data.work_bits; modes = profile_data.modes; expected_rows = numel (selected) * (numel (work_bits) + ... double (profile_data.native)) * numel (modes); rows_out = {}; high_fixtures = cell (numel (selected), 1); high_econ = cell (numel (selected), 1); for case_index = 1:numel (selected) case_data = selected(case_index); for work_index = 1:numel (work_bits) bits = work_bits(work_index); fixture = svt_build_case (case_data, bits); if (work_index == numel (work_bits)) high_fixtures{case_index} = fixture; endif for mode_index = 1:numel (modes) mode = char (modes{mode_index}); measured = svt_run_svd (fixture.A, mode, profile_data.evaluation_bits); measured.case_id = char (case_data.id); measured.tier = char (case_data.tier); measured.family = char (case_data.family); measured.work_bits = bits; measured.precision_role = "MP"; measured.native = false; measured.fixture_identity = fixture.identity; measured.input_snapshot = fixture.A; rows_out{end + 1} = measured; if (work_index == numel (work_bits) && strcmp (mode, "econ")) high_econ{case_index} = measured; endif endfor endfor if (profile_data.native) fixture = high_fixtures{case_index}; for mode_index = 1:numel (modes) mode = char (modes{mode_index}); native = svt_run_native_svd (fixture.A, mode); native.case_id = char (case_data.id); native.tier = char (case_data.tier); native.family = char (case_data.family); native.work_bits = 0; native.precision_role = "EXPLICIT_NATIVE_COMPARISON"; native.fixture_identity = fixture.identity; rows_out{end + 1} = native; endfor endif endfor ## References are separate from measured rows and use the frozen represented ## input at each reference precision. references = {}; for case_index = 1:numel (selected) case_data = selected(case_index); case_references = {}; for reference_index = 1:numel (profile_data.reference_bits) reference_bits = profile_data.reference_bits(reference_index); fixture = svt_build_case (case_data, reference_bits); mpbits (reference_bits); reference = svt_reference (fixture.A, reference_bits); reference.case_id = char (case_data.id); reference.family = char (case_data.family); reference.reference_role = "SEPARATE_REFERENCE"; case_references{end + 1} = reference; endfor high_reference = case_references{end}; for row_index = 1:numel (rows_out) row = rows_out{row_index}; if (! row.native && strcmp (row.case_id, case_data.id) ... && row.work_bits == work_bits(end)) row.reference_bits = profile_data.reference_bits; row.reference_status = "consistent_reference"; row.reference_absolute_max = max (abs (svt_widen (row.values, ... high_reference.input_precision_bits) ... - high_reference.values)); rows_out{row_index} = row; endif endfor references{end + 1} = case_references; endfor target_bits = 60; if (strcmp (profile_name, "demo")), target_bits = 80; endif certificates = {}; ## V1a is run for every highest-work-precision economy row. for case_index = 1:numel (selected) fixture = high_fixtures{case_index}; row = high_econ{case_index}; certificate = svt_certify_values (fixture.A, row.U, row.S, row.V, ... profile_data.evaluation_bits); certificate.meets_accuracy_target = svt_value_target (certificate, ... target_bits); job = svt_job (row.case_id, "V1A", certificate.method, ... certificate.status, certificate.meets_accuracy_target, ... certificate, "highest-work-precision economy row"); certificates{end + 1} = job; endfor ## Selected native inputs are certified separately after explicit conversion. if (strcmp (profile_name, "demo") && strcmp (tier, "all")) native_names = {"S1-NRO-TWO", "A5-GEO", "S4-DD-SYM"}; for name_index = 1:numel (native_names) case_index = find (strcmp ({selected.id}, native_names{name_index}), 1); if (isempty (case_index)), continue; endif fixture = high_fixtures{case_index}; mpbits (profile_data.evaluation_bits); native_input = mp (double (fixture.A)); [native_u, native_s, native_v] = svd (native_input, "econ"); certificate = svt_certify_values (native_input, native_u, native_s, ... native_v, profile_data.evaluation_bits); certificate.meets_accuracy_target = svt_value_target (certificate, ... target_bits); job = svt_job (native_names{name_index}, "V1A-NATIVE", ... certificate.method, certificate.status, ... certificate.meets_accuracy_target, certificate, ... "selected frozen native input; explicit MP conversion"); certificates{end + 1} = job; endfor endif ## V1b positive cluster jobs. Internal multiplicity is permitted; only the ## external signed-dilation separation may make the result inconclusive. for case_index = 1:numel (selected) fixture = high_fixtures{case_index}; row = high_econ{case_index}; indices = []; if (isfield (fixture, "cluster_indices")) indices = fixture.cluster_indices; elseif (strcmp (fixture.family, "lauchli")) k = min (size (fixture.A)); if (k >= 2), indices = 2:k; endif endif if (! isempty (indices)) certificate = svt_certify_projector (fixture.A, row.U, row.S, row.V, ... profile_data.evaluation_bits, indices); certificate.meets_accuracy_target = ... strcmp (certificate.projector_status, "CERTIFIED") ... && certificate.bU.hi <= svt_pow2 (-target_bits) ... && certificate.bV.hi <= svt_pow2 (-target_bits); job = svt_job (row.case_id, "V1B", certificate.method, ... certificate.projector_status, ... certificate.meets_accuracy_target, certificate, ... "positive singular cluster projector"); certificates{end + 1} = job; endif endfor ## V2 simple-factor jobs cover a nontrivial rectangular real/complex pair, ## in addition to the named geometric Hadamard and graded NRO fixtures. factor_names = {"A5-GEO", "S1-NRO-GRADED"}; for name_index = 1:numel (factor_names) case_index = find (strcmp ({selected.id}, factor_names{name_index}), 1); if (isempty (case_index)), continue; endif fixture = high_fixtures{case_index}; row = high_econ{case_index}; k = min (size (fixture.A)); certificate = svt_certify_factor_boxes (fixture.A, row.U, row.S, row.V, ... profile_data.evaluation_bits, 1:k); certificate.meets_accuracy_target = svt_factor_target (certificate, ... target_bits); job = svt_job (row.case_id, "V2", certificate.method, certificate.status, ... certificate.meets_accuracy_target, certificate, ... "named positive separated factor fixture"); certificates{end + 1} = job; endfor if (strcmp (tier, "all")) [simple_real, simple_complex] = svt_simple_factor_inputs (profile_data.evaluation_bits); simple_inputs = {simple_real, simple_complex}; simple_names = {"V2-SIMPLE-REAL", "V2-SIMPLE-COMPLEX"}; for simple_index = 1:2 input = simple_inputs{simple_index}; [u, s, v] = svd (input, "econ"); certificate = svt_certify_factor_boxes (input, u, s, v, ... profile_data.evaluation_bits); certificate.meets_accuracy_target = svt_factor_target (certificate, ... target_bits); job = svt_job (simple_names{simple_index}, "V2", certificate.method, ... certificate.status, certificate.meets_accuracy_target, ... certificate, "separate 3-by-2 simple factor control"); certificates{end + 1} = job; endfor endif ## V3 positive inverse checks use public solve outputs. Negative controls are ## recorded as INCONCLUSIVE/UNSUPPORTED, never as a singularity proof. inverse_names = {"S1-NRO-TWO", "A6-NRO-COMPANION", "S4-DD-SYM"}; for name_index = 1:numel (inverse_names) case_index = find (strcmp ({selected.id}, inverse_names{name_index}), 1); if (isempty (case_index)), continue; endif fixture = high_fixtures{case_index}; q = profile_data.evaluation_bits; mpbits (q); input = svt_widen (fixture.A, q); identity = mp (eye (rows (input))); inverse = input \ identity; certificate = svt_certify_inverse (input, inverse, q); certificate.meets_accuracy_target = strcmp (certificate.status, "CERTIFIED") ... && certificate.residual.hi < mp (1) ... && certificate.sigma_min_lower > mp (0); job = svt_job (inverse_names{name_index}, "V3", certificate.method, ... certificate.status, certificate.meets_accuracy_target, ... certificate, "public solve output inverse verification"); certificates{end + 1} = job; endfor if (strcmp (tier, "all")) bad_case_index = find (strcmp ({selected.id}, "A5-RANK4"), 1); if (! isempty (bad_case_index)) fixture = high_fixtures{bad_case_index}; q = profile_data.evaluation_bits; mpbits (q); bad = svt_certify_inverse (fixture.A, mp (eye (rows (fixture.A))), q); bad.meets_accuracy_target = ! strcmp (bad.status, "CERTIFIED"); certificates{end + 1} = svt_job (fixture.id, "V3-NEGATIVE-SINGULAR", ... bad.method, bad.status, ... bad.meets_accuracy_target, bad, ... "rank-deficient negative control"); endif poor_input = mp (eye (3)); poor_inverse = mp (zeros (3, 3)); bad = svt_certify_inverse (poor_input, poor_inverse, profile_data.evaluation_bits); bad.meets_accuracy_target = ! strcmp (bad.status, "CERTIFIED"); certificates{end + 1} = svt_job ("V3-POOR-INVERSE", "V3-NEGATIVE-POOR", ... bad.method, bad.status, ... bad.meets_accuracy_target, bad, ... "zero approximate inverse negative control"); rectangular = high_fixtures{find (strcmp ({selected.id}, "A4-LAU-TALL"), 1)}; rectangular_inverse = mp (zeros (rows (rectangular.A), columns (rectangular.A))); bad = svt_certify_inverse (rectangular.A, rectangular_inverse, ... profile_data.evaluation_bits); bad.meets_accuracy_target = strcmp (bad.status, "UNSUPPORTED_RECTANGULAR"); certificates{end + 1} = svt_job (rectangular.id, "V3-NEGATIVE-RECTANGULAR", ... bad.method, bad.status, ... bad.meets_accuracy_target, bad, ... "rectangular inverse route is unsupported"); endif all_rows_pass = true; for index = 1:numel (rows_out) all_rows_pass = all_rows_pass && strcmp (rows_out{index}.status, "PASS"); endfor all_jobs_pass = true; for index = 1:numel (certificates) all_jobs_pass = all_jobs_pass && certificates{index}.gate_ok; endfor results = struct (); results.schema = "svt-v1"; results.profile = profile_name; results.tier = tier; results.plot = plot_enabled; results.rows = rows_out; results.references = references; results.certificates = certificates; results.measured_svd_rows = numel (rows_out); results.expected_svd_rows = expected_rows; results.reference_job_count = numel (selected) * numel (profile_data.reference_bits); results.v_job_count = numel (certificates); results.coverage = struct ("cases", numel (selected), "expected_cases", ... numel (selected), "svd_rows", numel (rows_out), ... "expected_svd_rows", expected_rows, ... "references", results.reference_job_count, ... "v_jobs", results.v_job_count); results.scope_ok = svt_check_coverage (rows_out, expected_rows); results.ok = results.scope_ok && all_rows_pass && all_jobs_pass ... && strcmp (tier, "all"); if (results.ok) results.status = "PASS"; results.message = "complete measured profile and mandatory V jobs passed"; elseif (results.scope_ok && all_rows_pass && all_jobs_pass) results.status = "PASS"; results.message = "selected tier passed; tier-only run is not full-suite PASS"; else results.status = "FAIL"; results.message = "a measured row, coverage gate, or mandatory V job failed"; endif results.environment = struct ("octave", version (), "entry_mpbits", saved_bits, ... "evaluation_bits", profile_data.evaluation_bits, ... "native_rows_are_explicit", true, ... "paper_algorithm_reproduction", false); clear cleanup; endfunction function job = svt_job (case_id, tier, method, status, gate_ok, certificate, notes) job = struct ("schema", "svt-verification-job-v1", "case_id", case_id, ... "tier", tier, "method", method, "status", status, ... "gate_ok", logical (gate_ok), "notes", notes, ... "paper_algorithm_reproduction", false, "certificate", certificate); endfunction function good = svt_value_target (certificate, target_bits) good = strcmp (certificate.status, "CERTIFIED"); if (! good), return; endif lower = certificate.values_lower; upper = certificate.values_upper; scale = certificate.values_upper(1); tolerance = svt_pow2 (-target_bits); for index = 1:numel (lower) width = upper(index) - lower(index); if (lower(index) > mp (0)) good = good && width / lower(index) <= tolerance; else good = good && width <= scale * tolerance; endif endfor endfunction function good = svt_factor_target (certificate, target_bits) if (strcmp (certificate.status, "UNSUPPORTED_MULTIPLICITY")) ## The repeated-pair part is intentionally not an individual-factor claim. good = true; for index = 1:numel (certificate.individual_status) state = certificate.individual_status{index}; good = good && any (strcmp (state, {"CERTIFIED", "UNSUPPORTED_MULTIPLICITY"})); endfor return; endif good = strcmp (certificate.status, "CERTIFIED"); if (! good), return; endif tolerance = svt_pow2 (-target_bits); for index = 1:numel (certificate.individual_status) good = good && strcmp (certificate.individual_status{index}, "CERTIFIED"); endfor if (isfield (certificate, "dU")) good = good && certificate.dU.hi <= tolerance ... && certificate.dV.hi <= tolerance; endif endfunction function [real_input, complex_input] = svt_simple_factor_inputs (q) saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (q); real_input = mp (zeros (3, 2)); real_input(1, 1) = mp (4); real_input(2, 2) = mp (2); real_input(3, 2) = mp ("0.5"); left_phase = svt_phase_diagonal (3); complex_input = left_phase * real_input; clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_json_safe.m0000644000230300031750000000263115274353472024560 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function output = svt_json_safe (value, q, method) ## Convert an in-memory result tree to JSON-safe data. MP values use V4 ## exact snapshots; ordinary native values remain explicitly native data. if (nargin < 3), method = "svt_exact_dyadic_v1"; endif if (isa (value, "mp")) output = svt_serialize_mp_array (value, q, method); elseif (isstruct (value)) if (numel (value) != 1) output = cell (numel (value), 1); for index = 1:numel (value) output{index} = svt_json_safe (value(index), q, method); endfor else names = fieldnames (value); output = struct (); for index = 1:numel (names) name = names{index}; output.(name) = svt_json_safe (value.(name), q, method); endfor endif elseif (iscell (value)) output = cell (numel (value), 1); for index = 1:numel (value) output{index} = svt_json_safe (value{index}, q, method); endfor elseif (ischar (value) || islogical (value) || isstring (value) ... || (isnumeric (value) && isreal (value))) output = value; elseif (isnumeric (value) && ! isreal (value)) output = struct ("kind", "native-complex", "real", real (value), ... "imag", imag (value)); elseif (isempty (value)) output = []; else error ("mplapack:svt:JsonValue", "unsupported result value for JSON"); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_v0_contract.m0000644000230300031750000000272415274353472025036 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function contract = svt_v0_contract (q) ## Runtime audit of the scalar assumptions used by the local verifier. if (! isnumeric (q) || ! isscalar (q) || ! isfinite (q) || q != fix (q) ... || q < 64 || q > 4096) error ("mplapack:svt:ContractPrecision", ... "Tier V requires 64 <= q <= 4096"); endif saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (q); low_range = svt_pow2 (-32768); high_range = svt_pow2 (32768); primitive_low = svt_pow2 (-8192); primitive_high = svt_pow2 (8192); if (! isfinite (low_range) || ! isfinite (high_range) ... || low_range == mp (0) || high_range == mp (0) ... || low_range * high_range != mp (1) ... || primitive_low == mp (0) || ! isfinite (primitive_high)) error ("mplapack:svt:ContractRange", ... "MPFR backend range audit failed"); endif contract = struct ("schema", "svt-v0-contract-v1", "q", q, ... "rounding", "MPFR_RNDN audited in local source", ... "comparison", "finite MPFR comparison", ... "minimum_primitive", primitive_low, ... "maximum_primitive", primitive_high, ... "backend_minimum", low_range, "backend_maximum", high_range, ... "backend_subnormalization", "not observed in audited range", ... "status", "AUDITED"); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_dyadic_encode.m0000644000230300031750000000511315274353472025361 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function encoded = svt_dyadic_encode (value, q) ## Encode a finite represented MPFR scalar without inspecting its payload. require_encoding_precision (q); if (! isa (value, "mp") || ! isscalar (value) || ! isreal (value)) error ("mplapack:svt:DyadicType", "dyadic encoder expects a real mp scalar"); endif source_signbit = logical (signbit (value)); value = svt_widen (value, q); if (! isfinite (value)) error ("mplapack:svt:DyadicNonfinite", "cannot encode a nonfinite value"); endif if (value == mp (0)) encoded = struct ("sign", 0, "mantissa_hex", "0", "exponent2", 0, ... "zero_signbit", source_signbit); return; endif sign = 1; if (value < mp (0)) sign = -1; endif magnitude = abs (value); lower = -32769; upper = 32769; while (upper - lower > 1) midpoint = fix ((lower + upper) / 2); if (magnitude >= svt_pow2 (midpoint)) lower = midpoint; else upper = midpoint; endif endwhile if (lower < -32768 || lower > 32768) error ("mplapack:svt:DyadicRange", "dyadic exponent exceeds audited range"); endif exponent = lower; scaled = magnitude / svt_pow2 (exponent); bits = repmat ('0', 1, q); for index = 1:q if (scaled >= mp (1)) bits(index) = '1'; scaled = scaled - mp (1); endif scaled = scaled * mp (2); endfor if (scaled != mp (0)) error ("mplapack:svt:DyadicExtraction", ... "represented MP value did not terminate within its precision"); endif last_one = find (bits == '1', 1, "last"); if (isempty (last_one)) error ("mplapack:svt:DyadicExtraction", "nonzero value has no extracted bit"); endif trailing_zeroes = q - last_one; bits = bits(1:last_one); while (mod (numel (bits), 4) != 0) bits = ['0', bits]; endwhile digits = '0123456789abcdef'; mantissa_hex = repmat ('0', 1, numel (bits) / 4); for group = 1:numel (mantissa_hex) nibble = 0; for bit = 1:4 nibble = 2 * nibble + (bits(4 * (group - 1) + bit) == '1'); endfor mantissa_hex(group) = digits(nibble + 1); endfor exponent2 = exponent - (q - 1) + trailing_zeroes; encoded = struct ("sign", sign, "mantissa_hex", mantissa_hex, ... "exponent2", exponent2, "zero_signbit", false); endfunction function require_encoding_precision(q) if (! isnumeric (q) || ! isscalar (q) || ! isfinite (q) || q != fix (q) ... || q < 64 || q > 4096 || mpbits () != q) error ("mplapack:svt:DyadicPrecision", ... "encoder requires ambient precision q in [64,4096]"); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_hadamard.m0000644000230300031750000000123015274353472024344 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [h, g] = svt_hadamard (n) ## Build the Sylvester H and its one-row cyclic downward shift G as dense mp ## matrices. Integer +/-1 entries are exact in every supported precision. if (! isnumeric (n) || ! isreal (n) || ! isscalar (n) ... || ! isfinite (n) || n != fix (n) || n < 1 ... || 2 ^ svt_ceil_log2_integer (n) != n) error ("mplapack:svt:InvalidHadamardSize", ... "Hadamard size must be a positive power of two"); endif h = mp (1); while rows (h) < n h = [h, h; h, -h]; endwhile if (n == 1) g = h; else g = [h(n, :); h(1:n-1, :)]; endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_certify_values.m0000644000230300031750000001130015274353472025626 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function certificate = svt_certify_values (a, u, s, v, q) ## V1a polar/Weyl certificate for all singular values. The SVD factors are ## inputs to this checker; it never invokes SVD internally. certificate = struct ("schema", "svt-v1a-certificate-v1", ... "method", "svt_polar_weyl_v1", "status", "ERROR", ... "paper_algorithm_reproduction", false, "q", q); if (! isa (a, "mp") || ! isa (u, "mp") || ! isa (s, "mp") || ! isa (v, "mp") ... || ndims (a) != 2 || ndims (u) != 2 || ndims (s) != 2 || ndims (v) != 2) error ("mplapack:svt:CertificateInput", "V1a requires 2-D mp inputs"); endif [m, n] = size (a); k = min (m, n); if (m < 1 || n < 1 || q != fix (q) || q < 64 || q > 4096) certificate.status = "UNSUPPORTED_EMPTY"; return; endif if (size (u, 1) != m || size (u, 2) != k ... || size (v, 1) != n || size (v, 2) != k ... || size (s, 1) != k || size (s, 2) != k) error ("mplapack:svt:CertificateShape", "V1a factors do not have economy shapes"); endif if (! isreal (s) || any (any (! isfinite (s))) ... || any (any (! isfinite (u))) || any (any (! isfinite (v)))) error ("mplapack:svt:CertificateInput", "V1a factors must be finite"); endif for row = 1:k if (s(row, row) < mp (0)) error ("mplapack:svt:CertificateInput", "V1a singular values must be nonnegative"); endif for column = 1:k if (row != column && s(row, column) != mp (0)) error ("mplapack:svt:CertificateInput", "V1a S must be diagonal"); endif endfor if (row < k && s(row, row) < s(row + 1, row + 1)) error ("mplapack:svt:CertificateInput", "V1a singular values must be descending"); endif endfor saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (q); svt_v0_contract (q); aq = svt_iv ("matrix_point", a, q); uq = svt_iv ("matrix_point", u, q); sq = svt_iv ("matrix_point", s, q); vq = svt_iv ("matrix_point", v, q); identity = svt_iv ("matrix_point", mp (eye (k)), q); gram_u = svt_iv ("matrix_sub", ... svt_iv ("matrix_mul", svt_iv ("matrix_ctranspose", uq), uq), identity); gram_v = svt_iv ("matrix_sub", ... svt_iv ("matrix_mul", svt_iv ("matrix_ctranspose", vq), vq), identity); reconstruction = svt_iv ("matrix_sub", aq, ... svt_iv ("matrix_mul", ... svt_iv ("matrix_mul", uq, sq), ... svt_iv ("matrix_ctranspose", vq))); g_u = svt_iv ("matrix_fro_upper", gram_u); g_v = svt_iv ("matrix_fro_upper", gram_v); residual = svt_iv ("matrix_fro_upper", reconstruction); certificate.gU = g_u; certificate.gV = g_v; certificate.residual = residual; certificate.input_shape = [m, n]; u_shape = size (u); s_shape = size (s); v_shape = size (v); certificate.factor_shapes = [u_shape; s_shape; v_shape]; a_info = __mplapack_core__ ("value_shape_info", a); u_info = __mplapack_core__ ("value_shape_info", u); s_info = __mplapack_core__ ("value_shape_info", s); v_info = __mplapack_core__ ("value_shape_info", v); certificate.source_precisions = [a_info.precision_bits, u_info.precision_bits, ... s_info.precision_bits, v_info.precision_bits]; if (g_u.lo >= mp (1) || g_v.lo >= mp (1)) certificate.status = "INCONCLUSIVE"; certificate.reason = "raw factor Gram defect is not below one"; clear cleanup; return; endif one = svt_iv ("point", mp (1), q); d_u = svt_iv ("div", g_u, svt_iv ("add", one, ... svt_iv ("sqrt", svt_iv ("sub", one, g_u)))); d_v = svt_iv ("div", g_v, svt_iv ("add", one, ... svt_iv ("sqrt", svt_iv ("sub", one, g_v)))); v_norm = svt_iv ("sqrt", svt_iv ("add", one, g_v)); s_max = svt_iv ("point", s(1, 1), q); epsilon = svt_iv ("add", residual, svt_iv ("mul", s_max, ... svt_iv ("add", svt_iv ("mul", d_u, v_norm), d_v))); certificate.dU = d_u; certificate.dV = d_v; certificate.v_norm = v_norm; certificate.epsilon = epsilon; values_lower = mp (zeros (k, 1)); values_upper = mp (zeros (k, 1)); for index = 1:k singular = svt_iv ("point", s(index, index), q); lower = svt_iv ("sub", singular, epsilon).lo; if (lower < mp (0)), lower = mp (0); endif values_lower(index) = lower; values_upper(index) = svt_iv ("add", singular, epsilon).hi; endfor certificate.values_lower = values_lower; certificate.values_upper = values_upper; certificate.status = "CERTIFIED"; certificate.claim = "every ordered singular value of represented A is enclosed"; clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_make_hadamard_spectrum.m0000644000230300031750000001161115274353472027267 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_make_hadamard_spectrum (case_id, parameters, work_bits) ## Construct the C0 mixed diagonal spectrum cases used by A5. if (nargin != 3 || ! ischar (case_id) || ! isstruct (parameters) ... || ! isfield (parameters, "n") || ! isfield (parameters, "mode")) error ("mplapack:svt:InvalidHadamardSpectrumRequest", ... "invalid Hadamard-spectrum request"); endif n = parameters.n; mode = char (parameters.mode); if (! isnumeric (n) || ! isscalar (n) || n != fix (n) || n < 1 ... || ! any (strcmp (mode, {"geometric", "close", "repeat", "rank4", "rank5"})) ... || work_bits != fix (work_bits)) error ("mplapack:svt:InvalidHadamardSpectrumParameters", ... "invalid Hadamard-spectrum parameters"); endif if (any (strcmp (mode, {"close", "rank5"}))) if (! isfield (parameters, "b") || parameters.b != fix (parameters.b) ... || parameters.b < 1) error ("mplapack:svt:InvalidHadamardSpectrumParameters", ... "close/rank5 mode requires positive integer b"); endif perturbation_bits = parameters.b; else perturbation_bits = 0; endif if (strcmp (mode, "geometric")) if (! isfield (parameters, "a") || parameters.a != fix (parameters.a) ... || parameters.a < 1) error ("mplapack:svt:InvalidHadamardSpectrumParameters", ... "geometric mode requires positive integer a"); endif required_bits = parameters.a * (n - 1) + svt_ceil_log2_integer (n) + 2; elseif (perturbation_bits > 0) required_bits = perturbation_bits + svt_ceil_log2_integer (n) + 5; else required_bits = svt_ceil_log2_integer (n) + 5; endif svt_require_guard (required_bits, work_bits, "Hadamard spectrum exact construction"); saved_bits = mpbits (); cleanup = onCleanup (@() mpbits (saved_bits)); mpbits (work_bits); values = mp (zeros (n, 1)); if (strcmp (mode, "geometric")) for index = 1:n values(index) = svt_pow2 (-parameters.a * (index - 1)); endfor elseif (strcmp (mode, "close") || strcmp (mode, "repeat")) if (n != 8) error ("mplapack:svt:InvalidHadamardSpectrumParameters", ... "close/repeat fixtures are defined for n=8"); endif delta = mp (0); if (strcmp (mode, "close")) delta = svt_pow2 (-parameters.b); endif base = {"4", "2", "1", "1", "0.5", "0.25", "0.125", "0.0625"}; for index = 1:n values(index) = mp (base{index}); endfor values(3) = values(3) + delta; elseif (strcmp (mode, "rank4")) base = {"1", "0.5", "0.25", "0.125", "0", "0", "0", "0"}; if (n != numel (base)) error ("mplapack:svt:InvalidHadamardSpectrumParameters", ... "rank4 fixture is defined for n=8"); endif for index = 1:n values(index) = mp (base{index}); endfor else if (n != 8) error ("mplapack:svt:InvalidHadamardSpectrumParameters", ... "rank5 fixture is defined for n=8"); endif base = {"1", "0.5", "0.25", "0.125", "0", "0", "0", "0"}; for index = 1:n values(index) = mp (base{index}); endfor values(5) = svt_pow2 (-parameters.b); endif diagonal = diag (values); [h, g] = svt_hadamard (n); mixed = svt_mix (diagonal); model_rank = sum (values != mp (0)); cluster_indices = []; null_indices = []; if (strcmp (mode, "close") || strcmp (mode, "repeat")) cluster_indices = [3, 4]; elseif (strcmp (mode, "rank4")) null_indices = 5:8; elseif (strcmp (mode, "rank5")) null_indices = 6:8; endif left_projector = []; right_projector = []; if (! isempty (cluster_indices)) left_projector = svt_known_projector (h, cluster_indices); right_projector = svt_known_projector (g, cluster_indices); elseif (! isempty (null_indices)) left_projector = svt_known_projector (h, null_indices); right_projector = svt_known_projector (g, null_indices); endif identity = svt_case_identity (case_id, "hadamard_spectrum", diagonal, mixed, ... work_bits, "exact_dyadic", ... "C0 two-sided Hadamard equivalence; model rank is constructive metadata"); result = struct ("id", case_id, "tier", "A", "family", "hadamard_spectrum", ... "parameters", parameters, "n", n, "mode", mode, ... "values", values, "model", diagonal, "A", mixed, ... "H", h, "G", g, "analytic_values", sort (values, "descend"), ... "rank", model_rank, "model_rank", model_rank, ... "full_rank", model_rank == n, "det_model", [], ... "cluster_indices", cluster_indices, "null_indices", null_indices, ... "left_projector", left_projector, "right_projector", right_projector, ... "construction_guard_bits", required_bits, "identity", identity, ... "status", "CONSTRUCTED"); clear cleanup; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_manifest_profile.m0000644000230300031750000000226615274353472026143 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function profile_data = svt_manifest_profile (manifest, name) if (! isfield (manifest.profiles, name)) error ("mplapack:svt:ManifestInvalid", ... "normative SVT manifest has no profile: %s", name); endif profile_data = manifest.profiles.(name); required = {"work_bits", "native", "modes", "cases", ... "expected_svd_rows", "reference_bits", "evaluation_bits"}; for index = 1:numel (required) if (! isfield (profile_data, required{index})) error ("mplapack:svt:ManifestInvalid", ... "profile %s lacks field %s", name, required{index}); endif endfor if (numel (unique ({profile_data.cases.id})) != numel (profile_data.cases)) error ("mplapack:svt:ManifestInvalid", ... "profile %s contains duplicate case IDs", name); endif expected = numel (profile_data.cases) * ... (numel (profile_data.work_bits) + double (profile_data.native)) * ... numel (profile_data.modes); if (expected != profile_data.expected_svd_rows) error ("mplapack:svt:ManifestInvalid", ... "profile %s has inconsistent measured-row count", name); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_run_native_svd.m0000644000230300031750000000344415274353472025642 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function row = svt_run_native_svd (input, mode) ## Run an explicitly requested native binary64 comparison row. This path is ## never selected by the MP runner and its conversion is recorded in-row. if (! isa (input, "mp") || ! any (strcmp (mode, {"values", "econ"}))) error ("mplapack:svt:InvalidNativeSvdRequest", ... "native SVD requires an mp input and values/econ mode"); endif native_input = double (input); before = native_input; row = struct (); row.schema = "svt-row-v1"; row.mode = mode; row.native = true; row.input_shape = size (native_input); row.input_precision_bits = 53; row.evaluation_bits = 53; row.api = "explicit double(A) -> builtin binary64 svd"; row.input_conversion = "explicit requested native comparison; not an MP fallback"; timer = tic (); if (strcmp (mode, "values")) row.values = svd (native_input); row.has_factors = false; else [row.U, row.S, row.V] = svd (native_input, "econ"); row.values = diag (row.S); row.has_factors = true; endif row.svd_seconds = toc (timer); row.input_unchanged = isequal (native_input, before); if (! row.input_unchanged) error ("mplapack:svt:NativeInputMutation", ... "native SVD changed its converted input"); endif k = min (size (native_input)); if (! isreal (row.values) || any (! isfinite (row.values)) ... || any (row.values < 0) ... || (numel (row.values) > 1 && any (row.values(1:end-1) < row.values(2:end)))) error ("mplapack:svt:NativeSvdContract", ... "native SVD returned invalid singular values"); endif if (numel (row.values) != k) error ("mplapack:svt:NativeSvdContract", ... "native SVD returned an invalid value count"); endif row.status = "PASS"; endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_mix.m0000644000230300031750000000070015274353472023401 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = svt_mix (value) ## Apply the fixed two-sided orthogonal equivalence H*B*G'/n. [h, g] = svt_hadamard (rows (value)); if (rows (value) != columns (value) || rows (value) != rows (h)) error ("mplapack:svt:InvalidMixShape", ... "Hadamard mixing requires a square matrix of matching order"); endif result = (h * value * g') * (mp (1) / mp (rows (value))); endfunction mplapack-interop-0.5.1/examples/svd_tiers/private/svt_build_case.m0000644000230300031750000000306015274353472024700 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function fixture = svt_build_case (case_data, work_bits) ## Dispatch one manifest record to its already-audited constructor. if (! isstruct (case_data) || numel (case_data) != 1 ... || ! isfield (case_data, "id") || ! isfield (case_data, "family") ... || ! isfield (case_data, "parameters")) error ("mplapack:svt:InvalidCase", "manifest case is incomplete"); endif case_id = char (case_data.id); family = char (case_data.family); parameters = case_data.parameters; switch (family) case "nro_block" fixture = svt_make_nro (case_id, parameters, work_bits); case "jacobi_stirling" fixture = svt_make_jacobi_stirling (case_id, parameters, work_bits); case "lah" fixture = svt_make_lah (case_id, parameters, work_bits); case "dd_path" fixture = svt_make_dd_path (case_id, parameters, work_bits); case "pascal" fixture = svt_make_pascal (case_id, parameters, work_bits); case "vandermonde" fixture = svt_make_vandermonde (case_id, parameters, work_bits); case "bidiagonal" fixture = svt_make_bidiagonal (case_id, parameters, work_bits); case "lauchli" fixture = svt_make_lauchli (case_id, parameters, work_bits); case "hadamard_spectrum" fixture = svt_make_hadamard_spectrum (case_id, parameters, work_bits); case "nro_companion" fixture = svt_make_nro_companion (case_id, parameters, work_bits); otherwise error ("mplapack:svt:UnknownCaseFamily", "unknown case family: %s", family); endswitch endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_construction_selftest.m0000644000230300031750000000467415274353472025613 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_construction_selftest () ## Focused SVT02 tests for exact common constructors and identity metadata. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_construction_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); for n = [1, 2, 4, 8, 16] [h, g] = svt_hadamard (n); identity = mp (eye (n)); assert (all (all (h * h' == mp (n) * identity))); assert (all (all (g * g' == mp (n) * identity))); endfor [h, g] = svt_hadamard (8); assert (all (all (g == [h(8, :); h(1:7, :)]))); phases = svt_phase_diagonal (8); assert (! isreal (phases)); assert (all (all (phases * phases' == mp (eye (8))))); diagonal = diag (mp ([1, 2, 4, 8, 16, 32, 64, 128])); mixed = svt_mix (diagonal); assert (all (all (mixed == svt_mix (diagonal)))); scale_up = mixed * svt_pow2 (600); scale_down = mixed * svt_pow2 (-600); assert (all (all (scale_up * svt_pow2 (-600) == mixed))); assert (all (all (scale_down * svt_pow2 (600) == mixed))); svt_require_guard (32, 256, "sufficient test"); svt_expect_construction_error (@() svt_require_guard (33, 32, "below guard")); svt_expect_construction_error (@() svt_hadamard (3)); svt_expect_construction_error (@() svt_ceil_log2_integer (0)); identity = svt_case_identity ("TEST", "hadamard", diagonal, mixed, ... 256, "exact_dyadic", "SVT02 selftest"); assert (strcmp (identity.schema, "svt-input-v1")); assert (identity.model_shape == [8, 8]); assert (identity.represented_precision_bits == 256); assert (identity.model_is_real && identity.represented_is_real); report = struct ("ok", true, "hadamard_orders", [1, 2, 4, 8, 16], ... "phase_identity", true, "scale_round_trip", true, ... "guard_rejection", true, "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_expect_construction_error (thunk) caught = false; try thunk (); catch caught = true; end_try_catch assert (caught, "expected SVT02 construction error was not raised"); endfunction function svt_restore_construction_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_svd_contract_selftest.m0000644000230300031750000000476715274353472025555 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_svd_contract_selftest () ## Focused SVT03 tests on the measured runner and provisional metric layer. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_svd_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); real_input = mp ({'1', '3', '5'; '2', '4', '6'}); values_row = svt_run_svd (real_input, "values", 512); econ_row = svt_run_svd (real_input, "econ", 512); assert (! values_row.has_factors); assert (econ_row.has_factors); assert (values_row.value_info.count == 2); assert (econ_row.input_unchanged); assert (econ_row.metrics.status == "PASS"); assert (econ_row.metrics.rho_rec < mp ('1e-70')); assert (size (econ_row.U) == [2, 2]); assert (size (econ_row.S) == [2, 2]); assert (size (econ_row.V) == [3, 2]); complex_input = mp ({'(1,1)', '(3,-2)'; '(2,-1)', '(4,2)'}); complex_row = svt_run_svd (complex_input, "econ", 512); assert (! isreal (complex_row.U) && isreal (complex_row.S) ... && ! isreal (complex_row.V)); assert (complex_row.metrics.rho_rec < mp ('1e-70')); zero_input = mp (zeros (2, 3)); zero_row = svt_run_svd (zero_input, "econ", 512); assert (zero_row.metrics.zero_norm_branch); assert (zero_row.metrics.status == "ZERO_NORM_ABSOLUTE_DIAGNOSTICS"); assert (zero_row.metrics.reconstruction == mp (0)); saved_for_reference = mpbits (); mpbits (128); small_input = diag (mp ([1, 2 ^ (-100)])); low = svt_reference (small_input, 128); high = svt_reference (small_input, 256); comparison = svt_compare_references (low, high); assert (! comparison.resolved(2)); assert (strcmp (comparison.status, "consistent_reference")); mpbits (saved_for_reference); ## The runner itself restores the ambient default after the SVD call. mpbits (73); ambient_input = mp ({'1', '0'; '0', '2'}); svt_run_svd (ambient_input, "values", 256); assert (mpbits () == 73); report = struct ("ok", true, "values_mode", true, "economy_mode", true, ... "complex_V_not_VT", true, "zero_reference", true, ... "below_resolution", true, "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_svd_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_v0_selftest.m0000644000230300031750000001033015274353472023370 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_v0_selftest () ## SVT12 scalar-contract, interval, rectangle, matrix, and V4 gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_v0_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); for q = [64, 128, 256] contract = svt_v0_contract (q); assert (strcmp (contract.status, "AUDITED")); mpbits (q); one = mp (1); three = mp (3); one_third = one / three; encoded_third = svt_dyadic_encode (one_third, q); decoded_third = svt_dyadic_decode (encoded_third, q); assert (decoded_third == one_third); endfor mpbits (128); a = svt_iv ("point", mp (1), 128); b = svt_iv ("point", -mp (1), 128); cancellation = svt_iv ("add", a, b); assert (cancellation.lo == mp (0) && cancellation.hi == mp (0)); addition = svt_iv ("add", a, svt_iv ("point", mp (2), 128)); assert (addition.lo <= mp (3) && addition.hi >= mp (3)); product = svt_iv ("mul", addition, svt_iv ("point", mp ('-2'), 128)); assert (product.lo <= mp ('-6') && product.hi >= mp ('-6')); crossing = struct ("schema", "svt-interval-real-v1", "kind", "real", ... "q", 128, "lo", mp ('-1'), "hi", mp ('2')); square = svt_iv ("square", crossing); assert (square.lo == mp (0) && square.hi >= mp (4)); division_rejected = false; try svt_iv ("div", a, crossing); catch division_rejected = true; end_try_catch assert (division_rejected); sqrt_interval = svt_iv ("sqrt", svt_iv ("point", mp (4), 128)); assert (sqrt_interval.lo <= mp (2) && sqrt_interval.hi >= mp (2)); invalid_zero = false; try svt_iv ("primitive", mp (0), false, 128); catch invalid_zero = true; end_try_catch assert (invalid_zero); complex_a = mp ('1', '2'); complex_b = mp ('3', '-1'); complex_product = svt_iv ("mul", svt_iv ("point", complex_a, 128), ... svt_iv ("point", complex_b, 128)); assert (complex_product.real.lo <= mp ('5') && complex_product.real.hi >= mp ('5')); assert (complex_product.imag.lo <= mp ('5') && complex_product.imag.hi >= mp ('5')); complex_matrix = svt_iv ("matrix_point", mp ({'(1,2)', '(3,-1)'; '(0,1)', '(2,0)'}), 128); matrix_product = svt_iv ("matrix_mul", complex_matrix, ... svt_iv ("matrix_ctranspose", complex_matrix)); upper_norm = svt_iv ("matrix_fro_upper", matrix_product); assert (upper_norm.hi > mp (0)); column_lower = svt_iv ("matrix_column_lower", complex_matrix); assert (all (column_lower > mp (0))); mpbits (256); values = cell (1, 5); values{1} = mp (1); values{2} = -mp (1); values{3} = mp (2) ^ (-600); values{4} = mp (2) ^ (600); values{5} = mp (1) / mp (3); for index = 1:numel (values) encoded = svt_dyadic_encode (values{index}, 256); decoded = svt_dyadic_decode (encoded, 256); assert (decoded == values{index}); assert (encoded.sign == 0 || any (encoded.sign == [-1, 1])); endfor negative_zero = mp ('-0'); encoded_zero = svt_dyadic_encode (negative_zero, 256); assert (encoded_zero.sign == 0 && encoded_zero.zero_signbit); assert (svt_dyadic_decode (encoded_zero, 256) == mp (0)); complex_value = mp ('1', '-2'); encoded_complex = svt_dyadic_complex_encode (complex_value, 256); decoded_complex = svt_dyadic_complex_decode (encoded_complex, 256); assert (decoded_complex == complex_value); insufficient = false; try svt_dyadic_decode (svt_dyadic_encode (mp (1) / mp (3), 256), 64); catch insufficient = true; end_try_catch assert (insufficient); assert (mpbits () == 256); report = struct ("ok", true, "contract_q64_256", true, ... "interval_cancellation", true, "range_fail_closed", true, ... "complex_rectangle", true, "matrix_bounds", true, ... "dyadic_roundtrip", true, "signed_zero", true, ... "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_v0_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_nro_companion_selftest.m0000644000230300031750000000473115274353472025714 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_nro_companion_selftest () ## SVT11 NRO companion and measured-row gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_nro_companion_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); small = svt_make_nro_companion ("A6-NRO-SMALL", ... struct ("n", 8, "nu", 16), 256); assert (small.horner_matches_k); assert (all (all (abs (small.A) <= mp (small.entry_bound)))); assert (small.det_model == mp (-1)); assert (small.full_rank && small.rank == 8); assert (all (all (small.published_left_error == mp (0)))); assert (all (all (small.published_right_error == mp (0)))); manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "nro_companion")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_nro_companion (entry.id, entry.parameters, ... profile.work_bits(bits_index)); assert (fixture.horner_matches_k); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (mp_row.metrics.status, "PASS")); endif measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 8 + 12); assert (mpbits () == 256); report = struct ("ok", true, "horner", true, "entry_bound", true, ... "published_inverse", true, "measured_rows", measured_rows, ... "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_nro_companion_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_v2_factor_selftest.m0000644000230300031750000000620015274353472024731 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_v2_factor_selftest () ## SVT15 compatible factor-box and common-phase gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_v2_factor_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); base = mp ([3, 0; 0, 1; 0, 0]); [u, s, v] = svd (base, "econ"); boxes = svt_certify_factor_boxes (base, u, s, v, 256, [1, 2]); assert (strcmp (boxes.status, "CERTIFIED")); assert (boxes.common_phase && boxes.boxes_U.real_lower(1, 1) < u(1, 1)); assert (boxes.boxes_U.real_upper(1, 1) > u(1, 1)); left_phase = mp (eye (3)); right_phase = mp (eye (2)); left_phase(1, 1) = mp ('0', '1'); right_phase(2, 2) = -mp (1); complex_base = left_phase * base * right_phase'; [uc, sc, vc] = svd (complex_base, "econ"); complex_boxes = svt_certify_factor_boxes (complex_base, uc, sc, vc, 256, [1, 2]); assert (strcmp (complex_boxes.status, "CERTIFIED")); ## Common signs/phases on both members preserve compatibility. common_u = u; common_v = v; common_u(:, 1) = -common_u(:, 1); common_v(:, 1) = -common_v(:, 1); common = svt_certify_factor_boxes (base, common_u, s, common_v, 256, [1, 2]); assert (strcmp (common.status, "CERTIFIED")); only_v_matrix = v; only_v_matrix(:, 1) = -only_v_matrix(:, 1); only_v = svt_certify_factor_boxes (base, u, s, only_v_matrix, 256, 1); assert (! strcmp (only_v.status, "CERTIFIED")); repeated_input = mp (diag ([2, 2])); [ur, sr, vr] = svd (repeated_input, "econ"); repeated = svt_certify_factor_boxes (repeated_input, ur, sr, vr, 256, [1, 2]); assert (strcmp (repeated.status, "UNSUPPORTED_MULTIPLICITY")); geometric = svt_make_hadamard_spectrum ("A5-GEO-BOX", ... struct ("n", 8, "mode", "geometric", "a", 4), 256); [ug, sg, vg] = svd (geometric.A, "econ"); geometric_boxes = svt_certify_factor_boxes (geometric.A, ug, sg, vg, 256, 1:8); assert (strcmp (geometric_boxes.status, "CERTIFIED")); ## Deliberate target/exterior mixing leaves the factorization uncertified. mixing = mp (eye (3)); mixing(1, 1) = mp (1) / sqrt (mp (2)); mixing(1, 2) = -mp (1) / sqrt (mp (2)); mixing(2, 1) = mp (1) / sqrt (mp (2)); mixing(2, 2) = mp (1) / sqrt (mp (2)); narrow = mp (diag ([3, 2, 1])); [un, sn, vn] = svd (narrow, "econ"); insufficient_gap = svt_certify_factor_boxes (narrow, un * mixing, sn, vn, 256, 2); assert (! strcmp (insufficient_gap.status, "CERTIFIED")); assert (mpbits () == 256); report = struct ("ok", true, "real_rectangular", true, "complex", true, ... "common_phase", true, "single_phase_rejected", true, ... "multiplicity", true, "geometric", true, ... "gap_failure", true, "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_v2_factor_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_nro_selftest.m0000644000230300031750000001016015274353472023642 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_nro_selftest () ## Constructor and invariant gate for SVT04. Measured row execution is ## included for the three smoke fixtures; the complete profile wall is ## repeated by the profile runner once all families are registered. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_nro_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); two = svt_make_nro ("S1-NRO-TWO", struct ("m", 4, "mode", "two", "b", 12), 256); three = svt_make_nro ("S1-NRO-THREE", struct ("m", 4, "mode", "three", "b", 12), 256); graded = svt_make_nro ("S1-NRO-GRADED", struct ("m", 4, "mode", "graded", "g", 4), 256); cases = {two, three, graded}; for case_index = 1:numel (cases) fixture = cases{case_index}; assert (norm (fixture.A * fixture.inverse_formula - mp (eye (8)), "fro") == mp (0)); assert (fixture.rank == 8 && fixture.full_rank); assert (fixture.det_model == mp (1)); assert (all (all (fixture.analytic_values >= mp (0)))); assert (all (all (fixture.analytic_values(1:end-1) ... >= fixture.analytic_values(2:end)))); for index = 1:4 pair = fixture.unscaled_analytic_values(2 * index - 1:2 * index); assert (abs (pair(1) * pair(2) - mp (1)) < mp ('1e-70') ... || fixture.weights(index) == mp (0)); endfor endfor zero_level = svt_make_nro ("S1-NRO-B0", ... struct ("m", 4, "mode", "two", "b", 0), 128); assert (zero_level.analytic_values(1) > mp (1)); assert (abs (zero_level.unscaled_analytic_values(1) ... * zero_level.unscaled_analytic_values(2) - mp (1)) < mp ('1e-30')); scaled = svt_make_nro ("S1-NRO-SCALE", ... struct ("m", 4, "mode", "two", "b", 12, ... "scale_bits", 600), 256); assert (all (all (scaled.A == two.A * svt_pow2 (600)))); assert (all (all (scaled.inverse_formula * scaled.A - mp (eye (8)) == mp (0)))); rejected = false; try svt_make_nro ("bad", struct ("m", 6, "mode", "two", "b", 1), 128); catch rejected = true; end_try_catch assert (rejected); ## SVT04's measured family wall: every S1 smoke/demo MP precision, explicit ## native comparison, and values/economy mode. These are real rows only; ## complex rows are added by the later Lauchli phase-control milestone. manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "nro_block")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_nro (entry.id, entry.parameters, ... profile.work_bits(bits_index)); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; measured = svt_run_svd (fixture.A, mode, profile.evaluation_bits); assert (strcmp (measured.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (measured.metrics.status, "PASS")); endif native = svt_run_native_svd (fixture.A, mode); assert (strcmp (native.status, "PASS")); measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 24 + 60); assert (mpbits () == 256); report = struct ("ok", true, "variants", 3, "inverse_checks", true, ... "reciprocal_checks", true, "b0", true, "scale", true, ... "measured_rows", measured_rows, ... "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_nro_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_v1_projector_selftest.m0000644000230300031750000000561315274353472025470 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_v1_projector_selftest () ## SVT14 cluster-projector certificate and adversarial gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_v1_projector_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); a = mp (diag ([4, 2, 2, 1])); [u, s, v] = svd (a, "econ"); cluster = svt_certify_projector (a, u, s, v, 256, [2, 3]); assert (strcmp (cluster.status, "CERTIFIED")); assert (cluster.delta_lower > mp (0) && cluster.bU.hi < mp ('1e-50')); ## Swapping columns inside the repeated group preserves the subspace. permutation = [1, 3, 2, 4]; permuted = svt_certify_projector (a, u(:, permutation), s, v(:, permutation), ... 256, [2, 3]); assert (strcmp (permuted.status, "CERTIFIED")); ## A genuine internal orthogonal rotation of a repeated pair is accepted. rotation = mp (eye (4)); rotation(2, 2) = mp (3) / mp (5); rotation(2, 3) = -mp (4) / mp (5); rotation(3, 2) = mp (4) / mp (5); rotation(3, 3) = mp (3) / mp (5); rotated = svt_certify_projector (a, u * rotation, s, v * rotation, 256, [2, 3]); assert (strcmp (rotated.status, "CERTIFIED")); ## A column from outside the cluster breaks the factorization and must not ## receive a certified cluster claim. wrong = svt_certify_projector (a, u(:, [2, 1, 3, 4]), s, v, 256, [2, 3]); assert (! strcmp (wrong.status, "CERTIFIED")); ## Rectangular dilation includes structural zero eigenvalues in its gap. tall = mp ([4, 0; 0, 2; 0, 0]); [ut, st, vt] = svd (tall, "econ"); tall_cluster = svt_certify_projector (tall, ut, st, vt, 256, [2]); assert (strcmp (tall_cluster.status, "CERTIFIED")); assert (tall_cluster.complement_count > 0); ## Mixing a target column with an exterior value collapses the certified gap. gap_rotation = mp (eye (4)); gap_rotation(1, 1) = mp (1) / sqrt (mp (2)); gap_rotation(1, 2) = -mp (1) / sqrt (mp (2)); gap_rotation(2, 1) = mp (1) / sqrt (mp (2)); gap_rotation(2, 2) = mp (1) / sqrt (mp (2)); collapsed = svt_certify_projector (a, u * gap_rotation, s, v * gap_rotation, ... 256, [2]); assert (! strcmp (collapsed.status, "CERTIFIED")); assert (mpbits () == 256); report = struct ("ok", true, "repeat", true, "permutation", true, ... "internal_rotation", true, "wrong_column_rejected", true, ... "structural_zero_gap", true, "exterior_gap_collapse", true, ... "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_v1_projector_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_pascal_selftest.m0000644000230300031750000000511715274353472024315 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_pascal_selftest () ## SVT08 Pascal constructor and measured-row gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_pascal_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); fixture = svt_make_pascal ("A1-PASCAL-SMALL", ... struct ("n", 4, "representation", "symmetric"), 256); expected_q = mp ([1, 0, 0, 0; 1, 1, 0, 0; 1, 2, 1, 0; 1, 3, 3, 1]); expected_p = mp ([1, 1, 1, 1; 1, 2, 3, 4; 1, 3, 6, 10; 1, 4, 10, 20]); assert (all (all (fixture.Q == expected_q))); assert (all (all (fixture.P == expected_p))); assert (all (all (fixture.q_times_q_transpose_error == mp (0)))); assert (all (all (tril (fixture.Q) == fixture.Q))); assert (all (all (diag (fixture.Q) == mp (ones (4, 1))))); manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "pascal")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_pascal (entry.id, entry.parameters, ... profile.work_bits(bits_index)); assert (all (all (fixture.q_times_q_transpose_error == mp (0)))); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (mp_row.metrics.status, "PASS")); endif measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 16 + 24); assert (mpbits () == 256); report = struct ("ok", true, "known_q", true, "known_p", true, ... "factor_identity", true, "measured_rows", measured_rows, ... "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_pascal_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/svd_tiers/svt_lauchli_selftest.m0000644000230300031750000000672115274353472024475 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function report = svt_lauchli_selftest () ## SVT11 Lauchli/projector and measured-row gate. suite_dir = fileparts (mfilename ("fullpath")); added = false; if (! any (strcmp (strsplit (path (), pathsep), suite_dir))) addpath (suite_dir); added = true; endif cleanup_path = onCleanup (@() svt_restore_lauchli_path (suite_dir, added)); saved_bits = mpbits (); cleanup_precision = onCleanup (@() mpbits (saved_bits)); mpbits (256); tall = svt_make_lauchli ("A4-LAU-TALL-SMALL", ... struct ("n", 4, "b", 20, "representation", "tall"), 256); wide = svt_make_lauchli ("A4-LAU-WIDE-SMALL", ... struct ("n", 4, "b", 20, "representation", "wide"), 256); expected_normal = mp (ones (4, 4)) + tall.mu * tall.mu * mp (eye (4)); assert (all (all (tall.normal_equations_model == expected_normal))); assert (norm (tall.tall' * tall.tall - expected_normal, "fro") == mp (0)); assert (all (all (tall.right_projector * tall.right_projector ... - tall.right_projector == mp (0)))); assert (all (all (wide.A == tall.tall'))); assert (tall.analytic_values(1) > tall.analytic_values(2)); assert (all (all (tall.analytic_values(2:end) == tall.mu))); complex_fixture = svt_make_lauchli ("A4-LAU-COMPLEX-SMALL", ... struct ("n", 4, "b", 20, ... "representation", "tall", ... "quarter_turn_phases", true), 256); assert (! isreal (complex_fixture.A)); phased_normal = complex_fixture.phase_right * expected_normal ... * complex_fixture.phase_right'; phase_normal_error = norm (complex_fixture.A' * complex_fixture.A ... - phased_normal, "fro"); assert (phase_normal_error < mp ('1e-200')); assert (all (all (complex_fixture.analytic_values == tall.analytic_values))); manifest = svt_load_manifest (); profile_names = {"smoke", "demo"}; measured_rows = 0; for profile_index = 1:numel (profile_names) profile = svt_manifest_profile (manifest, profile_names{profile_index}); for case_index = 1:numel (profile.cases) entry = profile.cases(case_index); if (! strcmp (entry.family, "lauchli")) continue; endif for bits_index = 1:numel (profile.work_bits) fixture = svt_make_lauchli (entry.id, entry.parameters, ... profile.work_bits(bits_index)); for mode_index = 1:numel (profile.modes) mode = profile.modes{mode_index}; mp_row = svt_run_svd (fixture.A, mode, profile.evaluation_bits); native_row = svt_run_native_svd (fixture.A, mode); assert (strcmp (mp_row.status, "PASS") && strcmp (native_row.status, "PASS")); if (strcmp (mode, "econ")) assert (strcmp (mp_row.metrics.status, "PASS")); endif measured_rows = measured_rows + 2; endfor endfor endfor endfor assert (measured_rows == 16 + 36); assert (mpbits () == 256); report = struct ("ok", true, "tall", true, "wide", true, ... "phase", true, "projectors", true, "negative_control", true, ... "measured_rows", measured_rows, "status", "PASS"); clear cleanup_precision; clear cleanup_path; endfunction function svt_restore_lauchli_path (suite_dir, added) if (added) rmpath (suite_dir); endif endfunction mplapack-interop-0.5.1/examples/tiered/0000755000230300031750000000000015274353472017335 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/tiered/svd-tier-s/0000755000230300031750000000000015274353472021332 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/tiered/svd-tier-s/nro_scale_down.m0000644000230300031750000000222115274353472024501 0ustar rafaelrafael% NRO scale-down control. % % Question: A global dyadic scale-down of the NRO block. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-s/nro_scale_down.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("demo", struct ("tier", "S", ... "case_id", "S1-NRO-SCALE-DOWN", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("S1-NRO-SCALE-DOWN: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-s/nro_scale_down.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-s/nro_two.m0000644000230300031750000000220615274353472023177 0ustar rafaelrafael% NRO two-level block. % % Question: A dense block matrix with two reciprocal singular-value levels. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-s/nro_two.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "S", ... "case_id", "S1-NRO-TWO", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("S1-NRO-TWO: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-s/nro_two.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-s/dd_sym.m0000644000230300031750000000217715274353472022776 0ustar rafaelrafael% Symmetric diagonally dominant path. % % Question: A nearly singular symmetric tridiagonal path. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-s/dd_sym.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "S", ... "case_id", "S4-DD-SYM", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("S4-DD-SYM: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-s/dd_sym.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-s/nro_graded.m0000644000230300031750000000221615274353472023615 0ustar rafaelrafael% NRO graded block. % % Question: A block matrix with geometrically graded off-diagonal weights. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-s/nro_graded.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "S", ... "case_id", "S1-NRO-GRADED", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("S1-NRO-GRADED: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-s/nro_graded.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-s/nro_scale_up.m0000644000230300031750000000220515274353472024160 0ustar rafaelrafael% NRO scale-up control. % % Question: A global dyadic scale-up of the NRO block. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-s/nro_scale_up.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("demo", struct ("tier", "S", ... "case_id", "S1-NRO-SCALE-UP", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("S1-NRO-SCALE-UP: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-s/nro_scale_up.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-s/nro_three.m0000644000230300031750000000221415274353472023474 0ustar rafaelrafael% NRO three-level block. % % Question: A dense block matrix with extreme and unit singular groups. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-s/nro_three.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "S", ... "case_id", "S1-NRO-THREE", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("S1-NRO-THREE: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-s/nro_three.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-s/jacobi_stirling.m0000644000230300031750000000217615274353472024660 0ustar rafaelrafael% Jacobi--Stirling matrix. % % Question: A unit lower-triangular combinatorial matrix. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-s/jacobi_stirling.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "S", ... "case_id", "S2-JS", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("S2-JS: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-s/jacobi_stirling.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-s/lah.m0000644000230300031750000000216415274353472022257 0ustar rafaelrafael% Unsigned Lah matrix. % % Question: A rapidly growing unit lower-triangular combinatorial matrix. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-s/lah.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "S", ... "case_id", "S3-LAH", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("S3-LAH: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-s/lah.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-s/dd_nonsym.m0000644000230300031750000000222115274353472023477 0ustar rafaelrafael% Nonsymmetric diagonally dominant path. % % Question: A nearly singular nonsymmetric tridiagonal path. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-s/dd_nonsym.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "S", ... "case_id", "S4-DD-NONSYM", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("S4-DD-NONSYM: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-s/dd_nonsym.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/0000755000230300031750000000000015274353472021310 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/tiered/svd-tier-a/lauchli_complex.m0000644000230300031750000000220715274353472024637 0ustar rafaelrafael% Complex phase Lauchli matrix. % % Question: A complex phase Lauchli control. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/lauchli_complex.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("demo", struct ("tier", "A", ... "case_id", "A4-LAU-COMPLEX", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A4-LAU-COMPLEX: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/lauchli_complex.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/hadamard_close.m0000644000230300031750000000220515274353472024413 0ustar rafaelrafael% Close Hadamard spectrum. % % Question: A pair of nearly equal positive singular values. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/hadamard_close.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A5-CLOSE", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A5-CLOSE: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/hadamard_close.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/hadamard_rank4.m0000644000230300031750000000220415274353472024324 0ustar rafaelrafael% Rank-four Hadamard spectrum. % % Question: A deliberately rank-deficient dense matrix. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/hadamard_rank4.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A5-RANK4", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A5-RANK4: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/hadamard_rank4.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/hadamard_geometric.m0000644000230300031750000000223615274353472025270 0ustar rafaelrafael% Geometric Hadamard spectrum. % % Question: A two-sided Hadamard mixing of a geometrically decaying spectrum. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/hadamard_geometric.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A5-GEO", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A5-GEO: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/hadamard_geometric.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/hadamard_repeat.m0000644000230300031750000000217715274353472024576 0ustar rafaelrafael% Repeated Hadamard spectrum. % % Question: A repeated singular-value subspace. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/hadamard_repeat.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A5-REPEAT", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A5-REPEAT: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/hadamard_repeat.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/hadamard_rank5.m0000644000230300031750000000222415274353472024327 0ustar rafaelrafael% Near-rank-deficient Hadamard spectrum. % % Question: A tiny fifth singular value next to a null space. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/hadamard_rank5.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A5-RANK5", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A5-RANK5: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/hadamard_rank5.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/bidiag_mixed.m0000644000230300031750000000223715274353472024077 0ustar rafaelrafael% Orthogonally mixed bidiagonal. % % Question: A sign-mixed bidiagonal control with the same singular geometry. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/bidiag_mixed.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A3-BDI-MIXED", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A3-BDI-MIXED: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/bidiag_mixed.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/lauchli_tall.m0000644000230300031750000000217015274353472024123 0ustar rafaelrafael% Tall Lauchli matrix. % % Question: A tall rank-sensitive Lauchli matrix. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/lauchli_tall.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A4-LAU-TALL", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A4-LAU-TALL: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/lauchli_tall.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/lauchli_wide.m0000644000230300031750000000217415274353472024123 0ustar rafaelrafael% Wide Lauchli matrix. % % Question: A wide transpose-oriented Lauchli matrix. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/lauchli_wide.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A4-LAU-WIDE", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A4-LAU-WIDE: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/lauchli_wide.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/vandermonde.m0000644000230300031750000000220015274353472023762 0ustar rafaelrafael% Dyadic Vandermonde matrix. % % Question: A rectangular Vandermonde matrix at dyadic nodes. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/vandermonde.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A2-VAND", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A2-VAND: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/vandermonde.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/bidiag_raw.m0000644000230300031750000000222115274353472023553 0ustar rafaelrafael% Raw graded bidiagonal. % % Question: A graded bidiagonal matrix with dyadic diagonal and superdiagonal. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/bidiag_raw.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A3-BDI-RAW", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A3-BDI-RAW: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/bidiag_raw.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/pascal_lower.m0000644000230300031750000000221215274353472024136 0ustar rafaelrafael% Lower Pascal matrix. % % Question: A triangular totally-nonnegative Pascal matrix. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/pascal_lower.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A1-PASCAL-LOWER", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A1-PASCAL-LOWER: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/pascal_lower.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/pascal_sym.m0000644000230300031750000000217515274353472023626 0ustar rafaelrafael% Symmetric Pascal matrix. % % Question: A dense symmetric Pascal construction. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/pascal_sym.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A1-PASCAL-SYM", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A1-PASCAL-SYM: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/pascal_sym.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/svd-tier-a/nro_companion.m0000644000230300031750000000222415274353472024327 0ustar rafaelrafael% NRO companion-like matrix. % % Question: A nonsymmetric companion-like accuracy control. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public svd path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/svd-tier-a/nro_companion.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_svd_tiers ("smoke", struct ("tier", "A", ... "case_id", "A6-NRO-COMPANION", ... "plot", false)); assert (result.scope_ok && strcmp (result.status, "PASS") ... && result.case_count == 1); fprintf ("A6-NRO-COMPANION: PASS; selected cases=%d; measured rows=%d\n", ... result.case_count, result.measured_svd_rows); fprintf ("See docs/examples/tiered/svd-tier-a/nro_companion.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/0000755000230300031750000000000015274353472021460 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/tiered/neig-tier-s/oo128_close.m0000644000230300031750000000216615274353472023700 0ustar rafaelrafael% Ozaki--Ogita close-spectrum form. % % Question: The 128-bit close-spectrum paired-block case. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/oo128_close.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "OO128_CLOSE", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("OO128_CLOSE: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/oo128_close.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/oo53_real.m0000644000230300031750000000221615274353472023427 0ustar rafaelrafael% Ozaki--Ogita real standard form. % % Question: The fixed-precision error-free triple-product generator in real standard form. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/oo53_real.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "OO53_REAL", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("OO53_REAL: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/oo53_real.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/sim_jordan.m0000644000230300031750000000217415274353472023767 0ustar rafaelrafael% Single Jordan similarity. % % Question: A defective 2-by-2 Jordan block embedded in a dense similarity. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/sim_jordan.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "SIM_JORDAN", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("SIM_JORDAN: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/sim_jordan.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/forsythe_zero.m0000644000230300031750000000217015274353472024540 0ustar rafaelrafael% Forsythe zero-limit Jordan block. % % Question: The genuine zero-coupling Jordan limit. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/forsythe_zero.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "FORSYTHE_ZERO", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("FORSYTHE_ZERO: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/forsythe_zero.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/forsythe_scaled.m0000644000230300031750000000217715274353472025023 0ustar rafaelrafael% Scaled Forsythe control. % % Question: The explicitly scaled normal companion control. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/forsythe_scaled.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "FORSYTHE_SCALED", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("FORSYTHE_SCALED: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/forsythe_scaled.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/forsythe.m0000644000230300031750000000215715274353472023506 0ustar rafaelrafael% Forsythe cyclic perturbation. % % Question: The tiny-corner cyclic perturbation of a Jordan block. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/forsythe.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "FORSYTHE", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("FORSYTHE: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/forsythe.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/sim_simple.m0000644000230300031750000000215015274353472023775 0ustar rafaelrafael% Near-simple similarity. % % Question: A diagonalizable pair with a tiny dyadic gap. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/sim_simple.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "SIM_SIMPLE", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("SIM_SIMPLE: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/sim_simple.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/sim_repeat.m0000644000230300031750000000217315274353472023771 0ustar rafaelrafael% Semisimple repeated similarity. % % Question: A repeated eigenvalue with a two-dimensional eigenspace. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/sim_repeat.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "SIM_REPEAT", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("SIM_REPEAT: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/sim_repeat.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/toeplitz.m0000644000230300031750000000217415274353472023514 0ustar rafaelrafael% Nonnormal Toeplitz representation. % % Question: The diagonally scaled nonsymmetric tridiagonal Toeplitz model. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/toeplitz.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "TOEPLITZ", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("TOEPLITZ: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/toeplitz.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/oo53_pair.m0000644000230300031750000000216615274353472023443 0ustar rafaelrafael% Ozaki--Ogita paired standard form. % % Question: The paired-block standard form generated at 53 bits. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/oo53_pair.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "OO53_PAIR", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("OO53_PAIR: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/oo53_pair.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/toeplitz_sym.m0000644000230300031750000000222215274353472024376 0ustar rafaelrafael% Symmetric Toeplitz control. % % Question: The explicitly symmetric coordinate representation of the Toeplitz control. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/toeplitz_sym.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "TOEPLITZ_SYM", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("TOEPLITZ_SYM: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/toeplitz_sym.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-s/sim_two_jordan.m0000644000230300031750000000221015274353472024647 0ustar rafaelrafael% Two Jordan clusters. % % Question: Two nearby defective clusters and their merged-subspace warning. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-s/sim_two_jordan.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "S", ... "case_id", "SIM_TWO_JORDAN", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("SIM_TWO_JORDAN: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-s/sim_two_jordan.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-a/0000755000230300031750000000000015274353472021436 5ustar rafaelrafaelmplapack-interop-0.5.1/examples/tiered/neig-tier-a/grcar.m0000644000230300031750000000213215274353472022710 0ustar rafaelrafael% Grcar nonnormal band matrix. % % Question: A dense-output nonsymmetric Grcar band matrix. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-a/grcar.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "A", ... "case_id", "GRCAR", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("GRCAR: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-a/grcar.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-a/markov.m0000644000230300031750000000215315274353472023114 0ustar rafaelrafael% Stochastic Markov matrix. % % Question: A positive stochastic matrix with a controlled spectral scale. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-a/markov.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "A", ... "case_id", "MARKOV", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("MARKOV: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-a/markov.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-a/frank0.m0000644000230300031750000000213215274353472022773 0ustar rafaelrafael% Frank matrix orientation 0. % % Question: The standard upper-Hessenberg Frank matrix. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-a/frank0.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "A", ... "case_id", "FRANK0", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("FRANK0: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-a/frank0.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-a/perron_pos.m0000644000230300031750000000217415274353472024006 0ustar rafaelrafael% Positive Perron similarity. % % Question: A positive diagonal similarity with a nontrivial Perron pair. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-a/perron_pos.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "A", ... "case_id", "PERRON_POS", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("PERRON_POS: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-a/perron_pos.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-a/wilkinson.m0000644000230300031750000000217615274353472023637 0ustar rafaelrafael% Wilkinson companion-like matrix. % % Question: The recurrence-generated Wilkinson polynomial companion model. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-a/wilkinson.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "A", ... "case_id", "WILKINSON", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("WILKINSON: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-a/wilkinson.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-a/had_complex.m0000644000230300031750000000220115274353472024072 0ustar rafaelrafael% Complex Hadamard phase control. % % Question: A complex phase similarity of the Hadamard-bidiagonal case. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-a/had_complex.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("demo", struct ("tier", "A", ... "case_id", "HAD_COMPLEX", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("HAD_COMPLEX: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-a/had_complex.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-a/mks.m0000644000230300031750000000213215274353472022404 0ustar rafaelrafael% MKS rank-one Toeplitz perturbation. % % Question: A nilpotent power plus a rank-one perturbation. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-a/mks.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "A", ... "case_id", "MKS", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("MKS: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-a/mks.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-a/frank1.m0000644000230300031750000000214215274353472022775 0ustar rafaelrafael% Frank matrix reflected orientation. % % Question: The explicitly reflected Frank orientation. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-a/frank1.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "A", ... "case_id", "FRANK1", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("FRANK1: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-a/frank1.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/tiered/neig-tier-a/had_bidiag.m0000644000230300031750000000224015274353472023645 0ustar rafaelrafael% Hadamard-similar upper bidiagonal. % % Question: An upper bidiagonal matrix with separated integer eigenvalues after a Hadamard similarity. % Steps: % 1. Select this exact case from the frozen manifest. % 2. Run the public eig path at the profile's MP precisions. % 3. Inspect the residuals and precision roles reported by the case runner. % Matching documentation: docs/examples/tiered/neig-tier-a/had_bidiag.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (fileparts (fileparts (mfilename ("fullpath")))); suite_root = fullfile (example_root, "neig_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); result = mp_neig_tiers ("smoke", struct ("tier", "A", ... "case_id", "HAD_BIDIAG", ... "plot", false)); assert (result.ok && result.coverage.case_count == 1); fprintf ("HAD_BIDIAG: PASS; selected cases=%d; measured rows=%d\n", ... result.coverage.case_count, result.coverage.measured_eig_rows); fprintf ("See docs/examples/tiered/neig-tier-a/had_bidiag.md for interpretation.\n"); clear cleanup_path; mplapack-interop-0.5.1/examples/13_nonsymmetric_eig_suite.m0000644000230300031750000000157115274353472023332 0ustar rafaelrafael% Reproducible smoke example for difficult dense nonsymmetric eigensystems. % % The suite uses the existing public mp/eig API. It runs all five exact or % independently referenced representations in both balance modes, with % native and MP controls, and reports residual/conditioning diagnostics. if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (mfilename ("fullpath")); addpath (fullfile (example_root, "nonsymmetric_eig")); saved_bits = mpbits (); unwind_protect results = mp_eig_suite ("smoke"); assert (results.ok && numel (results.rows) == 30); fprintf ("Nonsymmetric eigensystem smoke PASS: %d rows, evaluation=%d bits\n", ... numel (results.rows), results.evaluation_bits); disp ("See docs/nonsymmetric-eig-suite.md for constructions and metrics."); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/examples/15_svd_tier_a.m0000644000230300031750000000665615274353472020700 0ustar rafaelrafael% SVT Tier-A case index. % % This short numbered entry point preserves the historical family entry. % It lists one runnable example per manifest case. The full measured wall is % run by mp_svd_tiers ("smoke"/"demo") and by the repository test suite. % % Question: Which singular-value cases belong to Tier-A, and where is the % detailed interpretation for each one? % Steps: inspect the list, then run any matching .m file directly. % Matching documentation: docs/examples/tiered/README.md if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif example_root = fileparts (mfilename ("fullpath")); suite_root = fullfile (example_root, "svd_tiers"); addpath (suite_root); cleanup_path = onCleanup (@() rmpath (suite_root)); repo_root = fileparts (fileparts (mfilename ("fullpath"))); case_ids = { "A1-PASCAL-LOWER"; ... "A1-PASCAL-SYM"; ... "A2-VAND"; ... "A3-BDI-RAW"; ... "A3-BDI-MIXED"; ... "A4-LAU-TALL"; ... "A4-LAU-WIDE"; ... "A4-LAU-COMPLEX"; ... "A5-GEO"; ... "A5-CLOSE"; ... "A5-REPEAT"; ... "A5-RANK4"; ... "A5-RANK5"; ... "A6-NRO-COMPANION" }; case_examples = { "examples/tiered/svd-tier-a/pascal_lower.m"; ... "examples/tiered/svd-tier-a/pascal_sym.m"; ... "examples/tiered/svd-tier-a/vandermonde.m"; ... "examples/tiered/svd-tier-a/bidiag_raw.m"; ... "examples/tiered/svd-tier-a/bidiag_mixed.m"; ... "examples/tiered/svd-tier-a/lauchli_tall.m"; ... "examples/tiered/svd-tier-a/lauchli_wide.m"; ... "examples/tiered/svd-tier-a/lauchli_complex.m"; ... "examples/tiered/svd-tier-a/hadamard_geometric.m"; ... "examples/tiered/svd-tier-a/hadamard_close.m"; ... "examples/tiered/svd-tier-a/hadamard_repeat.m"; ... "examples/tiered/svd-tier-a/hadamard_rank4.m"; ... "examples/tiered/svd-tier-a/hadamard_rank5.m"; ... "examples/tiered/svd-tier-a/nro_companion.m" }; case_docs = { "docs/examples/tiered/svd-tier-a/pascal_lower.md"; ... "docs/examples/tiered/svd-tier-a/pascal_sym.md"; ... "docs/examples/tiered/svd-tier-a/vandermonde.md"; ... "docs/examples/tiered/svd-tier-a/bidiag_raw.md"; ... "docs/examples/tiered/svd-tier-a/bidiag_mixed.md"; ... "docs/examples/tiered/svd-tier-a/lauchli_tall.md"; ... "docs/examples/tiered/svd-tier-a/lauchli_wide.md"; ... "docs/examples/tiered/svd-tier-a/lauchli_complex.md"; ... "docs/examples/tiered/svd-tier-a/hadamard_geometric.md"; ... "docs/examples/tiered/svd-tier-a/hadamard_close.md"; ... "docs/examples/tiered/svd-tier-a/hadamard_repeat.md"; ... "docs/examples/tiered/svd-tier-a/hadamard_rank4.md"; ... "docs/examples/tiered/svd-tier-a/hadamard_rank5.md"; ... "docs/examples/tiered/svd-tier-a/nro_companion.md" }; assert (numel (case_ids) == numel (case_examples)); assert (numel (case_ids) == numel (case_docs)); for index = 1:numel (case_ids) assert (exist (fullfile (repo_root, case_examples{index}), "file") == 2); assert (exist (fullfile (repo_root, case_docs{index}), "file") == 2); fprintf ("%s\t%s\t%s\n", case_ids{index}, case_examples{index}, case_docs{index}); endfor fprintf ("SVT Tier-A index: %d cases.\n", numel (case_ids)); % Preserve the historical full-profile aggregator contract. The split files % above are the teaching surface; this call remains the counted regression. result = mp_svd_tiers ("smoke", struct ("tier", "A", "plot", false)); assert (result.scope_ok); assert (strcmp (result.status, "PASS")); fprintf ("SVT Tier-A smoke PASS: %d measured rows.\n", ... result.measured_svd_rows); clear cleanup_path; mplapack-interop-0.5.1/examples/08_advanced_dense.m0000644000230300031750000000121415274353472021467 0ustar rafaelrafael% A compact advanced dense workflow: Schur, matrix functions, and polynomials. if (exist ("mpbits", "file") != 2) pkg load mplapack-interop endif saved_bits = mpbits (); unwind_protect mpbits (256); A = mp ({"0", "1"; "-2", "-3"}); [U, T] = schur (A); assert (double (norm (U' * A * U - T, "fro")) < 1e-45); E = expm (A); L = logm (E); assert (double (norm (expm (L) - E, "fro")) < 1e-35); p = mp ({"1", "-3", "2"}); r = roots (p); assert (double (norm (polyval (p, r), "fro")) < 1e-35); fprintf ("advanced dense PASS: Schur/matrix functions/polynomials\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/src/0000755000230300031750000000000015274353472015032 5ustar rafaelrafaelmplapack-interop-0.5.1/src/mp_norm.cc0000644000230300031750000004253515274353472017021 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_norm.h" #include #include #include #include #include #include #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_precision.h" namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrNormRequest; using octave_mplapack::MpfrScalarStorage; void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ("MPLAPACK norm precision is outside MPFR limits"); } MpfrScalarStorage::NativeScalar make_zero (mpfr_prec_t precision_bits) { auto result = MpfrScalarStorage::NativeScalar::with_precision (precision_bits); mpfr_set_zero (result.mpfr_data (), 1); return result; } MpfrScalarStorage::NativeScalar absolute_value (const MpfrScalarStorage::NativeScalar& value, mpfr_prec_t precision_bits) { auto result = MpfrScalarStorage::NativeScalar::with_precision (precision_bits); mpfr_abs (result.mpfr_data (), value.mpfr_data (), MPFR_RNDN); return result; } MpfrScalarStorage::NativeScalar absolute_value (const octave_mplapack::MpfrComplexScalarStorage::NativeScalar& value, mpfr_prec_t precision_bits) { auto result = MpfrScalarStorage::NativeScalar::with_precision (precision_bits); mpc_abs (result.mpfr_data (), value.mpc_data (), MPFR_RNDN); return result; } template MpfrScalarStorage maximum_abs (const Matrix& input) { const mpfr_prec_t precision_bits = input.precision_bits (); auto result = make_zero (precision_bits); for (std::size_t index = 0; index < input.numel (); ++index) { auto value = absolute_value (input.data ()[index], precision_bits); if (mpfr_nan_p (value.mpfr_data ()) != 0 || mpfr_cmp (value.mpfr_data (), result.mpfr_data ()) > 0) mpfr_set (result.mpfr_data (), value.mpfr_data (), MPFR_RNDN); } return MpfrScalarStorage (std::move (result)); } template MpfrScalarStorage minimum_abs (const Matrix& input) { const mpfr_prec_t precision_bits = input.precision_bits (); if (input.numel () == 0) return MpfrScalarStorage (make_zero (precision_bits)); auto result = absolute_value (input.data ()[0], precision_bits); for (std::size_t index = 1; index < input.numel (); ++index) { auto value = absolute_value (input.data ()[index], precision_bits); if (mpfr_nan_p (value.mpfr_data ()) != 0 || mpfr_cmp (value.mpfr_data (), result.mpfr_data ()) < 0) mpfr_set (result.mpfr_data (), value.mpfr_data (), MPFR_RNDN); } return MpfrScalarStorage (std::move (result)); } template MpfrScalarStorage zero_count (const Matrix& input) { const mpfr_prec_t precision_bits = input.precision_bits (); auto result = make_zero (precision_bits); for (std::size_t index = 0; index < input.numel (); ++index) { const auto value = absolute_value (input.data ()[index], precision_bits); if (mpfr_zero_p (value.mpfr_data ()) == 0) mpfr_add_ui (result.mpfr_data (), result.mpfr_data (), 1, MPFR_RNDN); } return MpfrScalarStorage (std::move (result)); } template MpfrScalarStorage finite_vector_norm (const Matrix& input, double exponent) { const mpfr_prec_t precision_bits = input.precision_bits (); auto sum = make_zero (precision_bits); auto p = MpfrScalarStorage::NativeScalar::with_precision (precision_bits); auto reciprocal = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); mpfr_set_d (p.mpfr_data (), exponent, MPFR_RNDN); mpfr_set_d (reciprocal.mpfr_data (), 1.0 / exponent, MPFR_RNDN); for (std::size_t index = 0; index < input.numel (); ++index) { auto absolute = absolute_value (input.data ()[index], precision_bits); auto term = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); mpfr_pow (term.mpfr_data (), absolute.mpfr_data (), p.mpfr_data (), MPFR_RNDN); mpfr_add (sum.mpfr_data (), sum.mpfr_data (), term.mpfr_data (), MPFR_RNDN); } auto result = MpfrScalarStorage::NativeScalar::with_precision (precision_bits); if (input.numel () == 0) mpfr_set_zero (result.mpfr_data (), 1); else mpfr_pow (result.mpfr_data (), sum.mpfr_data (), reciprocal.mpfr_data (), MPFR_RNDN); return MpfrScalarStorage (std::move (result)); } MpfrScalarStorage real_vector_norm (const MpfrMatrixStorage& input, const MpfrNormRequest& request) { const mpfr_prec_t precision_bits = input.precision_bits (); switch (request.kind) { case MpfrNormRequest::Kind::one: { auto result = make_zero (precision_bits); for (std::size_t index = 0; index < input.numel (); ++index) { auto value = absolute_value (input.data ()[index], precision_bits); mpfr_add (result.mpfr_data (), result.mpfr_data (), value.mpfr_data (), MPFR_RNDN); } return MpfrScalarStorage (std::move (result)); } case MpfrNormRequest::Kind::two: case MpfrNormRequest::Kind::frobenius: { if (input.numel () == 0) return MpfrScalarStorage (make_zero (precision_bits)); auto work = MpfrMatrixStorage (input.rows (), input.columns (), precision_bits, input); MplapackMpfrPrecisionScope scope (precision_bits); auto result = Rnrm2 ( MpfrMatrixStorage::checked_mplapack_dimension (input.numel ()), work.data (), 1); return MpfrScalarStorage (std::move (result)); } case MpfrNormRequest::Kind::infinity: return maximum_abs (input); case MpfrNormRequest::Kind::negative_infinity: return minimum_abs (input); case MpfrNormRequest::Kind::zero: return zero_count (input); case MpfrNormRequest::Kind::finite: return finite_vector_norm (input, request.exponent); } throw std::logic_error ("unknown real vector norm kind"); } MpfrScalarStorage complex_vector_norm (const MpfrComplexMatrixStorage& input, const MpfrNormRequest& request) { const mpfr_prec_t precision_bits = input.precision_bits (); switch (request.kind) { case MpfrNormRequest::Kind::one: case MpfrNormRequest::Kind::frobenius: case MpfrNormRequest::Kind::infinity: case MpfrNormRequest::Kind::negative_infinity: case MpfrNormRequest::Kind::zero: if (request.kind == MpfrNormRequest::Kind::one) { auto result = make_zero (precision_bits); for (std::size_t index = 0; index < input.numel (); ++index) { auto value = absolute_value (input.data ()[index], precision_bits); mpfr_add (result.mpfr_data (), result.mpfr_data (), value.mpfr_data (), MPFR_RNDN); } return MpfrScalarStorage (std::move (result)); } if (request.kind == MpfrNormRequest::Kind::infinity) return maximum_abs (input); if (request.kind == MpfrNormRequest::Kind::negative_infinity) return minimum_abs (input); if (request.kind == MpfrNormRequest::Kind::zero) return zero_count (input); break; case MpfrNormRequest::Kind::two: { if (input.numel () == 0) return MpfrScalarStorage (make_zero (precision_bits)); auto work = octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( input, precision_bits); octave_mplapack::MpfrMpcPrecisionScope scope (precision_bits); auto result = RCnrm2 ( MpfrComplexMatrixStorage::checked_mplapack_dimension (input.numel ()), work.data (), 1); return MpfrScalarStorage (std::move (result)); } case MpfrNormRequest::Kind::finite: return finite_vector_norm (input, request.exponent); } // The only fall-through is Frobenius, which is the vector 2-norm of all // entries and uses the same MPFR/MPC-native BLAS path. auto work = octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( input, precision_bits); octave_mplapack::MpfrMpcPrecisionScope scope (precision_bits); auto result = RCnrm2 ( MpfrComplexMatrixStorage::checked_mplapack_dimension (input.numel ()), work.data (), 1); return MpfrScalarStorage (std::move (result)); } MpfrScalarStorage real_matrix_standard_norm (const MpfrMatrixStorage& input, const MpfrNormRequest& request) { const mpfr_prec_t precision_bits = input.precision_bits (); if (input.numel () == 0) return MpfrScalarStorage (make_zero (precision_bits)); auto work = MpfrMatrixStorage (input.rows (), input.columns (), precision_bits, input); MpfrMatrixStorage work_space ( request.kind == MpfrNormRequest::Kind::infinity ? input.rows () : 1, 1, precision_bits); const char norm_code = request.kind == MpfrNormRequest::Kind::one ? '1' : request.kind == MpfrNormRequest::Kind::infinity ? 'I' : 'F'; MplapackMpfrPrecisionScope scope (precision_bits); auto result = Rlange (&norm_code, MpfrMatrixStorage::checked_mplapack_dimension ( input.rows ()), MpfrMatrixStorage::checked_mplapack_dimension ( input.columns ()), work.data (), work.leading_dimension (), work_space.data ()); return MpfrScalarStorage (std::move (result)); } MpfrScalarStorage complex_matrix_standard_norm (const MpfrComplexMatrixStorage& input, const MpfrNormRequest& request) { const mpfr_prec_t precision_bits = input.precision_bits (); if (input.numel () == 0) return MpfrScalarStorage (make_zero (precision_bits)); auto work = octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( input, precision_bits); MpfrMatrixStorage work_space ( request.kind == MpfrNormRequest::Kind::infinity ? input.rows () : 1, 1, precision_bits); const char norm_code = request.kind == MpfrNormRequest::Kind::one ? '1' : request.kind == MpfrNormRequest::Kind::infinity ? 'I' : 'F'; octave_mplapack::MpfrMpcPrecisionScope scope (precision_bits); auto result = Clange (&norm_code, MpfrComplexMatrixStorage::checked_mplapack_dimension ( input.rows ()), MpfrComplexMatrixStorage::checked_mplapack_dimension ( input.columns ()), work.data (), work.leading_dimension (), work_space.data ()); return MpfrScalarStorage (std::move (result)); } mpfr_prec_t checked_workspace_length (const MpfrScalarStorage::NativeScalar& query) { if (mpfr_nan_p (query.mpfr_data ()) != 0 || mpfr_inf_p (query.mpfr_data ()) != 0 || mpfr_sgn (query.mpfr_data ()) <= 0 || mpfr_integer_p (query.mpfr_data ()) == 0) throw std::runtime_error ("MPLAPACK SVD returned an invalid workspace query"); const auto value = mpfr_get_uj (query.mpfr_data (), MPFR_RNDZ); if (value > static_cast (std::numeric_limits::max ())) throw std::overflow_error ("MPLAPACK SVD workspace is too large"); return static_cast (value); } MpfrMatrixStorage real_singular_values (const MpfrMatrixStorage& input) { const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); MpfrMatrixStorage result (k, 1, precision_bits); if (k == 0) return result; auto a_work = MpfrMatrixStorage (m, n, precision_bits, input); MpfrMatrixStorage u (1, 1, precision_bits); MpfrMatrixStorage vt (1, 1, precision_bits); MpfrMatrixStorage query_work (1, 1, precision_bits); MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope scope (precision_bits); Rgesvd ("N", "N", MpfrMatrixStorage::checked_mplapack_dimension (m), MpfrMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), result.data (), u.data (), 1, vt.data (), 1, query_work.data (), -1, info); if (info != 0) throw std::runtime_error ("MPLAPACK Rgesvd workspace query failed"); const auto lwork = checked_workspace_length (query_work.at (0, 0)); MpfrMatrixStorage work (static_cast (lwork), 1, precision_bits); a_work = MpfrMatrixStorage (m, n, precision_bits, input); Rgesvd ("N", "N", MpfrMatrixStorage::checked_mplapack_dimension (m), MpfrMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), result.data (), u.data (), 1, vt.data (), 1, work.data (), lwork, info); } if (info != 0) throw std::runtime_error ("MPLAPACK Rgesvd failed to converge"); return result; } MpfrMatrixStorage complex_singular_values (const MpfrComplexMatrixStorage& input) { const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); MpfrMatrixStorage result (k, 1, precision_bits); if (k == 0) return result; auto a_work = octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( input, precision_bits); MpfrComplexMatrixStorage u (1, 1, precision_bits); MpfrComplexMatrixStorage vt (1, 1, precision_bits); MpfrComplexMatrixStorage query_work (1, 1, precision_bits); MpfrMatrixStorage rwork (5 * k, 1, precision_bits); MpfrComplexMatrixStorage::MplapackInteger info = 0; { octave_mplapack::MpfrMpcPrecisionScope scope (precision_bits); Cgesvd ("N", "N", MpfrComplexMatrixStorage::checked_mplapack_dimension (m), MpfrComplexMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), result.data (), u.data (), 1, vt.data (), 1, query_work.data (), -1, rwork.data (), info); if (info != 0) throw std::runtime_error ("MPLAPACK Cgesvd workspace query failed"); const auto& query = query_work.at (0, 0); auto query_real = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); mpfr_set (query_real.mpfr_data (), mpc_realref (query.mpc_data ()), MPFR_RNDN); const auto actual_lwork = checked_workspace_length (query_real); MpfrComplexMatrixStorage work (static_cast (actual_lwork), 1, precision_bits); a_work = octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( input, precision_bits); Cgesvd ("N", "N", MpfrComplexMatrixStorage::checked_mplapack_dimension (m), MpfrComplexMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), result.data (), u.data (), 1, vt.data (), 1, work.data (), actual_lwork, rwork.data (), info); } if (info != 0) throw std::runtime_error ("MPLAPACK Cgesvd failed to converge"); return result; } template MpfrScalarStorage largest_singular_value (const Matrix& input) { if (input.numel () == 0) return MpfrScalarStorage (make_zero (input.precision_bits ())); auto values = [&] { if constexpr (std::is_same_v) return real_singular_values (input); else return complex_singular_values (input); } (); return MpfrScalarStorage (std::move (values.at (0, 0))); } } // namespace namespace octave_mplapack { MpfrScalarStorage mplapack_mpfr_norm (const MpfrMatrixStorage& input, const MpfrNormRequest& request) { validate_precision (input.precision_bits ()); const bool vector = input.rows () == 1 || input.columns () == 1; if (vector) return real_vector_norm (input, request); if (request.kind == MpfrNormRequest::Kind::two) return largest_singular_value (input); if (request.kind == MpfrNormRequest::Kind::one || request.kind == MpfrNormRequest::Kind::infinity || request.kind == MpfrNormRequest::Kind::frobenius) return real_matrix_standard_norm (input, request); throw std::invalid_argument ( "matrix norm supports only 1, 2, Inf, and fro norms"); } MpfrScalarStorage mplapack_mpc_norm (const MpfrComplexMatrixStorage& input, const MpfrNormRequest& request) { validate_precision (input.precision_bits ()); const bool vector = input.rows () == 1 || input.columns () == 1; if (vector) return complex_vector_norm (input, request); if (request.kind == MpfrNormRequest::Kind::two) return largest_singular_value (input); if (request.kind == MpfrNormRequest::Kind::one || request.kind == MpfrNormRequest::Kind::infinity || request.kind == MpfrNormRequest::Kind::frobenius) return complex_matrix_standard_norm (input, request); throw std::invalid_argument ( "matrix norm supports only 1, 2, Inf, and fro norms"); } MpfrMatrixStorage mplapack_mpfr_singular_values (const MpfrMatrixStorage& input) { return real_singular_values (input); } MpfrMatrixStorage mplapack_mpc_singular_values (const MpfrComplexMatrixStorage& input) { return complex_singular_values (input); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_matrix_storage.cc0000644000230300031750000001600515274353472021067 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_storage.h" #include #include #include #include #include #include namespace { void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ("matrix precision is outside MPFR limits"); } } // namespace namespace octave_mplapack { static_assert (std::is_same_v); static_assert (std::is_same_v); static_assert (std::is_same_v); static_assert (std::is_integral_v); static_assert (std::is_signed_v); MpfrMatrixStorage::MpfrMatrixStorage (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits) : m_rows (rows), m_columns (columns), m_precision_bits (precision_bits), m_values (make_elements (checked_element_count (rows, columns), precision_bits)) { checked_mplapack_dimension (rows); checked_mplapack_dimension (columns); } MpfrMatrixStorage::MpfrMatrixStorage ( std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const std::vector& column_major_values) : MpfrMatrixStorage (rows, columns, precision_bits) { if (column_major_values.size () != m_values.size ()) throw std::invalid_argument ("double matrix element count mismatch"); for (std::size_t index = 0; index < m_values.size (); ++index) mpfr_set_d (m_values[index].mpfr_data (), column_major_values[index], MPFR_RNDN); } MpfrMatrixStorage::MpfrMatrixStorage ( std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const std::vector& column_major_values) : MpfrMatrixStorage (rows, columns, precision_bits) { if (column_major_values.size () != m_values.size ()) throw std::invalid_argument ("text matrix element count mismatch"); for (std::size_t index = 0; index < m_values.size (); ++index) if (mpfr_set_str (m_values[index].mpfr_data (), column_major_values[index].c_str (), 10, MPFR_RNDN) != 0) throw std::invalid_argument ("invalid matrix element text"); } MpfrMatrixStorage::MpfrMatrixStorage ( std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const MpfrMatrixStorage& source) : MpfrMatrixStorage (rows, columns, precision_bits) { if (source.rows () != rows || source.columns () != columns) throw std::invalid_argument ("matrix promotion shape mismatch"); for (std::size_t index = 0; index < m_values.size (); ++index) mpfr_set (m_values[index].mpfr_data (), source.m_values[index].mpfr_data (), MPFR_RNDN); } MpfrMatrixStorage& MpfrMatrixStorage::operator= (MpfrMatrixStorage other) noexcept { swap (other); return *this; } void MpfrMatrixStorage::swap (MpfrMatrixStorage& other) noexcept { using std::swap; swap (m_rows, other.m_rows); swap (m_columns, other.m_columns); swap (m_precision_bits, other.m_precision_bits); m_values.swap (other.m_values); } std::size_t MpfrMatrixStorage::rows () const noexcept { return m_rows; } std::size_t MpfrMatrixStorage::columns () const noexcept { return m_columns; } std::size_t MpfrMatrixStorage::numel () const noexcept { return m_values.size (); } mpfr_prec_t MpfrMatrixStorage::precision_bits () const noexcept { return m_precision_bits; } MpfrMatrixStorage::MplapackInteger MpfrMatrixStorage::leading_dimension () const { return checked_mplapack_dimension (std::max (1, m_rows)); } MpfrMatrixStorage::NativeScalar * MpfrMatrixStorage::data () noexcept { return m_values.data (); } const MpfrMatrixStorage::NativeScalar * MpfrMatrixStorage::data () const noexcept { return m_values.data (); } MpfrMatrixStorage::NativeScalar& MpfrMatrixStorage::at (std::size_t row, std::size_t column) { return m_values.at (offset (row, column)); } const MpfrMatrixStorage::NativeScalar& MpfrMatrixStorage::at (std::size_t row, std::size_t column) const { return m_values.at (offset (row, column)); } bool MpfrMatrixStorage::all_elements_have_uniform_precision () const noexcept { return std::all_of ( m_values.begin (), m_values.end (), [this] (const NativeScalar& value) { return value.precision () == m_precision_bits; }); } bool MpfrMatrixStorage::element_exactly_equal_text ( std::size_t row, std::size_t column, const std::string& text) const { NativeScalar expected = NativeScalar::with_precision (m_precision_bits); if (mpfr_set_str (expected.mpfr_data (), text.c_str (), 10, MPFR_RNDN) != 0) throw std::invalid_argument ("invalid matrix comparison text"); return mpfr_equal_p (at (row, column).mpfr_data (), expected.mpfr_data ()) != 0; } bool MpfrMatrixStorage::element_exactly_equal_double ( std::size_t row, std::size_t column, double value) const noexcept { try { return mpfr_cmp_d (at (row, column).mpfr_data (), value) == 0; } catch (...) { return false; } } bool MpfrMatrixStorage::element_exactly_equal ( std::size_t row, std::size_t column, const MpfrMatrixStorage& other, std::size_t other_row, std::size_t other_column) const { return mpfr_equal_p (at (row, column).mpfr_data (), other.at (other_row, other_column).mpfr_data ()) != 0; } std::size_t MpfrMatrixStorage::checked_element_count (std::size_t rows, std::size_t columns) { checked_mplapack_dimension (rows); checked_mplapack_dimension (columns); if (rows != 0 && columns > std::numeric_limits::max () / rows) throw std::overflow_error ("matrix element count overflow"); return rows * columns; } MpfrMatrixStorage::MplapackInteger MpfrMatrixStorage::checked_mplapack_dimension (std::size_t value) { using Limit = std::numeric_limits; if (value > static_cast (Limit::max ())) throw std::overflow_error ("matrix dimension exceeds MPLAPACK INTEGER"); return static_cast (value); } std::vector MpfrMatrixStorage::make_elements (std::size_t count, mpfr_prec_t precision_bits) { validate_precision (precision_bits); std::vector values; values.reserve (count); for (std::size_t index = 0; index < count; ++index) values.emplace_back (NativeScalar::with_precision (precision_bits)); return values; } std::size_t MpfrMatrixStorage::offset (std::size_t row, std::size_t column) const { if (row >= m_rows || column >= m_columns) throw std::out_of_range ("matrix element index out of range"); return row + column * m_rows; } void swap (MpfrMatrixStorage& lhs, MpfrMatrixStorage& rhs) noexcept { lhs.swap (rhs); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_lu.cc0000644000230300031750000001366315274353472020215 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_lu.h" #include #include #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_precision.h" namespace octave_mplapack { void require_mplapack_mpc_lu_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work) { if (operation_precision < MPFR_PREC_MIN || operation_precision > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK MPC LU precision is outside the MPFR range"); const auto precision_override = mpfrxx::mpc_precision_override_storage (); const bool matches = mpfrxx::default_precision_bits () == operation_precision && precision_override.active && precision_override.real_precision_bits == operation_precision && precision_override.imag_precision_bits == operation_precision && a_work.precision_bits () == operation_precision && a_work.all_elements_have_uniform_precision (); if (! matches) throw std::runtime_error ( "MPLAPACK complex precision contract mismatch at Cgetrf boundary"); } namespace { void set_zero (mpc_ptr value) { mpc_set_ui_ui (value, 0, 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } void set_one (mpc_ptr value) { mpc_set_ui_ui (value, 1, 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } // namespace MpcLuResult mplapack_mpc_matrix_lu (const MpfrComplexMatrixStorage& input) { const mpfr_prec_t operation_precision = input.precision_bits (); if (operation_precision < MPFR_PREC_MIN || operation_precision > MPFR_PREC_MAX) throw std::invalid_argument ("complex LU precision is outside the MPFR range"); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); // Match the real M21 interface: every zero-dimensional input is normalized // to empty 0x0 outputs, and no zero-sized array is passed to Cgetrf. if (m == 0 || n == 0) return {MpfrComplexMatrixStorage (0, 0, operation_precision), MpfrComplexMatrixStorage (0, 0, operation_precision), MpfrComplexMatrixStorage (0, 0, operation_precision), std::vector (), 0}; const auto m_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (m); const auto n_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (n); if (k > std::numeric_limits::max () / sizeof (MpfrComplexMatrixStorage::MplapackInteger) || m > std::numeric_limits::max () / sizeof (MpfrComplexMatrixStorage::MplapackInteger)) throw std::overflow_error ("complex LU pivot allocation size overflow"); // Cgetrf destructively overwrites A. This is an operation-owned copy so // the public mp value retains value semantics even for singular factors. MpfrComplexMatrixStorage a_work = mplapack_mpc_matrix_copy_at_precision (input, operation_precision); std::vector ipiv (k); MpfrComplexMatrixStorage::MplapackInteger info = 0; { MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_lu_precision_contract (operation_precision, a_work); Cgetrf (m_arg, n_arg, a_work.data (), a_work.leading_dimension (), ipiv.data (), info); require_mplapack_mpc_lu_precision_contract (operation_precision, a_work); } if (info < 0) throw MpcCgetrfError (MpcCgetrfError::Kind::invalid_argument, info, "MPLAPACK Cgetrf rejected an argument"); if (info > static_cast (k)) throw MpcCgetrfError (MpcCgetrfError::Kind::internal, info, "MPLAPACK Cgetrf returned an invalid INFO value"); // IPIV is a sequence of swaps. Replay it so permutation[d] is the source // row at destination row d, which is the public P*A and A(p,:) contract. std::vector permutation (m); std::iota (permutation.begin (), permutation.end (), static_cast (1)); for (std::size_t step = 0; step < k; ++step) { const auto pivot = ipiv[step]; if (pivot < 1 || pivot > m_arg) throw MpcCgetrfError (MpcCgetrfError::Kind::internal, 0, "MPLAPACK Cgetrf returned an invalid pivot"); std::swap (permutation[step], permutation[static_cast (pivot - 1)]); } std::vector seen (m, false); for (const auto source : permutation) { if (source < 1 || source > m_arg || seen[static_cast (source - 1)]) throw MpcCgetrfError ( MpcCgetrfError::Kind::internal, 0, "MPLAPACK Cgetrf returned an invalid final permutation"); seen[static_cast (source - 1)] = true; } MpfrComplexMatrixStorage lower (m, k, operation_precision); MpfrComplexMatrixStorage upper (k, n, operation_precision); for (std::size_t column = 0; column < k; ++column) for (std::size_t row = 0; row < m; ++row) { if (row == column) set_one (lower.at (row, column).mpc_data ()); else if (row > column) mpc_set (lower.at (row, column).mpc_data (), a_work.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else set_zero (lower.at (row, column).mpc_data ()); } for (std::size_t column = 0; column < n; ++column) for (std::size_t row = 0; row < k; ++row) { if (row <= column) mpc_set (upper.at (row, column).mpc_data (), a_work.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else set_zero (upper.at (row, column).mpc_data ()); } return {std::move (a_work), std::move (lower), std::move (upper), std::move (permutation), info}; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_structured_eig.cc0000644000230300031750000003263415274353472021075 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_structured_eig.h" #include #include #include #include #include #include #include #include #include #include "mp_complex_precision.h" #include "mp_precision.h" namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrScalarStorage; void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK structured eig precision is outside MPFR limits"); } std::size_t checked_workspace_length (const MpfrScalarStorage::NativeScalar& query, const char *routine) { if (mpfr_nan_p (query.mpfr_data ()) != 0 || mpfr_inf_p (query.mpfr_data ()) != 0 || mpfr_integer_p (query.mpfr_data ()) == 0 || mpfr_sgn (query.mpfr_data ()) <= 0) throw std::runtime_error (std::string (routine) + " returned an invalid workspace query"); mpz_t value; mpz_t max_mplapack; mpz_t max_size; mpz_init (value); mpz_init (max_mplapack); mpz_init (max_size); mpfr_get_z (value, query.mpfr_data (), MPFR_RNDZ); const auto mplapack_max = std::numeric_limits::max (); const auto size_max = std::numeric_limits::max (); mpz_import (max_mplapack, 1, -1, sizeof (mplapack_max), 0, 0, &mplapack_max); mpz_import (max_size, 1, -1, sizeof (size_max), 0, 0, &size_max); const bool fits = mpz_cmp (value, max_mplapack) <= 0 && mpz_cmp (value, max_size) <= 0; if (! fits) { mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); throw std::overflow_error (std::string (routine) + " workspace exceeds allocation limits"); } const auto result = static_cast ( mpfr_get_uj (query.mpfr_data (), MPFR_RNDZ)); mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); return result; } std::size_t checked_integer_workspace_length (MpfrMatrixStorage::MplapackInteger value, const char *routine) { if (value <= 0) throw std::runtime_error (std::string (routine) + " returned an invalid integer workspace query"); return static_cast (value); } std::size_t checked_complex_workspace_length ( const MpfrComplexMatrixStorage::NativeScalar& query, const char *routine) { if (mpfr_sgn (mpc_imagref (query.mpc_data ())) != 0) throw std::runtime_error (std::string (routine) + " returned a complex workspace query"); auto real_query = MpfrScalarStorage::NativeScalar::with_precision ( query.real_precision ()); mpfr_set (real_query.mpfr_data (), mpc_realref (query.mpc_data ()), MPFR_RNDN); return checked_workspace_length (real_query, routine); } bool is_exactly_symmetric (const MpfrMatrixStorage& input) { for (std::size_t column = 0; column < input.columns (); ++column) for (std::size_t row = column + 1; row < input.rows (); ++row) if (mpfr_equal_p (input.at (row, column).mpfr_data (), input.at (column, row).mpfr_data ()) == 0) return false; return true; } bool is_exactly_hermitian (const MpfrComplexMatrixStorage& input) { for (std::size_t column = 0; column < input.columns (); ++column) { if (mpfr_zero_p (mpc_imagref (input.at (column, column).mpc_data ())) == 0) return false; for (std::size_t row = column + 1; row < input.rows (); ++row) { const auto& lhs = input.at (row, column); const auto& rhs = input.at (column, row); if (mpfr_equal_p (mpc_realref (lhs.mpc_data ()), mpc_realref (rhs.mpc_data ())) == 0) return false; auto negated_imag = MpfrScalarStorage::NativeScalar::with_precision ( lhs.imag_precision ()); mpfr_neg (negated_imag.mpfr_data (), mpc_imagref (lhs.mpc_data ()), MPFR_RNDN); if (mpfr_equal_p (negated_imag.mpfr_data (), mpc_imagref (rhs.mpc_data ())) == 0) return false; } } return true; } void require_real_contract (mpfr_prec_t precision, const MpfrMatrixStorage& a, const MpfrMatrixStorage& w, const MpfrMatrixStorage& work) { if (mpfrxx::default_precision_bits () != precision || a.precision_bits () != precision || w.precision_bits () != precision || work.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! w.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rsyevd boundary"); } void require_complex_contract (mpfr_prec_t precision, const MpfrComplexMatrixStorage& a, const MpfrMatrixStorage& w, const MpfrComplexMatrixStorage& work, const MpfrMatrixStorage& rwork) { const auto state = mpfrxx::mpc_precision_override_storage (); if (mpfrxx::default_precision_bits () != precision || ! state.active || state.real_precision_bits != precision || state.imag_precision_bits != precision || a.precision_bits () != precision || w.precision_bits () != precision || work.precision_bits () != precision || rwork.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! w.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision () || ! rwork.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPC precision contract mismatch at Cheevd boundary"); } void fill_diagonal (MpfrMatrixStorage& diagonal, const MpfrMatrixStorage& eigenvalues) { for (std::size_t column = 0; column < diagonal.columns (); ++column) for (std::size_t row = 0; row < diagonal.rows (); ++row) { if (row == column) mpfr_set (diagonal.at (row, column).mpfr_data (), eigenvalues.at (row, 0).mpfr_data (), MPFR_RNDN); else mpfr_set_zero (diagonal.at (row, column).mpfr_data (), 1); } } } // namespace namespace octave_mplapack { bool mplapack_mpfr_matrix_is_exactly_symmetric ( const MpfrMatrixStorage& input) noexcept { return is_exactly_symmetric (input); } bool mplapack_mpc_matrix_is_exactly_hermitian ( const MpfrComplexMatrixStorage& input) noexcept { return is_exactly_hermitian (input); } MpfrStructuredEigResult mplapack_mpfr_matrix_structured_eig (const MpfrMatrixStorage& input) { if (input.rows () != input.columns ()) throw std::invalid_argument ( "structured eig requires a square real matrix"); if (! is_exactly_symmetric (input)) throw std::invalid_argument ( "eig currently requires an exactly symmetric real mp matrix"); const mpfr_prec_t precision = input.precision_bits (); validate_precision (precision); const std::size_t n = input.rows (); MpfrStructuredEigResult result { MpfrMatrixStorage (n, 1, precision), MpfrMatrixStorage (n, n, precision), MpfrMatrixStorage (n, n, precision) }; if (n == 0) return result; MpfrMatrixStorage a_work (n, n, precision, input); MpfrMatrixStorage query_w (n, 1, precision); MpfrMatrixStorage query_work (1, 1, precision); std::vector query_iwork (1); MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope scope (precision); require_real_contract (precision, a_work, query_w, query_work); Rsyevd ("V", "U", MpfrMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), query_w.data (), query_work.data (), -1, query_iwork.data (), -1, info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK Rsyevd changed the current-thread default precision"); } if (info < 0) throw MpfrStructuredEigError ( -static_cast (info), "MPLAPACK Rsyevd rejected a workspace query"); if (info > 0) throw MpfrStructuredEigError ( static_cast (info), "MPLAPACK Rsyevd workspace query failed"); const std::size_t lwork = checked_workspace_length (query_work.at (0, 0), "MPLAPACK Rsyevd"); const std::size_t liwork = checked_integer_workspace_length ( query_iwork.at (0), "MPLAPACK Rsyevd"); MpfrMatrixStorage work (lwork, 1, precision); a_work = MpfrMatrixStorage (n, n, precision, input); MpfrMatrixStorage eigenvalues (n, 1, precision); std::vector iwork (liwork); info = 0; { MplapackMpfrPrecisionScope scope (precision); require_real_contract (precision, a_work, eigenvalues, work); Rsyevd ("V", "U", MpfrMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), eigenvalues.data (), work.data (), static_cast (lwork), iwork.data (), static_cast (liwork), info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK Rsyevd changed the current-thread default precision"); } if (info != 0) throw MpfrStructuredEigError ( static_cast (info), info < 0 ? "MPLAPACK Rsyevd rejected an argument" : "MPLAPACK Rsyevd failed to converge"); result.eigenvalues = std::move (eigenvalues); result.vectors = std::move (a_work); fill_diagonal (result.diagonal, result.eigenvalues); return result; } MpcStructuredEigResult mplapack_mpc_matrix_structured_eig (const MpfrComplexMatrixStorage& input) { if (input.rows () != input.columns ()) throw std::invalid_argument ( "structured eig requires a square complex matrix"); if (! is_exactly_hermitian (input)) throw std::invalid_argument ( "eig currently requires an exactly Hermitian complex mp matrix"); const mpfr_prec_t precision = input.precision_bits (); validate_precision (precision); const std::size_t n = input.rows (); MpcStructuredEigResult result { MpfrMatrixStorage (n, 1, precision), MpfrComplexMatrixStorage (n, n, precision), MpfrMatrixStorage (n, n, precision) }; if (n == 0) return result; MpfrComplexMatrixStorage a_work = input; MpfrMatrixStorage query_w (n, 1, precision); MpfrComplexMatrixStorage query_work (1, 1, precision); MpfrMatrixStorage query_rwork (1, 1, precision); std::vector query_iwork (1); MpfrComplexMatrixStorage::MplapackInteger info = 0; { MpfrMpcPrecisionScope scope (precision); require_complex_contract (precision, a_work, query_w, query_work, query_rwork); Cheevd ("V", "U", MpfrComplexMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), query_w.data (), query_work.data (), -1, query_rwork.data (), -1, query_iwork.data (), -1, info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK Cheevd changed the current-thread default precision"); } if (info < 0) throw MpcStructuredEigError ( -static_cast (info), "MPLAPACK Cheevd rejected a workspace query"); if (info > 0) throw MpcStructuredEigError ( static_cast (info), "MPLAPACK Cheevd workspace query failed"); const std::size_t lwork = checked_complex_workspace_length ( query_work.at (0, 0), "MPLAPACK Cheevd"); const std::size_t lrwork = checked_workspace_length ( query_rwork.at (0, 0), "MPLAPACK Cheevd real workspace"); const std::size_t liwork = checked_integer_workspace_length ( query_iwork.at (0), "MPLAPACK Cheevd"); MpfrComplexMatrixStorage work (lwork, 1, precision); MpfrMatrixStorage rwork (lrwork, 1, precision); MpfrComplexMatrixStorage::MplapackInteger info2 = 0; std::vector iwork (liwork); a_work = input; MpfrMatrixStorage eigenvalues (n, 1, precision); { MpfrMpcPrecisionScope scope (precision); require_complex_contract (precision, a_work, eigenvalues, work, rwork); Cheevd ("V", "U", MpfrComplexMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), eigenvalues.data (), work.data (), static_cast (lwork), rwork.data (), static_cast (lrwork), iwork.data (), static_cast (liwork), info2); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK Cheevd changed the current-thread default precision"); } if (info2 != 0) throw MpcStructuredEigError ( static_cast (info2), info2 < 0 ? "MPLAPACK Cheevd rejected an argument" : "MPLAPACK Cheevd failed to converge"); result.eigenvalues = std::move (eigenvalues); result.vectors = std::move (a_work); fill_diagonal (result.diagonal, result.eigenvalues); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_arithmetic.cc0000644000230300031750000000434315274353472020172 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_scalar_storage.h" #include namespace octave_mplapack { MpfrScalarStorage MpfrScalarStorage::add (const MpfrScalarStorage& rhs) const { const mpfr_prec_t result_precision = std::max (precision_bits (), rhs.precision_bits ()); MpfrScalarStorage result (result_precision, UninitializedTag {}); mpfr_add (result.m_value.mpfr_data (), m_value.mpfr_data (), rhs.m_value.mpfr_data (), MPFR_RNDN); return result; } MpfrScalarStorage MpfrScalarStorage::subtract (const MpfrScalarStorage& rhs) const { const mpfr_prec_t result_precision = std::max (precision_bits (), rhs.precision_bits ()); MpfrScalarStorage result (result_precision, UninitializedTag {}); mpfr_sub (result.m_value.mpfr_data (), m_value.mpfr_data (), rhs.m_value.mpfr_data (), MPFR_RNDN); return result; } MpfrScalarStorage MpfrScalarStorage::multiply (const MpfrScalarStorage& rhs) const { const mpfr_prec_t result_precision = std::max (precision_bits (), rhs.precision_bits ()); MpfrScalarStorage result (result_precision, UninitializedTag {}); mpfr_mul (result.m_value.mpfr_data (), m_value.mpfr_data (), rhs.m_value.mpfr_data (), MPFR_RNDN); return result; } MpfrScalarStorage MpfrScalarStorage::divide (const MpfrScalarStorage& rhs) const { const mpfr_prec_t result_precision = std::max (precision_bits (), rhs.precision_bits ()); MpfrScalarStorage result (result_precision, UninitializedTag {}); mpfr_div (result.m_value.mpfr_data (), m_value.mpfr_data (), rhs.m_value.mpfr_data (), MPFR_RNDN); return result; } MpfrScalarStorage MpfrScalarStorage::power (const MpfrScalarStorage& rhs) const { const mpfr_prec_t result_precision = std::max (precision_bits (), rhs.precision_bits ()); MpfrScalarStorage result (result_precision, UninitializedTag {}); mpfr_pow (result.m_value.mpfr_data (), m_value.mpfr_data (), rhs.m_value.mpfr_data (), MPFR_RNDN); return result; } MpfrScalarStorage MpfrScalarStorage::negate () const { MpfrScalarStorage result (precision_bits (), UninitializedTag {}); mpfr_neg (result.m_value.mpfr_data (), m_value.mpfr_data (), MPFR_RNDN); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_scalar_storage.h0000644000230300031750000000357615274353472020703 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SCALAR_STORAGE_H #define OCTAVE_MPLAPACK_MP_SCALAR_STORAGE_H #include #include #include namespace octave_mplapack { class MpfrScalarStorage { public: using NativeScalar = mpfrxx::mpfr_class; MpfrScalarStorage (const std::string& text, mpfr_prec_t precision_bits); MpfrScalarStorage (double value, mpfr_prec_t precision_bits); explicit MpfrScalarStorage (NativeScalar value); MpfrScalarStorage (const MpfrScalarStorage&) = default; MpfrScalarStorage (MpfrScalarStorage&&) noexcept = default; ~MpfrScalarStorage () = default; MpfrScalarStorage& operator= (MpfrScalarStorage other) noexcept; void swap (MpfrScalarStorage& other) noexcept; mpfr_prec_t precision_bits () const noexcept; bool exactly_equal (const MpfrScalarStorage& other) const noexcept; bool exactly_equal_string (const std::string& text) const; bool exactly_equal_double (double value) const noexcept; bool is_nan () const noexcept; bool is_infinite () const noexcept; bool is_zero () const noexcept; bool signbit () const noexcept; std::string to_canonical_string () const; double to_double () const noexcept; MpfrScalarStorage add (const MpfrScalarStorage& rhs) const; MpfrScalarStorage subtract (const MpfrScalarStorage& rhs) const; MpfrScalarStorage multiply (const MpfrScalarStorage& rhs) const; MpfrScalarStorage divide (const MpfrScalarStorage& rhs) const; MpfrScalarStorage power (const MpfrScalarStorage& rhs) const; MpfrScalarStorage negate () const; const NativeScalar& native_value () const noexcept; private: struct UninitializedTag { }; MpfrScalarStorage (mpfr_prec_t precision_bits, UninitializedTag); NativeScalar m_value; }; void swap (MpfrScalarStorage& lhs, MpfrScalarStorage& rhs) noexcept; } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_matrix_storage.h0000644000230300031750000000557715274353472020745 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_MATRIX_STORAGE_H #define OCTAVE_MPLAPACK_MP_MATRIX_STORAGE_H #include #include #include #include #include "mp_scalar_storage.h" namespace octave_mplapack { class MpfrMatrixStorage { public: using NativeScalar = MpfrScalarStorage::NativeScalar; using MplapackInteger = mplapackint; MpfrMatrixStorage (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits); MpfrMatrixStorage (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const std::vector& column_major_values); MpfrMatrixStorage (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const std::vector& column_major_values); MpfrMatrixStorage (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const MpfrMatrixStorage& source); MpfrMatrixStorage (const MpfrMatrixStorage&) = default; MpfrMatrixStorage (MpfrMatrixStorage&&) noexcept = default; ~MpfrMatrixStorage () = default; MpfrMatrixStorage& operator= (MpfrMatrixStorage other) noexcept; void swap (MpfrMatrixStorage& other) noexcept; std::size_t rows () const noexcept; std::size_t columns () const noexcept; std::size_t numel () const noexcept; mpfr_prec_t precision_bits () const noexcept; MplapackInteger leading_dimension () const; NativeScalar * data () noexcept; const NativeScalar * data () const noexcept; NativeScalar& at (std::size_t row, std::size_t column); const NativeScalar& at (std::size_t row, std::size_t column) const; bool all_elements_have_uniform_precision () const noexcept; bool element_exactly_equal_text (std::size_t row, std::size_t column, const std::string& text) const; bool element_exactly_equal_double (std::size_t row, std::size_t column, double value) const noexcept; bool element_exactly_equal (std::size_t row, std::size_t column, const MpfrMatrixStorage& other, std::size_t other_row, std::size_t other_column) const; static std::size_t checked_element_count (std::size_t rows, std::size_t columns); static MplapackInteger checked_mplapack_dimension (std::size_t value); private: static std::vector make_elements ( std::size_t count, mpfr_prec_t precision_bits); std::size_t offset (std::size_t row, std::size_t column) const; std::size_t m_rows; std::size_t m_columns; mpfr_prec_t m_precision_bits; std::vector m_values; }; void swap (MpfrMatrixStorage& lhs, MpfrMatrixStorage& rhs) noexcept; } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_value.cc0000644000230300031750000000701215274353472017151 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_value.h" #include "mp_native_serialization.h" #include #include #include #include #include namespace { constexpr mpfr_prec_t registration_precision = MPFR_PREC_MIN; } DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA ( octave_mplapack_mpfr_scalar_internal, "mplapack_mpfr_scalar_internal", "mplapack_mpfr_scalar_internal"); octave_mplapack_mpfr_scalar_internal:: octave_mplapack_mpfr_scalar_internal () : m_storage ("0", registration_precision) { } octave_mplapack_mpfr_scalar_internal:: octave_mplapack_mpfr_scalar_internal (const std::string& text, mpfr_prec_t precision_bits) : m_storage (text, precision_bits) { } octave_mplapack_mpfr_scalar_internal:: octave_mplapack_mpfr_scalar_internal (double value, mpfr_prec_t precision_bits) : m_storage (value, precision_bits) { } octave_mplapack_mpfr_scalar_internal:: octave_mplapack_mpfr_scalar_internal ( octave_mplapack::MpfrScalarStorage storage) : m_storage (std::move (storage)) { } octave_base_value * octave_mplapack_mpfr_scalar_internal::clone () const { return new octave_mplapack_mpfr_scalar_internal (*this); } octave_base_value * octave_mplapack_mpfr_scalar_internal::empty_clone () const { return clone (); } dim_vector octave_mplapack_mpfr_scalar_internal::dims () const { return dim_vector (1, 1); } bool octave_mplapack_mpfr_scalar_internal::is_defined () const { return true; } bool octave_mplapack_mpfr_scalar_internal::is_storable () const { return true; } bool octave_mplapack_mpfr_scalar_internal::is_real_scalar () const { return true; } bool octave_mplapack_mpfr_scalar_internal::isreal () const { return true; } bool octave_mplapack_mpfr_scalar_internal::is_scalar_type () const { return true; } bool octave_mplapack_mpfr_scalar_internal::save_ascii (std::ostream& os) { return octave_mplapack::save_native_mpfr_scalar (os, m_storage); } bool octave_mplapack_mpfr_scalar_internal::load_ascii (std::istream& is) { return octave_mplapack::load_native_mpfr_scalar (is, m_storage); } bool octave_mplapack_mpfr_scalar_internal::save_binary (std::ostream& os, bool) { return octave_mplapack::save_native_mpfr_scalar (os, m_storage); } bool octave_mplapack_mpfr_scalar_internal::load_binary ( std::istream& is, bool, octave::mach_info::float_format) { return octave_mplapack::load_native_mpfr_scalar (is, m_storage); } void octave_mplapack_mpfr_scalar_internal::print (std::ostream& os, bool) { print_raw (os); } void octave_mplapack_mpfr_scalar_internal::print_raw (std::ostream& os, bool) const { os << "[internal MPLAPACK MPFR scalar; " << m_storage.precision_bits () << " bits]"; } const octave_mplapack::MpfrScalarStorage& octave_mplapack_mpfr_scalar_internal::storage () const noexcept { return m_storage; } const octave_mplapack_mpfr_scalar_internal& octave_mplapack_mpfr_scalar_internal::checked_value ( const octave_value& value) { if (value.type_id () != static_type_id ()) error_with_id ("mplapack:InvalidNativeValue", "expected an internal MPLAPACK MPFR scalar"); const auto *native_value = dynamic_cast (value.internal_rep ()); if (! native_value) error_with_id ("mplapack:InvalidNativeValue", "invalid internal MPLAPACK MPFR scalar representation"); return *native_value; } mplapack-interop-0.5.1/src/mp_blas.cc0000644000230300031750000001275715274353472016772 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_blas.h" #include #include #include namespace { void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ("MPLAPACK MPFR precision is outside the MPFR range"); } void set_zero (octave_mplapack::MpfrMatrixStorage& matrix) { for (std::size_t index = 0; index < matrix.numel (); ++index) mpfr_set_zero (matrix.data ()[index].mpfr_data (), 1); } mpfrxx::mpfr_class make_scalar_at_precision (const mpfrxx::mpfr_class& source, mpfr_prec_t precision_bits) { mpfrxx::mpfr_class result = mpfrxx::mpfr_class::with_precision (precision_bits); mpfr_set (result.mpfr_data (), source.mpfr_data (), MPFR_RNDN); return result; } mpfrxx::mpfr_class make_scalar_at_precision (double source, mpfr_prec_t precision_bits) { mpfrxx::mpfr_class result = mpfrxx::mpfr_class::with_precision (precision_bits); mpfr_set_d (result.mpfr_data (), source, MPFR_RNDN); return result; } } // namespace namespace octave_mplapack { void require_mplapack_mpfr_precision_contract ( mpfr_prec_t operation_precision, const mpfrxx::mpfr_class& alpha, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& b_work, const mpfrxx::mpfr_class& beta, const MpfrMatrixStorage& c) { validate_precision (operation_precision); const bool matches = mpfrxx::default_precision_bits () == operation_precision && alpha.precision () == operation_precision && beta.precision () == operation_precision && a_work.precision_bits () == operation_precision && b_work.precision_bits () == operation_precision && c.precision_bits () == operation_precision; if (! matches) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rgemm boundary"); } MpfrMatrixStorage mplapack_mpfr_matrix_multiply (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs) { if (lhs.columns () != rhs.rows ()) throw std::invalid_argument ("matrix multiplication dimension mismatch"); const mpfr_prec_t operation_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); validate_precision (operation_precision); MpfrMatrixStorage a_work (lhs.rows (), lhs.columns (), operation_precision, lhs); MpfrMatrixStorage b_work (rhs.rows (), rhs.columns (), operation_precision, rhs); MpfrMatrixStorage result (lhs.rows (), rhs.columns (), operation_precision); // No arithmetic call is needed for an empty product. In particular, this // avoids passing a null data pointer to Rgemm while retaining result shape // and explicit operation precision metadata. if (result.numel () == 0 || lhs.columns () == 0) { set_zero (result); return result; } mpfrxx::mpfr_class alpha = mpfrxx::mpfr_class::with_precision (operation_precision); mpfrxx::mpfr_class beta = mpfrxx::mpfr_class::with_precision (operation_precision); mpfr_set_ui (alpha.mpfr_data (), 1, MPFR_RNDN); mpfr_set_zero (beta.mpfr_data (), 1); { MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_precision_contract ( operation_precision, alpha, a_work, b_work, beta, result); Rgemm ("N", "N", MpfrMatrixStorage::checked_mplapack_dimension (lhs.rows ()), MpfrMatrixStorage::checked_mplapack_dimension (rhs.columns ()), MpfrMatrixStorage::checked_mplapack_dimension (lhs.columns ()), alpha, a_work.data (), a_work.leading_dimension (), b_work.data (), b_work.leading_dimension (), beta, result.data (), result.leading_dimension ()); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgemm changed the current-thread default precision"); } return result; } MpfrMatrixStorage mplapack_mpfr_matrix_scale (const MpfrMatrixStorage& matrix, const mpfrxx::mpfr_class& scalar) { const mpfr_prec_t operation_precision = std::max (matrix.precision_bits (), scalar.precision ()); validate_precision (operation_precision); MpfrMatrixStorage result (matrix.rows (), matrix.columns (), operation_precision, matrix); const mpfrxx::mpfr_class scalar_work = make_scalar_at_precision (scalar, operation_precision); MplapackMpfrPrecisionScope precision_scope (operation_precision); for (std::size_t index = 0; index < result.numel (); ++index) mpfr_mul (result.data ()[index].mpfr_data (), result.data ()[index].mpfr_data (), scalar_work.mpfr_data (), MPFR_RNDN); return result; } MpfrMatrixStorage mplapack_mpfr_matrix_scale (const MpfrMatrixStorage& matrix, double scalar) { const mpfr_prec_t operation_precision = matrix.precision_bits (); validate_precision (operation_precision); MpfrMatrixStorage result (matrix.rows (), matrix.columns (), operation_precision, matrix); const mpfrxx::mpfr_class scalar_work = make_scalar_at_precision (scalar, operation_precision); MplapackMpfrPrecisionScope precision_scope (operation_precision); for (std::size_t index = 0; index < result.numel (); ++index) mpfr_mul (result.data ()[index].mpfr_data (), result.data ()[index].mpfr_data (), scalar_work.mpfr_data (), MPFR_RNDN); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_matrix_assignment.cc0000644000230300031750000001262715274353472021601 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_assignment.h" #include #include namespace { std::size_t checked_product (std::size_t lhs, std::size_t rhs) { if (lhs != 0 && rhs > std::numeric_limits::max () / lhs) throw std::overflow_error ("assignment selection size overflow"); return lhs * rhs; } bool is_scalar (const octave_mplapack::MpfrAssignmentOperand& rhs) { return rhs.rows == 1 && rhs.columns == 1; } bool is_vector (const octave_mplapack::MpfrAssignmentOperand& rhs) { return rhs.rows == 1 || rhs.columns == 1; } void validate_rhs (const octave_mplapack::MpfrAssignmentOperand& rhs) { if (! rhs.copy_element) throw std::invalid_argument ("assignment RHS has no copier"); (void) checked_product (rhs.rows, rhs.columns); } void copy_rhs_element (octave_mplapack::MpfrMatrixStorage::NativeScalar& destination, const octave_mplapack::MpfrAssignmentOperand& rhs, std::size_t row, std::size_t column) { rhs.copy_element (destination, row, column); } } // namespace namespace octave_mplapack { MpfrMatrixStorage mpfr_matrix_assign_two_subscript ( const MpfrMatrixStorage& source, const std::vector& row_indices, const std::vector& column_indices, const MpfrAssignmentOperand& rhs, mpfr_prec_t result_precision) { validate_rhs (rhs); const std::size_t selected_count = checked_product (row_indices.size (), column_indices.size ()); // An empty selection is a structural no-op. Empty RHS deletion is rejected // by the bridge before reaching this native operation. if (selected_count == 0) { if (! is_scalar (rhs) && checked_product (rhs.rows, rhs.columns) != 0) throw std::invalid_argument ( "non-scalar RHS is not conformant with an empty selection"); MpfrMatrixStorage result (source.rows (), source.columns (), result_precision, source); return result; } const bool scalar_rhs = is_scalar (rhs); const bool exact_shape = rhs.rows == row_indices.size () && rhs.columns == column_indices.size (); const bool vector_shape = ! exact_shape && ! scalar_rhs && (row_indices.size () == 1 || column_indices.size () == 1) && is_vector (rhs) && checked_product (rhs.rows, rhs.columns) == selected_count; if (! scalar_rhs && ! exact_shape && ! vector_shape) throw std::invalid_argument ( "assignment RHS dimensions are not conformant with the selection"); for (const std::size_t row : row_indices) if (row >= source.rows ()) throw std::out_of_range ("assignment index is out of bounds"); for (const std::size_t column : column_indices) if (column >= source.columns ()) throw std::out_of_range ("assignment index is out of bounds"); MpfrMatrixStorage result (source.rows (), source.columns (), result_precision, source); for (std::size_t column = 0; column < column_indices.size (); ++column) for (std::size_t row = 0; row < row_indices.size (); ++row) { const std::size_t target_row = row_indices[row]; const std::size_t target_column = column_indices[column]; std::size_t rhs_row = 0; std::size_t rhs_column = 0; if (! scalar_rhs) { if (exact_shape) { rhs_row = row; rhs_column = column; } else { const std::size_t linear = row + column * row_indices.size (); rhs_row = linear % rhs.rows; rhs_column = linear / rhs.rows; } } copy_rhs_element (result.at (target_row, target_column), rhs, rhs_row, rhs_column); } return result; } MpfrMatrixStorage mpfr_matrix_assign_linear (const MpfrMatrixStorage& source, const std::vector& indices, const MpfrAssignmentOperand& rhs, mpfr_prec_t result_precision) { validate_rhs (rhs); const std::size_t selected_count = indices.size (); if (selected_count == 0) { if (! is_scalar (rhs) && checked_product (rhs.rows, rhs.columns) != 0) throw std::invalid_argument ( "non-scalar RHS is not conformant with an empty selection"); MpfrMatrixStorage result (source.rows (), source.columns (), result_precision, source); return result; } const bool scalar_rhs = is_scalar (rhs); const std::size_t rhs_count = checked_product (rhs.rows, rhs.columns); if (! scalar_rhs && rhs_count != selected_count) throw std::invalid_argument ( "assignment RHS element count does not match linear selection"); for (const std::size_t index : indices) if (index >= source.numel ()) throw std::out_of_range ("assignment index is out of bounds"); MpfrMatrixStorage result (source.rows (), source.columns (), result_precision, source); for (std::size_t index = 0; index < selected_count; ++index) { std::size_t rhs_row = 0; std::size_t rhs_column = 0; if (! scalar_rhs) { rhs_row = index % rhs.rows; rhs_column = index / rhs.rows; } copy_rhs_element (result.data ()[indices[index]], rhs, rhs_row, rhs_column); } return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_script_sequence.h0000644000230300031750000000221215274353472021070 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SCRIPT_SEQUENCE_H #define OCTAVE_MPLAPACK_MP_SCRIPT_SEQUENCE_H #include #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { struct MpScriptSortRealResult { MpfrMatrixStorage values; std::vector indices; }; struct MpScriptSortComplexResult { MpfrComplexMatrixStorage values; std::vector indices; }; MpScriptSortRealResult mpfr_script_sort (const MpfrMatrixStorage& source, std::size_t dimension, bool descending); MpScriptSortComplexResult mpc_script_sort ( const MpfrComplexMatrixStorage& source, std::size_t dimension, bool descending); MpfrMatrixStorage mpfr_script_diff (const MpfrMatrixStorage& source, std::size_t order, std::size_t dimension); MpfrComplexMatrixStorage mpc_script_diff ( const MpfrComplexMatrixStorage& source, std::size_t order, std::size_t dimension); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_script_reductions.h0000644000230300031750000000437715274353472021455 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SCRIPT_REDUCTIONS_H #define OCTAVE_MPLAPACK_MP_SCRIPT_REDUCTIONS_H #include #include #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { enum class MpScriptReductionOperation { sum, prod, sumsq, cumsum, cumprod }; enum class MpScriptExtremumOperation { minimum, maximum }; enum class MpScriptComparisonMethod { automatic, real, absolute }; struct MpScriptReductionOptions { std::size_t dimension = 1; bool all = false; bool omit_nan = false; bool reverse = false; bool output_double = false; }; struct MpScriptExtremumOptions : MpScriptReductionOptions { MpScriptComparisonMethod comparison = MpScriptComparisonMethod::automatic; }; struct MpScriptExtremumResultReal { MpfrMatrixStorage values; std::vector indices; }; struct MpScriptExtremumResultComplex { MpfrComplexMatrixStorage values; std::vector indices; }; MpfrMatrixStorage mpfr_script_reduce ( const MpfrMatrixStorage& source, MpScriptReductionOperation operation, const MpScriptReductionOptions& options); MpfrComplexMatrixStorage mpc_script_reduce ( const MpfrComplexMatrixStorage& source, MpScriptReductionOperation operation, const MpScriptReductionOptions& options); MpfrMatrixStorage mpc_script_sumsq ( const MpfrComplexMatrixStorage& source, const MpScriptReductionOptions& options); MpScriptExtremumResultReal mpfr_script_extremum ( const MpfrMatrixStorage& source, MpScriptExtremumOperation operation, const MpScriptExtremumOptions& options); MpScriptExtremumResultComplex mpc_script_extremum ( const MpfrComplexMatrixStorage& source, MpScriptExtremumOperation operation, const MpScriptExtremumOptions& options); MpScriptExtremumResultReal mpfr_script_extremum_pair ( const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs, MpScriptExtremumOperation operation, const MpScriptExtremumOptions& options); MpScriptExtremumResultComplex mpc_script_extremum_pair ( const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs, MpScriptExtremumOperation operation, const MpScriptExtremumOptions& options); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_matrix_arithmetic.h0000644000230300031750000000227615274353472021423 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_MATRIX_ARITHMETIC_H #define OCTAVE_MPLAPACK_MP_MATRIX_ARITHMETIC_H #include #include "mp_matrix_storage.h" #include "mp_scalar_storage.h" namespace octave_mplapack { enum class MpfrElementwiseBinaryOperation { add, subtract, multiply, divide, power }; struct MpfrElementwiseOperand { const MpfrScalarStorage *scalar = nullptr; const MpfrMatrixStorage *matrix = nullptr; static MpfrElementwiseOperand from_scalar ( const MpfrScalarStorage& value) noexcept; static MpfrElementwiseOperand from_matrix ( const MpfrMatrixStorage& value) noexcept; bool is_scalar () const noexcept; mpfr_prec_t precision_bits () const; std::size_t rows () const; std::size_t columns () const; const MpfrMatrixStorage::NativeScalar& at (std::size_t row, std::size_t column) const; }; MpfrMatrixStorage mpfr_matrix_elementwise_binary ( const MpfrElementwiseOperand& lhs, const MpfrElementwiseOperand& rhs, MpfrElementwiseBinaryOperation operation); MpfrMatrixStorage mpfr_matrix_negate ( const MpfrMatrixStorage& source); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_matrix_inspection.cc0000644000230300031750000001132215274353472021573 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_inspection.h" #include #include #include namespace octave_mplapack { MpfrMatrixStorage select_matrix (const MpfrMatrixStorage& source, const std::vector& row_indices, const std::vector& column_indices) { MpfrMatrixStorage result (row_indices.size (), column_indices.size (), source.precision_bits ()); for (std::size_t column = 0; column < column_indices.size (); ++column) { if (column_indices[column] >= source.columns ()) throw std::out_of_range ("matrix column index out of range"); for (std::size_t row = 0; row < row_indices.size (); ++row) { if (row_indices[row] >= source.rows ()) throw std::out_of_range ("matrix row index out of range"); mpfr_set (result.at (row, column).mpfr_data (), source.at (row_indices[row], column_indices[column]).mpfr_data (), MPFR_RNDN); } } return result; } MpfrMatrixStorage select_linear (const MpfrMatrixStorage& source, const std::vector& indices) { MpfrMatrixStorage result (indices.size (), 1, source.precision_bits ()); for (std::size_t row = 0; row < indices.size (); ++row) { if (indices[row] >= source.numel ()) throw std::out_of_range ("matrix linear index out of range"); mpfr_set (result.at (row, 0).mpfr_data (), source.data ()[indices[row]].mpfr_data (), MPFR_RNDN); } return result; } std::string format_matrix (const MpfrMatrixStorage& source) { std::ostringstream output; if (source.rows () == 0 || source.columns () == 0) { output << "mp " << source.rows () << 'x' << source.columns () << " matrix []"; return output.str (); } output << '['; for (std::size_t row = 0; row < source.rows (); ++row) { if (row != 0) output << "\n "; for (std::size_t column = 0; column < source.columns (); ++column) { if (column != 0) output << ' '; MpfrScalarStorage scalar ( MpfrMatrixStorage::NativeScalar (source.at (row, column))); output << scalar.to_canonical_string (); } } output << ']'; return output.str (); } MpfrComplexMatrixStorage select_complex_matrix (const MpfrComplexMatrixStorage& source, const std::vector& row_indices, const std::vector& column_indices) { MpfrComplexMatrixStorage result (row_indices.size (), column_indices.size (), source.precision_bits ()); for (std::size_t column = 0; column < column_indices.size (); ++column) { if (column_indices[column] >= source.columns ()) throw std::out_of_range ("complex matrix column index out of range"); for (std::size_t row = 0; row < row_indices.size (); ++row) { if (row_indices[row] >= source.rows ()) throw std::out_of_range ("complex matrix row index out of range"); mpc_set (result.at (row, column).mpc_data (), source.at (row_indices[row], column_indices[column]).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } return result; } MpfrComplexMatrixStorage select_complex_linear (const MpfrComplexMatrixStorage& source, const std::vector& indices) { MpfrComplexMatrixStorage result (indices.size (), 1, source.precision_bits ()); for (std::size_t row = 0; row < indices.size (); ++row) { if (indices[row] >= source.numel ()) throw std::out_of_range ("complex matrix linear index out of range"); mpc_set (result.at (row, 0).mpc_data (), source.data ()[indices[row]].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } return result; } std::string format_complex_matrix (const MpfrComplexMatrixStorage& source) { std::ostringstream output; if (source.rows () == 0 || source.columns () == 0) { output << "mp " << source.rows () << 'x' << source.columns () << " complex matrix []"; return output.str (); } output << '['; for (std::size_t row = 0; row < source.rows (); ++row) { if (row != 0) output << "\n "; for (std::size_t column = 0; column < source.columns (); ++column) { if (column != 0) output << ' '; MpfrComplexScalarStorage scalar (source.at (row, column)); output << scalar.to_canonical_string (); } } output << ']'; return output.str (); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_lapack.h0000644000230300031750000000210715274353472020661 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_LAPACK_H #define OCTAVE_MPLAPACK_MP_COMPLEX_LAPACK_H #include #include "mp_complex_matrix_storage.h" namespace octave_mplapack { class MpcCgesvError : public std::runtime_error { public: enum class Kind { singular, invalid_argument }; MpcCgesvError (Kind kind, MpfrComplexMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrComplexMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrComplexMatrixStorage::MplapackInteger m_info; }; void require_mplapack_mpc_solve_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& b_work); MpfrComplexMatrixStorage mplapack_mpc_matrix_solve ( const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_lapack.h0000644000230300031750000001110015274353472017123 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_LAPACK_H #define OCTAVE_MPLAPACK_MP_LAPACK_H #include #include #include #include #include #include "mp_matrix_storage.h" namespace octave_mplapack { class MpfrRgesvError : public std::runtime_error { public: enum class Kind { singular, invalid_argument }; MpfrRgesvError (Kind kind, int info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } int info () const noexcept { return m_info; } private: Kind m_kind; int m_info; }; class MpfrRgelsError : public std::runtime_error { public: enum class Kind { rank_deficient, invalid_argument }; MpfrRgelsError (Kind kind, int info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } int info () const noexcept { return m_info; } private: Kind m_kind; int m_info; }; class MpfrRpotrfError : public std::runtime_error { public: enum class Kind { invalid_argument, internal }; MpfrRpotrfError (Kind kind, int info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } int info () const noexcept { return m_info; } private: Kind m_kind; int m_info; }; class MpfrRankRevealingError : public std::runtime_error { public: enum class Kind { convergence, invalid_argument, internal }; MpfrRankRevealingError (Kind kind, int info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } int info () const noexcept { return m_info; } private: Kind m_kind; int m_info; }; struct MpfrRankRevealingSolveResult { MpfrMatrixStorage solution; MpfrMatrixStorage::MplapackInteger rank; }; struct MpfrCholeskyResult { MpfrMatrixStorage factor; MpfrMatrixStorage::MplapackInteger info; }; struct MpfrQrResult { MpfrMatrixStorage q; MpfrMatrixStorage r; }; struct MpfrPivotedQrResult { MpfrMatrixStorage q; MpfrMatrixStorage r; std::vector permutation; }; struct MpfrLuResult { MpfrMatrixStorage packed; MpfrMatrixStorage lower; MpfrMatrixStorage upper; std::vector permutation; MpfrMatrixStorage::MplapackInteger info; }; void require_mplapack_mpfr_solve_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& b_work); void require_mplapack_mpfr_rgels_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& b_work, const MpfrMatrixStorage& work); void require_mplapack_mpfr_rank_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& b_work, const mpfrxx::mpfr_class& rcond, const MpfrMatrixStorage& singular_values, const MpfrMatrixStorage& work); void require_mplapack_mpfr_rpotrf_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work); void require_mplapack_mpfr_rgetrf_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work); void require_mplapack_mpfr_qr_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& tau, const MpfrMatrixStorage& work); MpfrMatrixStorage mplapack_mpfr_matrix_solve ( const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs); MpfrMatrixStorage mplapack_mpfr_matrix_rectangular_solve ( const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs); MpfrRankRevealingSolveResult mplapack_mpfr_matrix_rank_revealing_solve ( const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs); MpfrCholeskyResult mplapack_mpfr_matrix_cholesky ( const MpfrMatrixStorage& input, bool lower); MpfrQrResult mplapack_mpfr_matrix_qr ( const MpfrMatrixStorage& input, bool economy, bool want_q); MpfrPivotedQrResult mplapack_mpfr_matrix_pivoted_qr ( const MpfrMatrixStorage& input, bool economy, bool want_q); MpfrLuResult mplapack_mpfr_matrix_lu (const MpfrMatrixStorage& input); MpfrMatrixStorage mplapack_mpfr_matrix_left_divide ( const MpfrMatrixStorage& rhs, const mpfrxx::mpfr_class& lhs); MpfrMatrixStorage mplapack_mpfr_matrix_left_divide ( const MpfrMatrixStorage& rhs, double lhs); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_matrix_concat.cc0000644000230300031750000000526215274353472020675 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_concat.h" #include namespace octave_mplapack { MpfrMatrixStorage mpfr_matrix_concatenate ( const std::vector& operands, int dimension, std::size_t result_rows, std::size_t result_columns, mpfr_prec_t result_precision) { if (operands.empty ()) throw std::invalid_argument ("concatenation requires at least one operand"); if (dimension != 0 && dimension != 1) throw std::invalid_argument ("concatenation dimension must be 0 or 1"); MpfrMatrixStorage result (result_rows, result_columns, result_precision); std::size_t offset = 0; for (const MpfrConcatOperand& operand : operands) { if (! operand.copy_element) throw std::invalid_argument ("concatenation operand has no copier"); // Octave's concatenation skips empty inputs once the result has a // non-empty payload. The validated result shape already accounts for // their structural dimensions, so there is no element data to copy. if (operand.rows == 0 || operand.columns == 0) continue; if (dimension == 1) { if (operand.rows != result_rows) throw std::invalid_argument ("horizontal concatenation row mismatch"); if (offset > result_columns || operand.columns > result_columns - offset) throw std::invalid_argument ( "horizontal concatenation result dimensions mismatch"); for (std::size_t column = 0; column < operand.columns; ++column) for (std::size_t row = 0; row < operand.rows; ++row) operand.copy_element (result.at (row, offset + column), row, column); offset += operand.columns; } else { if (operand.columns != result_columns) throw std::invalid_argument ("vertical concatenation column mismatch"); if (offset > result_rows || operand.rows > result_rows - offset) throw std::invalid_argument ( "vertical concatenation result dimensions mismatch"); for (std::size_t column = 0; column < operand.columns; ++column) for (std::size_t row = 0; row < operand.rows; ++row) operand.copy_element (result.at (offset + row, column), row, column); offset += operand.rows; } } const std::size_t expected_offset = dimension == 1 ? result_columns : result_rows; if (result.numel () != 0 && offset != expected_offset) throw std::invalid_argument ("concatenation result dimensions mismatch"); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_general_eig.h0000644000230300031750000000260415274353472020142 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_GENERAL_EIG_H #define OCTAVE_MPLAPACK_MP_GENERAL_EIG_H #include #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { class MpfrGeneralEigError : public std::runtime_error { public: MpfrGeneralEigError (int info, const char *message) : std::runtime_error (message), m_info (info) { } int info () const noexcept { return m_info; } private: int m_info; }; class MpcGeneralEigError : public std::runtime_error { public: MpcGeneralEigError (int info, const char *message) : std::runtime_error (message), m_info (info) { } int info () const noexcept { return m_info; } private: int m_info; }; struct MpfrGeneralEigResult { MpfrComplexMatrixStorage eigenvalues; MpfrComplexMatrixStorage right_vectors; MpfrComplexMatrixStorage left_vectors; MpfrComplexMatrixStorage diagonal; }; struct MpcGeneralEigResult { MpfrComplexMatrixStorage eigenvalues; MpfrComplexMatrixStorage right_vectors; MpfrComplexMatrixStorage left_vectors; MpfrComplexMatrixStorage diagonal; }; MpfrGeneralEigResult mplapack_mpfr_matrix_general_eig ( const MpfrMatrixStorage& input, bool balance); MpcGeneralEigResult mplapack_mpc_matrix_general_eig ( const MpfrComplexMatrixStorage& input, bool balance); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_script_ranges.cc0000644000230300031750000003500615274353472020704 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_script_ranges.h" #include #include #include #include #include #include "mp_complex_precision.h" namespace { using Real = octave_mplapack::MpfrScalarStorage::NativeScalar; using Complex = octave_mplapack::MpfrComplexScalarStorage::NativeScalar; Real copy_real (const Real& source, mpfr_prec_t precision) { Real result = Real::with_precision (precision); mpfr_set (result.mpfr_data (), source.mpfr_data (), MPFR_RNDN); return result; } Complex copy_complex (const Complex& source, mpfr_prec_t precision) { Complex result = Complex::with_precision (precision); mpc_set (result.mpc_data (), source.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } std::size_t compatible_dimension (std::size_t lhs, std::size_t rhs, const char *dimension) { if (lhs == rhs) return lhs; if (lhs == 1) return rhs; if (rhs == 1) return lhs; throw std::invalid_argument (std::string ("nonconformant ") + dimension + " dimensions for utility operation"); } std::size_t broadcast_index (std::size_t index, std::size_t source_dimension) { return source_dimension == 1 ? 0 : index; } int normalized_sign (const Real& value) { return mpfr_sgn (value.mpfr_data ()); } void check_finite_range_endpoint (const Real& value) { if (mpfr_nan_p (value.mpfr_data ()) || mpfr_inf_p (value.mpfr_data ())) throw std::invalid_argument ("range endpoints must be finite"); } void check_range_size (std::size_t count) { octave_mplapack::MpfrMatrixStorage::checked_mplapack_dimension (count); } } // namespace namespace octave_mplapack { MpfrMatrixStorage mpfr_script_colon (const MpfrScalarStorage& first, const MpfrScalarStorage& step, const MpfrScalarStorage& last) { const mpfr_prec_t precision = first.precision_bits (); check_finite_range_endpoint (first.native_value ()); check_finite_range_endpoint (step.native_value ()); check_finite_range_endpoint (last.native_value ()); if (mpfr_zero_p (step.native_value ().mpfr_data ())) throw std::invalid_argument ("range step must not be zero"); const int step_sign = normalized_sign (step.native_value ()); const int endpoint_order = mpfr_cmp (first.native_value ().mpfr_data (), last.native_value ().mpfr_data ()); if ((step_sign > 0 && endpoint_order > 0) || (step_sign < 0 && endpoint_order < 0)) return MpfrMatrixStorage (1, 0, precision); Real current = copy_real (first.native_value (), precision); std::size_t count = 0; while ((step_sign > 0 && mpfr_cmp (current.mpfr_data (), last.native_value ().mpfr_data ()) <= 0) || (step_sign < 0 && mpfr_cmp (current.mpfr_data (), last.native_value ().mpfr_data ()) >= 0)) { if (count == std::numeric_limits::max ()) throw std::overflow_error ("range element count overflow"); ++count; check_range_size (count); Real next = Real::with_precision (precision); mpfr_add (next.mpfr_data (), current.mpfr_data (), step.native_value ().mpfr_data (), MPFR_RNDN); if (mpfr_equal_p (next.mpfr_data (), current.mpfr_data ())) throw std::invalid_argument ("range step is too small at this precision"); current = std::move (next); } MpfrMatrixStorage result (1, count, precision); current = copy_real (first.native_value (), precision); for (std::size_t index = 0; index < count; ++index) { mpfr_set (result.at (0, index).mpfr_data (), current.mpfr_data (), MPFR_RNDN); Real next = Real::with_precision (precision); mpfr_add (next.mpfr_data (), current.mpfr_data (), step.native_value ().mpfr_data (), MPFR_RNDN); current = std::move (next); } return result; } MpfrMatrixStorage mpfr_script_linspace (const MpfrScalarStorage& first, const MpfrScalarStorage& last, std::size_t count) { check_range_size (count); const mpfr_prec_t precision = first.precision_bits (); MpfrMatrixStorage result (1, count, precision); if (count == 0) return result; if (count == 1) { mpfr_set (result.at (0, 0).mpfr_data (), last.native_value ().mpfr_data (), MPFR_RNDN); return result; } Real delta = Real::with_precision (precision); mpfr_sub (delta.mpfr_data (), last.native_value ().mpfr_data (), first.native_value ().mpfr_data (), MPFR_RNDN); for (std::size_t index = 0; index < count; ++index) { if (index == 0) mpfr_set (result.at (0, index).mpfr_data (), first.native_value ().mpfr_data (), MPFR_RNDN); else if (index + 1 == count) mpfr_set (result.at (0, index).mpfr_data (), last.native_value ().mpfr_data (), MPFR_RNDN); else { Real increment = Real::with_precision (precision); mpfr_mul_ui (increment.mpfr_data (), delta.mpfr_data (), static_cast (index), MPFR_RNDN); mpfr_div_ui (increment.mpfr_data (), increment.mpfr_data (), static_cast (count - 1), MPFR_RNDN); mpfr_add (result.at (0, index).mpfr_data (), first.native_value ().mpfr_data (), increment.mpfr_data (), MPFR_RNDN); } } return result; } MpfrComplexMatrixStorage mpc_script_linspace (const MpfrComplexScalarStorage& first, const MpfrComplexScalarStorage& last, std::size_t count) { check_range_size (count); const mpfr_prec_t precision = first.precision_bits (); MpfrMpcPrecisionScope scope (precision); MpfrComplexMatrixStorage result (1, count, precision); if (count == 0) return result; if (count == 1) { mpc_set (result.at (0, 0).mpc_data (), last.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } Complex delta = Complex::with_precision (precision); mpc_sub (delta.mpc_data (), last.native_value ().mpc_data (), first.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); for (std::size_t index = 0; index < count; ++index) { if (index == 0) mpc_set (result.at (0, index).mpc_data (), first.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else if (index + 1 == count) mpc_set (result.at (0, index).mpc_data (), last.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else { Complex increment = Complex::with_precision (precision); mpc_mul_ui (increment.mpc_data (), delta.mpc_data (), static_cast (index), MPC_RND (MPFR_RNDN, MPFR_RNDN)); mpc_div_ui (increment.mpc_data (), increment.mpc_data (), static_cast (count - 1), MPC_RND (MPFR_RNDN, MPFR_RNDN)); mpc_add (result.at (0, index).mpc_data (), first.native_value ().mpc_data (), increment.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } return result; } MpfrMatrixStorage mpfr_script_logspace (const MpfrScalarStorage& first, const MpfrScalarStorage& last, std::size_t count) { check_range_size (count); const mpfr_prec_t precision = first.precision_bits (); MpfrMatrixStorage result (1, count, precision); if (count == 0) return result; Real ten = Real::with_precision (precision); mpfr_set_ui (ten.mpfr_data (), 10, MPFR_RNDN); Real pi = Real::with_precision (precision); mpfr_const_pi (pi.mpfr_data (), MPFR_RNDN); const bool octave_pi_endpoint = mpfr_equal_p (last.native_value ().mpfr_data (), pi.mpfr_data ()) || mpfr_cmp_d (last.native_value ().mpfr_data (), std::acos (-1.0)) == 0; if (count == 1) { if (octave_pi_endpoint) mpfr_set (result.at (0, 0).mpfr_data (), last.native_value ().mpfr_data (), MPFR_RNDN); else mpfr_pow (result.at (0, 0).mpfr_data (), ten.mpfr_data (), last.native_value ().mpfr_data (), MPFR_RNDN); return result; } Real delta = Real::with_precision (precision); mpfr_sub (delta.mpfr_data (), last.native_value ().mpfr_data (), first.native_value ().mpfr_data (), MPFR_RNDN); for (std::size_t index = 0; index < count; ++index) { if (index + 1 == count && octave_pi_endpoint) { mpfr_set (result.at (0, index).mpfr_data (), last.native_value ().mpfr_data (), MPFR_RNDN); continue; } Real exponent = Real::with_precision (precision); if (index == 0) mpfr_set (exponent.mpfr_data (), first.native_value ().mpfr_data (), MPFR_RNDN); else if (index + 1 == count) mpfr_set (exponent.mpfr_data (), last.native_value ().mpfr_data (), MPFR_RNDN); else { mpfr_mul_ui (exponent.mpfr_data (), delta.mpfr_data (), static_cast (index), MPFR_RNDN); mpfr_div_ui (exponent.mpfr_data (), exponent.mpfr_data (), static_cast (count - 1), MPFR_RNDN); mpfr_add (exponent.mpfr_data (), exponent.mpfr_data (), first.native_value ().mpfr_data (), MPFR_RNDN); } mpfr_pow (result.at (0, index).mpfr_data (), ten.mpfr_data (), exponent.mpfr_data (), MPFR_RNDN); } return result; } MpfrMatrixStorage mpfr_script_round (const MpfrMatrixStorage& source, MpScriptRoundingOperation operation) { MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) { mpfr_ptr destination = result.data ()[index].mpfr_data (); mpfr_srcptr input = source.data ()[index].mpfr_data (); switch (operation) { case MpScriptRoundingOperation::floor: mpfr_floor (destination, input); break; case MpScriptRoundingOperation::ceil: mpfr_ceil (destination, input); break; case MpScriptRoundingOperation::fix: mpfr_trunc (destination, input); break; case MpScriptRoundingOperation::round: mpfr_round (destination, input); break; } } return result; } MpfrMatrixStorage mpfr_script_remainder (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs, bool modulus) { const std::size_t rows = compatible_dimension (lhs.rows (), rhs.rows (), "row"); const std::size_t columns = compatible_dimension (lhs.columns (), rhs.columns (), "column"); const mpfr_prec_t precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); MpfrMatrixStorage result (rows, columns, precision); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) { const auto& left = lhs.at (broadcast_index (row, lhs.rows ()), broadcast_index (column, lhs.columns ())); const auto& right = rhs.at (broadcast_index (row, rhs.rows ()), broadcast_index (column, rhs.columns ())); Real left_value = copy_real (left, precision); Real right_value = copy_real (right, precision); Real remainder = Real::with_precision (precision); mpfr_fmod (remainder.mpfr_data (), left_value.mpfr_data (), right_value.mpfr_data (), MPFR_RNDN); if (modulus && ! mpfr_zero_p (remainder.mpfr_data ()) && mpfr_signbit (remainder.mpfr_data ()) != mpfr_signbit (right_value.mpfr_data ())) mpfr_add (remainder.mpfr_data (), remainder.mpfr_data (), right_value.mpfr_data (), MPFR_RNDN); mpfr_set (result.at (row, column).mpfr_data (), remainder.mpfr_data (), MPFR_RNDN); } return result; } MpfrMatrixStorage mpfr_script_hypot (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs) { const std::size_t rows = compatible_dimension (lhs.rows (), rhs.rows (), "row"); const std::size_t columns = compatible_dimension (lhs.columns (), rhs.columns (), "column"); const mpfr_prec_t precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); MpfrMatrixStorage result (rows, columns, precision); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) mpfr_hypot (result.at (row, column).mpfr_data (), lhs.at (broadcast_index (row, lhs.rows ()), broadcast_index (column, lhs.columns ())).mpfr_data (), rhs.at (broadcast_index (row, rhs.rows ()), broadcast_index (column, rhs.columns ())).mpfr_data (), MPFR_RNDN); return result; } MpfrMatrixStorage mpfr_script_atan2 (const MpfrMatrixStorage& y, const MpfrMatrixStorage& x) { const std::size_t rows = compatible_dimension (y.rows (), x.rows (), "row"); const std::size_t columns = compatible_dimension (y.columns (), x.columns (), "column"); const mpfr_prec_t precision = std::max (y.precision_bits (), x.precision_bits ()); MpfrMatrixStorage result (rows, columns, precision); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) mpfr_atan2 (result.at (row, column).mpfr_data (), y.at (broadcast_index (row, y.rows ()), broadcast_index (column, y.columns ())).mpfr_data (), x.at (broadcast_index (row, x.rows ()), broadcast_index (column, x.columns ())).mpfr_data (), MPFR_RNDN); return result; } MpfrMatrixStorage mpfr_script_eps (const MpfrMatrixStorage& source) { MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) { Real next = copy_real (source.data ()[index], source.precision_bits ()); mpfr_nextabove (next.mpfr_data ()); mpfr_sub (result.data ()[index].mpfr_data (), next.mpfr_data (), source.data ()[index].mpfr_data (), MPFR_RNDN); } return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_det_inv.h0000644000230300031750000000337215274353472017334 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_DET_INV_H #define OCTAVE_MPLAPACK_MP_DET_INV_H #include #include "mp_complex_matrix_storage.h" #include "mp_complex_scalar_storage.h" #include "mp_matrix_storage.h" #include "mp_scalar_storage.h" namespace octave_mplapack { class MpfrDetInvError : public std::runtime_error { public: enum class Kind { singular, invalid_argument, internal }; MpfrDetInvError (Kind kind, MpfrMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrMatrixStorage::MplapackInteger m_info; }; class MpcDetInvError : public std::runtime_error { public: enum class Kind { singular, invalid_argument, internal }; MpcDetInvError (Kind kind, MpfrComplexMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrComplexMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrComplexMatrixStorage::MplapackInteger m_info; }; MpfrScalarStorage mplapack_mpfr_matrix_det (const MpfrMatrixStorage& input); MpfrMatrixStorage mplapack_mpfr_matrix_inverse ( const MpfrMatrixStorage& input); MpfrComplexScalarStorage mplapack_mpc_matrix_det ( const MpfrComplexMatrixStorage& input); MpfrComplexMatrixStorage mplapack_mpc_matrix_inverse ( const MpfrComplexMatrixStorage& input); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_random.cc0000644000230300031750000001631715274353472017325 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_random.h" #include #include #include #include namespace octave_mplapack { namespace { constexpr std::uint64_t splitmix_increment = 0x9e3779b97f4a7c15ULL; constexpr std::uint64_t splitmix_multiplier_1 = 0xbf58476d1ce4e5b9ULL; constexpr std::uint64_t splitmix_multiplier_2 = 0x94d049bb133111ebULL; std::uint64_t splitmix_next (std::uint64_t& state) noexcept { state += splitmix_increment; std::uint64_t value = state; value = (value ^ (value >> 30)) * splitmix_multiplier_1; value = (value ^ (value >> 27)) * splitmix_multiplier_2; return value ^ (value >> 31); } class MpRandomEngine { public: explicit MpRandomEngine (MpRandomState& state) : m_state (state) { if (m_state.first == 0 && m_state.second == 0) throw std::invalid_argument ("MPLAPACK RNG state must not be all zero"); } std::uint64_t next () noexcept { // xorshift128+ with the state transition and output function specified // using uint64_t operations. This deliberately does not use C rand(), // a floating distribution, or implementation-defined integer widths. std::uint64_t x = m_state.first; const std::uint64_t y = m_state.second; m_state.first = y; x ^= x << 23; m_state.second = x ^ y ^ (x >> 17) ^ (y >> 26); return m_state.second + y; } private: MpRandomState& m_state; }; void set_mpz_from_u64 (mpz_ptr destination, std::uint64_t value) { std::array bytes {}; for (std::size_t index = 0; index < bytes.size (); ++index) bytes[index] = static_cast ( value >> (8 * (bytes.size () - index - 1))); mpz_import (destination, bytes.size (), 1, 1, 1, 0, bytes.data ()); } void random_bits (mpz_ptr destination, std::size_t bit_count, MpRandomEngine& engine) { mpz_set_ui (destination, 0); mpz_t word; mpz_init (word); std::size_t consumed = 0; while (consumed < bit_count) { const std::size_t remaining = bit_count - consumed; const std::size_t take = remaining < 64 ? remaining : 64; std::uint64_t raw = engine.next (); if (take < 64) raw &= (std::uint64_t (1) << take) - 1; set_mpz_from_u64 (word, raw); mpz_mul_2exp (destination, destination, take); mpz_add (destination, destination, word); consumed += take; } mpz_clear (word); } void set_uniform_from_bits (mpfr_ptr destination, mpfr_prec_t precision_bits, MpRandomEngine& engine) { mpz_t integer; mpz_init (integer); random_bits (integer, static_cast (precision_bits), engine); if (static_cast (precision_bits) > static_cast (std::numeric_limits::max ())) { mpz_clear (integer); throw std::overflow_error ("MPFR precision exceeds exponent range"); } mpfr_set_z_2exp (destination, integer, -static_cast (precision_bits), MPFR_RNDN); mpz_clear (integer); } void set_integer_from_z (mpfr_ptr destination, mpfr_prec_t precision_bits, mpz_srcptr integer) { mpfr_set_z (destination, integer, MPFR_RNDN); mpz_t round_trip; mpz_init (round_trip); mpfr_get_z (round_trip, destination, MPFR_RNDZ); const bool exact = mpz_cmp (round_trip, integer) == 0; mpz_clear (round_trip); if (! exact) throw std::range_error ( "integer result cannot be represented exactly at current mpbits"); (void) precision_bits; } } // namespace MpRandomState mp_random_seed (std::uint64_t seed) noexcept { std::uint64_t expansion = seed; MpRandomState result {splitmix_next (expansion), splitmix_next (expansion)}; if (result.first == 0 && result.second == 0) result.second = 1; return result; } MpfrMatrixStorage mp_random_uniform (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, MpRandomState& state) { MpRandomEngine engine (state); MpfrMatrixStorage result (rows, columns, precision_bits); for (std::size_t index = 0; index < result.numel (); ++index) set_uniform_from_bits (result.data ()[index].mpfr_data (), precision_bits, engine); return result; } MpfrMatrixStorage mp_random_normal (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, MpRandomState& state) { MpRandomEngine engine (state); MpfrMatrixStorage result (rows, columns, precision_bits); mpfr_t u1; mpfr_t u2; mpfr_t pi; mpfr_t two_pi; mpfr_t radius; mpfr_t angle; mpfr_init2 (u1, precision_bits); mpfr_init2 (u2, precision_bits); mpfr_init2 (pi, precision_bits); mpfr_init2 (two_pi, precision_bits); mpfr_init2 (radius, precision_bits); mpfr_init2 (angle, precision_bits); mpfr_const_pi (pi, MPFR_RNDN); mpfr_mul_ui (two_pi, pi, 2, MPFR_RNDN); for (std::size_t index = 0; index < result.numel (); ++index) { do set_uniform_from_bits (u1, precision_bits, engine); while (mpfr_zero_p (u1)); set_uniform_from_bits (u2, precision_bits, engine); mpfr_log (radius, u1, MPFR_RNDN); mpfr_neg (radius, radius, MPFR_RNDN); mpfr_mul_ui (radius, radius, 2, MPFR_RNDN); mpfr_sqrt (radius, radius, MPFR_RNDN); mpfr_mul (angle, two_pi, u2, MPFR_RNDN); mpfr_cos (angle, angle, MPFR_RNDN); mpfr_mul (result.data ()[index].mpfr_data (), radius, angle, MPFR_RNDN); } mpfr_clear (u1); mpfr_clear (u2); mpfr_clear (pi); mpfr_clear (two_pi); mpfr_clear (radius); mpfr_clear (angle); return result; } MpfrMatrixStorage mp_random_integer (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const MpfrScalarStorage& lower, const MpfrScalarStorage& upper, MpRandomState& state) { const mpfr_srcptr lower_value = lower.native_value ().mpfr_data (); const mpfr_srcptr upper_value = upper.native_value ().mpfr_data (); if (! mpfr_integer_p (lower_value) || ! mpfr_integer_p (upper_value)) throw std::invalid_argument ("mprandi bounds must be exact integers"); if (mpfr_cmp (lower_value, upper_value) > 0) throw std::invalid_argument ("mprandi lower bound exceeds upper bound"); mpz_t lower_integer; mpz_t upper_integer; mpz_t span; mpz_t candidate; mpz_init (lower_integer); mpz_init (upper_integer); mpz_init (span); mpz_init (candidate); mpfr_get_z (lower_integer, lower_value, MPFR_RNDZ); mpfr_get_z (upper_integer, upper_value, MPFR_RNDZ); mpz_sub (span, upper_integer, lower_integer); mpz_add_ui (span, span, 1); const std::size_t bit_count = mpz_sizeinbase (span, 2); MpRandomEngine engine (state); MpfrMatrixStorage result (rows, columns, precision_bits); for (std::size_t index = 0; index < result.numel (); ++index) { do random_bits (candidate, bit_count, engine); while (mpz_cmp (candidate, span) >= 0); mpz_add (candidate, candidate, lower_integer); set_integer_from_z (result.data ()[index].mpfr_data (), precision_bits, candidate); mpz_sub (candidate, candidate, lower_integer); } mpz_clear (lower_integer); mpz_clear (upper_integer); mpz_clear (span); mpz_clear (candidate); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_script_logic.h0000644000230300031750000000262415274353472020364 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SCRIPT_LOGIC_H #define OCTAVE_MPLAPACK_MP_SCRIPT_LOGIC_H #include #include #include "mp_complex_arithmetic.h" #include "mp_matrix_arithmetic.h" namespace octave_mplapack { enum class MpScriptComparisonOperation { equal, not_equal, less, less_equal, greater, greater_equal }; enum class MpScriptLogicalOperation { and_op, or_op, xor_op }; struct MpScriptLogicalResult { std::size_t rows = 0; std::size_t columns = 0; std::vector values; }; MpScriptLogicalResult mpfr_script_compare ( const MpfrElementwiseOperand& lhs, const MpfrElementwiseOperand& rhs, MpScriptComparisonOperation operation); MpScriptLogicalResult mpc_script_compare ( const MpcElementwiseOperand& lhs, const MpcElementwiseOperand& rhs, MpScriptComparisonOperation operation); MpScriptLogicalResult mpfr_script_logical ( const MpfrElementwiseOperand& source); MpScriptLogicalResult mpc_script_logical ( const MpcElementwiseOperand& source); MpScriptLogicalResult mpfr_script_logical_binary ( const MpfrElementwiseOperand& lhs, const MpfrElementwiseOperand& rhs, MpScriptLogicalOperation operation); MpScriptLogicalResult mpc_script_logical_binary ( const MpcElementwiseOperand& lhs, const MpcElementwiseOperand& rhs, MpScriptLogicalOperation operation); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_matrix_value.cc0000644000230300031750000000665015274353472022273 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_matrix_value.h" #include "mp_native_serialization.h" #include #include #include #include #include #include namespace { octave_idx_type checked_dimension (std::size_t value) { if (value > static_cast ( std::numeric_limits::max ())) throw std::overflow_error ("complex matrix dimension exceeds octave_idx_type"); return static_cast (value); } } DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA ( octave_mplapack_mpc_matrix_internal, "mplapack_mpc_matrix_internal", "mplapack_mpc_matrix_internal"); octave_mplapack_mpc_matrix_internal::octave_mplapack_mpc_matrix_internal () : m_storage (0, 0, MPFR_PREC_MIN) { } octave_mplapack_mpc_matrix_internal::octave_mplapack_mpc_matrix_internal ( octave_mplapack::MpfrComplexMatrixStorage storage) : m_storage (std::move (storage)) { } octave_base_value *octave_mplapack_mpc_matrix_internal::clone () const { return new octave_mplapack_mpc_matrix_internal (*this); } octave_base_value *octave_mplapack_mpc_matrix_internal::empty_clone () const { return clone (); } dim_vector octave_mplapack_mpc_matrix_internal::dims () const { return dim_vector (checked_dimension (m_storage.rows ()), checked_dimension (m_storage.columns ())); } bool octave_mplapack_mpc_matrix_internal::is_defined () const { return true; } bool octave_mplapack_mpc_matrix_internal::is_storable () const { return true; } bool octave_mplapack_mpc_matrix_internal::is_complex_matrix () const { return true; } bool octave_mplapack_mpc_matrix_internal::isreal () const { return false; } bool octave_mplapack_mpc_matrix_internal::is_matrix_type () const { return true; } bool octave_mplapack_mpc_matrix_internal::save_ascii (std::ostream& os) { return octave_mplapack::save_native_mpc_matrix (os, m_storage); } bool octave_mplapack_mpc_matrix_internal::load_ascii (std::istream& is) { return octave_mplapack::load_native_mpc_matrix (is, m_storage); } bool octave_mplapack_mpc_matrix_internal::save_binary (std::ostream& os, bool) { return octave_mplapack::save_native_mpc_matrix (os, m_storage); } bool octave_mplapack_mpc_matrix_internal::load_binary ( std::istream& is, bool, octave::mach_info::float_format) { return octave_mplapack::load_native_mpc_matrix (is, m_storage); } void octave_mplapack_mpc_matrix_internal::print (std::ostream& os, bool) { print_raw (os); } void octave_mplapack_mpc_matrix_internal::print_raw (std::ostream& os, bool) const { os << "[internal MPLAPACK MPC " << m_storage.rows () << 'x' << m_storage.columns () << " matrix; " << m_storage.precision_bits () << " bits]"; } const octave_mplapack::MpfrComplexMatrixStorage& octave_mplapack_mpc_matrix_internal::storage () const noexcept { return m_storage; } const octave_mplapack_mpc_matrix_internal& octave_mplapack_mpc_matrix_internal::checked_value (const octave_value& value) { if (value.type_id () != static_type_id ()) error_with_id ("mplapack:InvalidNativeValue", "expected an internal MPLAPACK MPC matrix"); const auto *native_value = dynamic_cast ( value.internal_rep ()); if (! native_value) error_with_id ("mplapack:InvalidNativeValue", "invalid internal MPLAPACK MPC matrix representation"); return *native_value; } mplapack-interop-0.5.1/src/mp_script_compat.cc0000644000230300031750000006023315274353472020710 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_script_compat.h" #include #include #include #include #include "mp_complex_precision.h" #include namespace { using namespace octave_mplapack; void apply_real_unary (mpfr_ptr destination, mpfr_srcptr source, MpScriptUnaryOperation operation) { switch (operation) { case MpScriptUnaryOperation::absolute: mpfr_abs (destination, source, MPFR_RNDN); return; case MpScriptUnaryOperation::angle: { mpfr_t zero; mpfr_init2 (zero, mpfr_get_prec (source)); mpfr_set_zero (zero, 1); mpfr_atan2 (destination, zero, source, MPFR_RNDN); mpfr_clear (zero); } return; case MpScriptUnaryOperation::sign: if (mpfr_nan_p (source)) mpfr_set_nan (destination); else mpfr_set_si (destination, mpfr_sgn (source), MPFR_RNDN); return; } throw std::logic_error ("unknown real script unary operation"); } void apply_complex_real_unary (mpfr_ptr destination, mpc_srcptr source, MpScriptUnaryOperation operation) { switch (operation) { case MpScriptUnaryOperation::absolute: mpc_abs (destination, source, MPFR_RNDN); return; case MpScriptUnaryOperation::angle: mpc_arg (destination, source, MPFR_RNDN); return; case MpScriptUnaryOperation::sign: throw std::logic_error ("complex sign requires an MPC result"); } throw std::logic_error ("unknown complex real unary operation"); } void apply_complex_unary (mpc_ptr destination, mpc_srcptr source, MpScriptUnaryOperation operation) { const mpc_rnd_t rounding = MPC_RND (MPFR_RNDN, MPFR_RNDN); switch (operation) { case MpScriptUnaryOperation::sign: if (mpfr_zero_p (mpc_realref (source)) && mpfr_zero_p (mpc_imagref (source))) { mpc_set_ui (destination, 0, rounding); return; } { mpfr_t magnitude; mpfr_init2 (magnitude, mpfr_get_prec (mpc_realref (source))); mpc_abs (magnitude, source, MPFR_RNDN); mpc_div_fr (destination, source, magnitude, rounding); mpfr_clear (magnitude); } return; case MpScriptUnaryOperation::absolute: case MpScriptUnaryOperation::angle: throw std::logic_error ("complex real-valued operation used as MPC"); } throw std::logic_error ("unknown complex unary operation"); } bool predicate_value (mpfr_srcptr source, MpScriptPredicate predicate) { switch (predicate) { case MpScriptPredicate::isnan: return mpfr_nan_p (source) != 0; case MpScriptPredicate::isinf: return mpfr_inf_p (source) != 0; case MpScriptPredicate::isfinite: return mpfr_number_p (source) != 0; } throw std::logic_error ("unknown MPFR script predicate"); } bool predicate_value (mpc_srcptr source, MpScriptPredicate predicate) { const mpfr_srcptr real = mpc_realref (source); const mpfr_srcptr imag = mpc_imagref (source); switch (predicate) { case MpScriptPredicate::isnan: return mpfr_nan_p (real) != 0 || mpfr_nan_p (imag) != 0; case MpScriptPredicate::isinf: return mpfr_inf_p (real) != 0 || mpfr_inf_p (imag) != 0; case MpScriptPredicate::isfinite: return mpfr_number_p (real) != 0 && mpfr_number_p (imag) != 0; } throw std::logic_error ("unknown MPC script predicate"); } template MpScriptPredicateResult make_predicate_result (const Storage& source, MpScriptPredicate predicate) { MpScriptPredicateResult result; result.rows = source.rows (); result.columns = source.columns (); result.values.resize (source.numel ()); for (std::size_t index = 0; index < source.numel (); ++index) result.values[index] = predicate_value (source.data ()[index].mpfr_data (), predicate); return result; } MpScriptPredicateResult make_complex_predicate_result (const MpfrComplexMatrixStorage& source, MpScriptPredicate predicate) { MpScriptPredicateResult result; result.rows = source.rows (); result.columns = source.columns (); result.values.resize (source.numel ()); for (std::size_t index = 0; index < source.numel (); ++index) result.values[index] = predicate_value (source.data ()[index].mpc_data (), predicate); return result; } bool equal_real (mpfr_srcptr lhs, mpfr_srcptr rhs, bool nan_equal) noexcept { const bool lhs_nan = mpfr_nan_p (lhs) != 0; const bool rhs_nan = mpfr_nan_p (rhs) != 0; if (lhs_nan || rhs_nan) return nan_equal && lhs_nan && rhs_nan; return mpfr_cmp (lhs, rhs) == 0; } bool equal_complex (mpc_srcptr lhs, mpc_srcptr rhs, bool nan_equal) noexcept { return equal_real (mpc_realref (lhs), mpc_realref (rhs), nan_equal) && equal_real (mpc_imagref (lhs), mpc_imagref (rhs), nan_equal); } void apply_real_elementary (mpfr_ptr destination, mpfr_srcptr source, MpScriptElementaryOperation operation) { if (operation == MpScriptElementaryOperation::erf || operation == MpScriptElementaryOperation::erfc || operation == MpScriptElementaryOperation::gamma || operation == MpScriptElementaryOperation::lngamma) { const mpfr_prec_t precision = mpfr_get_prec (source); MplapackMpfrPrecisionScope scope (precision); auto operand = mpfrxx::mpfr_class::with_precision (precision); mpfr_set (operand.mpfr_data (), source, MPFR_RNDN); mpfrxx::mpfr_class result = mpfrxx::mpfr_class::with_precision (precision); try { switch (operation) { case MpScriptElementaryOperation::erf: result = mpfrxx::erf (operand); break; case MpScriptElementaryOperation::erfc: result = mpfrxx::erfc (operand); break; case MpScriptElementaryOperation::gamma: result = mpfrxx::gamma (operand); break; case MpScriptElementaryOperation::lngamma: result = mpfrxx::lngamma (operand); break; default: break; } } catch (const std::domain_error&) { // gmpfrxx_mkII deliberately reports Gamma poles as domain errors. // Octave's mapper returns signed infinity for Gamma at zero and // positive infinity at the other non-positive integer poles. if (operation == MpScriptElementaryOperation::gamma && mpfr_integer_p (source) && mpfr_cmp_si (source, 0) <= 0) { const int sign = mpfr_zero_p (source) && mpfr_signbit (source) ? -1 : 1; mpfr_set_inf (result.mpfr_data (), sign); } else if (operation == MpScriptElementaryOperation::lngamma && mpfr_integer_p (source) && mpfr_cmp_si (source, 0) <= 0) mpfr_set_inf (result.mpfr_data (), 1); else throw; } if ((operation == MpScriptElementaryOperation::gamma || operation == MpScriptElementaryOperation::lngamma) && mpfr_integer_p (source) && mpfr_cmp_si (source, 0) <= 0 && mpfr_nan_p (result.mpfr_data ())) { if (operation == MpScriptElementaryOperation::gamma) { const int sign = mpfr_zero_p (source) && mpfr_signbit (source) ? -1 : 1; mpfr_set_inf (result.mpfr_data (), sign); } else mpfr_set_inf (result.mpfr_data (), 1); } mpfr_set (destination, result.mpfr_data (), MPFR_RNDN); return; } switch (operation) { case MpScriptElementaryOperation::sqrt: mpfr_sqrt (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::exp: mpfr_exp (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::expm1: mpfr_expm1 (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::log: mpfr_log (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::log1p: mpfr_log1p (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::log10: mpfr_log10 (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::log2: mpfr_log2 (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::sin: mpfr_sin (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::cos: mpfr_cos (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::tan: mpfr_tan (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::asin: mpfr_asin (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::acos: mpfr_acos (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::atan: mpfr_atan (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::sinh: mpfr_sinh (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::cosh: mpfr_cosh (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::tanh: mpfr_tanh (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::asinh: mpfr_asinh (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::acosh: mpfr_acosh (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::atanh: mpfr_atanh (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::cbrt: mpfr_cbrt (destination, source, MPFR_RNDN); return; case MpScriptElementaryOperation::erf: case MpScriptElementaryOperation::erfc: case MpScriptElementaryOperation::gamma: case MpScriptElementaryOperation::lngamma: break; } throw std::logic_error ("unknown real elementary operation"); } mpfr_prec_t work_precision (mpfr_prec_t precision) { constexpr mpfr_prec_t guard_bits = 32; if (precision > MPFR_PREC_MAX - guard_bits) return precision; return precision + guard_bits; } void apply_complex_log2_via_gmpfrxx (mpc_ptr destination, mpc_srcptr source) { const mpfr_prec_t real_precision = mpfr_get_prec (mpc_realref (source)); const mpfr_prec_t imag_precision = mpfr_get_prec (mpc_imagref (source)); auto operand = mpfrxx::mpc_class::with_precision (real_precision, imag_precision); const mpc_rnd_t rounding = mpfrxx::mpc_class::default_rounding (); (void) mpc_set (operand.mpc_data (), source, rounding); const auto result = mpfrxx::log2 (operand); (void) mpc_set (destination, result.mpc_data (), rounding); } void apply_complex_elementary (mpc_ptr destination, mpc_srcptr source, MpScriptElementaryOperation operation) { const mpc_rnd_t rounding = MPC_RND (MPFR_RNDN, MPFR_RNDN); switch (operation) { case MpScriptElementaryOperation::sqrt: mpc_sqrt (destination, source, rounding); return; case MpScriptElementaryOperation::exp: mpc_exp (destination, source, rounding); return; case MpScriptElementaryOperation::log: mpc_log (destination, source, rounding); return; case MpScriptElementaryOperation::log10: mpc_log10 (destination, source, rounding); return; case MpScriptElementaryOperation::log2: apply_complex_log2_via_gmpfrxx (destination, source); return; case MpScriptElementaryOperation::sin: mpc_sin (destination, source, rounding); return; case MpScriptElementaryOperation::cos: mpc_cos (destination, source, rounding); return; case MpScriptElementaryOperation::tan: mpc_tan (destination, source, rounding); return; case MpScriptElementaryOperation::asin: mpc_asin (destination, source, rounding); if (mpfr_zero_p (mpc_imagref (source)) && mpfr_cmp_ui (mpc_realref (source), 1) > 0) mpfr_neg (mpc_imagref (destination), mpc_imagref (destination), MPFR_RNDN); return; case MpScriptElementaryOperation::acos: mpc_acos (destination, source, rounding); if (mpfr_zero_p (mpc_imagref (source)) && mpfr_cmp_ui (mpc_realref (source), 1) > 0) mpfr_neg (mpc_imagref (destination), mpc_imagref (destination), MPFR_RNDN); return; case MpScriptElementaryOperation::atan: mpc_atan (destination, source, rounding); return; case MpScriptElementaryOperation::sinh: mpc_sinh (destination, source, rounding); return; case MpScriptElementaryOperation::cosh: mpc_cosh (destination, source, rounding); return; case MpScriptElementaryOperation::tanh: mpc_tanh (destination, source, rounding); return; case MpScriptElementaryOperation::asinh: mpc_asinh (destination, source, rounding); return; case MpScriptElementaryOperation::acosh: mpc_acosh (destination, source, rounding); return; case MpScriptElementaryOperation::atanh: mpc_atanh (destination, source, rounding); return; case MpScriptElementaryOperation::cbrt: { mpfr_t third; mpfr_init2 (third, mpfr_get_prec (mpc_realref (source))); mpfr_set_ui (third, 1, MPFR_RNDN); mpfr_div_ui (third, third, 3, MPFR_RNDN); mpc_pow_fr (destination, source, third, rounding); mpfr_clear (third); } return; case MpScriptElementaryOperation::expm1: case MpScriptElementaryOperation::log1p: { const mpfr_prec_t precision = mpfr_get_prec (mpc_realref (source)); const mpfr_prec_t work = work_precision (precision); auto input = mpfrxx::mpc_class::with_precision (work); auto intermediate = mpfrxx::mpc_class::with_precision (work); mpc_set (input.mpc_data (), source, rounding); if (operation == MpScriptElementaryOperation::expm1) { mpc_exp (intermediate.mpc_data (), input.mpc_data (), rounding); mpc_sub_ui (intermediate.mpc_data (), intermediate.mpc_data (), 1, rounding); } else { mpc_add_ui (intermediate.mpc_data (), input.mpc_data (), 1, rounding); mpc_log (intermediate.mpc_data (), intermediate.mpc_data (), rounding); } mpc_set (destination, intermediate.mpc_data (), rounding); } return; case MpScriptElementaryOperation::erf: case MpScriptElementaryOperation::erfc: case MpScriptElementaryOperation::gamma: case MpScriptElementaryOperation::lngamma: throw std::invalid_argument ("gamma/erf family is implemented for real mp values only"); } throw std::logic_error ("unknown complex elementary operation"); } bool real_domain_requires_complex (mpfr_srcptr source, MpScriptElementaryOperation operation) noexcept { if (mpfr_nan_p (source)) return false; switch (operation) { case MpScriptElementaryOperation::sqrt: return mpfr_cmp_si (source, 0) < 0; case MpScriptElementaryOperation::log: return mpfr_cmp_si (source, 0) < 0; case MpScriptElementaryOperation::log1p: return mpfr_cmp_si (source, -1) < 0; case MpScriptElementaryOperation::asin: case MpScriptElementaryOperation::acos: return mpfr_cmp_si (source, -1) < 0 || mpfr_cmp_si (source, 1) > 0; case MpScriptElementaryOperation::acosh: return mpfr_cmp_si (source, 1) < 0; case MpScriptElementaryOperation::atanh: return mpfr_cmp_si (source, -1) < 0 || mpfr_cmp_si (source, 1) > 0; default: return false; } } } // namespace namespace octave_mplapack { MpfrScalarStorage mpfr_script_unary (const MpfrScalarStorage& source, MpScriptUnaryOperation operation) { MpfrScalarStorage::NativeScalar result = MpfrScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); apply_real_unary (result.mpfr_data (), source.native_value ().mpfr_data (), operation); return MpfrScalarStorage (std::move (result)); } MpfrMatrixStorage mpfr_script_unary (const MpfrMatrixStorage& source, MpScriptUnaryOperation operation) { MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) apply_real_unary (result.data ()[index].mpfr_data (), source.data ()[index].mpfr_data (), operation); return result; } MpfrScalarStorage mpc_script_real_unary (const MpfrComplexScalarStorage& source, MpScriptUnaryOperation operation) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrScalarStorage::NativeScalar result = MpfrScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); apply_complex_real_unary (result.mpfr_data (), source.native_value ().mpc_data (), operation); return MpfrScalarStorage (std::move (result)); } MpfrMatrixStorage mpc_script_real_unary (const MpfrComplexMatrixStorage& source, MpScriptUnaryOperation operation) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) apply_complex_real_unary (result.data ()[index].mpfr_data (), source.data ()[index].mpc_data (), operation); return result; } MpfrComplexScalarStorage mpc_script_unary (const MpfrComplexScalarStorage& source, MpScriptUnaryOperation operation) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexScalarStorage::NativeScalar result = MpfrComplexScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); apply_complex_unary (result.mpc_data (), source.native_value ().mpc_data (), operation); return MpfrComplexScalarStorage (std::move (result)); } MpfrComplexMatrixStorage mpc_script_unary (const MpfrComplexMatrixStorage& source, MpScriptUnaryOperation operation) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) apply_complex_unary (result.data ()[index].mpc_data (), source.data ()[index].mpc_data (), operation); return result; } MpScriptPredicateResult mpfr_script_predicate (const MpfrScalarStorage& source, MpScriptPredicate predicate) { return {1, 1, {static_cast ( predicate_value (source.native_value ().mpfr_data (), predicate))}}; } MpScriptPredicateResult mpfr_script_predicate (const MpfrMatrixStorage& source, MpScriptPredicate predicate) { return make_predicate_result (source, predicate); } MpScriptPredicateResult mpc_script_predicate (const MpfrComplexScalarStorage& source, MpScriptPredicate predicate) { return {1, 1, {static_cast ( predicate_value (source.native_value ().mpc_data (), predicate))}}; } MpScriptPredicateResult mpc_script_predicate (const MpfrComplexMatrixStorage& source, MpScriptPredicate predicate) { return make_complex_predicate_result (source, predicate); } bool mpfr_script_equal (const MpfrScalarStorage& lhs, const MpfrScalarStorage& rhs, bool nan_equal) noexcept { return equal_real (lhs.native_value ().mpfr_data (), rhs.native_value ().mpfr_data (), nan_equal); } bool mpfr_script_equal (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs, bool nan_equal) noexcept { if (lhs.rows () != rhs.rows () || lhs.columns () != rhs.columns ()) return false; for (std::size_t index = 0; index < lhs.numel (); ++index) if (! equal_real (lhs.data ()[index].mpfr_data (), rhs.data ()[index].mpfr_data (), nan_equal)) return false; return true; } bool mpc_script_equal (const MpfrComplexScalarStorage& lhs, const MpfrComplexScalarStorage& rhs, bool nan_equal) noexcept { return equal_complex (lhs.native_value ().mpc_data (), rhs.native_value ().mpc_data (), nan_equal); } bool mpc_script_equal (const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs, bool nan_equal) noexcept { if (lhs.rows () != rhs.rows () || lhs.columns () != rhs.columns ()) return false; for (std::size_t index = 0; index < lhs.numel (); ++index) if (! equal_complex (lhs.data ()[index].mpc_data (), rhs.data ()[index].mpc_data (), nan_equal)) return false; return true; } bool mpfr_script_power_requires_complex (mpfr_srcptr base, mpfr_srcptr exponent) noexcept { return mpfr_cmp_si (base, 0) < 0 && ! mpfr_integer_p (exponent); } bool mpfr_script_elementary_requires_complex ( mpfr_srcptr source, MpScriptElementaryOperation operation) noexcept { return real_domain_requires_complex (source, operation); } MpfrScalarStorage mpfr_script_elementary (const MpfrScalarStorage& source, MpScriptElementaryOperation operation) { MpfrScalarStorage::NativeScalar result = MpfrScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); apply_real_elementary (result.mpfr_data (), source.native_value ().mpfr_data (), operation); return MpfrScalarStorage (std::move (result)); } MpfrMatrixStorage mpfr_script_elementary (const MpfrMatrixStorage& source, MpScriptElementaryOperation operation) { MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) apply_real_elementary (result.data ()[index].mpfr_data (), source.data ()[index].mpfr_data (), operation); return result; } MpfrComplexScalarStorage mpfr_script_promote (const MpfrScalarStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexScalarStorage::NativeScalar result = MpfrComplexScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); mpc_set_fr (result.mpc_data (), source.native_value ().mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return MpfrComplexScalarStorage (std::move (result)); } MpfrComplexMatrixStorage mpfr_script_promote (const MpfrMatrixStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) mpc_set_fr (result.data ()[index].mpc_data (), source.data ()[index].mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrComplexScalarStorage mpc_script_elementary (const MpfrComplexScalarStorage& source, MpScriptElementaryOperation operation) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexScalarStorage::NativeScalar result = MpfrComplexScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); apply_complex_elementary (result.mpc_data (), source.native_value ().mpc_data (), operation); return MpfrComplexScalarStorage (std::move (result)); } MpfrComplexMatrixStorage mpc_script_elementary (const MpfrComplexMatrixStorage& source, MpScriptElementaryOperation operation) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) apply_complex_elementary (result.data ()[index].mpc_data (), source.data ()[index].mpc_data (), operation); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_matrix_value.cc0000644000230300031750000000706315274353472020543 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_value.h" #include "mp_native_serialization.h" #include #include #include #include #include #include #include namespace { octave_idx_type checked_octave_dimension (std::size_t value) { if (value > static_cast ( std::numeric_limits::max ())) throw std::overflow_error ("matrix dimension exceeds octave_idx_type"); return static_cast (value); } } // namespace DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA ( octave_mplapack_mpfr_matrix_internal, "mplapack_mpfr_matrix_internal", "mplapack_mpfr_matrix_internal"); octave_mplapack_mpfr_matrix_internal:: octave_mplapack_mpfr_matrix_internal () : m_storage (0, 0, MPFR_PREC_MIN) { } octave_mplapack_mpfr_matrix_internal:: octave_mplapack_mpfr_matrix_internal ( octave_mplapack::MpfrMatrixStorage storage) : m_storage (std::move (storage)) { } octave_base_value * octave_mplapack_mpfr_matrix_internal::clone () const { return new octave_mplapack_mpfr_matrix_internal (*this); } octave_base_value * octave_mplapack_mpfr_matrix_internal::empty_clone () const { return clone (); } dim_vector octave_mplapack_mpfr_matrix_internal::dims () const { return dim_vector (checked_octave_dimension (m_storage.rows ()), checked_octave_dimension (m_storage.columns ())); } bool octave_mplapack_mpfr_matrix_internal::is_defined () const { return true; } bool octave_mplapack_mpfr_matrix_internal::is_storable () const { return true; } bool octave_mplapack_mpfr_matrix_internal::is_real_matrix () const { return true; } bool octave_mplapack_mpfr_matrix_internal::isreal () const { return true; } bool octave_mplapack_mpfr_matrix_internal::is_matrix_type () const { return true; } bool octave_mplapack_mpfr_matrix_internal::save_ascii (std::ostream& os) { return octave_mplapack::save_native_mpfr_matrix (os, m_storage); } bool octave_mplapack_mpfr_matrix_internal::load_ascii (std::istream& is) { return octave_mplapack::load_native_mpfr_matrix (is, m_storage); } bool octave_mplapack_mpfr_matrix_internal::save_binary (std::ostream& os, bool) { return octave_mplapack::save_native_mpfr_matrix (os, m_storage); } bool octave_mplapack_mpfr_matrix_internal::load_binary ( std::istream& is, bool, octave::mach_info::float_format) { return octave_mplapack::load_native_mpfr_matrix (is, m_storage); } void octave_mplapack_mpfr_matrix_internal::print (std::ostream& os, bool) { print_raw (os); } void octave_mplapack_mpfr_matrix_internal::print_raw (std::ostream& os, bool) const { os << "[internal MPLAPACK MPFR " << m_storage.rows () << 'x' << m_storage.columns () << " matrix; " << m_storage.precision_bits () << " bits]"; } const octave_mplapack::MpfrMatrixStorage& octave_mplapack_mpfr_matrix_internal::storage () const noexcept { return m_storage; } const octave_mplapack_mpfr_matrix_internal& octave_mplapack_mpfr_matrix_internal::checked_value ( const octave_value& value) { if (value.type_id () != static_type_id ()) error_with_id ("mplapack:InvalidNativeValue", "expected an internal MPLAPACK MPFR matrix"); const auto *native_value = dynamic_cast (value.internal_rep ()); if (! native_value) error_with_id ("mplapack:InvalidNativeValue", "invalid internal MPLAPACK MPFR matrix representation"); return *native_value; } mplapack-interop-0.5.1/src/mp_script_structure.h0000644000230300031750000000327115274353472021326 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SCRIPT_STRUCTURE_H #define OCTAVE_MPLAPACK_MP_SCRIPT_STRUCTURE_H #include #include #include "mp_matrix_storage.h" #include "mp_complex_matrix_storage.h" namespace octave_mplapack { MpfrMatrixStorage mpfr_script_diag (const MpfrMatrixStorage& source, bool vector_input, std::int64_t diagonal); MpfrComplexMatrixStorage mpc_script_diag ( const MpfrComplexMatrixStorage& source, bool vector_input, std::int64_t diagonal); MpfrMatrixStorage mpfr_script_triangular (const MpfrMatrixStorage& source, std::int64_t diagonal, bool upper); MpfrComplexMatrixStorage mpc_script_triangular ( const MpfrComplexMatrixStorage& source, std::int64_t diagonal, bool upper); MpfrMatrixStorage mpfr_script_repmat (const MpfrMatrixStorage& source, std::size_t row_repetitions, std::size_t column_repetitions); MpfrComplexMatrixStorage mpc_script_repmat ( const MpfrComplexMatrixStorage& source, std::size_t row_repetitions, std::size_t column_repetitions); MpfrMatrixStorage mpfr_script_flip (const MpfrMatrixStorage& source, int dimension); MpfrComplexMatrixStorage mpc_script_flip ( const MpfrComplexMatrixStorage& source, int dimension); MpfrMatrixStorage mpfr_script_rot90 (const MpfrMatrixStorage& source, int turns); MpfrComplexMatrixStorage mpc_script_rot90 ( const MpfrComplexMatrixStorage& source, int turns); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_schur_qz.h0000644000230300031750000000261015274353472017534 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SCHUR_QZ_H #define OCTAVE_MPLAPACK_MP_SCHUR_QZ_H #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { struct MpHessResult { MpfrMatrixStorage p; MpfrMatrixStorage h; }; struct MpcHessResult { MpfrComplexMatrixStorage p; MpfrComplexMatrixStorage h; }; struct MpSchurResult { MpfrMatrixStorage u; MpfrMatrixStorage s; }; struct MpcSchurResult { MpfrComplexMatrixStorage u; MpfrComplexMatrixStorage s; }; struct MpQzResult { MpfrMatrixStorage aa; MpfrMatrixStorage bb; MpfrMatrixStorage q; MpfrMatrixStorage z; }; struct MpcQzResult { MpfrComplexMatrixStorage aa; MpfrComplexMatrixStorage bb; MpfrComplexMatrixStorage q; MpfrComplexMatrixStorage z; }; MpHessResult mplapack_mpfr_hess (const MpfrMatrixStorage& input); MpcHessResult mplapack_mpc_hess (const MpfrComplexMatrixStorage& input); MpSchurResult mplapack_mpfr_schur (const MpfrMatrixStorage& input); MpcSchurResult mplapack_mpc_schur (const MpfrComplexMatrixStorage& input); MpQzResult mplapack_mpfr_qz (const MpfrMatrixStorage& input_a, const MpfrMatrixStorage& input_b); MpcQzResult mplapack_mpc_qz (const MpfrComplexMatrixStorage& input_a, const MpfrComplexMatrixStorage& input_b); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_native_serialization.h0000644000230300031750000000254015274353472022123 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_NATIVE_SERIALIZATION_H #define OCTAVE_MPLAPACK_MP_NATIVE_SERIALIZATION_H #include #include "mp_complex_matrix_storage.h" #include "mp_complex_scalar_storage.h" #include "mp_matrix_storage.h" #include "mp_scalar_storage.h" namespace octave_mplapack { bool save_native_mpfr_scalar (std::ostream& stream, const MpfrScalarStorage& storage) noexcept; bool load_native_mpfr_scalar (std::istream& stream, MpfrScalarStorage& storage) noexcept; bool save_native_mpc_scalar (std::ostream& stream, const MpfrComplexScalarStorage& storage) noexcept; bool load_native_mpc_scalar (std::istream& stream, MpfrComplexScalarStorage& storage) noexcept; bool save_native_mpfr_matrix (std::ostream& stream, const MpfrMatrixStorage& storage) noexcept; bool load_native_mpfr_matrix (std::istream& stream, MpfrMatrixStorage& storage) noexcept; bool save_native_mpc_matrix (std::ostream& stream, const MpfrComplexMatrixStorage& storage) noexcept; bool load_native_mpc_matrix (std::istream& stream, MpfrComplexMatrixStorage& storage) noexcept; } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_structured_eig.h0000644000230300031750000000267315274353472020737 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_STRUCTURED_EIG_H #define OCTAVE_MPLAPACK_MP_STRUCTURED_EIG_H #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { class MpfrStructuredEigError : public std::runtime_error { public: MpfrStructuredEigError (int info, const char *message) : std::runtime_error (message), m_info (info) { } int info () const noexcept { return m_info; } private: int m_info; }; class MpcStructuredEigError : public std::runtime_error { public: MpcStructuredEigError (int info, const char *message) : std::runtime_error (message), m_info (info) { } int info () const noexcept { return m_info; } private: int m_info; }; struct MpfrStructuredEigResult { MpfrMatrixStorage eigenvalues; MpfrMatrixStorage vectors; MpfrMatrixStorage diagonal; }; struct MpcStructuredEigResult { MpfrMatrixStorage eigenvalues; MpfrComplexMatrixStorage vectors; MpfrMatrixStorage diagonal; }; MpfrStructuredEigResult mplapack_mpfr_matrix_structured_eig ( const MpfrMatrixStorage& input); MpcStructuredEigResult mplapack_mpc_matrix_structured_eig ( const MpfrComplexMatrixStorage& input); bool mplapack_mpfr_matrix_is_exactly_symmetric ( const MpfrMatrixStorage& input) noexcept; bool mplapack_mpc_matrix_is_exactly_hermitian ( const MpfrComplexMatrixStorage& input) noexcept; } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_precision.h0000644000230300031750000000172115274353472021422 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_PRECISION_H #define OCTAVE_MPLAPACK_MP_COMPLEX_PRECISION_H #include #include #include namespace octave_mplapack { // A complex numerical operation has two native defaults to control. Keeping // this composition in one scope prevents an MPC temporary from observing a // stale component precision when the operation enters MPLAPACK. class MpfrMpcPrecisionScope { public: explicit MpfrMpcPrecisionScope (mpfr_prec_t precision_bits); ~MpfrMpcPrecisionScope () noexcept; MpfrMpcPrecisionScope (const MpfrMpcPrecisionScope&) = delete; MpfrMpcPrecisionScope& operator= (const MpfrMpcPrecisionScope&) = delete; private: mpfr_prec_t m_mpfr_precision; mpfr_rnd_t m_mpfr_rounding; mpfrxx::mpc_precision_override_state m_mpc_precision; mpfrxx::mpc_rounding_override_state m_mpc_rounding; }; } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_rank.cc0000644000230300031750000002022615274353472020521 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_rank.h" #include #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_precision.h" namespace { octave_mplapack::MpfrComplexMatrixStorage::MplapackInteger checked_workspace_length (const mpfrxx::mpfr_class& query) { if (mpfr_nan_p (query.mpfr_data ()) != 0 || mpfr_inf_p (query.mpfr_data ()) != 0 || mpfr_integer_p (query.mpfr_data ()) == 0 || mpfr_sgn (query.mpfr_data ()) <= 0) throw std::invalid_argument ( "MPLAPACK Cgelsy workspace query returned an invalid size"); const auto max_mplapack = std::numeric_limits::max (); const auto max_size = std::numeric_limits::max (); if (mpfr_cmp_ui (query.mpfr_data (), static_cast (max_mplapack)) > 0 || mpfr_cmp_ui (query.mpfr_data (), static_cast (max_size)) > 0) throw std::overflow_error ( "MPLAPACK Cgelsy workspace exceeds allocation limits"); return static_cast ( mpfr_get_ui (query.mpfr_data (), MPFR_RNDZ)); } } // namespace namespace octave_mplapack { void require_mplapack_mpc_rank_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& b_work, const mpfrxx::mpfr_class& rcond, const MpfrComplexMatrixStorage& work, const MpfrMatrixStorage& rwork) { if (operation_precision < MPFR_PREC_MIN || operation_precision > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK MPC rank precision is outside the MPFR range"); const auto precision_override = mpfrxx::mpc_precision_override_storage (); const bool matches = mpfrxx::default_precision_bits () == operation_precision && precision_override.active && precision_override.real_precision_bits == operation_precision && precision_override.imag_precision_bits == operation_precision && a_work.precision_bits () == operation_precision && b_work.precision_bits () == operation_precision && a_work.all_elements_have_uniform_precision () && b_work.all_elements_have_uniform_precision () && rcond.precision () == operation_precision && work.precision_bits () == operation_precision && work.all_elements_have_uniform_precision () && rwork.precision_bits () == operation_precision && rwork.all_elements_have_uniform_precision (); if (! matches) throw std::runtime_error ( "MPLAPACK complex precision contract mismatch at Cgelsy boundary"); } MpcRankRevealingSolveResult mplapack_mpc_matrix_rank_solve (const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs) { if (rhs.rows () != lhs.rows ()) throw std::invalid_argument ("matrix solve dimensions must agree"); const mpfr_prec_t operation_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); const std::size_t m = lhs.rows (); const std::size_t n = lhs.columns (); const std::size_t nrhs = rhs.columns (); const std::size_t padded_rows = std::max (m, n); if (nrhs == 0 || std::min (m, n) == 0) return {MpfrComplexMatrixStorage (n, nrhs, operation_precision), 0}; const auto m_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (m); const auto n_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (n); const auto nrhs_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (nrhs); auto fill_rhs = [] (MpfrComplexMatrixStorage& destination, const MpfrComplexMatrixStorage& source) { for (std::size_t index = 0; index < destination.numel (); ++index) mpc_set_ui_ui (destination.data ()[index].mpc_data (), 0, 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) mpc_set (destination.at (row, column).mpc_data (), source.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; auto query_a = mplapack_mpc_matrix_copy_at_precision ( lhs, operation_precision); MpfrComplexMatrixStorage query_b (padded_rows, nrhs, operation_precision); fill_rhs (query_b, rhs); std::vector query_jpvt (n, 0); MpfrComplexMatrixStorage query_work (1, 1, operation_precision); MpfrMatrixStorage query_rwork (2 * n, 1, operation_precision); MpfrComplexMatrixStorage::MplapackInteger query_rank = 0; MpfrComplexMatrixStorage::MplapackInteger query_info = 0; { MpfrMpcPrecisionScope scope (operation_precision); mpfrxx::mpfr_class rcond = mpfrxx::mpfr_class::with_precision (operation_precision); const mpfrxx::mpfr_class epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); require_mplapack_mpc_rank_precision_contract ( operation_precision, query_a, query_b, rcond, query_work, query_rwork); Cgelsy (m_arg, n_arg, nrhs_arg, query_a.data (), query_a.leading_dimension (), query_b.data (), query_b.leading_dimension (), query_jpvt.data (), rcond, query_rank, query_work.data (), -1, query_rwork.data (), query_info); require_mplapack_mpc_rank_precision_contract ( operation_precision, query_a, query_b, rcond, query_work, query_rwork); } if (query_info != 0) throw MpcCgelsyError ( query_info > 0 ? MpcCgelsyError::Kind::convergence : MpcCgelsyError::Kind::invalid_argument, query_info, query_info > 0 ? "MPLAPACK Cgelsy workspace query failed" : "MPLAPACK Cgelsy rejected a workspace query argument"); const auto lwork = checked_workspace_length ( query_work.at (0, 0).real ()); auto a_work = mplapack_mpc_matrix_copy_at_precision ( lhs, operation_precision); MpfrComplexMatrixStorage b_work (padded_rows, nrhs, operation_precision); fill_rhs (b_work, rhs); std::vector jpvt (n, 0); MpfrComplexMatrixStorage work (static_cast (lwork), 1, operation_precision); MpfrMatrixStorage rwork (2 * n, 1, operation_precision); MpfrComplexMatrixStorage::MplapackInteger rank = 0; MpfrComplexMatrixStorage::MplapackInteger info = 0; { MpfrMpcPrecisionScope scope (operation_precision); mpfrxx::mpfr_class rcond = mpfrxx::mpfr_class::with_precision (operation_precision); const mpfrxx::mpfr_class epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); require_mplapack_mpc_rank_precision_contract ( operation_precision, a_work, b_work, rcond, work, rwork); Cgelsy (m_arg, n_arg, nrhs_arg, a_work.data (), a_work.leading_dimension (), b_work.data (), b_work.leading_dimension (), jpvt.data (), rcond, rank, work.data (), lwork, rwork.data (), info); require_mplapack_mpc_rank_precision_contract ( operation_precision, a_work, b_work, rcond, work, rwork); } if (info < 0) throw MpcCgelsyError (MpcCgelsyError::Kind::invalid_argument, info, "MPLAPACK Cgelsy rejected an argument"); if (info > 0) throw MpcCgelsyError (MpcCgelsyError::Kind::convergence, info, "MPLAPACK Cgelsy failed to converge"); const auto max_rank = static_cast< MpfrComplexMatrixStorage::MplapackInteger> (std::min (m, n)); if (rank < 0 || rank > max_rank) throw MpcCgelsyError (MpcCgelsyError::Kind::internal, 0, "MPLAPACK Cgelsy returned an invalid rank"); MpfrComplexMatrixStorage result (n, nrhs, operation_precision); for (std::size_t column = 0; column < nrhs; ++column) for (std::size_t row = 0; row < n; ++row) mpc_set (result.at (row, column).mpc_data (), b_work.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return {std::move (result), rank}; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_matrix_arithmetic.cc0000644000230300031750000001072515274353472021557 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_arithmetic.h" #include #include #include namespace { std::size_t compatible_dimension (std::size_t lhs, std::size_t rhs, const char *dimension_name) { if (lhs == rhs) return lhs; if (lhs == 1) return rhs; if (rhs == 1) return lhs; throw std::invalid_argument (std::string ("nonconformant ") + dimension_name + " dimensions for element-wise operation"); } std::size_t broadcast_index (std::size_t result_index, std::size_t source_dimension) { return source_dimension == 1 ? 0 : result_index; } void apply_binary (mpfr_ptr destination, mpfr_srcptr lhs, mpfr_srcptr rhs, octave_mplapack::MpfrElementwiseBinaryOperation operation) { switch (operation) { case octave_mplapack::MpfrElementwiseBinaryOperation::add: mpfr_add (destination, lhs, rhs, MPFR_RNDN); return; case octave_mplapack::MpfrElementwiseBinaryOperation::subtract: mpfr_sub (destination, lhs, rhs, MPFR_RNDN); return; case octave_mplapack::MpfrElementwiseBinaryOperation::multiply: mpfr_mul (destination, lhs, rhs, MPFR_RNDN); return; case octave_mplapack::MpfrElementwiseBinaryOperation::divide: mpfr_div (destination, lhs, rhs, MPFR_RNDN); return; case octave_mplapack::MpfrElementwiseBinaryOperation::power: mpfr_pow (destination, lhs, rhs, MPFR_RNDN); return; } throw std::logic_error ("unknown element-wise operation"); } } // namespace namespace octave_mplapack { MpfrElementwiseOperand MpfrElementwiseOperand::from_scalar (const MpfrScalarStorage& value) noexcept { return {&value, nullptr}; } MpfrElementwiseOperand MpfrElementwiseOperand::from_matrix (const MpfrMatrixStorage& value) noexcept { return {nullptr, &value}; } bool MpfrElementwiseOperand::is_scalar () const noexcept { return scalar != nullptr; } mpfr_prec_t MpfrElementwiseOperand::precision_bits () const { if (scalar) return scalar->precision_bits (); if (matrix) return matrix->precision_bits (); throw std::invalid_argument ("empty element-wise operand"); } std::size_t MpfrElementwiseOperand::rows () const { if (scalar) return 1; if (matrix) return matrix->rows (); throw std::invalid_argument ("empty element-wise operand"); } std::size_t MpfrElementwiseOperand::columns () const { if (scalar) return 1; if (matrix) return matrix->columns (); throw std::invalid_argument ("empty element-wise operand"); } const MpfrMatrixStorage::NativeScalar& MpfrElementwiseOperand::at (std::size_t row, std::size_t column) const { if (scalar) return scalar->native_value (); if (matrix) return matrix->at (row, column); throw std::invalid_argument ("empty element-wise operand"); } MpfrMatrixStorage mpfr_matrix_elementwise_binary ( const MpfrElementwiseOperand& lhs, const MpfrElementwiseOperand& rhs, MpfrElementwiseBinaryOperation operation) { const std::size_t result_rows = compatible_dimension (lhs.rows (), rhs.rows (), "row"); const std::size_t result_columns = compatible_dimension (lhs.columns (), rhs.columns (), "column"); const mpfr_prec_t result_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); MpfrMatrixStorage result (result_rows, result_columns, result_precision); for (std::size_t column = 0; column < result_columns; ++column) for (std::size_t row = 0; row < result_rows; ++row) { const std::size_t lhs_row = broadcast_index (row, lhs.rows ()); const std::size_t lhs_column = broadcast_index (column, lhs.columns ()); const std::size_t rhs_row = broadcast_index (row, rhs.rows ()); const std::size_t rhs_column = broadcast_index (column, rhs.columns ()); apply_binary (result.at (row, column).mpfr_data (), lhs.at (lhs_row, lhs_column).mpfr_data (), rhs.at (rhs_row, rhs_column).mpfr_data (), operation); } return result; } MpfrMatrixStorage mpfr_matrix_negate (const MpfrMatrixStorage& source) { MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) mpfr_neg (result.data ()[index].mpfr_data (), source.data ()[index].mpfr_data (), MPFR_RNDN); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_cholesky.cc0000644000230300031750000000650015274353472021406 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_cholesky.h" #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_precision.h" namespace octave_mplapack { void require_mplapack_mpc_cpotrf_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work) { if (operation_precision < MPFR_PREC_MIN || operation_precision > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK MPC Cholesky precision is outside the MPFR range"); const auto precision_override = mpfrxx::mpc_precision_override_storage (); const bool matches = mpfrxx::default_precision_bits () == operation_precision && precision_override.active && precision_override.real_precision_bits == operation_precision && precision_override.imag_precision_bits == operation_precision && a_work.precision_bits () == operation_precision && a_work.all_elements_have_uniform_precision (); if (! matches) throw std::runtime_error ( "MPLAPACK complex precision contract mismatch at Cpotrf boundary"); } MpcCholeskyResult mplapack_mpc_matrix_cholesky (const MpfrComplexMatrixStorage& input, bool lower) { if (input.rows () != input.columns ()) throw std::invalid_argument ( "MPLAPACK Cpotrf requires a square coefficient matrix"); const mpfr_prec_t operation_precision = input.precision_bits (); const std::size_t n = input.rows (); auto a_work = mplapack_mpc_matrix_copy_at_precision ( input, operation_precision); if (n == 0) return {std::move (a_work), 0}; const auto n_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (n); const auto lda = a_work.leading_dimension (); MpfrComplexMatrixStorage::MplapackInteger info = 0; { // Cpotrf overwrites the selected triangle. Keep the public value // immutable by factoring an operation-owned copy at p_op. MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_cpotrf_precision_contract ( operation_precision, a_work); Cpotrf (lower ? "L" : "U", n_arg, a_work.data (), lda, info); require_mplapack_mpc_cpotrf_precision_contract ( operation_precision, a_work); } if (info < 0) throw MpcCpotrfError (MpcCpotrfError::Kind::invalid_argument, info, "MPLAPACK Cpotrf rejected an argument"); if (static_cast (info) > n) throw MpcCpotrfError (MpcCpotrfError::Kind::internal, info, "MPLAPACK Cpotrf returned an invalid failure index"); const std::size_t completed = info == 0 ? n : static_cast (info - 1); MpfrComplexMatrixStorage result (completed, completed, operation_precision); for (std::size_t column = 0; column < completed; ++column) for (std::size_t row = 0; row < completed; ++row) { if (lower ? column > row : row > column) mpc_set_ui (result.at (row, column).mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); else mpc_set (result.at (row, column).mpc_data (), a_work.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } return {std::move (result), info}; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_schur_qz.cc0000644000230300031750000004701615274353472017703 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_schur_qz.h" #include #include #include #include #include #include #include #include #include #include "mp_complex_precision.h" namespace octave_mplapack { namespace { using Integer = MpfrMatrixStorage::MplapackInteger; bool mpfr_no_selection (mpfr_class, mpfr_class) { return false; } bool mpc_no_selection (mpc_class) { return false; } bool mpfr_qz_no_selection (mpfr_class, mpfr_class, mpfr_class) { return false; } bool mpc_qz_no_selection (mpc_class, mpc_class) { return false; } void require_square (std::size_t rows, std::size_t columns, const char *routine) { if (rows != columns) throw std::invalid_argument (std::string (routine) + " requires a square matrix"); } std::size_t checked_workspace (const MpfrScalarStorage::NativeScalar& query, const char *routine) { if (mpfr_nan_p (query.mpfr_data ()) != 0 || mpfr_inf_p (query.mpfr_data ()) != 0 || mpfr_integer_p (query.mpfr_data ()) == 0 || mpfr_sgn (query.mpfr_data ()) <= 0) throw std::runtime_error (std::string (routine) + " returned an invalid workspace query"); mpz_t value; mpz_t maximum; mpz_init (value); mpz_init (maximum); mpfr_get_z (value, query.mpfr_data (), MPFR_RNDZ); const auto limit = std::numeric_limits::max (); mpz_import (maximum, 1, -1, sizeof (limit), 0, 0, &limit); if (mpz_cmp (value, maximum) > 0) { mpz_clear (value); mpz_clear (maximum); throw std::overflow_error (std::string (routine) + " workspace exceeds allocation limits"); } const std::size_t result = static_cast ( mpfr_get_uj (query.mpfr_data (), MPFR_RNDZ)); mpz_clear (value); mpz_clear (maximum); return std::max (result, 1); } std::size_t checked_complex_workspace (const MpfrComplexMatrixStorage::NativeScalar& query, const char *routine) { if (mpfr_sgn (mpc_imagref (query.mpc_data ())) != 0) throw std::runtime_error (std::string (routine) + " returned a complex workspace query"); auto real_query = MpfrScalarStorage::NativeScalar::with_precision ( query.real_precision ()); mpfr_set (real_query.mpfr_data (), mpc_realref (query.mpc_data ()), MPFR_RNDN); return checked_workspace (real_query, routine); } void check_info (Integer info, const char *routine) { if (info != 0) throw std::runtime_error (std::string ("MPLAPACK ") + routine + " failed (info " + std::to_string (info) + ")"); } void make_identity (MpfrMatrixStorage& value) { for (std::size_t column = 0; column < value.columns (); ++column) for (std::size_t row = 0; row < value.rows (); ++row) if (row == column) mpfr_set_ui (value.at (row, column).mpfr_data (), 1, MPFR_RNDN); else mpfr_set_zero (value.at (row, column).mpfr_data (), 1); } void make_identity (MpfrComplexMatrixStorage& value) { for (std::size_t column = 0; column < value.columns (); ++column) for (std::size_t row = 0; row < value.rows (); ++row) if (row == column) mpc_set_ui (value.at (row, column).mpc_data (), 1, MPC_RND (MPFR_RNDN, MPFR_RNDN)); else mpc_set_ui (value.at (row, column).mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } MpfrMatrixStorage transpose (const MpfrMatrixStorage& input) { MpfrMatrixStorage result (input.columns (), input.rows (), input.precision_bits ()); for (std::size_t column = 0; column < input.columns (); ++column) for (std::size_t row = 0; row < input.rows (); ++row) mpfr_set (result.at (column, row).mpfr_data (), input.at (row, column).mpfr_data (), MPFR_RNDN); return result; } MpfrComplexMatrixStorage conjugate_transpose (const MpfrComplexMatrixStorage& input) { MpfrComplexMatrixStorage result (input.columns (), input.rows (), input.precision_bits ()); for (std::size_t column = 0; column < input.columns (); ++column) for (std::size_t row = 0; row < input.rows (); ++row) mpc_conj (result.at (column, row).mpc_data (), input.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrComplexMatrixStorage promote (const MpfrMatrixStorage& input) { MpfrComplexMatrixStorage result (input.rows (), input.columns (), input.precision_bits ()); for (std::size_t column = 0; column < input.columns (); ++column) for (std::size_t row = 0; row < input.rows (); ++row) { mpc_set_fr (result.at (row, column).mpc_data (), input.at (row, column).mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } return result; } MpfrMatrixStorage run_mpfr_hess (const MpfrMatrixStorage& input, MpfrMatrixStorage& p) { const auto precision = input.precision_bits (); const std::size_t n = input.rows (); MpfrMatrixStorage h (n, n, precision, input); MpfrMatrixStorage tau_storage (n, 1, precision); MpfrMatrixStorage query (1, 1, precision); Integer info = 0; { MplapackMpfrPrecisionScope scope (precision); Rgehrd (static_cast (n), 1, static_cast (n), h.data (), h.leading_dimension (), tau_storage.data (), query.data (), -1, info); } check_info (info, "Rgehrd workspace query"); const std::size_t lwork = checked_workspace (query.at (0, 0), "Rgehrd"); MpfrMatrixStorage work (lwork, 1, precision); h = MpfrMatrixStorage (n, n, precision, input); info = 0; { MplapackMpfrPrecisionScope scope (precision); Rgehrd (static_cast (n), 1, static_cast (n), h.data (), h.leading_dimension (), tau_storage.data (), work.data (), static_cast (lwork), info); } check_info (info, "Rgehrd"); p = MpfrMatrixStorage (n, n, precision, h); query = MpfrMatrixStorage (1, 1, precision); info = 0; { MplapackMpfrPrecisionScope scope (precision); Rorghr (static_cast (n), 1, static_cast (n), p.data (), p.leading_dimension (), tau_storage.data (), query.data (), -1, info); } check_info (info, "Rorghr workspace query"); const std::size_t lwork_q = checked_workspace (query.at (0, 0), "Rorghr"); MpfrMatrixStorage work_q (lwork_q, 1, precision); p = MpfrMatrixStorage (n, n, precision, p); info = 0; { MplapackMpfrPrecisionScope scope (precision); Rorghr (static_cast (n), 1, static_cast (n), p.data (), p.leading_dimension (), tau_storage.data (), work_q.data (), static_cast (lwork_q), info); } check_info (info, "Rorghr"); for (std::size_t column = 0; column < n; ++column) for (std::size_t row = column + 2; row < n; ++row) mpfr_set_zero (h.at (row, column).mpfr_data (), 1); return h; } MpfrComplexMatrixStorage run_mpc_hess (const MpfrComplexMatrixStorage& input, MpfrComplexMatrixStorage& p) { const auto precision = input.precision_bits (); const std::size_t n = input.rows (); MpfrComplexMatrixStorage h (input); MpfrComplexMatrixStorage tau (n, 1, precision); MpfrComplexMatrixStorage query (1, 1, precision); Integer info = 0; { MpfrMpcPrecisionScope scope (precision); Cgehrd (static_cast (n), 1, static_cast (n), h.data (), h.leading_dimension (), tau.data (), query.data (), -1, info); } check_info (info, "Cgehrd workspace query"); const std::size_t lwork = checked_complex_workspace ( query.at (0, 0), "Cgehrd"); MpfrComplexMatrixStorage work (lwork, 1, precision); h = input; info = 0; { MpfrMpcPrecisionScope scope (precision); Cgehrd (static_cast (n), 1, static_cast (n), h.data (), h.leading_dimension (), tau.data (), work.data (), static_cast (lwork), info); } check_info (info, "Cgehrd"); p = h; query = MpfrComplexMatrixStorage (1, 1, precision); info = 0; { MpfrMpcPrecisionScope scope (precision); Cunghr (static_cast (n), 1, static_cast (n), p.data (), p.leading_dimension (), tau.data (), query.data (), -1, info); } check_info (info, "Cunghr workspace query"); const std::size_t lwork_q = checked_complex_workspace ( query.at (0, 0), "Cunghr"); MpfrComplexMatrixStorage work_q (lwork_q, 1, precision); // The workspace query leaves the reflector representation intact; the // second call deliberately reuses that operation-owned copy. info = 0; { MpfrMpcPrecisionScope scope (precision); Cunghr (static_cast (n), 1, static_cast (n), p.data (), p.leading_dimension (), tau.data (), work_q.data (), static_cast (lwork_q), info); } check_info (info, "Cunghr"); for (std::size_t column = 0; column < n; ++column) for (std::size_t row = column + 2; row < n; ++row) mpc_set_ui (h.at (row, column).mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); return h; } MpfrMatrixStorage run_mpfr_schur (const MpfrMatrixStorage& input, MpfrMatrixStorage& u) { const auto precision = input.precision_bits (); const std::size_t n = input.rows (); MpfrMatrixStorage s (n, n, precision, input); MpfrMatrixStorage wr (n, 1, precision); MpfrMatrixStorage wi (n, 1, precision); MpfrMatrixStorage vs (n, n, precision); MpfrMatrixStorage query (1, 1, precision); MpfrMatrixStorage work_dummy (1, 1, precision); std::unique_ptr bwork (new bool[std::max (n, 1)]); Integer sdim = 0; Integer info = 0; { MplapackMpfrPrecisionScope scope (precision); Rgees ("V", "N", mpfr_no_selection, static_cast (n), s.data (), s.leading_dimension (), sdim, wr.data (), wi.data (), vs.data (), vs.leading_dimension (), query.data (), -1, bwork.get (), info); } check_info (info, "Rgees workspace query"); const std::size_t lwork = checked_workspace (query.at (0, 0), "Rgees"); MpfrMatrixStorage work (lwork, 1, precision); s = MpfrMatrixStorage (n, n, precision, input); info = 0; { MplapackMpfrPrecisionScope scope (precision); Rgees ("V", "N", mpfr_no_selection, static_cast (n), s.data (), s.leading_dimension (), sdim, wr.data (), wi.data (), vs.data (), vs.leading_dimension (), work.data (), static_cast (lwork), bwork.get (), info); } check_info (info, "Rgees"); // LAPACK's Schur vectors satisfy A = VS*T*VS'. Octave returns U=VS so // that S=U'*A*U. u = vs; return s; } MpfrComplexMatrixStorage run_mpc_schur (const MpfrComplexMatrixStorage& input, MpfrComplexMatrixStorage& u) { const auto precision = input.precision_bits (); const std::size_t n = input.rows (); MpfrComplexMatrixStorage s (input); MpfrComplexMatrixStorage w (n, 1, precision); MpfrComplexMatrixStorage vs (n, n, precision); MpfrComplexMatrixStorage query (1, 1, precision); MpfrMatrixStorage rwork (n, 1, precision); std::unique_ptr bwork (new bool[std::max (n, 1)]); Integer sdim = 0; Integer info = 0; { MpfrMpcPrecisionScope scope (precision); Cgees ("V", "N", mpc_no_selection, static_cast (n), s.data (), s.leading_dimension (), sdim, w.data (), vs.data (), vs.leading_dimension (), query.data (), -1, rwork.data (), bwork.get (), info); } check_info (info, "Cgees workspace query"); const std::size_t lwork = checked_complex_workspace ( query.at (0, 0), "Cgees"); MpfrComplexMatrixStorage work (lwork, 1, precision); s = input; info = 0; { MpfrMpcPrecisionScope scope (precision); Cgees ("V", "N", mpc_no_selection, static_cast (n), s.data (), s.leading_dimension (), sdim, w.data (), vs.data (), vs.leading_dimension (), work.data (), static_cast (lwork), rwork.data (), bwork.get (), info); } check_info (info, "Cgees"); u = vs; return s; } MpQzResult run_mpfr_qz (const MpfrMatrixStorage& input_a, const MpfrMatrixStorage& input_b) { const auto precision = input_a.precision_bits (); const std::size_t n = input_a.rows (); MpQzResult result { MpfrMatrixStorage (n, n, precision, input_a), MpfrMatrixStorage (n, n, precision, input_b), MpfrMatrixStorage (n, n, precision), MpfrMatrixStorage (n, n, precision) }; MpfrMatrixStorage alphar (n, 1, precision); MpfrMatrixStorage alphai (n, 1, precision); MpfrMatrixStorage beta (n, 1, precision); MpfrMatrixStorage vsl (n, n, precision); MpfrMatrixStorage vsr (n, n, precision); MpfrMatrixStorage query (1, 1, precision); std::unique_ptr bwork (new bool[std::max (n, 1)]); Integer sdim = 0; Integer info = 0; { MplapackMpfrPrecisionScope scope (precision); Rgges ("V", "V", "N", mpfr_qz_no_selection, static_cast (n), result.aa.data (), result.aa.leading_dimension (), result.bb.data (), result.bb.leading_dimension (), sdim, alphar.data (), alphai.data (), beta.data (), vsl.data (), vsl.leading_dimension (), vsr.data (), vsr.leading_dimension (), query.data (), -1, bwork.get (), info); } check_info (info, "Rgges workspace query"); const std::size_t lwork = checked_workspace (query.at (0, 0), "Rgges"); MpfrMatrixStorage work (lwork, 1, precision); result.aa = MpfrMatrixStorage (n, n, precision, input_a); result.bb = MpfrMatrixStorage (n, n, precision, input_b); info = 0; { MplapackMpfrPrecisionScope scope (precision); Rgges ("V", "V", "N", mpfr_qz_no_selection, static_cast (n), result.aa.data (), result.aa.leading_dimension (), result.bb.data (), result.bb.leading_dimension (), sdim, alphar.data (), alphai.data (), beta.data (), vsl.data (), vsl.leading_dimension (), vsr.data (), vsr.leading_dimension (), work.data (), static_cast (lwork), bwork.get (), info); } check_info (info, "Rgges"); result.q = transpose (vsl); result.z = vsr; return result; } MpcQzResult run_mpc_qz (const MpfrComplexMatrixStorage& input_a, const MpfrComplexMatrixStorage& input_b) { const auto precision = input_a.precision_bits (); const std::size_t n = input_a.rows (); MpcQzResult result { input_a, input_b, MpfrComplexMatrixStorage (n, n, precision), MpfrComplexMatrixStorage (n, n, precision) }; MpfrComplexMatrixStorage alpha (n, 1, precision); MpfrComplexMatrixStorage beta (n, 1, precision); MpfrComplexMatrixStorage vsl (n, n, precision); MpfrComplexMatrixStorage vsr (n, n, precision); MpfrComplexMatrixStorage query (1, 1, precision); // Cgges follows LAPACK's 8*N real-workspace requirement, even when the // selected ordering is disabled. MpfrMatrixStorage rwork (std::max (8 * n, 1), 1, precision); std::unique_ptr bwork (new bool[std::max (n, 1)]); Integer sdim = 0; Integer info = 0; { MpfrMpcPrecisionScope scope (precision); Cgges ("V", "V", "N", mpc_qz_no_selection, static_cast (n), result.aa.data (), result.aa.leading_dimension (), result.bb.data (), result.bb.leading_dimension (), sdim, alpha.data (), beta.data (), vsl.data (), vsl.leading_dimension (), vsr.data (), vsr.leading_dimension (), query.data (), -1, rwork.data (), bwork.get (), info); } check_info (info, "Cgges workspace query"); const std::size_t lwork = checked_complex_workspace ( query.at (0, 0), "Cgges"); MpfrComplexMatrixStorage work (lwork, 1, precision); result.aa = input_a; result.bb = input_b; info = 0; { MpfrMpcPrecisionScope scope (precision); Cgges ("V", "V", "N", mpc_qz_no_selection, static_cast (n), result.aa.data (), result.aa.leading_dimension (), result.bb.data (), result.bb.leading_dimension (), sdim, alpha.data (), beta.data (), vsl.data (), vsl.leading_dimension (), vsr.data (), vsr.leading_dimension (), work.data (), static_cast (lwork), rwork.data (), bwork.get (), info); } check_info (info, "Cgges"); result.q = conjugate_transpose (vsl); result.z = vsr; return result; } } // namespace MpHessResult mplapack_mpfr_hess (const MpfrMatrixStorage& input) { require_square (input.rows (), input.columns (), "hess"); MpHessResult result { MpfrMatrixStorage (input.rows (), input.columns (), input.precision_bits ()), MpfrMatrixStorage (input.rows (), input.columns (), input.precision_bits ()) }; if (input.rows () == 0) { make_identity (result.p); return result; } result.h = run_mpfr_hess (input, result.p); return result; } MpcHessResult mplapack_mpc_hess (const MpfrComplexMatrixStorage& input) { require_square (input.rows (), input.columns (), "hess"); MpcHessResult result { MpfrComplexMatrixStorage (input.rows (), input.columns (), input.precision_bits ()), MpfrComplexMatrixStorage (input.rows (), input.columns (), input.precision_bits ()) }; if (input.rows () == 0) { make_identity (result.p); return result; } result.h = run_mpc_hess (input, result.p); return result; } MpSchurResult mplapack_mpfr_schur (const MpfrMatrixStorage& input) { require_square (input.rows (), input.columns (), "schur"); MpSchurResult result { MpfrMatrixStorage (input.rows (), input.columns (), input.precision_bits ()), MpfrMatrixStorage (input.rows (), input.columns (), input.precision_bits ()) }; if (input.rows () == 0) { make_identity (result.u); return result; } result.s = run_mpfr_schur (input, result.u); return result; } MpcSchurResult mplapack_mpc_schur (const MpfrComplexMatrixStorage& input) { require_square (input.rows (), input.columns (), "schur"); MpcSchurResult result { MpfrComplexMatrixStorage (input.rows (), input.columns (), input.precision_bits()), MpfrComplexMatrixStorage (input.rows (), input.columns (), input.precision_bits ()) }; if (input.rows () == 0) { make_identity (result.u); return result; } result.s = run_mpc_schur (input, result.u); return result; } MpQzResult mplapack_mpfr_qz (const MpfrMatrixStorage& input_a, const MpfrMatrixStorage& input_b) { require_square (input_a.rows (), input_a.columns (), "qz"); require_square (input_b.rows (), input_b.columns (), "qz"); if (input_a.rows () != input_b.rows ()) throw std::invalid_argument ("qz requires equally sized matrix pairs"); return run_mpfr_qz (input_a, input_b); } MpcQzResult mplapack_mpc_qz (const MpfrComplexMatrixStorage& input_a, const MpfrComplexMatrixStorage& input_b) { require_square (input_a.rows (), input_a.columns (), "qz"); require_square (input_b.rows (), input_b.columns (), "qz"); if (input_a.rows () != input_b.rows ()) throw std::invalid_argument ("qz requires equally sized matrix pairs"); return run_mpc_qz (input_a, input_b); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_matrix_concat.h0000644000230300031750000000225715274353472020540 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_MATRIX_CONCAT_H #define OCTAVE_MPLAPACK_MP_MATRIX_CONCAT_H #include #include #include #include "mp_matrix_storage.h" namespace octave_mplapack { // A concatenation operand is a two-dimensional source whose elements can be // copied directly into a uniformly precisioned destination. The callback is // intentionally structural: it must copy one existing value, not perform // arithmetic or consult the MPFR default precision. struct MpfrConcatOperand { using CopyElement = std::function; std::size_t rows = 0; std::size_t columns = 0; mpfr_prec_t precision_bits = 0; bool has_mp_precision = false; CopyElement copy_element; }; MpfrMatrixStorage mpfr_matrix_concatenate ( const std::vector& operands, // Octave's dim_vector uses dimension 1 for horizontal and 0 for vertical // concatenation (the first dimension is the row dimension). int dimension, std::size_t result_rows, std::size_t result_columns, mpfr_prec_t result_precision); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_script_ranges.h0000644000230300031750000000334215274353472020544 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SCRIPT_RANGES_H #define OCTAVE_MPLAPACK_MP_SCRIPT_RANGES_H #include #include "mp_matrix_storage.h" #include "mp_scalar_storage.h" #include "mp_complex_matrix_storage.h" #include "mp_complex_scalar_storage.h" namespace octave_mplapack { enum class MpScriptRoundingOperation { floor, ceil, fix, round }; MpfrMatrixStorage mpfr_script_colon (const MpfrScalarStorage& first, const MpfrScalarStorage& step, const MpfrScalarStorage& last); MpfrMatrixStorage mpfr_script_linspace (const MpfrScalarStorage& first, const MpfrScalarStorage& last, std::size_t count); MpfrComplexMatrixStorage mpc_script_linspace ( const MpfrComplexScalarStorage& first, const MpfrComplexScalarStorage& last, std::size_t count); MpfrMatrixStorage mpfr_script_logspace (const MpfrScalarStorage& first, const MpfrScalarStorage& last, std::size_t count); MpfrMatrixStorage mpfr_script_round ( const MpfrMatrixStorage& source, MpScriptRoundingOperation operation); MpfrMatrixStorage mpfr_script_remainder ( const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs, bool modulus); MpfrMatrixStorage mpfr_script_hypot (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs); MpfrMatrixStorage mpfr_script_atan2 (const MpfrMatrixStorage& y, const MpfrMatrixStorage& x); MpfrMatrixStorage mpfr_script_eps (const MpfrMatrixStorage& source); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_script_statistics.h0000644000230300031750000000416515274353472021463 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SCRIPT_STATISTICS_H #define OCTAVE_MPLAPACK_MP_SCRIPT_STATISTICS_H #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { struct MpScriptStatisticsOptions { std::size_t dimension = 1; bool all = false; bool omit_nan = false; unsigned int correction = 0; }; struct MpScriptBoundsRealResult { MpfrMatrixStorage lower; MpfrMatrixStorage upper; }; struct MpScriptBoundsComplexResult { MpfrComplexMatrixStorage lower; MpfrComplexMatrixStorage upper; }; struct MpScriptVarianceRealResult { MpfrMatrixStorage values; MpfrMatrixStorage means; }; struct MpScriptVarianceComplexResult { MpfrMatrixStorage values; MpfrComplexMatrixStorage means; }; MpfrMatrixStorage mpfr_script_mean ( const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options); MpfrComplexMatrixStorage mpc_script_mean ( const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options); MpfrMatrixStorage mpfr_script_median ( const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options); MpfrComplexMatrixStorage mpc_script_median ( const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options); MpScriptVarianceRealResult mpfr_script_variance ( const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options, bool standard_deviation); MpScriptVarianceComplexResult mpc_script_variance ( const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options, bool standard_deviation); MpfrMatrixStorage mpfr_script_range ( const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options); MpfrComplexMatrixStorage mpc_script_range ( const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options); MpScriptBoundsRealResult mpfr_script_bounds ( const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options); MpScriptBoundsComplexResult mpc_script_bounds ( const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_script_sequence.cc0000644000230300031750000002060215274353472021231 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_script_sequence.h" #include #include #include #include #include #include "mp_complex_precision.h" namespace { using namespace octave_mplapack; using Real = MpfrScalarStorage::NativeScalar; using Complex = MpfrComplexScalarStorage::NativeScalar; bool real_nan (const Real& value) noexcept { return mpfr_nan_p (value.mpfr_data ()) != 0; } bool complex_nan (const Complex& value) noexcept { return mpfr_nan_p (mpc_realref (value.mpc_data ())) != 0 || mpfr_nan_p (mpc_imagref (value.mpc_data ())) != 0; } int compare_real (const Real& lhs, const Real& rhs) noexcept { const bool lhs_nan = real_nan (lhs); const bool rhs_nan = real_nan (rhs); if (lhs_nan != rhs_nan) return lhs_nan ? 1 : -1; if (lhs_nan) return 0; return mpfr_cmp (lhs.mpfr_data (), rhs.mpfr_data ()); } int compare_complex (const Complex& lhs, const Complex& rhs) { const bool lhs_nan = complex_nan (lhs); const bool rhs_nan = complex_nan (rhs); if (lhs_nan != rhs_nan) return lhs_nan ? 1 : -1; if (lhs_nan) return 0; const mpfr_prec_t precision = std::max (mpfr_get_prec (mpc_realref (lhs.mpc_data ())), mpfr_get_prec (mpc_realref (rhs.mpc_data ()))); mpfr_t lhs_key; mpfr_t rhs_key; mpfr_init2 (lhs_key, precision); mpfr_init2 (rhs_key, precision); mpc_abs (lhs_key, lhs.mpc_data (), MPFR_RNDN); mpc_abs (rhs_key, rhs.mpc_data (), MPFR_RNDN); int result = mpfr_cmp (lhs_key, rhs_key); if (result == 0) { mpfr_atan2 (lhs_key, mpc_imagref (lhs.mpc_data ()), mpc_realref (lhs.mpc_data ()), MPFR_RNDN); mpfr_atan2 (rhs_key, mpc_imagref (rhs.mpc_data ()), mpc_realref (rhs.mpc_data ()), MPFR_RNDN); result = mpfr_cmp (lhs_key, rhs_key); } mpfr_clear (lhs_key); mpfr_clear (rhs_key); return result; } template std::size_t input_index (const Storage& source, std::size_t position, std::size_t fixed, std::size_t dimension) { return dimension == 1 ? position + fixed * source.rows () : fixed + position * source.rows (); } template std::size_t sort_length (const Storage& source, std::size_t dimension) { if (dimension != 1 && dimension != 2) throw std::invalid_argument ("sort dimension must be 1 or 2"); return dimension == 1 ? source.rows () : source.columns (); } template std::size_t sort_slices (const Storage& source, std::size_t dimension) { return dimension == 1 ? source.columns () : source.rows (); } std::size_t sort_output_index (std::size_t position, std::size_t fixed, std::size_t rows, std::size_t dimension) { return dimension == 1 ? position + fixed * rows : fixed + position * rows; } template std::vector sort_indices (const Storage& source, std::size_t dimension, bool descending, Compare compare, SetValue set_value) { const std::size_t length = sort_length (source, dimension); const std::size_t slices = sort_slices (source, dimension); std::vector result (source.numel ()); std::vector order; order.reserve (length); for (std::size_t fixed = 0; fixed < slices; ++fixed) { order.clear (); for (std::size_t position = 0; position < length; ++position) order.push_back (input_index (source, position, fixed, dimension)); std::stable_sort (order.begin (), order.end (), [&] (std::size_t lhs, std::size_t rhs) { const int compared = compare (source.data ()[lhs], source.data ()[rhs]); return descending ? compared > 0 : compared < 0; }); for (std::size_t position = 0; position < length; ++position) { const std::size_t destination = sort_output_index (position, fixed, source.rows (), dimension); // Public sort indices are one-based positions within the sorted // dimension, as in Octave (not global linear indices). result[destination] = dimension == 1 ? order[position] % source.rows () + 1 : order[position] / source.rows () + 1; set_value (destination, source.data ()[order[position]]); } } return result; } template Storage diff_once (const Storage& source, std::size_t dimension, SetValue set_value) { if (dimension != 1 && dimension != 2) throw std::invalid_argument ("diff dimension must be 1 or 2"); const std::size_t rows = source.rows (); const std::size_t columns = source.columns (); const std::size_t result_rows = dimension == 1 && rows > 0 ? rows - 1 : rows; const std::size_t result_columns = dimension == 2 && columns > 0 ? columns - 1 : columns; Storage result (result_rows, result_columns, source.precision_bits ()); for (std::size_t column = 0; column < result_columns; ++column) for (std::size_t row = 0; row < result_rows; ++row) { const std::size_t lhs_row = dimension == 1 ? row + 1 : row; const std::size_t lhs_column = dimension == 1 ? column : column + 1; const std::size_t rhs_row = row; const std::size_t rhs_column = column; set_value (result.at (row, column), source.at (lhs_row, lhs_column), source.at (rhs_row, rhs_column)); } return result; } template Storage diff_result (const Storage& source, std::size_t order, std::size_t dimension, SetValue set_value) { if (dimension != 1 && dimension != 2) throw std::invalid_argument ("diff dimension must be 1 or 2"); if (order == 0) return source; Storage result = source; for (std::size_t iteration = 0; iteration < order; ++iteration) { if ((dimension == 1 && result.rows () == 0) || (dimension == 2 && result.columns () == 0)) break; result = diff_once (result, dimension, set_value); } return result; } } // namespace namespace octave_mplapack { MpScriptSortRealResult mpfr_script_sort (const MpfrMatrixStorage& source, std::size_t dimension, bool descending) { MpfrMatrixStorage values (source.rows (), source.columns (), source.precision_bits ()); auto set_value = [&] (std::size_t destination, const auto& value) { mpfr_set (values.data ()[destination].mpfr_data (), value.mpfr_data (), MPFR_RNDN); }; auto indices = sort_indices (source, dimension, descending, [] (const auto& lhs, const auto& rhs) { return compare_real (lhs, rhs); }, set_value); return {std::move (values), std::move (indices)}; } MpScriptSortComplexResult mpc_script_sort (const MpfrComplexMatrixStorage& source, std::size_t dimension, bool descending) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage values (source.rows (), source.columns (), source.precision_bits ()); auto set_value = [&] (std::size_t destination, const auto& value) { mpc_set (values.data ()[destination].mpc_data (), value.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; auto indices = sort_indices (source, dimension, descending, [] (const auto& lhs, const auto& rhs) { return compare_complex (lhs, rhs); }, set_value); return {std::move (values), std::move (indices)}; } MpfrMatrixStorage mpfr_script_diff (const MpfrMatrixStorage& source, std::size_t order, std::size_t dimension) { return diff_result (source, order, dimension, [] (auto& destination, const auto& lhs, const auto& rhs) { mpfr_sub (destination.mpfr_data (), lhs.mpfr_data (), rhs.mpfr_data (), MPFR_RNDN); }); } MpfrComplexMatrixStorage mpc_script_diff (const MpfrComplexMatrixStorage& source, std::size_t order, std::size_t dimension) { MpfrMpcPrecisionScope scope (source.precision_bits ()); return diff_result (source, order, dimension, [] (auto& destination, const auto& lhs, const auto& rhs) { mpc_sub (destination.mpc_data (), lhs.mpc_data (), rhs.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_blas.cc0000644000230300031750000001741215274353472020512 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_blas.h" #include #include #include #include #include "mp_complex_precision.h" namespace octave_mplapack { namespace { void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK MPC precision is outside the MPFR range"); } void set_zero (MpfrComplexMatrixStorage& matrix) { for (std::size_t index = 0; index < matrix.numel (); ++index) mpc_set_ui_ui (matrix.data ()[index].mpc_data (), 0, 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } // namespace void require_mplapack_mpc_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexScalarStorage& alpha, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& b_work, const MpfrComplexScalarStorage& beta, const MpfrComplexMatrixStorage& c) { validate_precision (operation_precision); const auto precision_override = mpfrxx::mpc_precision_override_storage (); const bool matches = mpfrxx::default_precision_bits () == operation_precision && precision_override.active && precision_override.real_precision_bits == operation_precision && precision_override.imag_precision_bits == operation_precision && alpha.precision_bits () == operation_precision && beta.precision_bits () == operation_precision && a_work.precision_bits () == operation_precision && b_work.precision_bits () == operation_precision && c.precision_bits () == operation_precision && a_work.all_elements_have_uniform_precision () && b_work.all_elements_have_uniform_precision () && c.all_elements_have_uniform_precision (); if (! matches) throw std::runtime_error ( "MPLAPACK complex precision contract mismatch at Cgemm boundary"); } MpfrComplexMatrixStorage mplapack_mpc_matrix_copy_at_precision ( const MpfrComplexMatrixStorage& source, mpfr_prec_t precision_bits) { validate_precision (precision_bits); MpfrMpcPrecisionScope scope (precision_bits); MpfrComplexMatrixStorage result (source.rows (), source.columns (), precision_bits); for (std::size_t index = 0; index < source.numel (); ++index) mpc_set (result.data ()[index].mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrComplexMatrixStorage mplapack_mpc_matrix_from_real (const MpfrMatrixStorage& source, mpfr_prec_t precision_bits) { validate_precision (precision_bits); MpfrMpcPrecisionScope scope (precision_bits); MpfrComplexMatrixStorage result (source.rows (), source.columns (), precision_bits); for (std::size_t index = 0; index < source.numel (); ++index) mpc_set_fr (result.data ()[index].mpc_data (), source.data ()[index].mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrComplexScalarStorage mplapack_mpc_scalar_copy_at_precision ( const MpfrComplexScalarStorage& source, mpfr_prec_t precision_bits) { validate_precision (precision_bits); MpfrMpcPrecisionScope scope (precision_bits); MpfrComplexScalarStorage::NativeScalar result = MpfrComplexScalarStorage::NativeScalar::with_precision (precision_bits); mpc_set (result.mpc_data (), source.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return MpfrComplexScalarStorage (std::move (result)); } MpfrComplexScalarStorage mplapack_mpc_scalar_from_real (const MpfrScalarStorage& source, mpfr_prec_t precision_bits) { validate_precision (precision_bits); MpfrMpcPrecisionScope scope (precision_bits); MpfrComplexScalarStorage::NativeScalar result = MpfrComplexScalarStorage::NativeScalar::with_precision (precision_bits); mpc_set_fr (result.mpc_data (), source.native_value ().mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return MpfrComplexScalarStorage (std::move (result)); } MpfrComplexMatrixStorage mplapack_mpc_matrix_multiply (const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs) { if (lhs.columns () != rhs.rows ()) throw std::invalid_argument ("complex matrix multiplication dimension mismatch"); const mpfr_prec_t operation_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); validate_precision (operation_precision); auto a_work = mplapack_mpc_matrix_copy_at_precision (lhs, operation_precision); auto b_work = mplapack_mpc_matrix_copy_at_precision (rhs, operation_precision); MpfrComplexMatrixStorage result (lhs.rows (), rhs.columns (), operation_precision); if (result.numel () == 0 || lhs.columns () == 0) { set_zero (result); return result; } MpfrComplexScalarStorage alpha (1.0, 0.0, operation_precision); MpfrComplexScalarStorage beta (0.0, 0.0, operation_precision); MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_precision_contract ( operation_precision, alpha, a_work, b_work, beta, result); Cgemm ("N", "N", MpfrComplexMatrixStorage::checked_mplapack_dimension (lhs.rows ()), MpfrComplexMatrixStorage::checked_mplapack_dimension (rhs.columns ()), MpfrComplexMatrixStorage::checked_mplapack_dimension (lhs.columns ()), alpha.native_value (), a_work.data (), a_work.leading_dimension (), b_work.data (), b_work.leading_dimension (), beta.native_value (), result.data (), result.leading_dimension ()); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK Cgemm changed the current-thread default precision"); return result; } MpfrComplexMatrixStorage mplapack_mpc_matrix_scale (const MpfrComplexMatrixStorage& matrix, const MpfrComplexScalarStorage& scalar) { const mpfr_prec_t operation_precision = std::max (matrix.precision_bits (), scalar.precision_bits ()); validate_precision (operation_precision); auto matrix_work = mplapack_mpc_matrix_copy_at_precision ( matrix, operation_precision); auto scalar_work = mplapack_mpc_scalar_copy_at_precision ( scalar, operation_precision); MpfrMpcPrecisionScope scope (operation_precision); MpfrComplexMatrixStorage result (matrix.rows (), matrix.columns (), operation_precision); for (std::size_t index = 0; index < result.numel (); ++index) mpc_mul (result.data ()[index].mpc_data (), matrix_work.data ()[index].mpc_data (), scalar_work.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrComplexScalarStorage mplapack_mpc_scalar_multiply (const MpfrComplexScalarStorage& lhs, const MpfrComplexScalarStorage& rhs) { const mpfr_prec_t operation_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); validate_precision (operation_precision); auto lhs_work = mplapack_mpc_scalar_copy_at_precision ( lhs, operation_precision); auto rhs_work = mplapack_mpc_scalar_copy_at_precision ( rhs, operation_precision); MpfrMpcPrecisionScope scope (operation_precision); MpfrComplexScalarStorage::NativeScalar result = MpfrComplexScalarStorage::NativeScalar::with_precision ( operation_precision); mpc_mul (result.mpc_data (), lhs_work.native_value ().mpc_data (), rhs_work.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return MpfrComplexScalarStorage (std::move (result)); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_matrix_inspection.h0000644000230300031750000000222115274353472021433 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_MATRIX_INSPECTION_H #define OCTAVE_MPLAPACK_MP_MATRIX_INSPECTION_H #include #include #include #include "mp_matrix_storage.h" #include "mp_complex_matrix_storage.h" namespace octave_mplapack { MpfrMatrixStorage select_matrix (const MpfrMatrixStorage& source, const std::vector& row_indices, const std::vector& column_indices); MpfrMatrixStorage select_linear (const MpfrMatrixStorage& source, const std::vector& indices); std::string format_matrix (const MpfrMatrixStorage& source); MpfrComplexMatrixStorage select_complex_matrix (const MpfrComplexMatrixStorage& source, const std::vector& row_indices, const std::vector& column_indices); MpfrComplexMatrixStorage select_complex_linear (const MpfrComplexMatrixStorage& source, const std::vector& indices); std::string format_complex_matrix (const MpfrComplexMatrixStorage& source); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_matrix_value.h0000644000230300031750000000324515274353472022132 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_MATRIX_VALUE_H #define OCTAVE_MPLAPACK_MP_COMPLEX_MATRIX_VALUE_H #include #include #include "mp_complex_matrix_storage.h" class octave_value; class octave_mplapack_mpc_matrix_internal : public octave_base_dld_value { public: octave_mplapack_mpc_matrix_internal (); explicit octave_mplapack_mpc_matrix_internal ( octave_mplapack::MpfrComplexMatrixStorage storage); octave_mplapack_mpc_matrix_internal (const octave_mplapack_mpc_matrix_internal&) = default; ~octave_mplapack_mpc_matrix_internal () override = default; octave_base_value * clone () const override; octave_base_value * empty_clone () const override; dim_vector dims () const override; bool is_defined () const override; bool is_storable () const override; bool is_complex_matrix () const override; bool isreal () const override; bool is_matrix_type () const override; bool save_ascii (std::ostream& os) override; bool load_ascii (std::istream& is) override; bool save_binary (std::ostream& os, bool save_as_floats) override; bool load_binary (std::istream& is, bool swap, octave::mach_info::float_format fmt) override; void print (std::ostream& os, bool pr_as_read_syntax = false) override; void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const override; const octave_mplapack::MpfrComplexMatrixStorage& storage () const noexcept; static const octave_mplapack_mpc_matrix_internal& checked_value ( const octave_value& value); DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA private: octave_mplapack::MpfrComplexMatrixStorage m_storage; }; #endif mplapack-interop-0.5.1/src/mp_complex_value.h0000644000230300031750000000366215274353472020551 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_VALUE_H #define OCTAVE_MPLAPACK_MP_COMPLEX_VALUE_H #include #include #include #include "mp_complex_scalar_storage.h" class octave_value; class octave_mplapack_mpc_scalar_internal : public octave_base_dld_value { public: octave_mplapack_mpc_scalar_internal (); octave_mplapack_mpc_scalar_internal (const std::string& text, mpfr_prec_t precision_bits); octave_mplapack_mpc_scalar_internal (double real, double imag, mpfr_prec_t precision_bits); explicit octave_mplapack_mpc_scalar_internal ( octave_mplapack::MpfrComplexScalarStorage storage); octave_mplapack_mpc_scalar_internal (const octave_mplapack_mpc_scalar_internal&) = default; ~octave_mplapack_mpc_scalar_internal () override = default; octave_base_value * clone () const override; octave_base_value * empty_clone () const override; dim_vector dims () const override; bool is_defined () const override; bool is_storable () const override; bool is_complex_scalar () const override; bool isreal () const override; bool is_scalar_type () const override; bool save_ascii (std::ostream& os) override; bool load_ascii (std::istream& is) override; bool save_binary (std::ostream& os, bool save_as_floats) override; bool load_binary (std::istream& is, bool swap, octave::mach_info::float_format fmt) override; void print (std::ostream& os, bool pr_as_read_syntax = false) override; void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const override; const octave_mplapack::MpfrComplexScalarStorage& storage () const noexcept; static const octave_mplapack_mpc_scalar_internal& checked_value ( const octave_value& value); DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA private: octave_mplapack::MpfrComplexScalarStorage m_storage; }; #endif mplapack-interop-0.5.1/src/mp_complex_lu.h0000644000230300031750000000237415274353472020054 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_LU_H #define OCTAVE_MPLAPACK_MP_COMPLEX_LU_H #include #include #include "mp_complex_matrix_storage.h" namespace octave_mplapack { class MpcCgetrfError : public std::runtime_error { public: enum class Kind { invalid_argument, internal }; MpcCgetrfError (Kind kind, MpfrComplexMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrComplexMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrComplexMatrixStorage::MplapackInteger m_info; }; struct MpcLuResult { MpfrComplexMatrixStorage packed; MpfrComplexMatrixStorage lower; MpfrComplexMatrixStorage upper; std::vector permutation; MpfrComplexMatrixStorage::MplapackInteger info; }; void require_mplapack_mpc_lu_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work); MpcLuResult mplapack_mpc_matrix_lu ( const MpfrComplexMatrixStorage& input); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_scalar_storage.cc0000644000230300031750000001305715274353472021034 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_scalar_storage.h" #include #include #include #include #include #include namespace { struct MpfrStringDeleter { void operator() (char *value) const noexcept { if (value) mpfr_free_str (value); } }; using MpfrString = std::unique_ptr; std::size_t checked_add (std::size_t lhs, std::size_t rhs) { if (rhs > std::numeric_limits::max () - lhs) throw std::overflow_error ("canonical string size overflow"); return lhs + rhs; } std::string canonical_exponent (mpfr_exp_t exponent) { if (exponent == std::numeric_limits::min ()) throw std::overflow_error ("canonical exponent overflow"); const mpfr_exp_t normalized = exponent - 1; std::array::digits10 + 4> buffer {}; auto result = std::to_chars (buffer.data (), buffer.data () + buffer.size (), normalized); if (result.ec != std::errc ()) throw std::overflow_error ("canonical exponent conversion failed"); std::string text; if (normalized >= 0) text.push_back ('+'); text.append (buffer.data (), result.ptr); return text; } } // namespace namespace octave_mplapack { MpfrScalarStorage::MpfrScalarStorage (const std::string& text, mpfr_prec_t precision_bits) : m_value (NativeScalar::with_precision (precision_bits)) { if (mpfr_set_str (m_value.mpfr_data (), text.c_str (), 10, MPFR_RNDN) != 0) throw std::invalid_argument ("invalid scalar text"); } MpfrScalarStorage::MpfrScalarStorage (double value, mpfr_prec_t precision_bits) : m_value (NativeScalar::with_precision (precision_bits)) { mpfr_set_d (m_value.mpfr_data (), value, MPFR_RNDN); } MpfrScalarStorage::MpfrScalarStorage (NativeScalar value) : m_value (std::move (value)) { } MpfrScalarStorage::MpfrScalarStorage (mpfr_prec_t precision_bits, UninitializedTag) : m_value (NativeScalar::with_precision (precision_bits)) { } MpfrScalarStorage& MpfrScalarStorage::operator= (MpfrScalarStorage other) noexcept { swap (other); return *this; } void MpfrScalarStorage::swap (MpfrScalarStorage& other) noexcept { m_value.swap (other.m_value); } mpfr_prec_t MpfrScalarStorage::precision_bits () const noexcept { return m_value.precision (); } bool MpfrScalarStorage::exactly_equal (const MpfrScalarStorage& other) const noexcept { return mpfr_equal_p (m_value.mpfr_data (), other.m_value.mpfr_data ()) != 0; } bool MpfrScalarStorage::exactly_equal_string (const std::string& text) const { const MpfrScalarStorage expected (text, precision_bits ()); return exactly_equal (expected); } bool MpfrScalarStorage::exactly_equal_double (double value) const noexcept { return mpfr_cmp_d (m_value.mpfr_data (), value) == 0; } bool MpfrScalarStorage::is_nan () const noexcept { return mpfr_nan_p (m_value.mpfr_data ()) != 0; } bool MpfrScalarStorage::is_infinite () const noexcept { return mpfr_inf_p (m_value.mpfr_data ()) != 0; } bool MpfrScalarStorage::is_zero () const noexcept { return mpfr_zero_p (m_value.mpfr_data ()) != 0; } bool MpfrScalarStorage::signbit () const noexcept { return mpfr_signbit (m_value.mpfr_data ()) != 0; } std::string MpfrScalarStorage::to_canonical_string () const { if (is_nan ()) return "NaN"; if (is_infinite ()) return signbit () ? "-Inf" : "Inf"; if (is_zero ()) return signbit () ? "-0" : "0"; const std::size_t digit_count = mpfr_get_str_ndigits (10, precision_bits ()); std::string capacity_probe; if (digit_count > std::numeric_limits::max () - 2 || digit_count > capacity_probe.max_size ()) throw std::overflow_error ("canonical digit buffer size overflow"); mpfr_exp_t exponent = 0; MpfrString raw_digits ( mpfr_get_str (nullptr, &exponent, 10, 0, m_value.mpfr_data (), MPFR_RNDN)); if (! raw_digits) throw std::runtime_error ("mpfr_get_str failed"); std::string digits (raw_digits.get ()); const bool negative = ! digits.empty () && digits.front () == '-'; if (negative) digits.erase (digits.begin ()); if (digits.empty () || digits.front () == '0') throw std::runtime_error ("invalid finite MPFR significand"); while (digits.size () > 1 && digits.back () == '0') digits.pop_back (); const std::string exponent_text = canonical_exponent (exponent); std::size_t output_size = negative ? 1 : 0; output_size = checked_add (output_size, digits.size ()); if (digits.size () > 1) output_size = checked_add (output_size, 1); output_size = checked_add (output_size, 1); output_size = checked_add (output_size, exponent_text.size ()); std::string output; if (output_size > output.max_size ()) throw std::length_error ("canonical string exceeds std::string capacity"); output.reserve (output_size); if (negative) output.push_back ('-'); output.push_back (digits.front ()); if (digits.size () > 1) { output.push_back ('.'); output.append (digits.begin () + 1, digits.end ()); } output.push_back ('e'); output.append (exponent_text); return output; } double MpfrScalarStorage::to_double () const noexcept { return mpfr_get_d (m_value.mpfr_data (), MPFR_RNDN); } const MpfrScalarStorage::NativeScalar& MpfrScalarStorage::native_value () const noexcept { return m_value; } void swap (MpfrScalarStorage& lhs, MpfrScalarStorage& rhs) noexcept { lhs.swap (rhs); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_script_structure.cc0000644000230300031750000003111715274353472021464 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_script_structure.h" #include #include #include #include #include "mp_complex_precision.h" namespace { std::size_t diagonal_length (std::size_t rows, std::size_t columns, std::int64_t diagonal) { const std::int64_t row_start = diagonal < 0 ? -diagonal : 0; const std::int64_t column_start = diagonal > 0 ? diagonal : 0; if (row_start >= static_cast (rows) || column_start >= static_cast (columns)) return 0; return std::min (rows - static_cast (row_start), columns - static_cast (column_start)); } std::size_t square_diagonal_dimension (std::size_t length, std::int64_t diagonal) { const std::uint64_t magnitude = diagonal < 0 ? static_cast (-(diagonal + 1)) + 1 : static_cast (diagonal); if (magnitude > std::numeric_limits::max () - length) throw std::overflow_error ("diagonal matrix dimension overflow"); return length + static_cast (magnitude); } int normalize_rot90 (int turns) { const int normalized = turns % 4; return normalized < 0 ? normalized + 4 : normalized; } } // namespace namespace octave_mplapack { MpfrMatrixStorage mpfr_script_diag (const MpfrMatrixStorage& source, bool vector_input, std::int64_t diagonal) { if (vector_input) { const std::size_t length = source.numel (); const std::size_t dimension = square_diagonal_dimension (length, diagonal); MpfrMatrixStorage result (dimension, dimension, source.precision_bits ()); const std::size_t row_start = diagonal < 0 ? static_cast (-diagonal) : 0; const std::size_t column_start = diagonal > 0 ? static_cast (diagonal) : 0; for (std::size_t index = 0; index < length; ++index) mpfr_set (result.at (row_start + index, column_start + index).mpfr_data (), source.data ()[index].mpfr_data (), MPFR_RNDN); return result; } const std::size_t length = diagonal_length (source.rows (), source.columns (), diagonal); MpfrMatrixStorage result (length, 1, source.precision_bits ()); const std::size_t row_start = diagonal < 0 ? static_cast (-diagonal) : 0; const std::size_t column_start = diagonal > 0 ? static_cast (diagonal) : 0; for (std::size_t index = 0; index < length; ++index) mpfr_set (result.at (index, 0).mpfr_data (), source.at (row_start + index, column_start + index).mpfr_data (), MPFR_RNDN); return result; } MpfrComplexMatrixStorage mpc_script_diag (const MpfrComplexMatrixStorage& source, bool vector_input, std::int64_t diagonal) { MpfrMpcPrecisionScope scope (source.precision_bits ()); if (vector_input) { const std::size_t length = source.numel (); const std::size_t dimension = square_diagonal_dimension (length, diagonal); MpfrComplexMatrixStorage result (dimension, dimension, source.precision_bits ()); const std::size_t row_start = diagonal < 0 ? static_cast (-diagonal) : 0; const std::size_t column_start = diagonal > 0 ? static_cast (diagonal) : 0; for (std::size_t index = 0; index < length; ++index) mpc_set (result.at (row_start + index, column_start + index).mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } const std::size_t length = diagonal_length (source.rows (), source.columns (), diagonal); MpfrComplexMatrixStorage result (length, 1, source.precision_bits ()); const std::size_t row_start = diagonal < 0 ? static_cast (-diagonal) : 0; const std::size_t column_start = diagonal > 0 ? static_cast (diagonal) : 0; for (std::size_t index = 0; index < length; ++index) mpc_set (result.at (index, 0).mpc_data (), source.at (row_start + index, column_start + index).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrMatrixStorage mpfr_script_triangular (const MpfrMatrixStorage& source, std::int64_t diagonal, bool upper) { MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) { const std::int64_t difference = static_cast (column) - static_cast (row); const bool keep = upper ? difference >= diagonal : difference <= diagonal; if (keep) mpfr_set (result.at (row, column).mpfr_data (), source.at (row, column).mpfr_data (), MPFR_RNDN); else mpfr_set_zero (result.at (row, column).mpfr_data (), 0); } return result; } MpfrComplexMatrixStorage mpc_script_triangular (const MpfrComplexMatrixStorage& source, std::int64_t diagonal, bool upper) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) { const std::int64_t difference = static_cast (column) - static_cast (row); const bool keep = upper ? difference >= diagonal : difference <= diagonal; if (keep) mpc_set (result.at (row, column).mpc_data (), source.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else mpc_set_ui (result.at (row, column).mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } return result; } MpfrMatrixStorage mpfr_script_repmat (const MpfrMatrixStorage& source, std::size_t row_repetitions, std::size_t column_repetitions) { if (source.rows () != 0 && row_repetitions > std::numeric_limits::max () / source.rows ()) throw std::overflow_error ("repmat row dimension overflow"); if (source.columns () != 0 && column_repetitions > std::numeric_limits::max () / source.columns ()) throw std::overflow_error ("repmat column dimension overflow"); const std::size_t rows = source.rows () * row_repetitions; const std::size_t columns = source.columns () * column_repetitions; MpfrMatrixStorage result (rows, columns, source.precision_bits ()); if (source.rows () == 0 || source.columns () == 0) return result; for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) mpfr_set (result.at (row, column).mpfr_data (), source.at (row % source.rows (), column % source.columns ()) .mpfr_data (), MPFR_RNDN); return result; } MpfrComplexMatrixStorage mpc_script_repmat (const MpfrComplexMatrixStorage& source, std::size_t row_repetitions, std::size_t column_repetitions) { MpfrMpcPrecisionScope scope (source.precision_bits ()); if (source.rows () != 0 && row_repetitions > std::numeric_limits::max () / source.rows ()) throw std::overflow_error ("repmat row dimension overflow"); if (source.columns () != 0 && column_repetitions > std::numeric_limits::max () / source.columns ()) throw std::overflow_error ("repmat column dimension overflow"); const std::size_t rows = source.rows () * row_repetitions; const std::size_t columns = source.columns () * column_repetitions; MpfrComplexMatrixStorage result (rows, columns, source.precision_bits ()); if (source.rows () == 0 || source.columns () == 0) return result; for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) mpc_set (result.at (row, column).mpc_data (), source.at (row % source.rows (), column % source.columns ()) .mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrMatrixStorage mpfr_script_flip (const MpfrMatrixStorage& source, int dimension) { if (dimension != 1 && dimension != 2) throw std::invalid_argument ("flip dimension must be 1 or 2"); MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) { const std::size_t source_row = dimension == 1 ? source.rows () - 1 - row : row; const std::size_t source_column = dimension == 2 ? source.columns () - 1 - column : column; mpfr_set (result.at (row, column).mpfr_data (), source.at (source_row, source_column).mpfr_data (), MPFR_RNDN); } return result; } MpfrComplexMatrixStorage mpc_script_flip (const MpfrComplexMatrixStorage& source, int dimension) { if (dimension != 1 && dimension != 2) throw std::invalid_argument ("flip dimension must be 1 or 2"); MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) { const std::size_t source_row = dimension == 1 ? source.rows () - 1 - row : row; const std::size_t source_column = dimension == 2 ? source.columns () - 1 - column : column; mpc_set (result.at (row, column).mpc_data (), source.at (source_row, source_column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } return result; } MpfrMatrixStorage mpfr_script_rot90 (const MpfrMatrixStorage& source, int turns) { const int normalized = normalize_rot90 (turns); const std::size_t result_rows = normalized % 2 == 0 ? source.rows () : source.columns (); const std::size_t result_columns = normalized % 2 == 0 ? source.columns () : source.rows (); MpfrMatrixStorage result (result_rows, result_columns, source.precision_bits ()); for (std::size_t column = 0; column < result_columns; ++column) for (std::size_t row = 0; row < result_rows; ++row) { std::size_t source_row = row; std::size_t source_column = column; if (normalized == 1) { source_row = column; source_column = source.columns () - 1 - row; } else if (normalized == 2) { source_row = source.rows () - 1 - row; source_column = source.columns () - 1 - column; } else if (normalized == 3) { source_row = source.rows () - 1 - column; source_column = row; } mpfr_set (result.at (row, column).mpfr_data (), source.at (source_row, source_column).mpfr_data (), MPFR_RNDN); } return result; } MpfrComplexMatrixStorage mpc_script_rot90 (const MpfrComplexMatrixStorage& source, int turns) { const int normalized = normalize_rot90 (turns); const std::size_t result_rows = normalized % 2 == 0 ? source.rows () : source.columns (); const std::size_t result_columns = normalized % 2 == 0 ? source.columns () : source.rows (); MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (result_rows, result_columns, source.precision_bits ()); for (std::size_t column = 0; column < result_columns; ++column) for (std::size_t row = 0; row < result_rows; ++row) { std::size_t source_row = row; std::size_t source_column = column; if (normalized == 1) { source_row = column; source_column = source.columns () - 1 - row; } else if (normalized == 2) { source_row = source.rows () - 1 - row; source_column = source.columns () - 1 - column; } else if (normalized == 3) { source_row = source.rows () - 1 - column; source_column = row; } mpc_set (result.at (row, column).mpc_data (), source.at (source_row, source_column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_general_eig.cc0000644000230300031750000004337715274353472020314 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_general_eig.h" #include #include #include #include #include #include #include #include #include #include "mp_complex_precision.h" namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrScalarStorage; void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK general eig precision is outside MPFR limits"); } std::size_t checked_workspace_length (const MpfrScalarStorage::NativeScalar& query, const char *routine) { if (mpfr_nan_p (query.mpfr_data ()) != 0 || mpfr_inf_p (query.mpfr_data ()) != 0 || mpfr_integer_p (query.mpfr_data ()) == 0 || mpfr_sgn (query.mpfr_data ()) <= 0) throw std::runtime_error (std::string (routine) + " returned an invalid workspace query"); mpz_t value; mpz_t max_mplapack; mpz_t max_size; mpz_init (value); mpz_init (max_mplapack); mpz_init (max_size); mpfr_get_z (value, query.mpfr_data (), MPFR_RNDZ); const auto mplapack_max = std::numeric_limits::max (); const auto size_max = std::numeric_limits::max (); mpz_import (max_mplapack, 1, -1, sizeof (mplapack_max), 0, 0, &mplapack_max); mpz_import (max_size, 1, -1, sizeof (size_max), 0, 0, &size_max); const bool fits = mpz_cmp (value, max_mplapack) <= 0 && mpz_cmp (value, max_size) <= 0; if (! fits) { mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); throw std::overflow_error (std::string (routine) + " workspace exceeds allocation limits"); } const auto result = static_cast ( mpfr_get_uj (query.mpfr_data (), MPFR_RNDZ)); mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); return result; } std::size_t checked_complex_workspace_length ( const MpfrComplexMatrixStorage::NativeScalar& query, const char *routine) { if (mpfr_sgn (mpc_imagref (query.mpc_data ())) != 0) throw std::runtime_error (std::string (routine) + " returned a complex workspace query"); auto real_query = MpfrScalarStorage::NativeScalar::with_precision ( query.real_precision ()); mpfr_set (real_query.mpfr_data (), mpc_realref (query.mpc_data ()), MPFR_RNDN); return checked_workspace_length (real_query, routine); } void set_complex_from_real (MpfrComplexMatrixStorage::NativeScalar& destination, const MpfrMatrixStorage::NativeScalar& real, const MpfrMatrixStorage::NativeScalar& imag) { mpfr_set (mpc_realref (destination.mpc_data ()), real.mpfr_data (), MPFR_RNDN); mpfr_set (mpc_imagref (destination.mpc_data ()), imag.mpfr_data (), MPFR_RNDN); } void set_complex_from_real (MpfrComplexMatrixStorage::NativeScalar& destination, const MpfrMatrixStorage::NativeScalar& real) { mpfr_set (mpc_realref (destination.mpc_data ()), real.mpfr_data (), MPFR_RNDN); mpfr_set_zero (mpc_imagref (destination.mpc_data ()), 1); } void fill_diagonal (MpfrComplexMatrixStorage& diagonal, const MpfrComplexMatrixStorage& eigenvalues) { for (std::size_t column = 0; column < diagonal.columns (); ++column) for (std::size_t row = 0; row < diagonal.rows (); ++row) { if (row == column) mpc_set (diagonal.at (row, column).mpc_data (), eigenvalues.at (row, 0).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else mpc_set_ui (diagonal.at (row, column).mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } void require_real_contract (mpfr_prec_t precision, const MpfrMatrixStorage& a, const MpfrMatrixStorage& wr, const MpfrMatrixStorage& wi, const MpfrMatrixStorage& vl, const MpfrMatrixStorage& vr, const MpfrMatrixStorage& scale, const MpfrMatrixStorage& rconde, const MpfrMatrixStorage& rcondv, const MpfrMatrixStorage& work, const MpfrScalarStorage::NativeScalar& abnrm) { if (mpfrxx::default_precision_bits () != precision || a.precision_bits () != precision || wr.precision_bits () != precision || wi.precision_bits () != precision || vl.precision_bits () != precision || vr.precision_bits () != precision || scale.precision_bits () != precision || rconde.precision_bits () != precision || rcondv.precision_bits () != precision || work.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! wr.all_elements_have_uniform_precision () || ! wi.all_elements_have_uniform_precision () || ! vl.all_elements_have_uniform_precision () || ! vr.all_elements_have_uniform_precision () || ! scale.all_elements_have_uniform_precision () || ! rconde.all_elements_have_uniform_precision () || ! rcondv.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision () || abnrm.precision () != precision) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rgeevx boundary"); } void require_complex_contract (mpfr_prec_t precision, const MpfrComplexMatrixStorage& a, const MpfrComplexMatrixStorage& w, const MpfrComplexMatrixStorage& vl, const MpfrComplexMatrixStorage& vr, const MpfrComplexMatrixStorage& work, const MpfrMatrixStorage& rwork, const MpfrMatrixStorage& scale, const MpfrMatrixStorage& rconde, const MpfrMatrixStorage& rcondv, const MpfrScalarStorage::NativeScalar& abnrm) { const auto state = mpfrxx::mpc_precision_override_storage (); if (mpfrxx::default_precision_bits () != precision || ! state.active || state.real_precision_bits != precision || state.imag_precision_bits != precision || a.precision_bits () != precision || w.precision_bits () != precision || vl.precision_bits () != precision || vr.precision_bits () != precision || work.precision_bits () != precision || rwork.precision_bits () != precision || scale.precision_bits () != precision || rconde.precision_bits () != precision || rcondv.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! w.all_elements_have_uniform_precision () || ! vl.all_elements_have_uniform_precision () || ! vr.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision () || ! rwork.all_elements_have_uniform_precision () || ! scale.all_elements_have_uniform_precision () || ! rconde.all_elements_have_uniform_precision () || ! rcondv.all_elements_have_uniform_precision () || abnrm.precision () != precision) throw std::runtime_error ( "MPLAPACK MPC precision contract mismatch at Cgeevx boundary"); } void convert_real_eigenpair_column (MpfrComplexMatrixStorage& destination, const MpfrMatrixStorage& source, std::size_t destination_column, std::size_t source_column) { for (std::size_t row = 0; row < source.rows (); ++row) set_complex_from_real (destination.at (row, destination_column), source.at (row, source_column)); } void convert_real_eigenvectors (MpfrComplexMatrixStorage& destination, const MpfrMatrixStorage& source, const MpfrMatrixStorage& wi) { const std::size_t n = source.columns (); std::size_t column = 0; while (column < n) { const int sign = mpfr_sgn (wi.at (column, 0).mpfr_data ()); if (sign > 0 && column + 1 < n && mpfr_sgn (wi.at (column + 1, 0).mpfr_data ()) < 0) { for (std::size_t row = 0; row < source.rows (); ++row) { auto& first = destination.at (row, column); set_complex_from_real (first, source.at (row, column), source.at (row, column + 1)); auto& second = destination.at (row, column + 1); set_complex_from_real (second, source.at (row, column), source.at (row, column + 1)); mpfr_neg (mpc_imagref (second.mpc_data ()), mpc_imagref (second.mpc_data ()), MPFR_RNDN); } column += 2; } else if (sign < 0 && column > 0 && mpfr_sgn (wi.at (column - 1, 0).mpfr_data ()) > 0) ++column; else { convert_real_eigenpair_column (destination, source, column, column); ++column; } } } MpfrComplexMatrixStorage make_real_complex_values (const MpfrMatrixStorage& wr, const MpfrMatrixStorage& wi) { const std::size_t n = wr.rows (); MpfrComplexMatrixStorage result (n, 1, wr.precision_bits ()); for (std::size_t index = 0; index < n; ++index) set_complex_from_real (result.at (index, 0), wr.at (index, 0), wi.at (index, 0)); return result; } } // namespace namespace octave_mplapack { MpfrGeneralEigResult mplapack_mpfr_matrix_general_eig (const MpfrMatrixStorage& input, bool balance) { if (input.rows () != input.columns ()) throw std::invalid_argument ("general eig requires a square real matrix"); const mpfr_prec_t precision = input.precision_bits (); validate_precision (precision); const std::size_t n = input.rows (); MpfrGeneralEigResult result { MpfrComplexMatrixStorage (n, 1, precision), MpfrComplexMatrixStorage (n, n, precision), MpfrComplexMatrixStorage (n, n, precision), MpfrComplexMatrixStorage (n, n, precision) }; if (n == 0) return result; MpfrMatrixStorage a_work (n, n, precision, input); MpfrMatrixStorage wr (n, 1, precision); MpfrMatrixStorage wi (n, 1, precision); MpfrMatrixStorage vl (n, n, precision); MpfrMatrixStorage vr (n, n, precision); MpfrMatrixStorage query_work (1, 1, precision); MpfrMatrixStorage scale (n, 1, precision); MpfrMatrixStorage rconde (n, 1, precision); MpfrMatrixStorage rcondv (n, 1, precision); MpfrScalarStorage::NativeScalar abnrm = MpfrScalarStorage::NativeScalar::with_precision (precision); std::vector iwork (std::max (1, n)); MpfrMatrixStorage::MplapackInteger ilo = 0; MpfrMatrixStorage::MplapackInteger ihi = 0; MpfrMatrixStorage::MplapackInteger info = 0; const char *balanc = balance ? "B" : "N"; { MplapackMpfrPrecisionScope scope (precision); require_real_contract (precision, a_work, wr, wi, vl, vr, scale, rconde, rcondv, query_work, abnrm); Rgeevx (balanc, "V", "V", "N", MpfrMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), wr.data (), wi.data (), vl.data (), vl.leading_dimension (), vr.data (), vr.leading_dimension (), ilo, ihi, scale.data (), abnrm, rconde.data (), rcondv.data (), query_work.data (), -1, iwork.data (), info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK Rgeevx changed the current-thread default precision"); } if (info < 0) throw MpfrGeneralEigError (-static_cast (info), "MPLAPACK Rgeevx rejected a workspace query"); if (info > 0) throw MpfrGeneralEigError (static_cast (info), "MPLAPACK Rgeevx workspace query failed"); const std::size_t lwork = checked_workspace_length (query_work.at (0, 0), "MPLAPACK Rgeevx"); MpfrMatrixStorage work (lwork, 1, precision); a_work = MpfrMatrixStorage (n, n, precision, input); wr = MpfrMatrixStorage (n, 1, precision); wi = MpfrMatrixStorage (n, 1, precision); vl = MpfrMatrixStorage (n, n, precision); vr = MpfrMatrixStorage (n, n, precision); info = 0; { MplapackMpfrPrecisionScope scope (precision); require_real_contract (precision, a_work, wr, wi, vl, vr, scale, rconde, rcondv, work, abnrm); Rgeevx (balanc, "V", "V", "N", MpfrMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), wr.data (), wi.data (), vl.data (), vl.leading_dimension (), vr.data (), vr.leading_dimension (), ilo, ihi, scale.data (), abnrm, rconde.data (), rcondv.data (), work.data (), static_cast (lwork), iwork.data (), info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK Rgeevx changed the current-thread default precision"); } if (info != 0) throw MpfrGeneralEigError (static_cast (info), info < 0 ? "MPLAPACK Rgeevx rejected an argument" : "MPLAPACK Rgeevx failed to converge"); result.eigenvalues = make_real_complex_values (wr, wi); convert_real_eigenvectors (result.right_vectors, vr, wi); convert_real_eigenvectors (result.left_vectors, vl, wi); fill_diagonal (result.diagonal, result.eigenvalues); return result; } MpcGeneralEigResult mplapack_mpc_matrix_general_eig (const MpfrComplexMatrixStorage& input, bool balance) { if (input.rows () != input.columns ()) throw std::invalid_argument ( "general eig requires a square complex matrix"); const mpfr_prec_t precision = input.precision_bits (); validate_precision (precision); const std::size_t n = input.rows (); MpcGeneralEigResult result { MpfrComplexMatrixStorage (n, 1, precision), MpfrComplexMatrixStorage (n, n, precision), MpfrComplexMatrixStorage (n, n, precision), MpfrComplexMatrixStorage (n, n, precision) }; if (n == 0) return result; MpfrComplexMatrixStorage a_work = input; MpfrComplexMatrixStorage w (n, 1, precision); MpfrComplexMatrixStorage vl (n, n, precision); MpfrComplexMatrixStorage vr (n, n, precision); MpfrComplexMatrixStorage query_work (1, 1, precision); MpfrMatrixStorage rwork (std::max (1, 2 * n), 1, precision); MpfrMatrixStorage scale (n, 1, precision); MpfrMatrixStorage rconde (n, 1, precision); MpfrMatrixStorage rcondv (n, 1, precision); MpfrScalarStorage::NativeScalar abnrm = MpfrScalarStorage::NativeScalar::with_precision (precision); MpfrComplexMatrixStorage::MplapackInteger ilo = 0; MpfrComplexMatrixStorage::MplapackInteger ihi = 0; MpfrComplexMatrixStorage::MplapackInteger info = 0; const char *balanc = balance ? "B" : "N"; { MpfrMpcPrecisionScope scope (precision); require_complex_contract (precision, a_work, w, vl, vr, query_work, rwork, scale, rconde, rcondv, abnrm); Cgeevx (balanc, "V", "V", "N", MpfrComplexMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), w.data (), vl.data (), vl.leading_dimension (), vr.data (), vr.leading_dimension (), ilo, ihi, scale.data (), abnrm, rconde.data (), rcondv.data (), query_work.data (), -1, rwork.data (), info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK Cgeevx changed the current-thread default precision"); } if (info < 0) throw MpcGeneralEigError (-static_cast (info), "MPLAPACK Cgeevx rejected a workspace query"); if (info > 0) throw MpcGeneralEigError (static_cast (info), "MPLAPACK Cgeevx workspace query failed"); const std::size_t lwork = checked_complex_workspace_length ( query_work.at (0, 0), "MPLAPACK Cgeevx"); MpfrComplexMatrixStorage work (lwork, 1, precision); a_work = input; w = MpfrComplexMatrixStorage (n, 1, precision); vl = MpfrComplexMatrixStorage (n, n, precision); vr = MpfrComplexMatrixStorage (n, n, precision); rwork = MpfrMatrixStorage (std::max (1, 2 * n), 1, precision); info = 0; { MpfrMpcPrecisionScope scope (precision); require_complex_contract (precision, a_work, w, vl, vr, work, rwork, scale, rconde, rcondv, abnrm); Cgeevx (balanc, "V", "V", "N", MpfrComplexMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), w.data (), vl.data (), vl.leading_dimension (), vr.data (), vr.leading_dimension (), ilo, ihi, scale.data (), abnrm, rconde.data (), rcondv.data (), work.data (), static_cast (lwork), rwork.data (), info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK Cgeevx changed the current-thread default precision"); } if (info != 0) throw MpcGeneralEigError (static_cast (info), info < 0 ? "MPLAPACK Cgeevx rejected an argument" : "MPLAPACK Cgeevx failed to converge"); result.eigenvalues = std::move (w); result.right_vectors = std::move (vr); result.left_vectors = std::move (vl); fill_diagonal (result.diagonal, result.eigenvalues); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_script_compat.h0000644000230300031750000000710315274353472020547 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SCRIPT_COMPAT_H #define OCTAVE_MPLAPACK_MP_SCRIPT_COMPAT_H #include #include #include "mp_complex_matrix_storage.h" #include "mp_complex_scalar_storage.h" #include "mp_matrix_storage.h" #include "mp_scalar_storage.h" namespace octave_mplapack { enum class MpScriptUnaryOperation { absolute, angle, sign }; enum class MpScriptPredicate { isnan, isinf, isfinite }; enum class MpScriptElementaryOperation { sqrt, exp, expm1, log, log1p, log10, log2, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, cbrt, erf, erfc, gamma, lngamma }; struct MpScriptPredicateResult { std::size_t rows = 0; std::size_t columns = 0; std::vector values; }; MpfrScalarStorage mpfr_script_unary ( const MpfrScalarStorage& source, MpScriptUnaryOperation operation); MpfrMatrixStorage mpfr_script_unary ( const MpfrMatrixStorage& source, MpScriptUnaryOperation operation); MpfrScalarStorage mpc_script_real_unary ( const MpfrComplexScalarStorage& source, MpScriptUnaryOperation operation); MpfrMatrixStorage mpc_script_real_unary ( const MpfrComplexMatrixStorage& source, MpScriptUnaryOperation operation); MpfrComplexScalarStorage mpc_script_unary ( const MpfrComplexScalarStorage& source, MpScriptUnaryOperation operation); MpfrComplexMatrixStorage mpc_script_unary ( const MpfrComplexMatrixStorage& source, MpScriptUnaryOperation operation); MpScriptPredicateResult mpfr_script_predicate ( const MpfrScalarStorage& source, MpScriptPredicate predicate); MpScriptPredicateResult mpfr_script_predicate ( const MpfrMatrixStorage& source, MpScriptPredicate predicate); MpScriptPredicateResult mpc_script_predicate ( const MpfrComplexScalarStorage& source, MpScriptPredicate predicate); MpScriptPredicateResult mpc_script_predicate ( const MpfrComplexMatrixStorage& source, MpScriptPredicate predicate); bool mpfr_script_equal (const MpfrScalarStorage& lhs, const MpfrScalarStorage& rhs, bool nan_equal) noexcept; bool mpfr_script_equal (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs, bool nan_equal) noexcept; bool mpc_script_equal (const MpfrComplexScalarStorage& lhs, const MpfrComplexScalarStorage& rhs, bool nan_equal) noexcept; bool mpc_script_equal (const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs, bool nan_equal) noexcept; bool mpfr_script_power_requires_complex (mpfr_srcptr base, mpfr_srcptr exponent) noexcept; bool mpfr_script_elementary_requires_complex ( mpfr_srcptr source, MpScriptElementaryOperation operation) noexcept; MpfrScalarStorage mpfr_script_elementary ( const MpfrScalarStorage& source, MpScriptElementaryOperation operation); MpfrMatrixStorage mpfr_script_elementary ( const MpfrMatrixStorage& source, MpScriptElementaryOperation operation); MpfrComplexScalarStorage mpfr_script_promote ( const MpfrScalarStorage& source); MpfrComplexMatrixStorage mpfr_script_promote ( const MpfrMatrixStorage& source); MpfrComplexScalarStorage mpc_script_elementary ( const MpfrComplexScalarStorage& source, MpScriptElementaryOperation operation); MpfrComplexMatrixStorage mpc_script_elementary ( const MpfrComplexMatrixStorage& source, MpScriptElementaryOperation operation); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_matrix_concat.cc0000644000230300031750000000516315274353472022424 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_matrix_concat.h" #include #include "mp_complex_precision.h" namespace octave_mplapack { MpfrComplexMatrixStorage mpc_matrix_concatenate ( const std::vector& operands, int dimension, std::size_t result_rows, std::size_t result_columns, mpfr_prec_t result_precision) { if (operands.empty ()) throw std::invalid_argument ("complex concatenation requires at least one operand"); if (dimension != 0 && dimension != 1) throw std::invalid_argument ("concatenation dimension must be 0 or 1"); MpfrMpcPrecisionScope scope (result_precision); MpfrComplexMatrixStorage result (result_rows, result_columns, result_precision); std::size_t offset = 0; for (const MpcConcatOperand& operand : operands) { if (! operand.copy_element) throw std::invalid_argument ("complex concatenation operand has no copier"); if (operand.rows == 0 || operand.columns == 0) continue; if (dimension == 1) { if (operand.rows != result_rows) throw std::invalid_argument ("horizontal concatenation row mismatch"); if (offset > result_columns || operand.columns > result_columns - offset) throw std::invalid_argument ( "horizontal concatenation result dimensions mismatch"); for (std::size_t column = 0; column < operand.columns; ++column) for (std::size_t row = 0; row < operand.rows; ++row) operand.copy_element (result.at (row, offset + column), row, column); offset += operand.columns; } else { if (operand.columns != result_columns) throw std::invalid_argument ("vertical concatenation column mismatch"); if (offset > result_rows || operand.rows > result_rows - offset) throw std::invalid_argument ( "vertical concatenation result dimensions mismatch"); for (std::size_t column = 0; column < operand.columns; ++column) for (std::size_t row = 0; row < operand.rows; ++row) operand.copy_element (result.at (offset + row, column), row, column); offset += operand.rows; } } const std::size_t expected_offset = dimension == 1 ? result_columns : result_rows; if (result.numel () != 0 && offset != expected_offset) throw std::invalid_argument ("complex concatenation result dimensions mismatch"); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_lapack.cc0000644000230300031750000011511615274353472017275 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_lapack.h" #include #include #include #include #include #include #include #include namespace { void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK MPFR precision is outside the MPFR range"); } mpfrxx::mpfr_class make_scalar_at_precision (const mpfrxx::mpfr_class& source, mpfr_prec_t precision_bits) { mpfrxx::mpfr_class result = mpfrxx::mpfr_class::with_precision (precision_bits); mpfr_set (result.mpfr_data (), source.mpfr_data (), MPFR_RNDN); return result; } mpfrxx::mpfr_class make_scalar_at_precision (double source, mpfr_prec_t precision_bits) { mpfrxx::mpfr_class result = mpfrxx::mpfr_class::with_precision (precision_bits); mpfr_set_d (result.mpfr_data (), source, MPFR_RNDN); return result; } octave_mplapack::MpfrMatrixStorage::MplapackInteger checked_workspace_length (const mpfrxx::mpfr_class& query) { if (mpfr_nan_p (query.mpfr_data ()) != 0 || mpfr_inf_p (query.mpfr_data ()) != 0 || mpfr_integer_p (query.mpfr_data ()) == 0 || mpfr_sgn (query.mpfr_data ()) <= 0) throw std::invalid_argument ("MPLAPACK workspace query returned an invalid size"); mpz_t value; mpz_t max_mplapack; mpz_t max_size; mpz_init (value); mpz_init (max_mplapack); mpz_init (max_size); mpfr_get_z (value, query.mpfr_data (), MPFR_RNDZ); const auto mplapack_max = std::numeric_limits::max (); const auto size_max = std::numeric_limits::max (); mpz_import (max_mplapack, 1, -1, sizeof (mplapack_max), 0, 0, &mplapack_max); mpz_import (max_size, 1, -1, sizeof (size_max), 0, 0, &size_max); const bool fits = mpz_cmp (value, max_mplapack) <= 0 && mpz_cmp (value, max_size) <= 0; if (! fits) { mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); throw std::overflow_error ("MPLAPACK workspace exceeds allocation limits"); } const auto result = static_cast ( mpfr_get_uj (query.mpfr_data (), MPFR_RNDZ)); mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); return result; } } // namespace namespace octave_mplapack { void require_mplapack_mpfr_solve_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& b_work) { validate_precision (operation_precision); const bool matches = mpfrxx::default_precision_bits () == operation_precision && a_work.precision_bits () == operation_precision && b_work.precision_bits () == operation_precision; if (! matches) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rgesv boundary"); } void require_mplapack_mpfr_rgels_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& b_work, const MpfrMatrixStorage& work) { validate_precision (operation_precision); const bool matches = mpfrxx::default_precision_bits () == operation_precision && a_work.precision_bits () == operation_precision && b_work.precision_bits () == operation_precision && work.precision_bits () == operation_precision; if (! matches) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rgels boundary"); } void require_mplapack_mpfr_rank_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& b_work, const mpfrxx::mpfr_class& rcond, const MpfrMatrixStorage& singular_values, const MpfrMatrixStorage& work) { validate_precision (operation_precision); const bool matches = mpfrxx::default_precision_bits () == operation_precision && a_work.precision_bits () == operation_precision && b_work.precision_bits () == operation_precision && rcond.precision () == operation_precision && singular_values.precision_bits () == operation_precision && work.precision_bits () == operation_precision; if (! matches) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at rank-revealing boundary"); } void require_mplapack_mpfr_rpotrf_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work) { validate_precision (operation_precision); const bool matches = mpfrxx::default_precision_bits () == operation_precision && a_work.precision_bits () == operation_precision && a_work.all_elements_have_uniform_precision (); if (! matches) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rpotrf boundary"); } void require_mplapack_mpfr_rgetrf_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work) { validate_precision (operation_precision); const bool matches = mpfrxx::default_precision_bits () == operation_precision && a_work.precision_bits () == operation_precision && a_work.all_elements_have_uniform_precision (); if (! matches) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rgetrf boundary"); } void require_mplapack_mpfr_qr_precision_contract ( mpfr_prec_t operation_precision, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& tau, const MpfrMatrixStorage& work) { validate_precision (operation_precision); const bool matches = mpfrxx::default_precision_bits () == operation_precision && a_work.precision_bits () == operation_precision && tau.precision_bits () == operation_precision && work.precision_bits () == operation_precision; if (! matches) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at QR boundary"); } struct MpfrQrFactorization { MpfrMatrixStorage factors; MpfrMatrixStorage tau; }; MpfrQrResult make_qr_result_from_factorization (MpfrQrFactorization factorization, bool economy, bool want_q) { MpfrMatrixStorage a_fact = std::move (factorization.factors); MpfrMatrixStorage tau = std::move (factorization.tau); const mpfr_prec_t operation_precision = a_fact.precision_bits (); const std::size_t m = a_fact.rows (); const std::size_t n = a_fact.columns (); const std::size_t k = std::min (m, n); const bool tall_economy = economy && m > n; const std::size_t q_columns = tall_economy ? n : m; const std::size_t r_rows = tall_economy ? n : m; MpfrMatrixStorage r (r_rows, n, operation_precision); for (std::size_t column = 0; column < n; ++column) for (std::size_t row = 0; row < r_rows; ++row) { if (row < k && row <= column) mpfr_set (r.at (row, column).mpfr_data (), a_fact.at (row, column).mpfr_data (), MPFR_RNDN); else mpfr_set_zero (r.at (row, column).mpfr_data (), 0); } if (! want_q) return {MpfrMatrixStorage (0, 0, operation_precision), std::move (r)}; const auto m_arg = MpfrMatrixStorage::checked_mplapack_dimension (m); const auto k_arg = MpfrMatrixStorage::checked_mplapack_dimension (k); const auto q_columns_arg = MpfrMatrixStorage::checked_mplapack_dimension (q_columns); MpfrMatrixStorage query_q (m, q_columns, operation_precision); for (std::size_t column = 0; column < q_columns; ++column) for (std::size_t row = 0; row < m; ++row) { if (column < n) mpfr_set (query_q.at (row, column).mpfr_data (), a_fact.at (row, column).mpfr_data (), MPFR_RNDN); else mpfr_set_zero (query_q.at (row, column).mpfr_data (), 0); } MpfrMatrixStorage query_tau_q (tau); MpfrMatrixStorage query_orgqr_work (1, 1, operation_precision); MpfrMatrixStorage::MplapackInteger query_orgqr_info = 0; { MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_qr_precision_contract ( operation_precision, query_q, query_tau_q, query_orgqr_work); Rorgqr (m_arg, q_columns_arg, k_arg, query_q.data (), query_q.leading_dimension (), query_tau_q.data (), query_orgqr_work.data (), -1, query_orgqr_info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rorgqr changed the current-thread default precision"); } if (query_orgqr_info != 0) throw std::runtime_error ( query_orgqr_info < 0 ? "MPLAPACK Rorgqr rejected a workspace query argument" : "MPLAPACK Rorgqr workspace query failed"); const auto orgqr_lwork = checked_workspace_length (query_orgqr_work.at (0, 0)); MpfrMatrixStorage q_work (m, q_columns, operation_precision); for (std::size_t column = 0; column < q_columns; ++column) for (std::size_t row = 0; row < m; ++row) { if (column < n) mpfr_set (q_work.at (row, column).mpfr_data (), a_fact.at (row, column).mpfr_data (), MPFR_RNDN); else mpfr_set_zero (q_work.at (row, column).mpfr_data (), 0); } MpfrMatrixStorage tau_q (tau); MpfrMatrixStorage orgqr_work ( static_cast (orgqr_lwork), 1, operation_precision); MpfrMatrixStorage::MplapackInteger orgqr_info = 0; { MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_qr_precision_contract ( operation_precision, q_work, tau_q, orgqr_work); Rorgqr (m_arg, q_columns_arg, k_arg, q_work.data (), q_work.leading_dimension (), tau_q.data (), orgqr_work.data (), orgqr_lwork, orgqr_info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rorgqr changed the current-thread default precision"); } if (orgqr_info < 0) throw std::runtime_error ("MPLAPACK Rorgqr rejected an argument"); if (orgqr_info > 0) throw std::runtime_error ("MPLAPACK Rorgqr failed"); return {std::move (q_work), std::move (r)}; } MpfrMatrixStorage mplapack_mpfr_matrix_solve (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs) { if (lhs.rows () != lhs.columns ()) throw std::invalid_argument ( "MPLAPACK Rgesv requires a square coefficient matrix"); if (rhs.rows () != lhs.rows ()) throw std::invalid_argument ("matrix solve dimensions must agree"); const mpfr_prec_t operation_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); validate_precision (operation_precision); // Rgesv overwrites both arguments. Keep public immutable values isolated // in operation-owned, uniformly precisioned working buffers. MpfrMatrixStorage a_work (lhs.rows (), lhs.columns (), operation_precision, lhs); MpfrMatrixStorage b_work (rhs.rows (), rhs.columns (), operation_precision, rhs); const std::size_t n = lhs.rows (); const std::size_t nrhs = rhs.columns (); if (n == 0 || nrhs == 0) return b_work; std::vector pivots (n); const auto n_arg = MpfrMatrixStorage::checked_mplapack_dimension (n); const auto nrhs_arg = MpfrMatrixStorage::checked_mplapack_dimension (nrhs); const auto lda = a_work.leading_dimension (); const auto ldb = b_work.leading_dimension (); MpfrMatrixStorage::MplapackInteger info = 0; { // MPLAPACK MPFR requires one uniform operation precision. The scope // supplies p to default-constructed temporaries in the LAPACK path. MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_solve_precision_contract ( operation_precision, a_work, b_work); Rgesv (n_arg, nrhs_arg, a_work.data (), lda, pivots.data (), b_work.data (), ldb, info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgesv changed the current-thread default precision"); } if (info > 0) throw MpfrRgesvError (MpfrRgesvError::Kind::singular, static_cast (info), "MPLAPACK Rgesv reported a singular matrix"); if (info < 0) throw MpfrRgesvError (MpfrRgesvError::Kind::invalid_argument, static_cast (info), "MPLAPACK Rgesv rejected an argument"); return b_work; } MpfrMatrixStorage mplapack_mpfr_matrix_rectangular_solve (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs) { if (lhs.rows () == lhs.columns ()) throw std::invalid_argument ( "MPLAPACK Rgels is only used for rectangular matrices"); if (rhs.rows () != lhs.rows ()) throw std::invalid_argument ("matrix solve dimensions must agree"); const mpfr_prec_t operation_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); validate_precision (operation_precision); const std::size_t m = lhs.rows (); const std::size_t n = lhs.columns (); const std::size_t nrhs = rhs.columns (); const std::size_t padded_rows = std::max (m, n); // Rgels overwrites A and B. Use operation-owned, uniformly p_op-precision // buffers; B is padded because LAPACK returns the n-row solution in it. if (nrhs == 0 || std::min (m, n) == 0) { MpfrMatrixStorage empty_result (n, nrhs, operation_precision); return empty_result; } const auto m_arg = MpfrMatrixStorage::checked_mplapack_dimension (m); const auto n_arg = MpfrMatrixStorage::checked_mplapack_dimension (n); const auto nrhs_arg = MpfrMatrixStorage::checked_mplapack_dimension (nrhs); MpfrMatrixStorage query_a (m, n, operation_precision, lhs); MpfrMatrixStorage query_b (padded_rows, nrhs, operation_precision); for (std::size_t index = 0; index < query_b.numel (); ++index) mpfr_set_zero (query_b.data ()[index].mpfr_data (), 0); for (std::size_t column = 0; column < nrhs; ++column) for (std::size_t row = 0; row < m; ++row) mpfr_set (query_b.at (row, column).mpfr_data (), rhs.at (row, column).mpfr_data (), MPFR_RNDN); const auto lda = query_a.leading_dimension (); const auto ldb = query_b.leading_dimension (); MpfrMatrixStorage query_work (1, 1, operation_precision); MpfrMatrixStorage::MplapackInteger query_info = 0; MpfrMatrixStorage::MplapackInteger lwork = 0; { // Rgels has nested QR/LQ routines and default REAL temporaries; keep the // complete workspace-query call inside the uniform operation scope. MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_rgels_precision_contract ( operation_precision, query_a, query_b, query_work); Rgels ("N", m_arg, n_arg, nrhs_arg, query_a.data (), lda, query_b.data (), ldb, query_work.data (), -1, query_info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgels changed the current-thread default precision"); } if (query_info != 0) { if (query_info > 0) throw MpfrRgelsError ( MpfrRgelsError::Kind::rank_deficient, static_cast (query_info), "MPLAPACK Rgels reported a rank-deficient workspace query"); throw MpfrRgelsError ( MpfrRgelsError::Kind::invalid_argument, static_cast (query_info), "MPLAPACK Rgels rejected a workspace query argument"); } lwork = checked_workspace_length (query_work.data ()[0]); // Recreate both inputs after the query: this is safe even for an // implementation that writes scratch values during a workspace query. MpfrMatrixStorage a_work (m, n, operation_precision, lhs); MpfrMatrixStorage b_work (padded_rows, nrhs, operation_precision); for (std::size_t index = 0; index < b_work.numel (); ++index) mpfr_set_zero (b_work.data ()[index].mpfr_data (), 0); for (std::size_t column = 0; column < nrhs; ++column) for (std::size_t row = 0; row < m; ++row) mpfr_set (b_work.at (row, column).mpfr_data (), rhs.at (row, column).mpfr_data (), MPFR_RNDN); const auto actual_lda = a_work.leading_dimension (); const auto actual_ldb = b_work.leading_dimension (); MpfrMatrixStorage work (static_cast (lwork), 1, operation_precision); MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_rgels_precision_contract ( operation_precision, a_work, b_work, work); Rgels ("N", m_arg, n_arg, nrhs_arg, a_work.data (), actual_lda, b_work.data (), actual_ldb, work.data (), lwork, info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgels changed the current-thread default precision"); } if (info > 0) throw MpfrRgelsError (MpfrRgelsError::Kind::rank_deficient, static_cast (info), "MPLAPACK Rgels reported a rank-deficient system"); if (info < 0) throw MpfrRgelsError (MpfrRgelsError::Kind::invalid_argument, static_cast (info), "MPLAPACK Rgels rejected an argument"); MpfrMatrixStorage result (n, nrhs, operation_precision); for (std::size_t column = 0; column < nrhs; ++column) for (std::size_t row = 0; row < n; ++row) mpfr_set (result.at (row, column).mpfr_data (), b_work.at (row, column).mpfr_data (), MPFR_RNDN); return result; } MpfrRankRevealingSolveResult mplapack_mpfr_matrix_rank_revealing_solve ( const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs) { if (rhs.rows () != lhs.rows ()) throw std::invalid_argument ("matrix solve dimensions must agree"); const mpfr_prec_t operation_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); validate_precision (operation_precision); const std::size_t m = lhs.rows (); const std::size_t n = lhs.columns (); const std::size_t nrhs = rhs.columns (); const std::size_t padded_rows = std::max (m, n); const MpfrMatrixStorage::MplapackInteger zero_rank = 0; if (nrhs == 0 || std::min (m, n) == 0) return {MpfrMatrixStorage (n, nrhs, operation_precision), zero_rank}; const auto m_arg = MpfrMatrixStorage::checked_mplapack_dimension (m); const auto n_arg = MpfrMatrixStorage::checked_mplapack_dimension (n); const auto nrhs_arg = MpfrMatrixStorage::checked_mplapack_dimension (nrhs); auto fill_rhs = [&] (MpfrMatrixStorage& destination) { for (std::size_t index = 0; index < destination.numel (); ++index) mpfr_set_zero (destination.data ()[index].mpfr_data (), 0); for (std::size_t column = 0; column < nrhs; ++column) for (std::size_t row = 0; row < m; ++row) mpfr_set (destination.at (row, column).mpfr_data (), rhs.at (row, column).mpfr_data (), MPFR_RNDN); }; MpfrMatrixStorage query_a (m, n, operation_precision, lhs); MpfrMatrixStorage query_b (padded_rows, nrhs, operation_precision); fill_rhs (query_b); MpfrMatrixStorage query_s (std::min (m, n), 1, operation_precision); MpfrMatrixStorage query_work (1, 1, operation_precision); MpfrMatrixStorage::MplapackInteger query_info = 0; MpfrMatrixStorage::MplapackInteger query_rank = 0; { // Rank-revealing MPLAPACK calls require one p_op and default REAL // temporaries inherit it from this scope. MplapackMpfrPrecisionScope precision_scope (operation_precision); mpfrxx::mpfr_class rcond = mpfrxx::mpfr_class::with_precision (operation_precision); const mpfrxx::mpfr_class epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); require_mplapack_mpfr_rank_precision_contract ( operation_precision, query_a, query_b, rcond, query_s, query_work); Rgelss (m_arg, n_arg, nrhs_arg, query_a.data (), query_a.leading_dimension (), query_b.data (), query_b.leading_dimension (), query_s.data (), rcond, query_rank, query_work.data (), -1, query_info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgelss changed the current-thread default precision"); } if (query_info != 0) throw MpfrRankRevealingError ( query_info > 0 ? MpfrRankRevealingError::Kind::convergence : MpfrRankRevealingError::Kind::invalid_argument, static_cast (query_info), query_info > 0 ? "MPLAPACK Rgelss workspace query failed to converge" : "MPLAPACK Rgelss rejected a workspace query argument"); const auto lwork = checked_workspace_length (query_work.data ()[0]); // Recreate destructive inputs after querying so query-side writes cannot // affect the actual rank-revealing solve. MpfrMatrixStorage a_work (m, n, operation_precision, lhs); MpfrMatrixStorage b_work (padded_rows, nrhs, operation_precision); fill_rhs (b_work); MpfrMatrixStorage singular_values (std::min (m, n), 1, operation_precision); MpfrMatrixStorage work (static_cast (lwork), 1, operation_precision); MpfrMatrixStorage::MplapackInteger rank = 0; MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope precision_scope (operation_precision); mpfrxx::mpfr_class rcond = mpfrxx::mpfr_class::with_precision (operation_precision); const mpfrxx::mpfr_class epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); require_mplapack_mpfr_rank_precision_contract ( operation_precision, a_work, b_work, rcond, singular_values, work); Rgelss (m_arg, n_arg, nrhs_arg, a_work.data (), a_work.leading_dimension (), b_work.data (), b_work.leading_dimension (), singular_values.data (), rcond, rank, work.data (), lwork, info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgelss changed the current-thread default precision"); } if (info < 0) throw MpfrRankRevealingError ( MpfrRankRevealingError::Kind::invalid_argument, static_cast (info), "MPLAPACK Rgelss rejected an argument"); if (info > 0) throw MpfrRankRevealingError ( MpfrRankRevealingError::Kind::convergence, static_cast (info), "MPLAPACK Rgelss failed to converge"); const auto max_rank = static_cast ( std::min (m, n)); if (rank < 0 || rank > max_rank) throw MpfrRankRevealingError ( MpfrRankRevealingError::Kind::internal, 0, "MPLAPACK Rgelss returned an invalid effective rank"); MpfrMatrixStorage result (n, nrhs, operation_precision); for (std::size_t column = 0; column < nrhs; ++column) for (std::size_t row = 0; row < n; ++row) mpfr_set (result.at (row, column).mpfr_data (), b_work.at (row, column).mpfr_data (), MPFR_RNDN); return {std::move (result), rank}; } MpfrCholeskyResult mplapack_mpfr_matrix_cholesky (const MpfrMatrixStorage& input, bool lower) { if (input.rows () != input.columns ()) throw std::invalid_argument ( "MPLAPACK Rpotrf requires a square coefficient matrix"); const mpfr_prec_t operation_precision = input.precision_bits (); validate_precision (operation_precision); const std::size_t n = input.rows (); MpfrMatrixStorage a_work (n, n, operation_precision, input); if (n == 0) return {std::move (a_work), 0}; const auto n_arg = MpfrMatrixStorage::checked_mplapack_dimension (n); const auto lda = a_work.leading_dimension (); MpfrMatrixStorage::MplapackInteger info = 0; { // Rpotrf overwrites its input. Factor an operation-owned p_op copy // so public mp values retain value semantics. MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_rpotrf_precision_contract ( operation_precision, a_work); Rpotrf (lower ? "L" : "U", n_arg, a_work.data (), lda, info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rpotrf changed the current-thread default precision"); } if (info < 0) throw MpfrRpotrfError (MpfrRpotrfError::Kind::invalid_argument, static_cast (info), "MPLAPACK Rpotrf rejected an argument"); if (info == 0) { for (std::size_t column = 0; column < n; ++column) for (std::size_t row = 0; row < n; ++row) if (lower ? column > row : row > column) mpfr_set_zero (a_work.at (row, column).mpfr_data (), 0); return {std::move (a_work), info}; } if (static_cast (info) > n) throw MpfrRpotrfError (MpfrRpotrfError::Kind::internal, static_cast (info), "MPLAPACK Rpotrf returned an invalid failure index"); // Dense chol's two-output form returns the leading factor before the first // non-positive pivot; one-output callers turn the same status into an error. const std::size_t completed = static_cast (info - 1); MpfrMatrixStorage partial (completed, completed, operation_precision); for (std::size_t column = 0; column < completed; ++column) for (std::size_t row = 0; row < completed; ++row) { if (lower ? column > row : row > column) mpfr_set_zero (partial.at (row, column).mpfr_data (), 0); else mpfr_set (partial.at (row, column).mpfr_data (), a_work.at (row, column).mpfr_data (), MPFR_RNDN); } return {std::move (partial), info}; } MpfrQrResult mplapack_mpfr_matrix_qr (const MpfrMatrixStorage& input, bool economy, bool want_q) { const mpfr_prec_t operation_precision = input.precision_bits (); validate_precision (operation_precision); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); const bool tall_economy = economy && m > n; const std::size_t q_columns = tall_economy ? n : m; const std::size_t r_rows = tall_economy ? n : m; // LAPACK has no useful pointer contract for zero-size arrays. The // structural result is unambiguous, so handle these shapes without a call. if (m == 0 || n == 0) { MpfrMatrixStorage q (m, q_columns, operation_precision); MpfrMatrixStorage r (r_rows, n, operation_precision); return {std::move (q), std::move (r)}; } const auto m_arg = MpfrMatrixStorage::checked_mplapack_dimension (m); const auto n_arg = MpfrMatrixStorage::checked_mplapack_dimension (n); MpfrMatrixStorage query_a (m, n, operation_precision, input); MpfrMatrixStorage query_tau (k, 1, operation_precision); MpfrMatrixStorage query_work (1, 1, operation_precision); MpfrMatrixStorage::MplapackInteger query_info = 0; { // Rgeqrf overwrites A and uses default-constructed REAL temporaries. MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_qr_precision_contract ( operation_precision, query_a, query_tau, query_work); Rgeqrf (m_arg, n_arg, query_a.data (), query_a.leading_dimension (), query_tau.data (), query_work.data (), -1, query_info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgeqrf changed the current-thread default precision"); } if (query_info != 0) throw std::runtime_error (query_info < 0 ? "MPLAPACK Rgeqrf rejected a workspace query argument" : "MPLAPACK Rgeqrf workspace query failed"); const auto rgeqrf_lwork = checked_workspace_length (query_work.at (0, 0)); // Recreate all destructive inputs after the query. This remains safe if a // vendor implementation writes scratch values during a query. MpfrMatrixStorage a_fact (m, n, operation_precision, input); MpfrMatrixStorage tau (k, 1, operation_precision); MpfrMatrixStorage rgeqrf_work ( static_cast (rgeqrf_lwork), 1, operation_precision); MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_qr_precision_contract ( operation_precision, a_fact, tau, rgeqrf_work); Rgeqrf (m_arg, n_arg, a_fact.data (), a_fact.leading_dimension (), tau.data (), rgeqrf_work.data (), rgeqrf_lwork, info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgeqrf changed the current-thread default precision"); } if (info < 0) throw std::runtime_error ("MPLAPACK Rgeqrf rejected an argument"); if (info > 0) throw std::runtime_error ("MPLAPACK Rgeqrf failed"); return make_qr_result_from_factorization ( {std::move (a_fact), std::move (tau)}, economy, want_q); } MpfrPivotedQrResult mplapack_mpfr_matrix_pivoted_qr (const MpfrMatrixStorage& input, bool economy, bool want_q) { const mpfr_prec_t operation_precision = input.precision_bits (); validate_precision (operation_precision); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); std::vector permutation (n); for (std::size_t column = 0; column < n; ++column) permutation[column] = static_cast (column + 1); // Avoid passing null or zero-sized arrays to LAPACK for empty shapes. if (m == 0 || n == 0) { const bool tall_economy = economy && m > n; const std::size_t q_columns = tall_economy ? n : m; const std::size_t r_rows = tall_economy ? n : m; MpfrMatrixStorage q (m, q_columns, operation_precision); MpfrMatrixStorage r (r_rows, n, operation_precision); return {std::move (q), std::move (r), std::move (permutation)}; } const auto m_arg = MpfrMatrixStorage::checked_mplapack_dimension (m); const auto n_arg = MpfrMatrixStorage::checked_mplapack_dimension (n); MpfrMatrixStorage query_a (m, n, operation_precision, input); MpfrMatrixStorage query_tau (k, 1, operation_precision); MpfrMatrixStorage query_work (1, 1, operation_precision); std::vector query_jpvt (n, 0); MpfrMatrixStorage::MplapackInteger query_info = 0; { // Rgeqp3 overwrites A and uses p_op default-precision REAL temporaries. MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_qr_precision_contract ( operation_precision, query_a, query_tau, query_work); Rgeqp3 (m_arg, n_arg, query_a.data (), query_a.leading_dimension (), query_jpvt.data (), query_tau.data (), query_work.data (), -1, query_info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgeqp3 changed the current-thread default precision"); } if (query_info != 0) throw std::runtime_error ( query_info < 0 ? "MPLAPACK Rgeqp3 rejected a workspace query argument" : "MPLAPACK Rgeqp3 workspace query failed"); const auto rgeqp3_lwork = checked_workspace_length (query_work.at (0, 0)); // Recreate destructive inputs after the query. JPVT is reset to all-free // columns for every public M19 factorization. MpfrMatrixStorage a_fact (m, n, operation_precision, input); MpfrMatrixStorage tau (k, 1, operation_precision); MpfrMatrixStorage rgeqp3_work ( static_cast (rgeqp3_lwork), 1, operation_precision); std::fill (permutation.begin (), permutation.end (), 0); MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_qr_precision_contract ( operation_precision, a_fact, tau, rgeqp3_work); Rgeqp3 (m_arg, n_arg, a_fact.data (), a_fact.leading_dimension (), permutation.data (), tau.data (), rgeqp3_work.data (), rgeqp3_lwork, info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgeqp3 changed the current-thread default precision"); } if (info < 0) throw std::runtime_error ("MPLAPACK Rgeqp3 rejected an argument"); if (info > 0) throw std::runtime_error ("MPLAPACK Rgeqp3 failed"); std::vector seen (n, false); for (std::size_t column = 0; column < n; ++column) { const auto pivot = permutation[column]; if (pivot < 1 || pivot > n_arg) throw std::runtime_error ("MPLAPACK Rgeqp3 returned an invalid permutation"); const std::size_t source = static_cast (pivot - 1); if (seen[source]) throw std::runtime_error ("MPLAPACK Rgeqp3 returned duplicate pivots"); seen[source] = true; } const auto result = make_qr_result_from_factorization ( {std::move (a_fact), std::move (tau)}, economy, want_q); return {std::move (result.q), std::move (result.r), std::move (permutation)}; } MpfrLuResult mplapack_mpfr_matrix_lu (const MpfrMatrixStorage& input) { const mpfr_prec_t operation_precision = input.precision_bits (); validate_precision (operation_precision); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); // Octave's dense LU returns empty 0x0 factors for every zero-dimensional // input. Avoid passing zero-sized storage to the LAPACK routine. if (m == 0 || n == 0) return {MpfrMatrixStorage (0, 0, operation_precision), MpfrMatrixStorage (0, 0, operation_precision), MpfrMatrixStorage (0, 0, operation_precision), std::vector (), 0}; const auto m_arg = MpfrMatrixStorage::checked_mplapack_dimension (m); const auto n_arg = MpfrMatrixStorage::checked_mplapack_dimension (n); MpfrMatrixStorage a_work (m, n, operation_precision, input); if (k > std::numeric_limits::max () / sizeof (MpfrMatrixStorage::MplapackInteger) || m > std::numeric_limits::max () / sizeof (MpfrMatrixStorage::MplapackInteger)) throw std::overflow_error ("LU pivot allocation size overflow"); std::vector ipiv (k); MpfrMatrixStorage::MplapackInteger info = 0; { // Rgetrf overwrites A and returns a row-swap sequence in IPIV. Keep the // public value immutable by factoring an operation-owned p_op copy. MplapackMpfrPrecisionScope precision_scope (operation_precision); require_mplapack_mpfr_rgetrf_precision_contract ( operation_precision, a_work); Rgetrf (m_arg, n_arg, a_work.data (), a_work.leading_dimension (), ipiv.data (), info); if (mpfrxx::default_precision_bits () != operation_precision) throw std::runtime_error ( "MPLAPACK MPFR Rgetrf changed the current-thread default precision"); } if (info < 0) throw std::invalid_argument ("MPLAPACK Rgetrf rejected an argument"); if (info > static_cast (k)) throw std::runtime_error ("MPLAPACK Rgetrf returned an invalid INFO value"); // IPIV is a sequence of swaps, not the final public permutation vector. // Replay it on [1,2,...,m] so perm[d] is the source row at output row d. std::vector permutation (m); std::iota (permutation.begin (), permutation.end (), static_cast (1)); for (std::size_t step = 0; step < k; ++step) { const auto pivot = ipiv[step]; if (pivot < 1 || pivot > m_arg) throw std::runtime_error ("MPLAPACK Rgetrf returned an invalid pivot"); std::swap (permutation[step], permutation[static_cast (pivot - 1)]); } // The replayed sequence must define a proper final permutation. Validate // it before any public P/p representation is constructed. std::vector seen (m, false); for (const auto source : permutation) { if (source < 1 || source > m_arg || seen[static_cast (source - 1)]) throw std::runtime_error ( "MPLAPACK Rgetrf returned an invalid final permutation"); seen[static_cast (source - 1)] = true; } MpfrMatrixStorage lower (m, k, operation_precision); MpfrMatrixStorage upper (k, n, operation_precision); for (std::size_t column = 0; column < k; ++column) for (std::size_t row = 0; row < m; ++row) { if (row == column) mpfr_set_ui (lower.at (row, column).mpfr_data (), 1, MPFR_RNDN); else if (row > column) mpfr_set (lower.at (row, column).mpfr_data (), a_work.at (row, column).mpfr_data (), MPFR_RNDN); else mpfr_set_zero (lower.at (row, column).mpfr_data (), 0); } for (std::size_t column = 0; column < n; ++column) for (std::size_t row = 0; row < k; ++row) { if (row <= column) mpfr_set (upper.at (row, column).mpfr_data (), a_work.at (row, column).mpfr_data (), MPFR_RNDN); else mpfr_set_zero (upper.at (row, column).mpfr_data (), 0); } return {std::move (a_work), std::move (lower), std::move (upper), std::move (permutation), info}; } MpfrMatrixStorage mplapack_mpfr_matrix_left_divide (const MpfrMatrixStorage& rhs, const mpfrxx::mpfr_class& lhs) { const mpfr_prec_t operation_precision = std::max (rhs.precision_bits (), lhs.precision ()); validate_precision (operation_precision); MpfrMatrixStorage result (rhs.rows (), rhs.columns (), operation_precision, rhs); const mpfrxx::mpfr_class lhs_work = make_scalar_at_precision (lhs, operation_precision); MplapackMpfrPrecisionScope precision_scope (operation_precision); for (std::size_t index = 0; index < result.numel (); ++index) mpfr_div (result.data ()[index].mpfr_data (), rhs.data ()[index].mpfr_data (), lhs_work.mpfr_data (), MPFR_RNDN); return result; } MpfrMatrixStorage mplapack_mpfr_matrix_left_divide (const MpfrMatrixStorage& rhs, double lhs) { const mpfr_prec_t operation_precision = rhs.precision_bits (); validate_precision (operation_precision); MpfrMatrixStorage result (rhs.rows (), rhs.columns (), operation_precision, rhs); const mpfrxx::mpfr_class lhs_work = make_scalar_at_precision (lhs, operation_precision); MplapackMpfrPrecisionScope precision_scope (operation_precision); for (std::size_t index = 0; index < result.numel (); ++index) mpfr_div (result.data ()[index].mpfr_data (), rhs.data ()[index].mpfr_data (), lhs_work.mpfr_data (), MPFR_RNDN); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_scalar_storage.cc0000644000230300031750000000752415274353472022565 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_scalar_storage.h" #include #include #include "mp_complex_precision.h" #include "mp_scalar_storage.h" namespace octave_mplapack { namespace { void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ("complex scalar precision is outside MPFR limits"); } std::string component_text (const mpfrxx::mpc_class& value, bool imaginary) { MpfrScalarStorage component ( imaginary ? value.imag () : value.real ()); return component.to_canonical_string (); } } // namespace MpfrComplexScalarStorage::MpfrComplexScalarStorage ( const std::string& text, mpfr_prec_t precision_bits) : m_value (NativeScalar::with_precision (precision_bits)) { validate_precision (precision_bits); MpfrMpcPrecisionScope scope (precision_bits); if (m_value.set_str (text, 10) != 0) throw std::invalid_argument ("invalid complex scalar text"); } MpfrComplexScalarStorage::MpfrComplexScalarStorage ( double real, double imag, mpfr_prec_t precision_bits) : m_value (NativeScalar::with_precision (precision_bits)) { validate_precision (precision_bits); MpfrMpcPrecisionScope scope (precision_bits); mpc_set_d_d (m_value.mpc_data (), real, imag, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } MpfrComplexScalarStorage::MpfrComplexScalarStorage ( const std::complex& value, mpfr_prec_t precision_bits) : MpfrComplexScalarStorage (value.real (), value.imag (), precision_bits) { } MpfrComplexScalarStorage::MpfrComplexScalarStorage (NativeScalar value) : m_value (std::move (value)) { validate_precision (m_value.precision ()); } MpfrComplexScalarStorage& MpfrComplexScalarStorage::operator= (MpfrComplexScalarStorage other) noexcept { swap (other); return *this; } void MpfrComplexScalarStorage::swap (MpfrComplexScalarStorage& other) noexcept { using std::swap; swap (m_value, other.m_value); } mpfr_prec_t MpfrComplexScalarStorage::precision_bits () const noexcept { return m_value.precision (); } bool MpfrComplexScalarStorage::exactly_equal ( const MpfrComplexScalarStorage& other) const noexcept { return mpfr_equal_p (mpc_realref (m_value.mpc_data ()), mpc_realref (other.m_value.mpc_data ())) != 0 && mpfr_equal_p (mpc_imagref (m_value.mpc_data ()), mpc_imagref (other.m_value.mpc_data ())) != 0; } bool MpfrComplexScalarStorage::is_nan () const noexcept { return mpfr_nan_p (mpc_realref (m_value.mpc_data ())) != 0 || mpfr_nan_p (mpc_imagref (m_value.mpc_data ())) != 0; } bool MpfrComplexScalarStorage::is_infinite () const noexcept { return mpfr_inf_p (mpc_realref (m_value.mpc_data ())) != 0 || mpfr_inf_p (mpc_imagref (m_value.mpc_data ())) != 0; } bool MpfrComplexScalarStorage::is_zero () const noexcept { return mpfr_zero_p (mpc_realref (m_value.mpc_data ())) != 0 && mpfr_zero_p (mpc_imagref (m_value.mpc_data ())) != 0; } bool MpfrComplexScalarStorage::real_signbit () const noexcept { return mpfr_signbit (mpc_realref (m_value.mpc_data ())) != 0; } bool MpfrComplexScalarStorage::imag_signbit () const noexcept { return mpfr_signbit (mpc_imagref (m_value.mpc_data ())) != 0; } std::string MpfrComplexScalarStorage::to_canonical_string () const { return "(" + component_text (m_value, false) + "," + component_text (m_value, true) + ")"; } std::complex MpfrComplexScalarStorage::to_double () const { return {m_value.real_to_double (), m_value.imag_to_double ()}; } const MpfrComplexScalarStorage::NativeScalar& MpfrComplexScalarStorage::native_value () const noexcept { return m_value; } void swap (MpfrComplexScalarStorage& lhs, MpfrComplexScalarStorage& rhs) noexcept { lhs.swap (rhs); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/octave_bridge.cc0000644000230300031750000134736115274353472020155 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mp_value.h" #include "mp_matrix_value.h" #include "mp_complex_value.h" #include "mp_complex_matrix_value.h" #include "mp_matrix_inspection.h" #include "mp_matrix_arithmetic.h" #include "mp_complex_arithmetic.h" #include "mp_complex_precision.h" #include "mp_matrix_structure.h" #include "mp_complex_structure.h" #include "mp_matrix_concat.h" #include "mp_complex_matrix_concat.h" #include "mp_matrix_assignment.h" #include "mp_blas.h" #include "mp_complex_blas.h" #include "mp_complex_lapack.h" #include "mp_complex_rank.h" #include "mp_complex_cholesky.h" #include "mp_complex_qr.h" #include "mp_complex_lu.h" #include "mp_lapack.h" #include "mp_det_inv.h" #include "mp_norm.h" #include "mp_svd.h" #include "mp_rank_condition.h" #include "mp_structured_eig.h" #include "mp_general_eig.h" #include "mp_generalized_eig.h" #include "mp_schur_qz.h" #include "mp_script_compat.h" #include "mp_script_reductions.h" #include "mp_script_logic.h" #include "mp_script_structure.h" #include "mp_script_ranges.h" #include "mp_script_statistics.h" #include "mp_script_sequence.h" #include "mp_precision.h" #include "mp_random.h" #ifndef MPLAPACK_PKG_VERSION #error "MPLAPACK_PKG_VERSION must be provided by the build" #endif #define MPLAPACK_STRINGIFY_IMPL(value) #value #define MPLAPACK_STRINGIFY(value) MPLAPACK_STRINGIFY_IMPL(value) namespace { bool initialize_internal_type (octave::interpreter& interp) { static std::once_flag registration_once; // Package unload may remove the function-table lock even though Octave // keeps registered native type code resident. Reassert the lock whenever // the entry point is loaded again; type registration itself remains once. octave_function *function = interp.get_evaluator ().current_function (); if (! function || ! function->is_dld_function ()) error_with_id ("mplapack:ModuleLifetime", "failed to resolve __mplapack_core__ for module locking"); function->lock (); std::call_once (registration_once, [] () { octave_mplapack_mpfr_scalar_internal::register_type (); octave_mplapack_mpfr_matrix_internal::register_type (); octave_mplapack_mpc_scalar_internal::register_type (); octave_mplapack_mpc_matrix_internal::register_type (); }); if (! function->islocked ()) error_with_id ("mplapack:ModuleLifetime", "failed to lock __mplapack_core__ in memory"); // Keep the project construction default and the current-thread MPFR // default synchronized whenever the native entry point is entered. octave_mplapack::synchronize_current_thread_precision (); return function->islocked (); } void require_argument_count (const octave_value_list& args, int expected, const std::string& command) { if (args.length () != expected) error_with_id ("mplapack:InvalidArguments", "__mplapack_core__(\"%s\") expects %d arguments", command.c_str (), expected - 1); } std::string require_string (const octave_value& value, const char *description) { if (! value.is_string ()) error_with_id ("mplapack:InvalidArguments", "%s must be a string", description); return value.string_value (); } mpfr_prec_t require_precision (const octave_value& value) { if (! value.is_real_scalar ()) error_with_id ("mplapack:InvalidPrecision", "precision must be a real numeric scalar"); const double supplied = value.double_value (); const long double precision = static_cast (supplied); if (! std::isfinite (supplied) || std::trunc (supplied) != supplied || precision < static_cast (MPFR_PREC_MIN) || precision > static_cast (MPFR_PREC_MAX)) error_with_id ("mplapack:InvalidPrecision", "precision must be an integer from MPFR_PREC_MIN " "through MPFR_PREC_MAX"); return static_cast (precision); } octave_mplapack::precision_count_t require_precision_count (const octave_value& value, const char *error_id) { using octave_mplapack::precision_count_t; if (! value.is_scalar_type () || ! value.isreal () || value.islogical () || value.is_string ()) error_with_id (error_id, "precision must be a real numeric scalar integer"); precision_count_t result = 0; if (value.is_uint64_type ()) result = value.uint64_scalar_value ().value (); else if (value.isinteger ()) { if (value.is_uint8_type () || value.is_uint16_type () || value.is_uint32_type ()) result = value.uint64_scalar_value ().value (); else { const std::int64_t supplied = value.int64_scalar_value ().value (); if (supplied <= 0) error_with_id (error_id, "precision must be positive"); result = static_cast (supplied); } } else if (value.is_double_type () || value.is_single_type ()) { const double supplied = value.double_value (); const double exact_integer_limit = value.is_single_type () ? 16777216.0 : 9007199254740992.0; if (! std::isfinite (supplied) || std::trunc (supplied) != supplied) error_with_id (error_id, "precision must be a finite integer"); if (supplied <= 0.0) error_with_id (error_id, "precision must be positive"); if (supplied > exact_integer_limit) error_with_id ( error_id, "floating precision exceeds its contiguous exact-integer range"); result = static_cast (supplied); } else error_with_id (error_id, "precision must be a real numeric scalar integer"); if (result == 0) error_with_id (error_id, "precision must be positive"); return result; } octave_value precision_count_value (octave_mplapack::precision_count_t value) { return octave_value (octave_uint64 (value)); } octave_value make_internal_scalar (const std::string& text, mpfr_prec_t precision_bits) { try { return octave_value ( new octave_mplapack_mpfr_scalar_internal (text, precision_bits)); } catch (const std::invalid_argument&) { error_with_id ("mplapack:InvalidScalarText", "invalid scalar text"); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } return octave_value (); } octave_value make_internal_scalar (double value, mpfr_prec_t precision_bits) { try { return octave_value ( new octave_mplapack_mpfr_scalar_internal (value, precision_bits)); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } return octave_value (); } octave_value make_internal_scalar (octave_mplapack::MpfrScalarStorage storage) { return octave_value ( new octave_mplapack_mpfr_scalar_internal (std::move (storage))); } octave_value make_internal_matrix (octave_mplapack::MpfrMatrixStorage storage) { return octave_value ( new octave_mplapack_mpfr_matrix_internal (std::move (storage))); } octave_value require_mp_payload (const octave_value& value); std::uint64_t require_rng_word (const octave_value& value, const char *description) { if (! value.is_uint64_type () || ! value.is_scalar_type ()) error_with_id ("mplapack:rng:InvalidState", "%s must be a uint64 scalar", description); return value.uint64_scalar_value ().value (); } octave_mplapack::MpRandomState require_rng_state (const octave_value& first, const octave_value& second) { octave_mplapack::MpRandomState state { require_rng_word (first, "rng state first word"), require_rng_word (second, "rng state second word")}; if (state.first == 0 && state.second == 0) error_with_id ("mplapack:rng:InvalidState", "rng state must not contain two zero words"); return state; } octave_value make_random_value (octave_mplapack::MpfrMatrixStorage storage) { if (storage.numel () == 1) return make_internal_scalar ( octave_mplapack::MpfrScalarStorage ( std::move (storage.data ()[0]))); return make_internal_matrix (std::move (storage)); } octave_value_list make_random_result (octave_mplapack::MpfrMatrixStorage storage, const octave_mplapack::MpRandomState& state) { return ovl (make_random_value (std::move (storage)), octave_uint64 (state.first), octave_uint64 (state.second)); } octave_mplapack::MpfrScalarStorage require_real_mp_scalar_for_rng (const octave_value& value, const char *description) { const octave_value payload = require_mp_payload (value); if (payload.type_id () != octave_mplapack_mpfr_scalar_internal::static_type_id ()) error_with_id ("mplapack:rng:InvalidBound", "%s must be a real scalar mp value", description); return octave_mplapack::MpfrScalarStorage ( octave_mplapack_mpfr_scalar_internal::checked_value (payload).storage ()); } octave_value make_internal_complex_scalar (const std::string& text, mpfr_prec_t precision_bits) { try { return octave_value ( new octave_mplapack_mpc_scalar_internal (text, precision_bits)); } catch (const std::invalid_argument&) { error_with_id ("mplapack:InvalidComplexScalarText", "invalid complex scalar text"); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } return octave_value (); } octave_value make_internal_complex_scalar (const Complex& value, mpfr_prec_t precision_bits) { try { return octave_value (new octave_mplapack_mpc_scalar_internal ( value.real (), value.imag (), precision_bits)); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } return octave_value (); } octave_value make_internal_complex_scalar ( octave_mplapack::MpfrComplexScalarStorage storage) { return octave_value ( new octave_mplapack_mpc_scalar_internal (std::move (storage))); } octave_value make_internal_complex_matrix ( octave_mplapack::MpfrComplexMatrixStorage storage) { return octave_value ( new octave_mplapack_mpc_matrix_internal (std::move (storage))); } octave_idx_type checked_octave_dimension_for_inspection (std::size_t value); std::size_t checked_size_dimension (octave_idx_type value); octave_value require_mp_payload (const octave_value& value); constexpr const char *mp_serialization_schema = "octave-mplapack-mp"; constexpr std::uint64_t mp_serialization_version = 1; Cell serialize_real_elements (const octave_mplapack::MpfrMatrixStorage& storage) { const octave_idx_type count = checked_octave_dimension_for_inspection (storage.numel ()); Cell elements (dim_vector (count, 1)); std::size_t index = 0; for (std::size_t column = 0; column < storage.columns (); ++column) for (std::size_t row = 0; row < storage.rows (); ++row) elements.xelem (static_cast (index++)) = octave_mplapack::MpfrScalarStorage ( storage.at (row, column)).to_canonical_string (); return elements; } Cell serialize_complex_elements ( const octave_mplapack::MpfrComplexMatrixStorage& storage) { const octave_idx_type count = checked_octave_dimension_for_inspection (storage.numel ()); Cell elements (dim_vector (count, 1)); std::size_t index = 0; for (std::size_t column = 0; column < storage.columns (); ++column) for (std::size_t row = 0; row < storage.rows (); ++row) elements.xelem (static_cast (index++)) = octave_mplapack::MpfrComplexScalarStorage ( storage.at (row, column)).to_canonical_string (); return elements; } octave_scalar_map serialize_mp_value (const octave_value& value) { const octave_value payload = require_mp_payload (value); octave_scalar_map state; state.assign ("schema", mp_serialization_schema); state.assign ("version", octave_uint64 (mp_serialization_version)); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload); state.assign ("kind", "real-scalar"); state.assign ("rows", octave_uint64 (1)); state.assign ("columns", octave_uint64 (1)); state.assign ("precision_bits", octave_uint64 (scalar.storage ().precision_bits ())); Cell elements (dim_vector (1, 1)); elements.xelem (0) = scalar.storage ().to_canonical_string (); state.assign ("elements", elements); return state; } if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload); state.assign ("kind", "complex-scalar"); state.assign ("rows", octave_uint64 (1)); state.assign ("columns", octave_uint64 (1)); state.assign ("precision_bits", octave_uint64 (scalar.storage ().precision_bits ())); Cell elements (dim_vector (1, 1)); elements.xelem (0) = scalar.storage ().to_canonical_string (); state.assign ("elements", elements); return state; } if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) { const auto& storage = octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); state.assign ("kind", "real-matrix"); state.assign ("rows", octave_uint64 (storage.rows ())); state.assign ("columns", octave_uint64 (storage.columns ())); state.assign ("precision_bits", octave_uint64 (storage.precision_bits ())); state.assign ("elements", serialize_real_elements (storage)); return state; } const auto& storage = octave_mplapack_mpc_matrix_internal::checked_value (payload).storage (); state.assign ("kind", "complex-matrix"); state.assign ("rows", octave_uint64 (storage.rows ())); state.assign ("columns", octave_uint64 (storage.columns ())); state.assign ("precision_bits", octave_uint64 (storage.precision_bits ())); state.assign ("elements", serialize_complex_elements (storage)); return state; } std::uint64_t serialized_uint64_field (const octave_scalar_map& state, const char *name) { if (! state.contains (name)) error_with_id ("mplapack:SerializationError", "serialized mp state is missing field '%s'", name); const octave_value field = state.contents (name); if (! field.is_uint64_type () || ! field.is_scalar_type ()) error_with_id ("mplapack:SerializationError", "serialized mp field '%s' must be a uint64 scalar", name); return field.uint64_scalar_value ().value (); } std::string serialized_string_field (const octave_scalar_map& state, const char *name) { if (! state.contains (name)) error_with_id ("mplapack:SerializationError", "serialized mp state is missing field '%s'", name); const octave_value field = state.contents (name); if (! field.is_string () || field.rows () != 1 || field.columns () == 0) error_with_id ("mplapack:SerializationError", "serialized mp field '%s' must be nonempty text", name); return field.string_value (); } std::size_t serialized_dimension_field (const octave_scalar_map& state, const char *name) { const std::uint64_t supplied = serialized_uint64_field (state, name); if (supplied > static_cast ( std::numeric_limits::max ()) || supplied > static_cast ( std::numeric_limits::max ())) error_with_id ("mplapack:mp:DimensionOverflow", "serialized mp dimension '%s' is too large", name); return checked_size_dimension (static_cast (supplied)); } mpfr_prec_t serialized_precision_field (const octave_scalar_map& state) { const std::uint64_t supplied = serialized_uint64_field (state, "precision_bits"); const mpfr_prec_t precision = static_cast (supplied); if (static_cast (precision) != supplied || precision < MPFR_PREC_MIN || precision > MPFR_PREC_MAX) error_with_id ("mplapack:SerializationError", "serialized mp precision is outside the MPFR range"); return precision; } std::vector serialized_elements_field (const octave_scalar_map& state, std::size_t expected_count) { if (! state.contains ("elements")) error_with_id ("mplapack:SerializationError", "serialized mp state is missing field 'elements'"); const octave_value field = state.contents ("elements"); if (! field.iscell () || field.numel () != static_cast (expected_count)) error_with_id ("mplapack:SerializationError", "serialized mp element count does not match its shape"); const Cell elements = field.cell_value (); std::vector result; result.reserve (expected_count); for (octave_idx_type index = 0; index < elements.numel (); ++index) { const octave_value element = elements.xelem (index); if (! element.is_string () || element.rows () != 1 || element.columns () == 0) error_with_id ("mplapack:SerializationError", "serialized mp elements must be nonempty text"); result.push_back (element.string_value ()); } return result; } octave_value deserialize_mp_value (const octave_value& value) { if (! value.isstruct () || value.numel () != 1) error_with_id ("mplapack:SerializationError", "loadobj expects one serialized mp struct"); const octave_scalar_map state = value.scalar_map_value (); if (serialized_string_field (state, "schema") != mp_serialization_schema || serialized_uint64_field (state, "version") != mp_serialization_version) error_with_id ("mplapack:SerializationError", "unsupported serialized mp schema or version"); const std::string kind = serialized_string_field (state, "kind"); const std::size_t rows = serialized_dimension_field (state, "rows"); const std::size_t columns = serialized_dimension_field (state, "columns"); const mpfr_prec_t precision = serialized_precision_field (state); const std::size_t count = octave_mplapack::MpfrMatrixStorage::checked_element_count ( rows, columns); const std::vector elements = serialized_elements_field (state, kind == "real-scalar" || kind == "complex-scalar" ? 1 : count); try { if (kind == "real-scalar") { if (rows != 1 || columns != 1) throw std::invalid_argument ("serialized scalar shape mismatch"); return make_internal_scalar (elements.at (0), precision); } if (kind == "complex-scalar") { if (rows != 1 || columns != 1) throw std::invalid_argument ("serialized scalar shape mismatch"); return make_internal_complex_scalar (elements.at (0), precision); } if (kind == "real-matrix") return make_internal_matrix ( octave_mplapack::MpfrMatrixStorage (rows, columns, precision, elements)); if (kind == "complex-matrix") return make_internal_complex_matrix ( octave_mplapack::MpfrComplexMatrixStorage (rows, columns, precision, elements)); error_with_id ("mplapack:SerializationError", "unknown serialized mp kind '%s'", kind.c_str ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:SerializationError", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:SerializationError", "%s", exception.what ()); } return octave_value (); } double require_double_scalar (const octave_value& value, const char *description) { if (! value.is_double_type () || ! value.is_real_scalar ()) error_with_id ("mplapack:InvalidArguments", "%s must be a real double scalar", description); return value.double_value (); } octave_value require_mp_payload (const octave_value& value) { if (value.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) return value; if (value.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) return value; if (value.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return value; if (value.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) return value; if ((! value.is_classdef_object () && ! value.isobject ()) || value.class_name () != "mp") error_with_id ("mplapack:InvalidNativeValue", "expected an internal MPLAPACK MPFR value or public mp value"); octave_value payload; if (value.is_classdef_object ()) { octave_classdef *object = value.classdef_object_value (true); if (! object || ! object->is_instance_of ("mp")) error_with_id ("mplapack:InvalidNativeValue", "invalid public mp representation"); try { payload = object->get_property (0, "payload_"); } catch (const std::exception&) { error_with_id ("mplapack:InvalidNativeValue", "public mp value has no valid native payload"); } } else { const octave_map object = value.map_value (); if (! object.isfield ("payload_") || object.numel () != 1) error_with_id ("mplapack:InvalidNativeValue", "public mp value has no valid payload field"); const Cell payload_field = object.contents ("payload_"); if (payload_field.numel () != 1) error_with_id ("mplapack:InvalidNativeValue", "public mp payload field is not scalar"); payload = payload_field.xelem (0); if (payload.isstruct ()) return deserialize_mp_value (payload); } if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) octave_mplapack_mpfr_scalar_internal::checked_value (payload); else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) octave_mplapack_mpfr_matrix_internal::checked_value (payload); else if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) octave_mplapack_mpc_scalar_internal::checked_value (payload); else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) octave_mplapack_mpc_matrix_internal::checked_value (payload); else error_with_id ("mplapack:InvalidNativeValue", "public mp value has an unknown native payload"); return payload; } octave_value require_scalar_payload (const octave_value& value) { if (value.type_id () != octave_mplapack_mpfr_scalar_internal::static_type_id () && value.type_id () != octave_mplapack_mpfr_matrix_internal::static_type_id () && (! (value.is_classdef_object () || value.isobject ()) || value.class_name () != "mp")) error_with_id ("mplapack:InvalidNativeValue", "expected an internal MPLAPACK MPFR scalar"); const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) error_with_id ("mplapack:mp:MatrixUnsupported", "operation is not implemented for dense mp matrices"); octave_mplapack_mpfr_scalar_internal::checked_value (payload); return payload; } octave_value require_matrix_payload (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) octave_mplapack_mpfr_matrix_internal::checked_value (payload); else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) octave_mplapack_mpc_matrix_internal::checked_value (payload); else error_with_id ("mplapack:InvalidNativeValue", "expected an internal MPLAPACK matrix"); return payload; } bool is_matrix_payload (const octave_value& value) { const int type = require_mp_payload (value).type_id (); return type == octave_mplapack_mpfr_matrix_internal::static_type_id () || type == octave_mplapack_mpc_matrix_internal::static_type_id (); } bool is_complex_payload (const octave_value& value) { const int type = require_mp_payload (value).type_id (); return type == octave_mplapack_mpc_scalar_internal::static_type_id () || type == octave_mplapack_mpc_matrix_internal::static_type_id (); } bool is_mp_value (const octave_value& value) { return (value.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) || (value.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) || (value.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) || (value.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) || ((value.is_classdef_object () || value.isobject ()) && value.class_name () == "mp"); } bool is_real_double_matrix_operand (const octave_value& value) { return value.is_double_type () && value.isreal () && ! value.is_real_scalar () && value.ndims () == 2; } bool is_double_matrix_operand (const octave_value& value) { return value.is_double_type () && ! value.is_real_scalar () && value.ndims () == 2; } octave_value require_arithmetic_mp_payload (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) error_with_id ("mplapack:mp:MatrixUnsupported", "this scalar-only arithmetic path does not accept dense mp matrices"); return require_scalar_payload (payload); } double require_arithmetic_double (const octave_value& value) { if (value.is_double_type ()) { if (! value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex arithmetic is not supported"); if (! value.is_real_scalar ()) error_with_id ("mplapack:mp:MatrixUnsupported", "this scalar-only arithmetic path does not accept matrix operands"); return value.double_value (); } if (value.isnumeric () && ! value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex arithmetic is not supported"); error_with_id ("mplapack:mp:UnsupportedOperand", "scalar arithmetic supports only mp and real double operands"); return 0.0; } std::size_t checked_size_dimension (octave_idx_type value) { if (value < 0) error_with_id ("mplapack:mp:InvalidDimensions", "matrix dimensions must be nonnegative"); using UnsignedOctaveIndex = std::make_unsigned_t; const auto converted = static_cast (value); if (converted > std::numeric_limits::max ()) error_with_id ("mplapack:mp:DimensionOverflow", "matrix dimension exceeds size_t"); const std::size_t result = static_cast (converted); try { octave_mplapack::MpfrMatrixStorage::checked_mplapack_dimension ( result); } catch (const std::overflow_error&) { error_with_id ("mplapack:mp:DimensionOverflow", "matrix dimension exceeds MPLAPACK INTEGER"); } return result; } octave_value make_matrix_from_double (const octave_value& value) { if (! value.is_double_type ()) error_with_id ("mplapack:mp:InvalidInput", "matrix input must be a real double array"); if (! value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex mp matrices are not supported"); if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional mp matrices are supported"); const Matrix input = value.matrix_value (); const std::size_t rows = checked_size_dimension (input.rows ()); const std::size_t columns = checked_size_dimension (input.columns ()); std::vector values; try { values.reserve ( octave_mplapack::MpfrMatrixStorage::checked_element_count ( rows, columns)); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) values.push_back (input.xelem (row, column)); return make_internal_matrix (octave_mplapack::MpfrMatrixStorage ( rows, columns, octave_mplapack::default_precision_bits (), values)); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } return octave_value (); } octave_mplapack::MpfrMatrixStorage make_double_matrix_storage (const octave_value& value, mpfr_prec_t precision_bits) { if (! value.is_double_type () || value.is_real_scalar ()) error_with_id ("mplapack:mp:UnsupportedOperand", "expected a non-scalar real double matrix"); if (! value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex matrix multiplication is not supported"); if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional matrix operands are supported"); const Matrix input = value.matrix_value (); const std::size_t rows = checked_size_dimension (input.rows ()); const std::size_t columns = checked_size_dimension (input.columns ()); std::vector values; values.reserve (octave_mplapack::MpfrMatrixStorage::checked_element_count ( rows, columns)); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) values.push_back (input.xelem (row, column)); return octave_mplapack::MpfrMatrixStorage (rows, columns, precision_bits, values); } octave_mplapack::MpfrComplexMatrixStorage make_complex_double_matrix_storage (const octave_value& value, mpfr_prec_t precision_bits) { if (! value.is_double_type () || value.is_real_scalar ()) error_with_id ("mplapack:mp:UnsupportedOperand", "expected a non-scalar double matrix"); if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional matrix operands are supported"); const std::size_t rows = checked_size_dimension (value.rows ()); const std::size_t columns = checked_size_dimension (value.columns ()); std::vector> values; values.reserve (octave_mplapack::MpfrComplexMatrixStorage:: checked_element_count (rows, columns)); if (value.isreal ()) { const Matrix input = value.matrix_value (); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) values.emplace_back (input.xelem (row, column), 0.0); } else { const ComplexMatrix input = value.complex_matrix_value (); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) values.emplace_back (input.xelem (row, column).real (), input.xelem (row, column).imag ()); } return octave_mplapack::MpfrComplexMatrixStorage ( rows, columns, precision_bits, values); } octave_value make_matrix_from_text_cell (const octave_value& value) { if (! value.iscell ()) error_with_id ("mplapack:mp:InvalidInput", "text matrix input must be a cell array"); if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional mp matrices are supported"); const Cell input = value.cell_value (); const std::size_t rows = checked_size_dimension (input.rows ()); const std::size_t columns = checked_size_dimension (input.columns ()); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) { const octave_value element = input.xelem (row, column); if (! element.is_string () || element.rows () != 1 || element.columns () == 0) error_with_id ( "mplapack:mp:InvalidInput", "each matrix cell must contain one nonempty text row"); } std::vector values; try { values.reserve ( octave_mplapack::MpfrMatrixStorage::checked_element_count ( rows, columns)); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) { const octave_value element = input.xelem (row, column); values.push_back (element.string_value ()); } return make_internal_matrix (octave_mplapack::MpfrMatrixStorage ( rows, columns, octave_mplapack::default_precision_bits (), values)); } catch (const std::invalid_argument&) { error_with_id ("mplapack:InvalidScalarText", "invalid text in mp matrix constructor"); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } return octave_value (); } octave_value make_complex_matrix_from_text_cell (const octave_value& value) { if (! value.iscell ()) error_with_id ("mplapack:mp:InvalidInput", "complex text matrix input must be a cell array"); if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional mp matrices are supported"); const Cell input = value.cell_value (); const std::size_t rows = checked_size_dimension (input.rows ()); const std::size_t columns = checked_size_dimension (input.columns ()); std::vector values; try { values.reserve ( octave_mplapack::MpfrComplexMatrixStorage::checked_element_count ( rows, columns)); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) { const octave_value element = input.xelem (row, column); if (! element.is_string () || element.rows () != 1 || element.columns () == 0) error_with_id ( "mplapack:mp:InvalidInput", "each complex matrix cell must contain nonempty text"); values.push_back (element.string_value ()); } return make_internal_complex_matrix ( octave_mplapack::MpfrComplexMatrixStorage ( rows, columns, octave_mplapack::default_precision_bits (), values)); } catch (const std::invalid_argument&) { error_with_id ("mplapack:InvalidComplexScalarText", "invalid text in complex mp matrix constructor"); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } return octave_value (); } std::size_t require_matrix_index (const octave_value& value) { if (! value.is_real_scalar ()) error_with_id ("mplapack:InvalidArguments", "matrix test index must be a real scalar integer"); const double supplied = value.double_value (); if (! std::isfinite (supplied) || std::trunc (supplied) != supplied || supplied < 1.0 || supplied > static_cast ( std::numeric_limits::max ())) error_with_id ("mplapack:InvalidArguments", "matrix test index must be a positive integer"); return static_cast (supplied - 1.0); } bool is_colon_index (const octave_value& value) { if (! value.is_string ()) return false; try { return value.string_value () == ":"; } catch (...) { return false; } } std::vector parse_index_vector (const octave_value& value, std::size_t limit, const char *description) { if (is_colon_index (value)) { std::vector result (limit); for (std::size_t index = 0; index < limit; ++index) result[index] = index; return result; } if (value.islogical ()) { if (value.ndims () != 2 || (value.numel () != 1 && value.numel () != limit)) error_with_id ("mplapack:mp:InvalidIndex", "%s logical mask must have one element or match the indexed dimension", description); const boolMatrix mask = value.bool_matrix_value (); if (mask.numel () == 1) return mask (0, 0) ? std::vector {0} : std::vector {}; std::vector result; result.reserve (static_cast (mask.numel ())); for (octave_idx_type index = 0; index < mask.numel (); ++index) if (mask(index)) result.push_back (static_cast (index)); return result; } if (! value.isnumeric () || value.islogical () || ! value.isreal () || value.ndims () != 2) error_with_id ("mplapack:mp:InvalidIndex", "%s must be a real integer scalar or vector", description); const octave_idx_type rows = value.rows (); const octave_idx_type columns = value.columns (); if (rows != 1 && columns != 1 && value.numel () != 0) error_with_id ("mplapack:mp:InvalidIndex", "%s must be a real integer scalar or vector", description); const NDArray indices = value.array_value (); std::vector result; result.reserve (static_cast (indices.numel ())); for (octave_idx_type index = 0; index < indices.numel (); ++index) { const double supplied = indices(index); if (! std::isfinite (supplied) || std::trunc (supplied) != supplied || supplied < 1.0) error_with_id ("mplapack:mp:InvalidIndex", "%s must contain positive integer indices", description); const long double wide = static_cast (supplied); if (wide > static_cast (std::numeric_limits::max ())) error_with_id ("mplapack:mp:InvalidIndex", "%s index is too large", description); const std::size_t zero_based = static_cast (supplied - 1.0); if (zero_based >= limit) error_with_id ("mplapack:mp:IndexOutOfBounds", "%s index is out of bounds", description); result.push_back (zero_based); } return result; } octave_idx_type checked_octave_dimension_for_inspection (std::size_t value) { if (value > static_cast ( std::numeric_limits::max ())) error_with_id ("mplapack:mp:DimensionOverflow", "matrix dimension exceeds octave_idx_type"); return static_cast (value); } octave_value make_inspection_result (octave_mplapack::MpfrMatrixStorage storage) { if (storage.rows () == 1 && storage.columns () == 1) { octave_mplapack::MpfrScalarStorage scalar ( std::move (storage.at (0, 0))); return make_internal_scalar (std::move (scalar)); } return make_internal_matrix (std::move (storage)); } octave_value make_complex_inspection_result ( octave_mplapack::MpfrComplexMatrixStorage storage) { if (storage.rows () == 1 && storage.columns () == 1) return make_internal_complex_scalar ( octave_mplapack::MpfrComplexScalarStorage ( octave_mplapack::MpfrComplexScalarStorage::NativeScalar ( storage.at (0, 0)))); return make_internal_complex_matrix (std::move (storage)); } struct PreparedConcatOperand { octave_mplapack::MpfrConcatOperand descriptor; }; struct PreparedComplexConcatOperand { octave_mplapack::MpcConcatOperand descriptor; }; octave_mplapack::MpcConcatOperand prepare_complex_concat_operand (const octave_value& value) { octave_mplapack::MpcConcatOperand operand; if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const octave_value kept_payload = payload; const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value ( kept_payload).storage (); operand.rows = operand.columns = 1; operand.precision_bits = scalar.precision_bits (); operand.has_mp_precision = true; operand.copy_element = [kept_payload] (mpfrxx::mpc_class& destination, std::size_t, std::size_t) { const auto& source = octave_mplapack_mpc_scalar_internal::checked_value ( kept_payload).storage (); mpc_set (destination.mpc_data (), source.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return operand; } if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { const octave_value kept_payload = payload; const auto& matrix = octave_mplapack_mpc_matrix_internal::checked_value ( kept_payload).storage (); operand.rows = matrix.rows (); operand.columns = matrix.columns (); operand.precision_bits = matrix.precision_bits (); operand.has_mp_precision = true; operand.copy_element = [kept_payload] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { const auto& source = octave_mplapack_mpc_matrix_internal::checked_value ( kept_payload).storage (); mpc_set (destination.mpc_data (), source.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return operand; } if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const octave_value kept_payload = payload; const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( kept_payload).storage (); operand.rows = operand.columns = 1; operand.precision_bits = scalar.precision_bits (); operand.has_mp_precision = true; operand.copy_element = [kept_payload] (mpfrxx::mpc_class& destination, std::size_t, std::size_t) { const auto& source = octave_mplapack_mpfr_scalar_internal::checked_value ( kept_payload).storage (); mpc_set_fr (destination.mpc_data (), source.native_value ().mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return operand; } if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) { const octave_value kept_payload = payload; const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value ( kept_payload).storage (); operand.rows = matrix.rows (); operand.columns = matrix.columns (); operand.precision_bits = matrix.precision_bits (); operand.has_mp_precision = true; operand.copy_element = [kept_payload] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value ( kept_payload).storage (); mpc_set_fr (destination.mpc_data (), source.at (row, column).mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return operand; } error_with_id ("mplapack:mp:InvalidNativeValue", "public mp value has an unknown native payload"); } if (! value.is_double_type ()) error_with_id ("mplapack:mp:UnsupportedOperand", "complex concatenation supports mp and double operands"); if (value.issparse ()) error_with_id ("mplapack:mp:SparseUnsupported", "sparse concatenation is not supported"); if (value.is_real_scalar () || value.is_complex_scalar ()) { const Complex scalar = value.complex_value (); operand.rows = operand.columns = 1; operand.copy_element = [scalar] (mpfrxx::mpc_class& destination, std::size_t, std::size_t) { mpc_set_d_d (destination.mpc_data (), scalar.real (), scalar.imag (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return operand; } if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional concatenation operands are supported"); const std::size_t rows = checked_size_dimension (value.rows ()); const std::size_t columns = checked_size_dimension (value.columns ()); operand.rows = rows; operand.columns = columns; if (value.isreal ()) { const Matrix input = value.matrix_value (); operand.copy_element = [input] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { mpc_set_d_d (destination.mpc_data (), input.xelem (static_cast (row), static_cast (column)), 0.0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; } else { const ComplexMatrix input = value.complex_matrix_value (); operand.copy_element = [input] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { const Complex value = input.xelem (static_cast (row), static_cast (column)); mpc_set_d_d (destination.mpc_data (), value.real (), value.imag (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; } return operand; } octave_value complex_matrix_concatenate_result (const octave_value_list& args, int dimension) { std::vector prepared; prepared.reserve (static_cast (args.length () - 1)); bool has_mp_precision = false; mpfr_prec_t result_precision = MPFR_PREC_MIN; dim_vector result_shape; bool shape_initialized = false; for (int index = 1; index < args.length (); ++index) { PreparedComplexConcatOperand current; current.descriptor = prepare_complex_concat_operand (args(index)); if (current.descriptor.has_mp_precision) { has_mp_precision = true; result_precision = std::max (result_precision, current.descriptor.precision_bits); } const octave_idx_type rows = checked_octave_dimension_for_inspection ( current.descriptor.rows); const octave_idx_type columns = checked_octave_dimension_for_inspection ( current.descriptor.columns); const dim_vector current_shape (rows, columns); if (! shape_initialized) { result_shape = current_shape; shape_initialized = true; } else if (! result_shape.hvcat (current_shape, dimension)) error_with_id ("mplapack:mp:DimensionMismatch", "%s concatenation dimensions mismatch", dimension == 1 ? "horizontal" : "vertical"); prepared.push_back (std::move (current)); } if (! has_mp_precision) error_with_id ("mplapack:mp:UnsupportedOperand", "complex concatenation requires at least one mp operand"); const std::size_t result_rows = checked_size_dimension (result_shape.xelem (0)); const std::size_t result_columns = checked_size_dimension (result_shape.xelem (1)); std::vector operands; operands.reserve (prepared.size ()); for (PreparedComplexConcatOperand& current : prepared) operands.push_back (std::move (current.descriptor)); try { return make_complex_inspection_result ( octave_mplapack::mpc_matrix_concatenate ( operands, dimension, result_rows, result_columns, result_precision)); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:DimensionMismatch", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } return octave_value (); } octave_mplapack::MpfrConcatOperand prepare_concat_operand (const octave_value& value) { octave_mplapack::MpfrConcatOperand operand; if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { operand.rows = 1; operand.columns = 1; const octave_value kept_payload = payload; const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( kept_payload).storage (); operand.precision_bits = scalar.precision_bits (); operand.has_mp_precision = true; operand.copy_element = [kept_payload] (octave_mplapack::MpfrMatrixStorage::NativeScalar& destination, std::size_t, std::size_t) { const auto& source = octave_mplapack_mpfr_scalar_internal::checked_value ( kept_payload).storage (); mpfr_set (destination.mpfr_data (), source.native_value () .mpfr_data (), MPFR_RNDN); }; return operand; } if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) { const octave_value kept_payload = payload; const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value ( kept_payload).storage (); operand.rows = matrix.rows (); operand.columns = matrix.columns (); operand.precision_bits = matrix.precision_bits (); operand.has_mp_precision = true; operand.copy_element = [kept_payload] (octave_mplapack::MpfrMatrixStorage::NativeScalar& destination, std::size_t row, std::size_t column) { const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value ( kept_payload).storage (); mpfr_set (destination.mpfr_data (), source.at (row, column).mpfr_data (), MPFR_RNDN); }; return operand; } error_with_id ("mplapack:mp:InvalidNativeValue", "public mp value has an unknown native payload"); } if (! value.is_double_type ()) error_with_id ("mplapack:mp:UnsupportedOperand", "concatenation supports mp and real double operands"); if (! value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex concatenation is not supported"); if (value.issparse ()) error_with_id ("mplapack:mp:SparseUnsupported", "sparse concatenation is not supported"); if (! value.is_real_scalar () && value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional concatenation operands are supported"); if (value.is_real_scalar ()) { const double scalar = value.double_value (); operand.rows = 1; operand.columns = 1; operand.copy_element = [scalar] (octave_mplapack::MpfrMatrixStorage::NativeScalar& destination, std::size_t, std::size_t) { mpfr_set_d (destination.mpfr_data (), scalar, MPFR_RNDN); }; return operand; } const Matrix input = value.matrix_value (); operand.rows = checked_size_dimension (input.rows ()); operand.columns = checked_size_dimension (input.columns ()); operand.copy_element = [input] (octave_mplapack::MpfrMatrixStorage::NativeScalar& destination, std::size_t row, std::size_t column) { mpfr_set_d (destination.mpfr_data (), input.xelem (static_cast (row), static_cast (column)), MPFR_RNDN); }; return operand; } octave_value matrix_concatenate_result (const octave_value_list& args, int dimension) { if (args.length () < 2) error_with_id ("mplapack:InvalidArguments", "concatenation expects at least one operand"); for (int index = 1; index < args.length (); ++index) if ((is_mp_value (args(index)) && is_complex_payload (args(index))) || (args(index).is_double_type () && ! args(index).isreal ())) return complex_matrix_concatenate_result (args, dimension); std::vector prepared; prepared.reserve (static_cast (args.length () - 1)); bool has_mp_precision = false; mpfr_prec_t result_precision = MPFR_PREC_MIN; dim_vector result_shape; bool shape_initialized = false; for (int index = 1; index < args.length (); ++index) { PreparedConcatOperand current; current.descriptor = prepare_concat_operand (args(index)); if (current.descriptor.has_mp_precision) { has_mp_precision = true; result_precision = std::max (result_precision, current.descriptor.precision_bits); } const octave_idx_type rows = checked_octave_dimension_for_inspection ( current.descriptor.rows); const octave_idx_type columns = checked_octave_dimension_for_inspection ( current.descriptor.columns); const dim_vector current_shape (rows, columns); if (! shape_initialized) { result_shape = current_shape; shape_initialized = true; } else if (! result_shape.hvcat (current_shape, dimension)) { if (dimension == 1) error_with_id ("mplapack:mp:DimensionMismatch", "horizontal concatenation dimensions mismatch"); error_with_id ("mplapack:mp:DimensionMismatch", "vertical concatenation dimensions mismatch"); } prepared.push_back (std::move (current)); } if (! has_mp_precision) error_with_id ("mplapack:mp:UnsupportedOperand", "concatenation requires at least one mp operand"); const std::size_t result_rows = checked_size_dimension (result_shape.xelem (0)); const std::size_t result_columns = checked_size_dimension (result_shape.xelem (1)); std::vector operands; operands.reserve (prepared.size ()); for (PreparedConcatOperand& current : prepared) operands.push_back (std::move (current.descriptor)); try { return make_inspection_result ( octave_mplapack::mpfr_matrix_concatenate ( operands, dimension, result_rows, result_columns, result_precision)); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:DimensionMismatch", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } return octave_value (); } struct ReshapeDimension { bool inferred; std::size_t value; }; std::size_t parse_reshape_dimension (const octave_value& value, const char *description) { if (! value.isnumeric () || value.islogical () || ! value.isreal () || ! value.is_real_scalar ()) error_with_id ("mplapack:mp:InvalidDimension", "%s must be a nonnegative integer scalar", description); if (value.is_uint64_type () || (value.isinteger () && (value.is_uint8_type () || value.is_uint16_type () || value.is_uint32_type ()))) { const std::uint64_t supplied = value.uint64_scalar_value ().value (); if (supplied > std::numeric_limits::max ()) error_with_id ("mplapack:mp:DimensionOverflow", "%s exceeds the native dimension range", description); return static_cast (supplied); } if (value.isinteger ()) { const std::int64_t supplied = value.int64_scalar_value ().value (); if (supplied < 0) error_with_id ("mplapack:mp:InvalidDimension", "%s must be a nonnegative integer scalar", description); if (static_cast (supplied) > std::numeric_limits::max ()) error_with_id ("mplapack:mp:DimensionOverflow", "%s exceeds the native dimension range", description); return static_cast (supplied); } const double supplied = value.double_value (); const double exact_integer_limit = value.is_single_type () ? 16777216.0 : 9007199254740992.0; if (! std::isfinite (supplied) || std::trunc (supplied) != supplied || supplied < 0.0 || supplied > exact_integer_limit) error_with_id ("mplapack:mp:InvalidDimension", "%s must be a nonnegative integer scalar", description); const long double wide = static_cast (supplied); if (wide > static_cast ( std::numeric_limits::max ())) error_with_id ("mplapack:mp:DimensionOverflow", "%s exceeds the native dimension range", description); return static_cast (supplied); } ReshapeDimension parse_reshape_dimension_spec (const octave_value& value, const char *description) { if (value.isnumeric () && ! value.islogical () && value.isreal () && value.isempty ()) return {true, 0}; return {false, parse_reshape_dimension (value, description)}; } std::array parse_reshape_vector (const octave_value& value) { if (! value.isnumeric () || value.islogical () || ! value.isreal () || value.ndims () != 2 || value.numel () != 2) error_with_id ("mplapack:mp:InvalidDimension", "reshape dimension vector must contain two real integers"); const NDArray dimensions = value.array_value (); return { parse_reshape_dimension_spec (dimensions (0), "reshape rows"), parse_reshape_dimension_spec (dimensions (1), "reshape columns") }; } std::pair resolve_reshape_dimensions (const octave_value& value, const octave_value& first, const octave_value *second) { const octave_value payload = require_mp_payload (value); const std::size_t source_numel = payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id () || payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id () ? 1 : payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id () ? octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage ().numel () : octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage ().numel (); std::array dimensions; if (second) { dimensions = { parse_reshape_dimension_spec (first, "reshape rows"), parse_reshape_dimension_spec (*second, "reshape columns") }; } else dimensions = parse_reshape_vector (first); if (dimensions[0].inferred && dimensions[1].inferred) error_with_id ("mplapack:mp:InvalidDimension", "only one reshape dimension may be inferred"); if (dimensions[0].inferred) { if (dimensions[1].value == 0 && source_numel != 0) error_with_id ("mplapack:mp:InvalidDimension", "reshape rows cannot be inferred from a zero column dimension"); dimensions[0].value = dimensions[1].value == 0 ? 0 : source_numel / dimensions[1].value; if (dimensions[1].value != 0 && source_numel % dimensions[1].value != 0) error_with_id ("mplapack:mp:InvalidDimension", "reshape rows cannot be inferred from the element count"); dimensions[0].inferred = false; } else if (dimensions[1].inferred) { if (dimensions[0].value == 0 && source_numel != 0) error_with_id ("mplapack:mp:InvalidDimension", "reshape columns cannot be inferred from a zero row dimension"); dimensions[1].value = dimensions[0].value == 0 ? 0 : source_numel / dimensions[0].value; if (dimensions[0].value != 0 && source_numel % dimensions[0].value != 0) error_with_id ("mplapack:mp:InvalidDimension", "reshape columns cannot be inferred from the element count"); dimensions[1].inferred = false; } try { if (octave_mplapack::MpfrMatrixStorage::checked_element_count ( dimensions[0].value, dimensions[1].value) != source_numel) error_with_id ("mplapack:mp:InvalidDimension", "reshape element count does not match"); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } return {dimensions[0].value, dimensions[1].value}; } octave_value complex_real_result (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return make_internal_scalar (octave_mplapack::mpfr_complex_scalar_real ( octave_mplapack_mpc_scalar_internal::checked_value (payload).storage ())); try { return make_inspection_result (octave_mplapack::mpfr_complex_matrix_real ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage ())); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } return octave_value (); } octave_value complex_imag_result (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return make_internal_scalar (octave_mplapack::mpfr_complex_scalar_imag ( octave_mplapack_mpc_scalar_internal::checked_value (payload).storage ())); try { return make_inspection_result (octave_mplapack::mpfr_complex_matrix_imag ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage ())); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } return octave_value (); } octave_value complex_conj_result (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return make_internal_complex_scalar ( octave_mplapack::mpfr_complex_scalar_conj ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ())); try { return make_complex_inspection_result ( octave_mplapack::mpfr_complex_matrix_conj ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage ())); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } return octave_value (); } octave_value matrix_transpose_result (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return make_internal_complex_scalar ( octave_mplapack::mpfr_complex_scalar_transpose ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ())); if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { try { return make_complex_inspection_result ( octave_mplapack::mpfr_complex_matrix_transpose ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage ())); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } } if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& source = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); return make_internal_scalar (octave_mplapack::MpfrScalarStorage ( octave_mplapack::MpfrScalarStorage::NativeScalar (source.native_value ()))); } try { return make_internal_matrix ( octave_mplapack::mpfr_matrix_transpose ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage ())); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } return octave_value (); } octave_value matrix_ctranspose_result (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return make_internal_complex_scalar ( octave_mplapack::mpfr_complex_scalar_ctranspose ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ())); if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { try { return make_complex_inspection_result ( octave_mplapack::mpfr_complex_matrix_ctranspose ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage ())); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } } return matrix_transpose_result (value); } octave_value matrix_reshape_result (const octave_value& value, const octave_value& first, const octave_value *second) { const octave_value payload = require_mp_payload (value); const auto dimensions = resolve_reshape_dimensions (value, first, second); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { if (dimensions.first != 1 || dimensions.second != 1) error_with_id ("mplapack:mp:InvalidDimension", "a complex scalar mp value can only be reshaped to 1x1"); const auto& source = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); return make_internal_complex_scalar ( octave_mplapack::mpfr_complex_scalar_transpose (source)); } if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) try { return make_complex_inspection_result ( octave_mplapack::mpfr_complex_matrix_reshape ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (), dimensions.first, dimensions.second)); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidDimension", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { if (dimensions.first != 1 || dimensions.second != 1) error_with_id ("mplapack:mp:InvalidDimension", "a scalar mp value can only be reshaped to 1x1"); const auto& source = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); return make_internal_scalar (octave_mplapack::MpfrScalarStorage ( octave_mplapack::MpfrScalarStorage::NativeScalar (source.native_value ()))); } try { return make_inspection_result (octave_mplapack::mpfr_matrix_reshape ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (), dimensions.first, dimensions.second)); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidDimension", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } return octave_value (); } octave_value matrix_subscript_result (const octave_value& value, const octave_value& row_spec, const octave_value& column_spec) { const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (value)).storage (); const auto row_indices = parse_index_vector (row_spec, source.rows (), "row index"); const auto column_indices = parse_index_vector (column_spec, source.columns (), "column index"); try { return make_inspection_result (octave_mplapack::select_matrix ( source, row_indices, column_indices)); } catch (const std::out_of_range& exception) { error_with_id ("mplapack:mp:IndexOutOfBounds", "%s", exception.what ()); } return octave_value (); } octave_value matrix_linear_subscript_result (const octave_value& value, const octave_value& index_spec) { const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (value)).storage (); if (is_colon_index (index_spec)) { std::vector all (source.numel ()); for (std::size_t index = 0; index < source.numel (); ++index) all[index] = index; return make_inspection_result ( octave_mplapack::select_linear (source, all)); } const auto indices = parse_index_vector (index_spec, source.numel (), "linear index"); try { return make_inspection_result (octave_mplapack::select_linear ( source, indices)); } catch (const std::out_of_range& exception) { error_with_id ("mplapack:mp:IndexOutOfBounds", "%s", exception.what ()); } return octave_value (); } octave_value complex_matrix_subscript_result (const octave_value& value, const octave_value& row_spec, const octave_value& column_spec) { const auto& source = octave_mplapack_mpc_matrix_internal::checked_value ( require_matrix_payload (value)).storage (); const auto row_indices = parse_index_vector (row_spec, source.rows (), "row index"); const auto column_indices = parse_index_vector (column_spec, source.columns (), "column index"); try { return make_complex_inspection_result ( octave_mplapack::select_complex_matrix (source, row_indices, column_indices)); } catch (const std::out_of_range& exception) { error_with_id ("mplapack:mp:IndexOutOfBounds", "%s", exception.what ()); } return octave_value (); } octave_value complex_matrix_linear_subscript_result (const octave_value& value, const octave_value& index_spec) { const auto& source = octave_mplapack_mpc_matrix_internal::checked_value ( require_matrix_payload (value)).storage (); if (is_colon_index (index_spec)) { std::vector all (source.numel ()); for (std::size_t index = 0; index < source.numel (); ++index) all[index] = index; return make_complex_inspection_result ( octave_mplapack::select_complex_linear (source, all)); } const auto indices = parse_index_vector (index_spec, source.numel (), "linear index"); try { return make_complex_inspection_result ( octave_mplapack::select_complex_linear (source, indices)); } catch (const std::out_of_range& exception) { error_with_id ("mplapack:mp:IndexOutOfBounds", "%s", exception.what ()); } return octave_value (); } struct PreparedComplexAssignmentOperand { std::size_t rows = 0; std::size_t columns = 0; mpfr_prec_t precision_bits = MPFR_PREC_MIN; bool has_mp_precision = false; std::function copy_element; }; bool complex_assignment_scalar (const PreparedComplexAssignmentOperand& rhs) { return rhs.rows == 1 && rhs.columns == 1; } std::size_t checked_complex_assignment_product (std::size_t lhs, std::size_t rhs) { if (lhs != 0 && rhs > std::numeric_limits::max () / lhs) throw std::overflow_error ("complex assignment selection size overflow"); return lhs * rhs; } PreparedComplexAssignmentOperand prepare_complex_assignment_rhs (const octave_value& value) { PreparedComplexAssignmentOperand prepared; if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const octave_value kept_payload = payload; const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value ( kept_payload).storage (); prepared.rows = prepared.columns = 1; prepared.precision_bits = scalar.precision_bits (); prepared.has_mp_precision = true; prepared.copy_element = [kept_payload] (mpfrxx::mpc_class& destination, std::size_t, std::size_t) { const auto& source = octave_mplapack_mpc_scalar_internal::checked_value ( kept_payload).storage (); mpc_set (destination.mpc_data (), source.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return prepared; } if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { const octave_value kept_payload = payload; const auto& matrix = octave_mplapack_mpc_matrix_internal::checked_value ( kept_payload).storage (); if (matrix.numel () == 0) error_with_id ("mplapack:mp:DeletionUnsupported", "empty RHS deletion is not supported"); prepared.rows = matrix.rows (); prepared.columns = matrix.columns (); prepared.precision_bits = matrix.precision_bits (); prepared.has_mp_precision = true; prepared.copy_element = [kept_payload] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { const auto& source = octave_mplapack_mpc_matrix_internal::checked_value ( kept_payload).storage (); mpc_set (destination.mpc_data (), source.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return prepared; } if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const octave_value kept_payload = payload; const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( kept_payload).storage (); prepared.rows = prepared.columns = 1; prepared.precision_bits = scalar.precision_bits (); prepared.has_mp_precision = true; prepared.copy_element = [kept_payload] (mpfrxx::mpc_class& destination, std::size_t, std::size_t) { const auto& source = octave_mplapack_mpfr_scalar_internal::checked_value ( kept_payload).storage (); mpc_set_fr (destination.mpc_data (), source.native_value ().mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return prepared; } if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) { const octave_value kept_payload = payload; const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value ( kept_payload).storage (); if (matrix.numel () == 0) error_with_id ("mplapack:mp:DeletionUnsupported", "empty RHS deletion is not supported"); prepared.rows = matrix.rows (); prepared.columns = matrix.columns (); prepared.precision_bits = matrix.precision_bits (); prepared.has_mp_precision = true; prepared.copy_element = [kept_payload] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value ( kept_payload).storage (); mpc_set_fr (destination.mpc_data (), source.at (row, column).mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return prepared; } error_with_id ("mplapack:mp:InvalidNativeValue", "public mp value has an unknown native payload"); } if (! value.is_double_type ()) error_with_id ("mplapack:mp:UnsupportedOperand", "complex assignment RHS supports mp and double values"); if (value.issparse ()) error_with_id ("mplapack:mp:SparseUnsupported", "sparse assignment is not supported"); if (value.is_real_scalar () || value.is_complex_scalar ()) { const Complex scalar = value.complex_value (); prepared.rows = prepared.columns = 1; prepared.copy_element = [scalar] (mpfrxx::mpc_class& destination, std::size_t, std::size_t) { mpc_set_d_d (destination.mpc_data (), scalar.real (), scalar.imag (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return prepared; } if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional assignment RHS values are supported"); if (value.numel () == 0) error_with_id ("mplapack:mp:DeletionUnsupported", "empty RHS deletion is not supported"); const ComplexMatrix input = value.complex_matrix_value (); prepared.rows = checked_size_dimension (input.rows ()); prepared.columns = checked_size_dimension (input.columns ()); prepared.copy_element = [input] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { const Complex value = input.xelem (static_cast (row), static_cast (column)); mpc_set_d_d (destination.mpc_data (), value.real (), value.imag (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; return prepared; } struct PreparedComplexAssignmentLhs { octave_value payload; std::optional owned; const octave_mplapack::MpfrComplexMatrixStorage& matrix_storage () const { if (owned) return *owned; return octave_mplapack_mpc_matrix_internal::checked_value ( payload).storage (); } }; PreparedComplexAssignmentLhs prepare_complex_assignment_lhs (const octave_value& value) { PreparedComplexAssignmentLhs prepared; prepared.payload = require_mp_payload (value); if (prepared.payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) return prepared; if (prepared.payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value ( prepared.payload).storage (); prepared.owned.emplace (1, 1, scalar.precision_bits ()); mpc_set (prepared.owned->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return prepared; } if (prepared.payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) { const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value ( prepared.payload).storage (); prepared.owned.emplace (matrix.rows (), matrix.columns (), matrix.precision_bits ()); for (std::size_t index = 0; index < matrix.numel (); ++index) mpc_set_fr (prepared.owned->data ()[index].mpc_data (), matrix.data ()[index].mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return prepared; } if (prepared.payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( prepared.payload).storage (); prepared.owned.emplace (1, 1, scalar.precision_bits ()); mpc_set_fr (prepared.owned->at (0, 0).mpc_data (), scalar.native_value ().mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return prepared; } error_with_id ("mplapack:mp:AssignmentUnsupported", "assignment requires a dense real or complex mp lhs"); return prepared; } octave_value complex_matrix_assignment_result (const octave_value& value, const octave_value& row_spec, const octave_value& column_spec, const octave_value& rhs_value) { PreparedComplexAssignmentLhs lhs = prepare_complex_assignment_lhs (value); const auto& source = lhs.matrix_storage (); const auto row_indices = parse_index_vector (row_spec, source.rows (), "row index"); const auto column_indices = parse_index_vector (column_spec, source.columns (), "column index"); PreparedComplexAssignmentOperand rhs = prepare_complex_assignment_rhs (rhs_value); const std::size_t selected_count = checked_complex_assignment_product (row_indices.size (), column_indices.size ()); if (selected_count == 0) { if (! complex_assignment_scalar (rhs) && checked_complex_assignment_product (rhs.rows, rhs.columns) != 0) error_with_id ("mplapack:mp:DimensionMismatch", "non-scalar RHS is not conformant with an empty selection"); } const bool scalar_rhs = complex_assignment_scalar (rhs); const bool exact_shape = rhs.rows == row_indices.size () && rhs.columns == column_indices.size (); const bool vector_shape = ! exact_shape && ! scalar_rhs && (row_indices.size () == 1 || column_indices.size () == 1) && (rhs.rows == 1 || rhs.columns == 1) && checked_complex_assignment_product (rhs.rows, rhs.columns) == selected_count; if (selected_count != 0 && ! scalar_rhs && ! exact_shape && ! vector_shape) error_with_id ("mplapack:mp:DimensionMismatch", "assignment RHS dimensions are not conformant with the selection"); for (std::size_t row : row_indices) if (row >= source.rows ()) error_with_id ("mplapack:mp:IndexOutOfBounds", "assignment index is out of bounds"); for (std::size_t column : column_indices) if (column >= source.columns ()) error_with_id ("mplapack:mp:IndexOutOfBounds", "assignment index is out of bounds"); const mpfr_prec_t result_precision = rhs.has_mp_precision ? std::max (source.precision_bits (), rhs.precision_bits) : source.precision_bits (); octave_mplapack::MpfrComplexMatrixStorage result ( source.rows (), source.columns (), result_precision); for (std::size_t index = 0; index < source.numel (); ++index) mpc_set (result.data ()[index].mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); for (std::size_t column = 0; column < column_indices.size (); ++column) for (std::size_t row = 0; row < row_indices.size (); ++row) { std::size_t rhs_row = 0; std::size_t rhs_column = 0; if (! scalar_rhs) { if (exact_shape) { rhs_row = row; rhs_column = column; } else { const std::size_t linear = row + column * row_indices.size (); rhs_row = linear % rhs.rows; rhs_column = linear / rhs.rows; } } rhs.copy_element (result.at (row_indices[row], column_indices[column]), rhs_row, rhs_column); } return make_complex_inspection_result (std::move (result)); } octave_value complex_matrix_linear_assignment_result (const octave_value& value, const octave_value& index_spec, const octave_value& rhs_value) { PreparedComplexAssignmentLhs lhs = prepare_complex_assignment_lhs (value); const auto& source = lhs.matrix_storage (); std::vector indices; if (is_colon_index (index_spec)) { indices.resize (source.numel ()); for (std::size_t index = 0; index < indices.size (); ++index) indices[index] = index; } else { indices = parse_index_vector (index_spec, source.numel (), "linear index"); } PreparedComplexAssignmentOperand rhs = prepare_complex_assignment_rhs (rhs_value); const bool scalar_rhs = complex_assignment_scalar (rhs); const std::size_t rhs_count = checked_complex_assignment_product (rhs.rows, rhs.columns); if (! scalar_rhs && rhs_count != indices.size ()) error_with_id ("mplapack:mp:DimensionMismatch", "assignment RHS element count does not match linear selection"); for (std::size_t index : indices) if (index >= source.numel ()) error_with_id ("mplapack:mp:IndexOutOfBounds", "assignment index is out of bounds"); const mpfr_prec_t result_precision = rhs.has_mp_precision ? std::max (source.precision_bits (), rhs.precision_bits) : source.precision_bits (); octave_mplapack::MpfrComplexMatrixStorage result ( source.rows (), source.columns (), result_precision); for (std::size_t index = 0; index < source.numel (); ++index) mpc_set (result.data ()[index].mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); for (std::size_t index = 0; index < indices.size (); ++index) { const std::size_t rhs_row = scalar_rhs ? 0 : index % rhs.rows; const std::size_t rhs_column = scalar_rhs ? 0 : index / rhs.rows; rhs.copy_element (result.data ()[indices[index]], rhs_row, rhs_column); } return make_complex_inspection_result (std::move (result)); } struct PreparedAssignmentOperand { octave_value payload; octave_mplapack::MpfrAssignmentOperand descriptor; }; PreparedAssignmentOperand prepare_assignment_rhs (const octave_value& value) { PreparedAssignmentOperand prepared; if (is_mp_value (value)) { prepared.payload = require_mp_payload (value); if (prepared.payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const octave_value kept_payload = prepared.payload; const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( kept_payload).storage (); prepared.descriptor.rows = 1; prepared.descriptor.columns = 1; prepared.descriptor.precision_bits = scalar.precision_bits (); prepared.descriptor.has_mp_precision = true; prepared.descriptor.copy_element = [kept_payload] ( octave_mplapack::MpfrMatrixStorage::NativeScalar& destination, std::size_t, std::size_t) { const auto& source = octave_mplapack_mpfr_scalar_internal::checked_value ( kept_payload).storage (); mpfr_set (destination.mpfr_data (), source.native_value ().mpfr_data (), MPFR_RNDN); }; return prepared; } if (prepared.payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) { const octave_value kept_payload = prepared.payload; const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value ( kept_payload).storage (); if (matrix.numel () == 0) error_with_id ("mplapack:mp:DeletionUnsupported", "empty RHS deletion is not supported"); prepared.descriptor.rows = matrix.rows (); prepared.descriptor.columns = matrix.columns (); prepared.descriptor.precision_bits = matrix.precision_bits (); prepared.descriptor.has_mp_precision = true; prepared.descriptor.copy_element = [kept_payload] ( octave_mplapack::MpfrMatrixStorage::NativeScalar& destination, std::size_t row, std::size_t column) { const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value ( kept_payload).storage (); mpfr_set (destination.mpfr_data (), source.at (row, column).mpfr_data (), MPFR_RNDN); }; return prepared; } error_with_id ("mplapack:mp:InvalidNativeValue", "public mp value has an unknown native payload"); } if (! value.is_double_type ()) error_with_id ("mplapack:mp:UnsupportedOperand", "assignment RHS supports mp and real double values"); if (! value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex assignment is not supported"); if (value.issparse ()) error_with_id ("mplapack:mp:SparseUnsupported", "sparse assignment is not supported"); if (! value.is_real_scalar () && value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional assignment RHS values are supported"); if (! value.is_real_scalar () && value.numel () == 0) error_with_id ("mplapack:mp:DeletionUnsupported", "empty RHS deletion is not supported"); if (value.is_real_scalar ()) { const double scalar = value.double_value (); prepared.descriptor.rows = 1; prepared.descriptor.columns = 1; prepared.descriptor.copy_element = [scalar] ( octave_mplapack::MpfrMatrixStorage::NativeScalar& destination, std::size_t, std::size_t) { mpfr_set_d (destination.mpfr_data (), scalar, MPFR_RNDN); }; return prepared; } const Matrix input = value.matrix_value (); prepared.descriptor.rows = checked_size_dimension (input.rows ()); prepared.descriptor.columns = checked_size_dimension (input.columns ()); prepared.descriptor.copy_element = [input] (octave_mplapack::MpfrMatrixStorage::NativeScalar& destination, std::size_t row, std::size_t column) { mpfr_set_d (destination.mpfr_data (), input.xelem (static_cast (row), static_cast (column)), MPFR_RNDN); }; return prepared; } struct PreparedAssignmentLhs { octave_value payload; std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage& matrix_storage () const { if (scalar_matrix) return *scalar_matrix; return octave_mplapack_mpfr_matrix_internal::checked_value ( payload).storage (); } }; PreparedAssignmentLhs prepare_assignment_lhs (const octave_value& value) { PreparedAssignmentLhs prepared; prepared.payload = require_mp_payload (value); if (prepared.payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) return prepared; const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( prepared.payload).storage (); prepared.scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (prepared.scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); return prepared; } mpfr_prec_t assignment_precision (const octave_mplapack::MpfrMatrixStorage& lhs, const octave_mplapack::MpfrAssignmentOperand& rhs) { mpfr_prec_t result = lhs.precision_bits (); if (rhs.has_mp_precision) result = std::max (result, rhs.precision_bits); return result; } mpfr_prec_t assignment_precision_for_selection ( const octave_mplapack::MpfrMatrixStorage& lhs, const octave_mplapack::MpfrAssignmentOperand& rhs, std::size_t selected_count) { // An empty indexed selection is a no-op; it does not consume an RHS value // and therefore must not widen the lhs merely because the RHS is precise. return selected_count == 0 ? lhs.precision_bits () : assignment_precision (lhs, rhs); } octave_value matrix_two_subscript_assignment_result (const octave_value& value, const octave_value& row_spec, const octave_value& column_spec, const octave_value& rhs_value) { PreparedAssignmentLhs lhs = prepare_assignment_lhs (value); const auto& lhs_storage = lhs.matrix_storage (); const auto row_indices = parse_index_vector (row_spec, lhs_storage.rows (), "row index"); const auto column_indices = parse_index_vector (column_spec, lhs_storage.columns (), "column index"); PreparedAssignmentOperand rhs = prepare_assignment_rhs (rhs_value); try { return make_inspection_result ( octave_mplapack::mpfr_matrix_assign_two_subscript ( lhs_storage, row_indices, column_indices, rhs.descriptor, assignment_precision_for_selection ( lhs_storage, rhs.descriptor, row_indices.empty () || column_indices.empty () ? 0 : 1))); } catch (const std::out_of_range& exception) { error_with_id ("mplapack:mp:IndexOutOfBounds", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:DimensionMismatch", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:AssignmentError", "%s", exception.what ()); } return octave_value (); } octave_value matrix_linear_assignment_result (const octave_value& value, const octave_value& index_spec, const octave_value& rhs_value) { PreparedAssignmentLhs lhs = prepare_assignment_lhs (value); const auto& lhs_storage = lhs.matrix_storage (); std::vector indices; if (is_colon_index (index_spec)) { indices.resize (lhs_storage.numel ()); for (std::size_t index = 0; index < indices.size (); ++index) indices[index] = index; } else { indices = parse_index_vector (index_spec, lhs_storage.numel (), "linear index"); } PreparedAssignmentOperand rhs = prepare_assignment_rhs (rhs_value); try { return make_inspection_result (octave_mplapack::mpfr_matrix_assign_linear ( lhs_storage, indices, rhs.descriptor, assignment_precision_for_selection ( lhs_storage, rhs.descriptor, indices.size ()))); } catch (const std::out_of_range& exception) { error_with_id ("mplapack:mp:IndexOutOfBounds", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:DimensionMismatch", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:AssignmentError", "%s", exception.what ()); } return octave_value (); } Matrix matrix_to_double (const octave_value& value) { const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (value)).storage (); Matrix result (checked_octave_dimension_for_inspection (source.rows ()), checked_octave_dimension_for_inspection (source.columns ())); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) result.xelem (static_cast (row), static_cast (column)) = mpfr_get_d (source.at (row, column).mpfr_data (), MPFR_RNDN); return result; } ComplexMatrix complex_matrix_to_double (const octave_value& value) { const auto& source = octave_mplapack_mpc_matrix_internal::checked_value ( require_matrix_payload (value)).storage (); ComplexMatrix result ( checked_octave_dimension_for_inspection (source.rows ()), checked_octave_dimension_for_inspection (source.columns ())); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) result.xelem (static_cast (row), static_cast (column)) = Complex (source.at (row, column).real_to_double (), source.at (row, column).imag_to_double ()); return result; } std::string matrix_display_text (const octave_value& value) { const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (value)).storage (); return octave_mplapack::format_matrix (source); } octave_scalar_map value_shape_info (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload); octave_scalar_map info; info.assign ("rows", octave_uint64 (1)); info.assign ("columns", octave_uint64 (1)); info.assign ("numel", octave_uint64 (1)); info.assign ("precision_bits", octave_uint64 (scalar.storage ().precision_bits ())); info.assign ("is_matrix", false); info.assign ("is_empty", false); info.assign ("is_complex", true); return info; } if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { const auto& matrix = octave_mplapack_mpc_matrix_internal::checked_value (payload); const auto& storage = matrix.storage (); octave_scalar_map info; info.assign ("rows", octave_uint64 (storage.rows ())); info.assign ("columns", octave_uint64 (storage.columns ())); info.assign ("numel", octave_uint64 (storage.numel ())); info.assign ("precision_bits", octave_uint64 (storage.precision_bits ())); info.assign ("is_matrix", true); info.assign ("is_empty", storage.numel () == 0); info.assign ("is_complex", true); return info; } octave_scalar_map info; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload); info.assign ("rows", octave_uint64 (1)); info.assign ("columns", octave_uint64 (1)); info.assign ("numel", octave_uint64 (1)); info.assign ("precision_bits", octave_uint64 (scalar.storage ().precision_bits ())); info.assign ("is_matrix", false); info.assign ("is_empty", false); info.assign ("is_complex", false); return info; } const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value (payload); const auto& storage = matrix.storage (); info.assign ("rows", octave_uint64 (storage.rows ())); info.assign ("columns", octave_uint64 (storage.columns ())); info.assign ("numel", octave_uint64 (storage.numel ())); info.assign ("precision_bits", octave_uint64 (storage.precision_bits ())); info.assign ("is_matrix", true); info.assign ("is_empty", storage.numel () == 0); info.assign ("is_complex", false); return info; } enum class ComplexScalarBinaryOperation { add, subtract, multiply, divide, power }; bool is_complex_arithmetic_operand (const octave_value& value) { if (is_mp_value (value)) return is_complex_payload (value); return value.is_double_type () && ! value.isreal (); } mpfr_prec_t arithmetic_mp_precision (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) return octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage ().precision_bits (); if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) return octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage ().precision_bits (); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ().precision_bits (); return octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage ().precision_bits (); } struct PreparedComplexArithmeticOperand { octave_value payload; std::optional scalar_owned; std::optional matrix_owned; octave_mplapack::MpcElementwiseOperand view; }; PreparedComplexArithmeticOperand prepare_complex_arithmetic_operand (const octave_value& value, mpfr_prec_t operation_precision) { PreparedComplexArithmeticOperand prepared; if (is_mp_value (value)) { prepared.payload = require_mp_payload (value); if (prepared.payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) prepared.view = octave_mplapack::MpcElementwiseOperand::from_real_scalar ( octave_mplapack_mpfr_scalar_internal::checked_value ( prepared.payload).storage ()); else if (prepared.payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) prepared.view = octave_mplapack::MpcElementwiseOperand::from_real_matrix ( octave_mplapack_mpfr_matrix_internal::checked_value ( prepared.payload).storage ()); else if (prepared.payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) prepared.view = octave_mplapack::MpcElementwiseOperand::from_complex_scalar ( octave_mplapack_mpc_scalar_internal::checked_value ( prepared.payload).storage ()); else prepared.view = octave_mplapack::MpcElementwiseOperand::from_complex_matrix ( octave_mplapack_mpc_matrix_internal::checked_value ( prepared.payload).storage ()); return prepared; } if (! value.is_double_type ()) error_with_id ("mplapack:mp:UnsupportedOperand", "complex element-wise arithmetic supports mp and double operands"); if (value.is_real_scalar () || value.is_complex_scalar ()) { const Complex scalar = value.complex_value (); prepared.scalar_owned.emplace (scalar.real (), scalar.imag (), operation_precision); prepared.view = octave_mplapack::MpcElementwiseOperand::from_complex_scalar ( *prepared.scalar_owned); return prepared; } if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "only two-dimensional matrix operands are supported"); prepared.matrix_owned.emplace ( make_complex_double_matrix_storage (value, operation_precision)); prepared.view = octave_mplapack::MpcElementwiseOperand::from_complex_matrix ( *prepared.matrix_owned); return prepared; } octave_value complex_scalar_binary_operation (const octave_value& lhs_value, const octave_value& rhs_value, ComplexScalarBinaryOperation operation) { mpfr_prec_t operation_precision = 0; if (is_mp_value (lhs_value)) operation_precision = arithmetic_mp_precision (lhs_value); if (is_mp_value (rhs_value)) operation_precision = std::max (operation_precision, arithmetic_mp_precision (rhs_value)); if (operation_precision == 0) operation_precision = octave_mplapack::default_precision_bits (); const auto native_operation = [&] () { switch (operation) { case ComplexScalarBinaryOperation::add: return octave_mplapack::MpcElementwiseBinaryOperation::add; case ComplexScalarBinaryOperation::subtract: return octave_mplapack::MpcElementwiseBinaryOperation::subtract; case ComplexScalarBinaryOperation::multiply: return octave_mplapack::MpcElementwiseBinaryOperation::multiply; case ComplexScalarBinaryOperation::divide: return octave_mplapack::MpcElementwiseBinaryOperation::divide; case ComplexScalarBinaryOperation::power: return octave_mplapack::MpcElementwiseBinaryOperation::power; } throw std::logic_error ("unknown complex element-wise operation"); } (); try { auto lhs = prepare_complex_arithmetic_operand (lhs_value, operation_precision); auto rhs = prepare_complex_arithmetic_operand (rhs_value, operation_precision); return make_complex_inspection_result ( octave_mplapack::mpc_matrix_elementwise_binary ( lhs.view, rhs.view, native_operation)); } catch (const std::invalid_argument& exception) { const std::string message = exception.what (); if (message.find ("nonconformant") != std::string::npos) error_with_id ("mplapack:mp:DimensionMismatch", "%s", exception.what ()); error_with_id ("mplapack:mp:UnsupportedOperand", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:ArithmeticError", "%s", exception.what ()); } return octave_value (); } struct PreparedScriptLogicOperand { std::optional real_scalar_owned; std::optional real_matrix_owned; std::optional complex_scalar_owned; std::optional complex_matrix_owned; octave_mplapack::MpfrElementwiseOperand real_view; octave_mplapack::MpcElementwiseOperand complex_view; }; octave_mplapack::MpfrMatrixStorage make_logic_real_matrix_storage (const octave_value& value, mpfr_prec_t precision) { if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "logical operands support only two-dimensional arrays"); const Matrix input = value.matrix_value (); const std::size_t rows = checked_size_dimension (input.rows ()); const std::size_t columns = checked_size_dimension (input.columns ()); std::vector values; values.reserve (octave_mplapack::MpfrMatrixStorage::checked_element_count ( rows, columns)); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) values.push_back (input.xelem (row, column)); return octave_mplapack::MpfrMatrixStorage (rows, columns, precision, values); } octave_mplapack::MpfrComplexMatrixStorage make_logic_complex_matrix_storage (const octave_value& value, mpfr_prec_t precision) { if (value.ndims () != 2) error_with_id ("mplapack:mp:MatrixUnsupported", "logical operands support only two-dimensional arrays"); const ComplexMatrix input = value.complex_matrix_value (); const std::size_t rows = checked_size_dimension (input.rows ()); const std::size_t columns = checked_size_dimension (input.columns ()); std::vector> values; values.reserve (octave_mplapack::MpfrComplexMatrixStorage:: checked_element_count (rows, columns)); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) values.emplace_back (input.xelem (row, column).real (), input.xelem (row, column).imag ()); return octave_mplapack::MpfrComplexMatrixStorage ( rows, columns, precision, values); } PreparedScriptLogicOperand prepare_script_logic_operand (const octave_value& value, mpfr_prec_t precision, bool complex_mode) { PreparedScriptLogicOperand prepared; if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (complex_mode) { if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) prepared.complex_view = octave_mplapack::MpcElementwiseOperand::from_complex_scalar ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ()); else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) prepared.complex_view = octave_mplapack::MpcElementwiseOperand::from_complex_matrix ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage ()); else if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) prepared.complex_view = octave_mplapack::MpcElementwiseOperand::from_real_scalar ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage ()); else prepared.complex_view = octave_mplapack::MpcElementwiseOperand::from_real_matrix ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage ()); } else if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) prepared.real_view = octave_mplapack::MpfrElementwiseOperand::from_scalar ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage ()); else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) prepared.real_view = octave_mplapack::MpfrElementwiseOperand::from_matrix ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage ()); else error_with_id ("mplapack:mp:UnsupportedOperand", "real logical operation cannot consume a complex mp value"); return prepared; } if ((! value.isnumeric () && ! value.islogical ()) || value.is_string ()) error_with_id ("mplapack:mp:UnsupportedOperand", "logical operations support mp and builtin numeric operands"); if (! complex_mode && value.isreal ()) { if (value.is_real_scalar ()) { prepared.real_scalar_owned.emplace (value.double_value (), precision); prepared.real_view = octave_mplapack::MpfrElementwiseOperand::from_scalar ( *prepared.real_scalar_owned); } else { prepared.real_matrix_owned.emplace ( make_logic_real_matrix_storage (value, precision)); prepared.real_view = octave_mplapack::MpfrElementwiseOperand::from_matrix ( *prepared.real_matrix_owned); } return prepared; } if (value.is_real_scalar ()) { prepared.real_scalar_owned.emplace (value.double_value (), precision); prepared.complex_view = octave_mplapack::MpcElementwiseOperand::from_real_scalar ( *prepared.real_scalar_owned); } else if (value.isreal ()) { prepared.real_matrix_owned.emplace ( make_logic_real_matrix_storage (value, precision)); prepared.complex_view = octave_mplapack::MpcElementwiseOperand::from_real_matrix ( *prepared.real_matrix_owned); } else if (value.is_complex_scalar ()) { const Complex input = value.complex_value (); prepared.complex_scalar_owned.emplace ( input.real (), input.imag (), precision); prepared.complex_view = octave_mplapack::MpcElementwiseOperand::from_complex_scalar ( *prepared.complex_scalar_owned); } else { prepared.complex_matrix_owned.emplace ( make_logic_complex_matrix_storage (value, precision)); prepared.complex_view = octave_mplapack::MpcElementwiseOperand::from_complex_matrix ( *prepared.complex_matrix_owned); } return prepared; } octave_value script_logical_result (const octave_mplapack::MpScriptLogicalResult& result) { if (result.rows == 1 && result.columns == 1) return octave_value (result.values.at (0) != 0); boolMatrix logicals (checked_octave_dimension_for_inspection (result.rows), checked_octave_dimension_for_inspection (result.columns)); for (std::size_t column = 0; column < result.columns; ++column) for (std::size_t row = 0; row < result.rows; ++row) logicals (static_cast (row), static_cast (column)) = result.values.at (row + column * result.rows) != 0; return octave_value (logicals); } mpfr_prec_t script_logic_precision (const octave_value& lhs, const octave_value& rhs) { mpfr_prec_t precision = 0; if (is_mp_value (lhs)) precision = arithmetic_mp_precision (lhs); if (is_mp_value (rhs)) precision = std::max (precision, arithmetic_mp_precision (rhs)); return precision == 0 ? octave_mplapack::default_precision_bits () : precision; } octave_value script_compare_operation ( const octave_value& lhs_value, const octave_value& rhs_value, octave_mplapack::MpScriptComparisonOperation operation) { if (! is_mp_value (lhs_value) && ! is_mp_value (rhs_value)) error_with_id ("mplapack:mp:UnsupportedOperand", "comparison requires at least one mp operand"); const bool complex_mode = is_complex_arithmetic_operand (lhs_value) || is_complex_arithmetic_operand (rhs_value); const mpfr_prec_t precision = script_logic_precision (lhs_value, rhs_value); try { auto lhs = prepare_script_logic_operand (lhs_value, precision, complex_mode); auto rhs = prepare_script_logic_operand (rhs_value, precision, complex_mode); const auto result = complex_mode ? octave_mplapack::mpc_script_compare (lhs.complex_view, rhs.complex_view, operation) : octave_mplapack::mpfr_script_compare (lhs.real_view, rhs.real_view, operation); return script_logical_result (result); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:ComparisonUnsupported", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:ComparisonError", "%s", exception.what ()); } return octave_value (); } octave_value script_logical_operation ( const octave_value& lhs_value, const octave_value& rhs_value, octave_mplapack::MpScriptLogicalOperation operation) { if (! is_mp_value (lhs_value) && ! is_mp_value (rhs_value)) error_with_id ("mplapack:mp:UnsupportedOperand", "logical operation requires at least one mp operand"); const bool complex_mode = is_complex_arithmetic_operand (lhs_value) || is_complex_arithmetic_operand (rhs_value); const mpfr_prec_t precision = script_logic_precision (lhs_value, rhs_value); try { auto lhs = prepare_script_logic_operand (lhs_value, precision, complex_mode); auto rhs = prepare_script_logic_operand (rhs_value, precision, complex_mode); const auto result = complex_mode ? octave_mplapack::mpc_script_logical_binary ( lhs.complex_view, rhs.complex_view, operation) : octave_mplapack::mpfr_script_logical_binary ( lhs.real_view, rhs.real_view, operation); return script_logical_result (result); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:LogicalUnsupported", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:LogicalError", "%s", exception.what ()); } return octave_value (); } octave_value script_logical_not_operation (const octave_value& value) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:UnsupportedOperand", "logical negation requires an mp operand"); const mpfr_prec_t precision = arithmetic_mp_precision (value); try { auto operand = prepare_script_logic_operand ( value, precision, is_complex_payload (value)); const auto source = is_complex_payload (value) ? octave_mplapack::mpc_script_logical (operand.complex_view) : octave_mplapack::mpfr_script_logical (operand.real_view); auto result = source; for (auto& entry : result.values) entry = entry == 0; return script_logical_result (result); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:LogicalError", "%s", exception.what ()); } return octave_value (); } enum class ScalarBinaryOperation { add, subtract, multiply, divide, power }; bool mpfr_elementwise_power_requires_complex ( const octave_mplapack::MpfrElementwiseOperand& lhs, const octave_mplapack::MpfrElementwiseOperand& rhs) { const std::size_t result_rows = std::max (lhs.rows (), rhs.rows ()); const std::size_t result_columns = std::max (lhs.columns (), rhs.columns ()); if ((lhs.rows () != rhs.rows () && lhs.rows () != 1 && rhs.rows () != 1) || (lhs.columns () != rhs.columns () && lhs.columns () != 1 && rhs.columns () != 1)) throw std::invalid_argument ("nonconformant dimensions for power"); for (std::size_t column = 0; column < result_columns; ++column) for (std::size_t row = 0; row < result_rows; ++row) { const auto& base = lhs.at (lhs.rows () == 1 ? 0 : row, lhs.columns () == 1 ? 0 : column); const auto& exponent = rhs.at (rhs.rows () == 1 ? 0 : row, rhs.columns () == 1 ? 0 : column); if (octave_mplapack::mpfr_script_power_requires_complex ( base.mpfr_data (), exponent.mpfr_data ())) return true; } return false; } octave_mplapack::MpfrScalarStorage apply_binary_operation (ScalarBinaryOperation operation, const octave_mplapack::MpfrScalarStorage& lhs, const octave_mplapack::MpfrScalarStorage& rhs) { switch (operation) { case ScalarBinaryOperation::add: return lhs.add (rhs); case ScalarBinaryOperation::subtract: return lhs.subtract (rhs); case ScalarBinaryOperation::multiply: return lhs.multiply (rhs); case ScalarBinaryOperation::divide: return lhs.divide (rhs); case ScalarBinaryOperation::power: return lhs.power (rhs); } throw std::logic_error ("unknown scalar binary operation"); } octave_value scalar_binary_operation (const octave_value& lhs_value, const octave_value& rhs_value, ScalarBinaryOperation operation) { if (is_complex_arithmetic_operand (lhs_value) || is_complex_arithmetic_operand (rhs_value)) { const auto complex_operation = [&] () { switch (operation) { case ScalarBinaryOperation::add: return ComplexScalarBinaryOperation::add; case ScalarBinaryOperation::subtract: return ComplexScalarBinaryOperation::subtract; case ScalarBinaryOperation::multiply: return ComplexScalarBinaryOperation::multiply; case ScalarBinaryOperation::divide: return ComplexScalarBinaryOperation::divide; case ScalarBinaryOperation::power: return ComplexScalarBinaryOperation::power; } throw std::logic_error ("unknown complex element-wise operation"); } (); return complex_scalar_binary_operation (lhs_value, rhs_value, complex_operation); } const bool lhs_is_mp = is_mp_value (lhs_value); const bool rhs_is_mp = is_mp_value (rhs_value); const bool lhs_is_matrix = lhs_is_mp && is_matrix_payload (lhs_value); const bool rhs_is_matrix = rhs_is_mp && is_matrix_payload (rhs_value); const bool lhs_is_double_matrix = is_double_matrix_operand (lhs_value); const bool rhs_is_double_matrix = is_double_matrix_operand (rhs_value); if (lhs_is_matrix || rhs_is_matrix || lhs_is_double_matrix || rhs_is_double_matrix) { const auto native_operation = [&] () { switch (operation) { case ScalarBinaryOperation::add: return octave_mplapack::MpfrElementwiseBinaryOperation::add; case ScalarBinaryOperation::subtract: return octave_mplapack::MpfrElementwiseBinaryOperation::subtract; case ScalarBinaryOperation::multiply: return octave_mplapack::MpfrElementwiseBinaryOperation::multiply; case ScalarBinaryOperation::divide: return octave_mplapack::MpfrElementwiseBinaryOperation::divide; case ScalarBinaryOperation::power: return octave_mplapack::MpfrElementwiseBinaryOperation::power; } throw std::logic_error ("unknown element-wise operation"); } (); const bool lhs_is_complex_double = lhs_value.is_double_type () && ! lhs_value.isreal (); const bool rhs_is_complex_double = rhs_value.is_double_type () && ! rhs_value.isreal (); if (lhs_is_complex_double || rhs_is_complex_double) error_with_id ("mplapack:mp:ComplexUnsupported", "complex element-wise arithmetic is not supported"); struct PreparedOperand { octave_value payload; std::optional scalar_owned; std::optional matrix_owned; octave_mplapack::MpfrElementwiseOperand view; }; auto precision_of_mp = [] (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) return octave_mplapack_mpfr_scalar_internal::checked_value ( payload).storage ().precision_bits (); return octave_mplapack_mpfr_matrix_internal::checked_value ( payload).storage ().precision_bits (); }; if (! lhs_is_mp && ! rhs_is_mp) error_with_id ("mplapack:mp:UnsupportedOperand", "element-wise arithmetic requires at least one mp operand"); mpfr_prec_t operation_precision = 0; if (lhs_is_mp) operation_precision = precision_of_mp (lhs_value); if (rhs_is_mp) operation_precision = std::max (operation_precision, precision_of_mp (rhs_value)); auto prepare = [operation_precision] (const octave_value& value) { PreparedOperand prepared; if (is_mp_value (value)) { prepared.payload = require_mp_payload (value); return prepared; } if (value.is_double_type ()) { if (! value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex element-wise arithmetic is not supported"); if (value.is_real_scalar ()) { prepared.scalar_owned.emplace (value.double_value (), operation_precision); } else { prepared.matrix_owned.emplace ( make_double_matrix_storage (value, operation_precision)); } return prepared; } error_with_id ("mplapack:mp:UnsupportedOperand", "element-wise arithmetic supports mp and real double operands"); return prepared; }; try { PreparedOperand lhs = prepare (lhs_value); PreparedOperand rhs = prepare (rhs_value); auto bind = [] (PreparedOperand& prepared) { if (prepared.scalar_owned) prepared.view = octave_mplapack::MpfrElementwiseOperand::from_scalar ( *prepared.scalar_owned); else if (prepared.matrix_owned) prepared.view = octave_mplapack::MpfrElementwiseOperand::from_matrix ( *prepared.matrix_owned); else if (prepared.payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( prepared.payload).storage (); prepared.view = octave_mplapack::MpfrElementwiseOperand::from_scalar ( scalar); } else { const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value ( prepared.payload).storage (); prepared.view = octave_mplapack::MpfrElementwiseOperand::from_matrix ( matrix); } }; bind (lhs); bind (rhs); if (operation == ScalarBinaryOperation::power && mpfr_elementwise_power_requires_complex (lhs.view, rhs.view)) return complex_scalar_binary_operation (lhs_value, rhs_value, ComplexScalarBinaryOperation::power); auto result = octave_mplapack::mpfr_matrix_elementwise_binary ( lhs.view, rhs.view, native_operation); if (result.rows () == 1 && result.columns () == 1) return make_internal_scalar ( octave_mplapack::MpfrScalarStorage ( std::move (result.at (0, 0)))); return make_internal_matrix (std::move (result)); } catch (const std::invalid_argument& exception) { const std::string message = exception.what (); if (message.find ("nonconformant") != std::string::npos) error_with_id ("mplapack:mp:DimensionMismatch", "%s", exception.what ()); error_with_id ("mplapack:mp:UnsupportedOperand", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:ArithmeticError", "%s", exception.what ()); } return octave_value (); } if (operation == ScalarBinaryOperation::power) { if (lhs_is_mp && rhs_is_mp) { const auto& lhs = octave_mplapack_mpfr_scalar_internal::checked_value ( require_arithmetic_mp_payload (lhs_value)).storage (); const auto& rhs = octave_mplapack_mpfr_scalar_internal::checked_value ( require_arithmetic_mp_payload (rhs_value)).storage (); if (octave_mplapack::mpfr_script_power_requires_complex ( lhs.native_value ().mpfr_data (), rhs.native_value ().mpfr_data ())) return complex_scalar_binary_operation ( lhs_value, rhs_value, ComplexScalarBinaryOperation::power); } else if (lhs_is_mp) { const auto& lhs = octave_mplapack_mpfr_scalar_internal::checked_value ( require_arithmetic_mp_payload (lhs_value)).storage (); const octave_mplapack::MpfrScalarStorage rhs ( require_arithmetic_double (rhs_value), lhs.precision_bits ()); if (octave_mplapack::mpfr_script_power_requires_complex ( lhs.native_value ().mpfr_data (), rhs.native_value ().mpfr_data ())) return complex_scalar_binary_operation ( lhs_value, rhs_value, ComplexScalarBinaryOperation::power); } else if (rhs_is_mp) { const auto& rhs = octave_mplapack_mpfr_scalar_internal::checked_value ( require_arithmetic_mp_payload (rhs_value)).storage (); const octave_mplapack::MpfrScalarStorage lhs ( require_arithmetic_double (lhs_value), rhs.precision_bits ()); if (octave_mplapack::mpfr_script_power_requires_complex ( lhs.native_value ().mpfr_data (), rhs.native_value ().mpfr_data ())) return complex_scalar_binary_operation ( lhs_value, rhs_value, ComplexScalarBinaryOperation::power); } } if (! lhs_is_mp && ! rhs_is_mp) error_with_id ("mplapack:mp:UnsupportedOperand", "scalar arithmetic requires at least one mp operand"); if (lhs_is_mp && rhs_is_mp) { const octave_value lhs_payload = require_arithmetic_mp_payload (lhs_value); const octave_value rhs_payload = require_arithmetic_mp_payload (rhs_value); const auto& lhs = octave_mplapack_mpfr_scalar_internal::checked_value ( lhs_payload).storage (); const auto& rhs = octave_mplapack_mpfr_scalar_internal::checked_value ( rhs_payload).storage (); try { return make_internal_scalar ( apply_binary_operation (operation, lhs, rhs)); } catch (const std::exception& exception) { error_with_id ("mplapack:ArithmeticError", "%s", exception.what ()); } } if (lhs_is_mp) { const octave_value lhs_payload = require_arithmetic_mp_payload (lhs_value); const auto& lhs = octave_mplapack_mpfr_scalar_internal::checked_value ( lhs_payload).storage (); const double rhs_double = require_arithmetic_double (rhs_value); try { const octave_mplapack::MpfrScalarStorage rhs ( rhs_double, lhs.precision_bits ()); return make_internal_scalar ( apply_binary_operation (operation, lhs, rhs)); } catch (const std::exception& exception) { error_with_id ("mplapack:ArithmeticError", "%s", exception.what ()); } } const octave_value rhs_payload = require_arithmetic_mp_payload (rhs_value); const auto& rhs = octave_mplapack_mpfr_scalar_internal::checked_value ( rhs_payload).storage (); const double lhs_double = require_arithmetic_double (lhs_value); try { const octave_mplapack::MpfrScalarStorage lhs ( lhs_double, rhs.precision_bits ()); return make_internal_scalar ( apply_binary_operation (operation, lhs, rhs)); } catch (const std::exception& exception) { error_with_id ("mplapack:ArithmeticError", "%s", exception.what ()); } return octave_value (); } octave_value complex_mtimes_operation (const octave_value& lhs_value, const octave_value& rhs_value) { mpfr_prec_t operation_precision = 0; if (is_mp_value (lhs_value)) operation_precision = arithmetic_mp_precision (lhs_value); if (is_mp_value (rhs_value)) operation_precision = std::max (operation_precision, arithmetic_mp_precision (rhs_value)); if (operation_precision == 0) operation_precision = octave_mplapack::default_precision_bits (); struct PreparedOperand { std::optional scalar; std::optional matrix; }; const auto prepare = [operation_precision] (const octave_value& value) { PreparedOperand prepared; if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) prepared.scalar.emplace ( octave_mplapack::mplapack_mpc_scalar_from_real ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (), operation_precision)); else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) prepared.matrix.emplace ( octave_mplapack::mplapack_mpc_matrix_from_real ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (), operation_precision)); else if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) prepared.scalar.emplace ( octave_mplapack::mplapack_mpc_scalar_copy_at_precision ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (), operation_precision)); else prepared.matrix.emplace ( octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (), operation_precision)); return prepared; } if (! value.is_double_type ()) error_with_id ("mplapack:mp:UnsupportedOperand", "complex matrix multiplication supports mp and double operands"); if (value.is_real_scalar () || value.is_complex_scalar ()) { const Complex scalar = value.complex_value (); prepared.scalar.emplace (scalar.real (), scalar.imag (), operation_precision); } else prepared.matrix.emplace (make_complex_double_matrix_storage ( value, operation_precision)); return prepared; }; try { const PreparedOperand lhs = prepare (lhs_value); const PreparedOperand rhs = prepare (rhs_value); if (lhs.matrix && rhs.matrix) return make_complex_inspection_result ( octave_mplapack::mplapack_mpc_matrix_multiply (*lhs.matrix, *rhs.matrix)); if (lhs.matrix && rhs.scalar) return make_complex_inspection_result ( octave_mplapack::mplapack_mpc_matrix_scale (*lhs.matrix, *rhs.scalar)); if (lhs.scalar && rhs.matrix) return make_complex_inspection_result ( octave_mplapack::mplapack_mpc_matrix_scale (*rhs.matrix, *lhs.scalar)); return make_internal_complex_scalar ( octave_mplapack::mplapack_mpc_scalar_multiply (*lhs.scalar, *rhs.scalar)); } catch (const std::invalid_argument& exception) { const std::string message = exception.what (); if (message.find ("dimension mismatch") != std::string::npos) error_with_id ("mplapack:mp:DimensionMismatch", "%s", exception.what ()); error_with_id ("mplapack:mp:UnsupportedOperand", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:MtimesError", "%s", exception.what ()); } return octave_value (); } octave_value complex_mldivide_operation (const octave_value& lhs_value, const octave_value& rhs_value, bool force_rank_revealing = false) { mpfr_prec_t operation_precision = 0; if (is_mp_value (lhs_value)) operation_precision = arithmetic_mp_precision (lhs_value); if (is_mp_value (rhs_value)) operation_precision = std::max (operation_precision, arithmetic_mp_precision (rhs_value)); if (operation_precision == 0) operation_precision = octave_mplapack::default_precision_bits (); struct PreparedOperand { std::optional scalar; std::optional matrix; }; const auto prepare = [operation_precision] (const octave_value& value) { PreparedOperand prepared; if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) prepared.scalar.emplace ( octave_mplapack::mplapack_mpc_scalar_from_real ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (), operation_precision)); else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) prepared.matrix.emplace ( octave_mplapack::mplapack_mpc_matrix_from_real ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (), operation_precision)); else if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) prepared.scalar.emplace ( octave_mplapack::mplapack_mpc_scalar_copy_at_precision ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (), operation_precision)); else prepared.matrix.emplace ( octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (), operation_precision)); return prepared; } if (! value.is_double_type ()) error_with_id ("mplapack:mp:UnsupportedOperand", "complex left division supports mp and double operands"); if (value.is_real_scalar () || value.is_complex_scalar ()) { const Complex scalar = value.complex_value (); prepared.scalar.emplace (scalar.real (), scalar.imag (), operation_precision); } else prepared.matrix.emplace (make_complex_double_matrix_storage ( value, operation_precision)); return prepared; }; try { const PreparedOperand lhs = prepare (lhs_value); const PreparedOperand rhs = prepare (rhs_value); if (lhs.scalar) { if (rhs.matrix) return make_complex_inspection_result ( octave_mplapack::mpc_matrix_elementwise_binary ( octave_mplapack::MpcElementwiseOperand::from_complex_matrix ( *rhs.matrix), octave_mplapack::MpcElementwiseOperand::from_complex_scalar ( *lhs.scalar), octave_mplapack::MpcElementwiseBinaryOperation::divide)); return make_complex_inspection_result ( octave_mplapack::mpc_matrix_elementwise_binary ( octave_mplapack::MpcElementwiseOperand::from_complex_scalar ( *rhs.scalar), octave_mplapack::MpcElementwiseOperand::from_complex_scalar ( *lhs.scalar), octave_mplapack::MpcElementwiseBinaryOperation::divide)); } std::optional rhs_matrix; if (rhs.matrix) rhs_matrix.emplace (*rhs.matrix); else { if (lhs.matrix->rows () != 1) throw std::invalid_argument ( "matrix left division requires a dense right-hand matrix"); rhs_matrix.emplace (1, 1, operation_precision); mpc_set (rhs_matrix->at (0, 0).mpc_data (), rhs.scalar->native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } if (lhs.matrix->rows () == lhs.matrix->columns () && ! force_rank_revealing) return make_complex_inspection_result ( octave_mplapack::mplapack_mpc_matrix_solve (*lhs.matrix, *rhs_matrix)); return make_complex_inspection_result ( octave_mplapack::mplapack_mpc_matrix_rank_solve ( *lhs.matrix, *rhs_matrix).solution); } catch (const octave_mplapack::MpcCgelsyError& exception) { if (exception.kind () == octave_mplapack::MpcCgelsyError::Kind::convergence) error_with_id ("mplapack:mp:ConvergenceFailure", "MPLAPACK Cgelsy failed to converge (info %d)", static_cast (exception.info ())); if (exception.kind () == octave_mplapack::MpcCgelsyError::Kind::invalid_argument) error_with_id ("mplapack:mp:RankRevealingError", "MPLAPACK Cgelsy rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:RankRevealingInternalError", "%s", exception.what ()); } catch (const octave_mplapack::MpcCgesvError& exception) { if (exception.kind () == octave_mplapack::MpcCgesvError::Kind::singular) error_with_id ("mplapack:mp:SingularMatrix", "mp left division: complex coefficient matrix is singular"); error_with_id ("mplapack:mp:CgesvError", "MPLAPACK Cgesv rejected argument %d", -static_cast (exception.info ())); } catch (const std::invalid_argument& exception) { const std::string message = exception.what (); if (message.find ("square") != std::string::npos) error_with_id ("mplapack:mp:NonSquareMatrix", "%s", exception.what ()); if (message.find ("dimensions") != std::string::npos) error_with_id ("mplapack:mp:DimensionMismatch", "%s", exception.what ()); error_with_id ("mplapack:mp:UnsupportedOperand", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:CgesvError", "%s", exception.what ()); } return octave_value (); } octave_mplapack::MpfrNormRequest parse_norm_request (const octave_value& value) { octave_mplapack::MpfrNormRequest request; if (value.is_string ()) { const std::string option = require_string (value, "norm option"); if (option != "fro") error_with_id ("mplapack:mp:InvalidOption", "norm string option must be \"fro\""); request.kind = octave_mplapack::MpfrNormRequest::Kind::frobenius; return request; } if (! value.is_real_scalar () || value.islogical ()) error_with_id ("mplapack:mp:InvalidOption", "norm p must be a real scalar or \"fro\""); const double exponent = value.double_value (); request.exponent = exponent; if (std::isnan (exponent)) error_with_id ("mplapack:mp:InvalidOption", "norm p must not be NaN"); if (std::isinf (exponent)) { request.kind = exponent > 0 ? octave_mplapack::MpfrNormRequest::Kind::infinity : octave_mplapack::MpfrNormRequest::Kind::negative_infinity; return request; } if (exponent == 0.0) { request.kind = octave_mplapack::MpfrNormRequest::Kind::zero; return request; } if (exponent == 1.0) { request.kind = octave_mplapack::MpfrNormRequest::Kind::one; return request; } if (exponent == 2.0) { request.kind = octave_mplapack::MpfrNormRequest::Kind::two; return request; } if (exponent > 0.0) { request.kind = octave_mplapack::MpfrNormRequest::Kind::finite; return request; } error_with_id ("mplapack:mp:InvalidOption", "norm p must be nonnegative, Inf, or -Inf"); return request; } octave_value mp_norm_operation (const octave_value& value, const octave_value& p) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "norm expects one mp value"); const auto request = parse_norm_request (p); const octave_value payload = require_mp_payload (value); try { if (is_complex_payload (value)) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("norm expects a valid complex mp value"); return make_internal_scalar ( octave_mplapack::mplapack_mpc_norm (*input, request)); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("norm expects a valid real mp value"); return make_internal_scalar ( octave_mplapack::mplapack_mpfr_norm (*input, request)); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidOption", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:NormError", "%s", exception.what ()); } return octave_value (); } octave_value mp_det_operation (const octave_value& value) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "det expects one mp value"); const octave_value payload = require_mp_payload (value); try { if (is_complex_payload (value)) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("det expects a valid complex mp value"); return make_internal_complex_scalar ( octave_mplapack::mplapack_mpc_matrix_det (*input)); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("det expects a valid real mp value"); return make_internal_scalar ( octave_mplapack::mplapack_mpfr_matrix_det (*input)); } catch (const octave_mplapack::MpfrDetInvError& exception) { if (exception.kind () == octave_mplapack::MpfrDetInvError::Kind::invalid_argument) error_with_id ("mplapack:mp:DetError", "MPLAPACK Rgetrf rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:DetError", "%s", exception.what ()); } catch (const octave_mplapack::MpcDetInvError& exception) { if (exception.kind () == octave_mplapack::MpcDetInvError::Kind::invalid_argument) error_with_id ("mplapack:mp:DetError", "MPLAPACK Cgetrf rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:DetError", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { if (std::string (exception.what ()).find ("square") != std::string::npos) error_with_id ("mplapack:mp:NonSquareMatrix", "%s", exception.what ()); error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:DetError", "%s", exception.what ()); } return octave_value (); } octave_value mp_rank_operation (const octave_value& value, const octave_value *tolerance_value) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "rank expects one real or complex mp matrix"); std::optional tolerance; if (tolerance_value) { const octave_value& supplied = *tolerance_value; if (is_mp_value (supplied)) { const octave_value payload = require_mp_payload (supplied); if (payload.type_id () != octave_mplapack_mpfr_scalar_internal::static_type_id ()) error_with_id ("mplapack:mp:InvalidOption", "rank tolerance must be a real scalar"); const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); tolerance.emplace (scalar.native_value ()); } else if (supplied.isnumeric () && ! supplied.islogical () && supplied.isreal () && supplied.is_real_scalar ()) tolerance.emplace (supplied.double_value (), octave_mplapack::default_precision_bits ()); else error_with_id ("mplapack:mp:InvalidOption", "rank tolerance must be a real scalar"); } const octave_value payload = require_mp_payload (value); try { if (is_complex_payload (value)) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("rank expects a valid complex mp value"); const auto result = octave_mplapack::mplapack_mpc_matrix_rank ( *input, tolerance ? &*tolerance : nullptr); return octave_value (static_cast (result)); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("rank expects a valid real mp value"); const auto result = octave_mplapack::mplapack_mpfr_matrix_rank ( *input, tolerance ? &*tolerance : nullptr); return octave_value (static_cast (result)); } catch (const octave_mplapack::MpfrRankConditionError& exception) { error_with_id ("mplapack:mp:RankError", "%s", exception.what ()); } catch (const octave_mplapack::MpcRankConditionError& exception) { error_with_id ("mplapack:mp:RankError", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:RankError", "%s", exception.what ()); } return octave_value (); } octave_mplapack::MpfrConditionKind require_condition_kind (const std::string& text) { if (text == "one") return octave_mplapack::MpfrConditionKind::one; if (text == "two") return octave_mplapack::MpfrConditionKind::two; if (text == "infinity") return octave_mplapack::MpfrConditionKind::infinity; if (text == "frobenius") return octave_mplapack::MpfrConditionKind::frobenius; error_with_id ("mplapack:mp:InvalidOption", "unsupported condition norm"); return octave_mplapack::MpfrConditionKind::two; } octave_value mp_condition_operation (const octave_value& value, octave_mplapack::MpfrConditionKind kind) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "cond expects one real or complex mp matrix"); const octave_value payload = require_mp_payload (value); try { if (is_complex_payload (value)) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("cond expects a valid complex mp value"); return make_internal_scalar ( octave_mplapack::mplapack_mpc_matrix_condition (*input, kind)); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("cond expects a valid real mp value"); return make_internal_scalar ( octave_mplapack::mplapack_mpfr_matrix_condition (*input, kind)); } catch (const octave_mplapack::MpfrRankConditionError& exception) { error_with_id ("mplapack:mp:ConditionError", "%s", exception.what ()); } catch (const octave_mplapack::MpcRankConditionError& exception) { error_with_id ("mplapack:mp:ConditionError", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { if (std::string (exception.what ()).find ("square") != std::string::npos) error_with_id ("mplapack:mp:NonSquareMatrix", "%s", exception.what ()); error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:ConditionError", "%s", exception.what ()); } return octave_value (); } octave_value mp_rcond_operation (const octave_value& value) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "rcond expects one real or complex mp matrix"); const octave_value payload = require_mp_payload (value); try { if (is_complex_payload (value)) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("rcond expects a valid complex mp value"); return make_internal_scalar ( octave_mplapack::mplapack_mpc_matrix_rcond (*input)); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("rcond expects a valid real mp value"); return make_internal_scalar ( octave_mplapack::mplapack_mpfr_matrix_rcond (*input)); } catch (const octave_mplapack::MpfrRankConditionError& exception) { error_with_id ("mplapack:mp:RcondError", "%s", exception.what ()); } catch (const octave_mplapack::MpcRankConditionError& exception) { error_with_id ("mplapack:mp:RcondError", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { if (std::string (exception.what ()).find ("square") != std::string::npos) error_with_id ("mplapack:mp:NonSquareMatrix", "%s", exception.what ()); error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:RcondError", "%s", exception.what ()); } return octave_value (); } octave_value_list mp_det_rcond_operation (const octave_value& value) { return ovl (mp_det_operation (value), mp_rcond_operation (value)); } octave_value mp_inverse_operation (const octave_value& value) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "inv expects one mp value"); const octave_value payload = require_mp_payload (value); try { if (is_complex_payload (value)) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("inv expects a valid complex mp value"); return make_complex_inspection_result ( octave_mplapack::mplapack_mpc_matrix_inverse (*input)); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else throw std::invalid_argument ("inv expects a valid real mp value"); return make_inspection_result ( octave_mplapack::mplapack_mpfr_matrix_inverse (*input)); } catch (const octave_mplapack::MpfrDetInvError& exception) { if (exception.kind () == octave_mplapack::MpfrDetInvError::Kind::singular) error_with_id ("mplapack:mp:SingularMatrix", "inv: input matrix is singular"); if (exception.kind () == octave_mplapack::MpfrDetInvError::Kind::invalid_argument) error_with_id ("mplapack:mp:InvError", "MPLAPACK Rgetri rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:InvError", "%s", exception.what ()); } catch (const octave_mplapack::MpcDetInvError& exception) { if (exception.kind () == octave_mplapack::MpcDetInvError::Kind::singular) error_with_id ("mplapack:mp:SingularMatrix", "inv: input matrix is singular"); if (exception.kind () == octave_mplapack::MpcDetInvError::Kind::invalid_argument) error_with_id ("mplapack:mp:InvError", "MPLAPACK Cgetri rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:InvError", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { if (std::string (exception.what ()).find ("square") != std::string::npos) error_with_id ("mplapack:mp:NonSquareMatrix", "%s", exception.what ()); error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:InvError", "%s", exception.what ()); } return octave_value (); } octave_value make_mtimes_result (octave_mplapack::MpfrMatrixStorage storage) { if (storage.rows () == 1 && storage.columns () == 1) { octave_mplapack::MpfrScalarStorage scalar ( std::move (storage.at (0, 0))); return make_internal_scalar (std::move (scalar)); } return make_internal_matrix (std::move (storage)); } octave_value make_mldivide_result (octave_mplapack::MpfrMatrixStorage storage) { return make_mtimes_result (std::move (storage)); } octave_value_list complex_cholesky_operation (const octave_value& value, bool lower) { const octave_value payload = require_mp_payload (value); std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "chol expects one complex mp value"); try { const auto factor = octave_mplapack::mplapack_mpc_matrix_cholesky (*input, lower); return ovl (make_complex_inspection_result (factor.factor), octave_value (static_cast (factor.info))); } catch (const octave_mplapack::MpcCpotrfError& exception) { if (exception.kind () == octave_mplapack::MpcCpotrfError::Kind::invalid_argument) error_with_id ("mplapack:mp:CpotrfError", "MPLAPACK Cpotrf rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:CpotrfInternalError", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { if (std::string (exception.what ()).find ("square") != std::string::npos) error_with_id ("mplapack:mp:NonSquareMatrix", "%s", exception.what ()); error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:CpotrfError", "%s", exception.what ()); } return ovl (); } octave_value_list mp_cholesky_operation (const octave_value& value, bool lower) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "chol expects one real mp value"); if (is_complex_payload (value)) return complex_cholesky_operation (value, lower); std::optional scalar_matrix; const octave_value payload = require_mp_payload (value); const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "chol expects one real mp value"); try { const auto factor = octave_mplapack::mplapack_mpfr_matrix_cholesky (*input, lower); return ovl (make_mtimes_result (factor.factor), octave_value (static_cast (factor.info))); } catch (const octave_mplapack::MpfrRpotrfError& exception) { if (exception.kind () == octave_mplapack::MpfrRpotrfError::Kind::invalid_argument) error_with_id ("mplapack:mp:RpotrfError", "MPLAPACK Rpotrf rejected argument %d", -exception.info ()); error_with_id ("mplapack:mp:RpotrfInternalError", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { if (std::string (exception.what ()).find ("square") != std::string::npos) error_with_id ("mplapack:mp:NonSquareMatrix", "%s", exception.what ()); error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:CholeskyError", "%s", exception.what ()); } return ovl (); } octave_value_list complex_qr_operation (const octave_value& value, bool economy, bool want_q) { const octave_value payload = require_mp_payload (value); std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "qr expects one complex mp value"); try { const auto factors = octave_mplapack::mplapack_mpc_matrix_qr (*input, economy, want_q); const octave_value r = make_complex_inspection_result (factors.r); if (! want_q) return ovl (r); return ovl (make_complex_inspection_result (factors.q), r); } catch (const octave_mplapack::MpcQrError& exception) { if (exception.kind () == octave_mplapack::MpcQrError::Kind::invalid_argument) error_with_id ("mplapack:mp:QrError", "MPLAPACK complex QR rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:QrInternalError", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:QrError", "%s", exception.what ()); } return ovl (); } octave_value_list mp_qr_operation (const octave_value& value, bool economy, bool want_q) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "qr expects one real mp value"); std::optional scalar_matrix; const octave_value payload = require_mp_payload (value); const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "qr expects one real mp value"); try { const auto factors = octave_mplapack::mplapack_mpfr_matrix_qr ( *input, economy, want_q); const octave_value r = make_mtimes_result (factors.r); if (! want_q) return ovl (r); return ovl (make_mtimes_result (factors.q), r); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:QrError", "%s", exception.what ()); } return ovl (); } octave_value_list mp_svd_operation (const octave_value& value, bool economy, bool want_factors) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "svd expects one real or complex mp value"); const octave_value payload = require_mp_payload (value); const bool complex = is_complex_payload (value); if (complex) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "svd expects one complex mp value"); try { if (! want_factors) return ovl (make_inspection_result ( octave_mplapack::mplapack_mpc_singular_values (*input))); const auto factors = octave_mplapack::mplapack_mpc_matrix_svd (*input, economy); return ovl (make_complex_inspection_result (factors.u), make_inspection_result (factors.s), make_complex_inspection_result (factors.v)); } catch (const octave_mplapack::MpcSvdError& exception) { if (exception.kind () == octave_mplapack::MpcSvdError::Kind::convergence) error_with_id ("mplapack:mp:ConvergenceFailure", "MPLAPACK Cgesvd failed to converge (info %d)", static_cast (exception.info ())); if (exception.kind () == octave_mplapack::MpcSvdError::Kind::invalid_argument) error_with_id ("mplapack:mp:SvdError", "MPLAPACK Cgesvd rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:SvdError", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:SvdError", "%s", exception.what ()); } return ovl (); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "svd expects one real mp value"); try { if (! want_factors) return ovl (make_inspection_result ( octave_mplapack::mplapack_mpfr_singular_values (*input))); const auto factors = octave_mplapack::mplapack_mpfr_matrix_svd (*input, economy); return ovl (make_inspection_result (factors.u), make_inspection_result (factors.s), make_inspection_result (factors.v)); } catch (const octave_mplapack::MpfrSvdError& exception) { if (exception.kind () == octave_mplapack::MpfrSvdError::Kind::convergence) error_with_id ("mplapack:mp:ConvergenceFailure", "MPLAPACK Rgesvd failed to converge (info %d)", static_cast (exception.info ())); if (exception.kind () == octave_mplapack::MpfrSvdError::Kind::invalid_argument) error_with_id ("mplapack:mp:SvdError", "MPLAPACK Rgesvd rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:SvdError", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:SvdError", "%s", exception.what ()); } return ovl (); } octave_value_list mp_structured_eig_operation (const octave_value& value, const std::string& output_mode) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "eig expects one real or complex mp value"); if (output_mode != "values" && output_mode != "matrix" && output_mode != "vector" && output_mode != "diagonal" && output_mode != "left" && output_mode != "left-vector") error_with_id ("mplapack:mp:InvalidArguments", "eig output mode is invalid"); const octave_value payload = require_mp_payload (value); if (is_complex_payload (value)) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "eig expects one complex mp value"); try { const auto result = octave_mplapack::mplapack_mpc_matrix_structured_eig (*input); if (output_mode == "values") return ovl (make_inspection_result (result.eigenvalues)); if (output_mode == "diagonal") return ovl (make_inspection_result (result.diagonal)); const octave_value vectors = make_complex_inspection_result (result.vectors); const octave_value second = output_mode == "vector" || output_mode == "left-vector" ? make_inspection_result (result.eigenvalues) : make_inspection_result (result.diagonal); if (output_mode == "left" || output_mode == "left-vector") return ovl (vectors, second, vectors); return ovl (vectors, second); } catch (const octave_mplapack::MpcStructuredEigError& exception) { if (exception.info () < 0) error_with_id ("mplapack:mp:EigError", "MPLAPACK Cheevd rejected argument %d", -exception.info ()); error_with_id ("mplapack:mp:ConvergenceFailure", "MPLAPACK Cheevd failed to converge (info %d)", exception.info ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:EigError", "%s", exception.what ()); } return ovl (); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "eig expects one real mp value"); try { const auto result = octave_mplapack::mplapack_mpfr_matrix_structured_eig (*input); if (output_mode == "values") return ovl (make_inspection_result (result.eigenvalues)); if (output_mode == "diagonal") return ovl (make_inspection_result (result.diagonal)); const octave_value vectors = make_inspection_result (result.vectors); const octave_value second = output_mode == "vector" || output_mode == "left-vector" ? make_inspection_result (result.eigenvalues) : make_inspection_result (result.diagonal); if (output_mode == "left" || output_mode == "left-vector") return ovl (vectors, second, vectors); return ovl (vectors, second); } catch (const octave_mplapack::MpfrStructuredEigError& exception) { if (exception.info () < 0) error_with_id ("mplapack:mp:EigError", "MPLAPACK Rsyevd rejected argument %d", -exception.info ()); error_with_id ("mplapack:mp:ConvergenceFailure", "MPLAPACK Rsyevd failed to converge (info %d)", exception.info ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:EigError", "%s", exception.what ()); } return ovl (); } bool mp_value_has_structured_eig_shape (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (is_complex_payload (value)) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else return false; return input->rows () == input->columns () && octave_mplapack::mplapack_mpc_matrix_is_exactly_hermitian ( *input); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else return false; return input->rows () == input->columns () && octave_mplapack::mplapack_mpfr_matrix_is_exactly_symmetric (*input); } octave_value_list mp_general_eig_operation (const octave_value& value, const std::string& output_mode, bool balance) { if (output_mode != "values" && output_mode != "matrix" && output_mode != "vector" && output_mode != "diagonal" && output_mode != "left" && output_mode != "left-vector") error_with_id ("mplapack:mp:InvalidArguments", "eig output mode is invalid"); const octave_value payload = require_mp_payload (value); if (is_complex_payload (value)) { std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "eig expects one complex mp value"); try { const auto result = octave_mplapack::mplapack_mpc_matrix_general_eig (*input, balance); if (output_mode == "values") return ovl (make_complex_inspection_result (result.eigenvalues)); if (output_mode == "diagonal") return ovl (make_complex_inspection_result (result.diagonal)); const octave_value vectors = make_complex_inspection_result (result.right_vectors); const octave_value diagonal = make_complex_inspection_result (result.diagonal); if (output_mode == "vector") return ovl (vectors, make_complex_inspection_result (result.eigenvalues)); if (output_mode == "left" || output_mode == "left-vector") { if (output_mode == "left-vector") return ovl (vectors, make_complex_inspection_result (result.eigenvalues), make_complex_inspection_result (result.left_vectors)); return ovl (vectors, diagonal, make_complex_inspection_result (result.left_vectors)); } return ovl (vectors, diagonal); } catch (const octave_mplapack::MpcGeneralEigError& exception) { if (exception.info () < 0) error_with_id ("mplapack:mp:EigError", "MPLAPACK Cgeevx rejected argument %d", -exception.info ()); error_with_id ("mplapack:mp:ConvergenceFailure", "MPLAPACK Cgeevx failed to converge (info %d)", exception.info ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:EigError", "%s", exception.what ()); } return ovl (); } std::optional scalar_matrix; const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "eig expects one real mp value"); try { const auto result = octave_mplapack::mplapack_mpfr_matrix_general_eig (*input, balance); if (output_mode == "values") return ovl (make_complex_inspection_result (result.eigenvalues)); if (output_mode == "diagonal") return ovl (make_complex_inspection_result (result.diagonal)); const octave_value vectors = make_complex_inspection_result (result.right_vectors); const octave_value diagonal = make_complex_inspection_result (result.diagonal); if (output_mode == "vector") return ovl (vectors, make_complex_inspection_result (result.eigenvalues)); if (output_mode == "left" || output_mode == "left-vector") { if (output_mode == "left-vector") return ovl (vectors, make_complex_inspection_result (result.eigenvalues), make_complex_inspection_result (result.left_vectors)); return ovl (vectors, diagonal, make_complex_inspection_result (result.left_vectors)); } return ovl (vectors, diagonal); } catch (const octave_mplapack::MpfrGeneralEigError& exception) { if (exception.info () < 0) error_with_id ("mplapack:mp:EigError", "MPLAPACK Rgeevx rejected argument %d", -exception.info ()); error_with_id ("mplapack:mp:ConvergenceFailure", "MPLAPACK Rgeevx failed to converge (info %d)", exception.info ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:EigError", "%s", exception.what ()); } return ovl (); } octave_value_list generalized_eig_result_to_octave ( const octave_mplapack::MpGeneralizedEigResult& result, const std::string& output_mode) { using RealResult = octave_mplapack::MpGeneralizedRealDefiniteEigResult; using ComplexResult = octave_mplapack::MpGeneralizedComplexDefiniteEigResult; using QzResult = octave_mplapack::MpGeneralizedQzEigResult; if (output_mode == "values") return std::visit ([] (const auto& value) -> octave_value_list { using Result = std::decay_t; if constexpr (std::is_same_v) return ovl (make_complex_inspection_result (value.eigenvalues)); else return ovl (make_inspection_result (value.eigenvalues)); }, result); if (output_mode == "diagonal") return std::visit ([] (const auto& value) -> octave_value_list { using Result = std::decay_t; if constexpr (std::is_same_v) return ovl (make_complex_inspection_result (value.diagonal)); else return ovl (make_inspection_result (value.diagonal)); }, result); return std::visit ([&] (const auto& value) -> octave_value_list { using Result = std::decay_t; const bool vector_output = output_mode == "vector" || output_mode == "left-vector"; if constexpr (std::is_same_v) { const octave_value vectors = make_inspection_result (value.right_vectors); const octave_value second = vector_output ? make_inspection_result (value.eigenvalues) : make_inspection_result (value.diagonal); if (output_mode == "left" || output_mode == "left-vector") return ovl (vectors, second, make_inspection_result (value.left_vectors)); return ovl (vectors, second); } else if constexpr (std::is_same_v) { const octave_value vectors = make_complex_inspection_result (value.right_vectors); const octave_value second = vector_output ? make_inspection_result (value.eigenvalues) : make_inspection_result (value.diagonal); if (output_mode == "left" || output_mode == "left-vector") return ovl (vectors, second, make_complex_inspection_result (value.left_vectors)); return ovl (vectors, second); } else { const octave_value vectors = make_complex_inspection_result (value.right_vectors); const octave_value second = vector_output ? make_complex_inspection_result (value.eigenvalues) : make_complex_inspection_result (value.diagonal); if (output_mode == "left" || output_mode == "left-vector") return ovl (vectors, second, make_complex_inspection_result (value.left_vectors)); return ovl (vectors, second); } }, result); } using GeneralizedMatrix = std::variant< octave_mplapack::MpfrMatrixStorage, octave_mplapack::MpfrComplexMatrixStorage>; GeneralizedMatrix generalized_matrix_payload (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); octave_mplapack::MpfrMatrixStorage matrix (1, 1, scalar.precision_bits ()); mpfr_set (matrix.at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); return matrix; } if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) return octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); octave_mplapack::MpfrComplexMatrixStorage matrix ( 1, 1, scalar.precision_bits ()); mpc_set (matrix.at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return matrix; } if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) return octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); error_with_id ("mplapack:mp:InvalidInput", "generalized eig expects mp matrix operands"); return octave_mplapack::MpfrMatrixStorage (0, 0, octave_mplapack::default_precision_bits ()); } mpfr_prec_t generalized_matrix_precision (const GeneralizedMatrix& matrix) { return std::visit ([] (const auto& value) { return value.precision_bits (); }, matrix); } GeneralizedMatrix generalized_matrix_at_precision (const GeneralizedMatrix& matrix, mpfr_prec_t precision_bits, bool complex_output) { return std::visit ([&] (const auto& value) -> GeneralizedMatrix { if constexpr (std::is_same_v, octave_mplapack::MpfrMatrixStorage>) { if (! complex_output) return octave_mplapack::MpfrMatrixStorage ( value.rows (), value.columns (), precision_bits, value); octave_mplapack::MpfrComplexMatrixStorage converted ( value.rows (), value.columns (), precision_bits); for (std::size_t column = 0; column < value.columns (); ++column) for (std::size_t row = 0; row < value.rows (); ++row) { mpfr_set (mpc_realref (converted.at (row, column).mpc_data ()), value.at (row, column).mpfr_data (), MPFR_RNDN); mpfr_set_zero (mpc_imagref (converted.at (row, column).mpc_data ()), 1); } return converted; } else { if (complex_output && value.precision_bits () == precision_bits) return value; octave_mplapack::MpfrComplexMatrixStorage converted ( value.rows (), value.columns (), precision_bits); for (std::size_t column = 0; column < value.columns (); ++column) for (std::size_t row = 0; row < value.rows (); ++row) mpc_set (converted.at (row, column).mpc_data (), value.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return converted; } }, matrix); } octave_value_list mp_generalized_eig_operation (const octave_value& value_a, const octave_value& value_b, const std::string& output_mode, const std::string& algorithm_name) { if (output_mode != "values" && output_mode != "matrix" && output_mode != "vector" && output_mode != "diagonal" && output_mode != "left" && output_mode != "left-vector") error_with_id ("mplapack:mp:InvalidArguments", "generalized eig output mode is invalid"); if (! is_mp_value (value_a) || ! is_mp_value (value_b)) error_with_id ("mplapack:mp:InvalidInput", "generalized eig expects two mp values"); octave_mplapack::GeneralizedEigAlgorithm algorithm; if (algorithm_name == "auto") algorithm = octave_mplapack::GeneralizedEigAlgorithm::auto_select; else if (algorithm_name == "chol") algorithm = octave_mplapack::GeneralizedEigAlgorithm::chol; else if (algorithm_name == "qz") algorithm = octave_mplapack::GeneralizedEigAlgorithm::qz; else error_with_id ("mplapack:mp:InvalidOption", "generalized eig algorithm must be \"chol\" or \"qz\""); try { auto a = generalized_matrix_payload (value_a); auto b = generalized_matrix_payload (value_b); const bool complex_output = std::holds_alternative (a) || std::holds_alternative (b); const mpfr_prec_t precision = std::max ( generalized_matrix_precision (a), generalized_matrix_precision (b)); a = generalized_matrix_at_precision (a, precision, complex_output); b = generalized_matrix_at_precision (b, precision, complex_output); if (complex_output) return generalized_eig_result_to_octave ( octave_mplapack::mplapack_mpc_matrix_generalized_eig ( std::get (a), std::get (b), algorithm), output_mode); else return generalized_eig_result_to_octave ( octave_mplapack::mplapack_mpfr_matrix_generalized_eig ( std::get (a), std::get (b), algorithm), output_mode); } catch (const octave_mplapack::MpGeneralizedEigError& exception) { if (exception.info () < 0) error_with_id ("mplapack:mp:EigError", "MPLAPACK generalized eig rejected argument %d", -exception.info ()); error_with_id ("mplapack:mp:ConvergenceFailure", "MPLAPACK generalized eig failed (info %d)", exception.info ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:EigError", "%s", exception.what ()); } return ovl (); } octave_value_list mp_eig_operation (const octave_value& value, const std::string& output_mode, const std::string& balance_mode) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "eig expects one real or complex mp value"); if (balance_mode != "auto" && balance_mode != "balance" && balance_mode != "nobalance") error_with_id ("mplapack:mp:InvalidOption", "eig balance mode is invalid"); if (mp_value_has_structured_eig_shape (value)) return mp_structured_eig_operation (value, output_mode); return mp_general_eig_operation (value, output_mode, balance_mode != "nobalance"); } octave_value_list complex_pivoted_qr_operation (const octave_value& value, bool economy, bool vector_output) { const octave_value payload = require_mp_payload (value); std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "qr expects one complex mp value"); try { const auto factors = octave_mplapack::mplapack_mpc_matrix_pivoted_qr ( *input, economy, true); const octave_value q = make_complex_inspection_result (factors.q); const octave_value r = make_complex_inspection_result (factors.r); const std::size_t n = factors.permutation.size (); if (vector_output) { Matrix p (1, checked_octave_dimension_for_inspection (n)); for (std::size_t column = 0; column < n; ++column) p.xelem (0, static_cast (column)) = static_cast (factors.permutation[column]); return ovl (q, r, octave_value (p)); } const octave_idx_type dimension = checked_octave_dimension_for_inspection (n); Matrix p (dimension, dimension); for (std::size_t column = 0; column < n; ++column) { const auto source = factors.permutation[column] - 1; p.xelem (static_cast (source), static_cast (column)) = 1.0; } return ovl (q, r, octave_value (p)); } catch (const octave_mplapack::MpcQrError& exception) { if (exception.kind () == octave_mplapack::MpcQrError::Kind::invalid_argument) error_with_id ("mplapack:mp:QrError", "MPLAPACK complex pivoted QR rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:QrInternalError", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:QrError", "%s", exception.what ()); } return ovl (); } octave_value_list mp_pivoted_qr_operation (const octave_value& value, bool economy, bool vector_output) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "qr expects one real mp value"); std::optional scalar_matrix; const octave_value payload = require_mp_payload (value); const octave_mplapack::MpfrMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "qr expects one real mp value"); try { const auto factors = octave_mplapack::mplapack_mpfr_matrix_pivoted_qr ( *input, economy, true); const octave_value q = make_mtimes_result (factors.q); const octave_value r = make_mtimes_result (factors.r); const std::size_t n = factors.permutation.size (); if (vector_output) { Matrix p (1, checked_octave_dimension_for_inspection (n)); for (std::size_t column = 0; column < n; ++column) p.xelem (0, static_cast (column)) = static_cast (factors.permutation[column]); return ovl (q, r, octave_value (p)); } const octave_idx_type dimension = checked_octave_dimension_for_inspection (n); Matrix p (dimension, dimension); for (std::size_t column = 0; column < n; ++column) { const auto source = factors.permutation[column] - 1; p.xelem (static_cast (source), static_cast (column)) = 1.0; } return ovl (q, r, octave_value (p)); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:QrError", "%s", exception.what ()); } return ovl (); } octave_value_list complex_lu_operation (const octave_value& value, const std::string& output_mode) { const octave_value payload = require_mp_payload (value); std::optional scalar_matrix; const octave_mplapack::MpfrComplexMatrixStorage *input = nullptr; if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpc_set (scalar_matrix->at (0, 0).mpc_data (), scalar.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) input = &octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "lu expects one complex mp value"); try { auto factors = octave_mplapack::mplapack_mpc_matrix_lu (*input); if (output_mode == "packed") return ovl (make_complex_inspection_result ( std::move (factors.packed))); const std::size_t permutation_size = factors.permutation.size (); const auto p_dimension = checked_octave_dimension_for_inspection (permutation_size); if (output_mode == "two") { const std::size_t m = factors.lower.rows (); const std::size_t k = factors.lower.columns (); octave_mplapack::MpfrComplexMatrixStorage lower_unpermuted ( m, k, factors.lower.precision_bits ()); std::vector inverse (permutation_size); for (std::size_t destination = 0; destination < permutation_size; ++destination) { const auto source = factors.permutation[destination]; if (source < 1 || source > permutation_size) error_with_id ( "mplapack:mp:LuError", "MPLAPACK Cgetrf returned an invalid permutation"); inverse[static_cast (source - 1)] = destination; } for (std::size_t column = 0; column < k; ++column) for (std::size_t row = 0; row < m; ++row) mpc_set (lower_unpermuted.at (row, column).mpc_data (), factors.lower.at (inverse[row], column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return ovl (make_complex_inspection_result ( std::move (lower_unpermuted)), make_complex_inspection_result (std::move (factors.upper))); } if (output_mode == "matrix" || output_mode == "vector") { if (output_mode == "vector") { Matrix permutation_vector = permutation_size == 0 ? Matrix (0, 0) : Matrix (p_dimension, 1); for (std::size_t row = 0; row < permutation_size; ++row) permutation_vector.xelem (static_cast (row), 0) = static_cast (factors.permutation[row]); return ovl (make_complex_inspection_result ( std::move (factors.lower)), make_complex_inspection_result ( std::move (factors.upper)), octave_value (permutation_vector)); } octave_mplapack::MpfrComplexMatrixStorage::checked_element_count ( permutation_size, permutation_size); Matrix permutation_matrix (p_dimension, p_dimension); for (std::size_t destination = 0; destination < permutation_size; ++destination) { const auto source = factors.permutation[destination]; if (source < 1 || source > permutation_size) error_with_id ( "mplapack:mp:LuError", "MPLAPACK Cgetrf returned an invalid permutation"); permutation_matrix.xelem ( static_cast (destination), static_cast (source - 1)) = 1.0; } return ovl (make_complex_inspection_result ( std::move (factors.lower)), make_complex_inspection_result (std::move (factors.upper)), octave_value (permutation_matrix)); } error_with_id ("mplapack:mp:InvalidArguments", "invalid LU output mode"); } catch (const octave_mplapack::MpcCgetrfError& exception) { if (exception.kind () == octave_mplapack::MpcCgetrfError::Kind::invalid_argument) error_with_id ("mplapack:mp:LuError", "MPLAPACK Cgetrf rejected argument %d", -static_cast (exception.info ())); error_with_id ("mplapack:mp:LuInternalError", "%s", exception.what ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:InvalidInput", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:LuError", "%s", exception.what ()); } return ovl (); } octave_value_list mp_lu_operation (const octave_value& value, const std::string& output_mode) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "lu expects one real mp value"); if (is_complex_payload (value)) return complex_lu_operation (value, output_mode); const octave_value payload = require_mp_payload (value); const octave_mplapack::MpfrMatrixStorage *input = nullptr; std::optional scalar_matrix; if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); scalar_matrix.emplace (1, 1, scalar.precision_bits ()); mpfr_set (scalar_matrix->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); input = &*scalar_matrix; } else if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) input = &octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); else error_with_id ("mplapack:mp:InvalidInput", "lu expects one real mp value"); try { auto factors = octave_mplapack::mplapack_mpfr_matrix_lu (*input); if (output_mode == "packed") return ovl (make_mtimes_result (std::move (factors.packed))); const std::size_t permutation_size = factors.permutation.size (); const auto p_dimension = checked_octave_dimension_for_inspection (permutation_size); if (output_mode == "two") { const std::size_t m = factors.lower.rows (); const std::size_t k = factors.lower.columns (); octave_mplapack::MpfrMatrixStorage lower_unpermuted ( m, k, factors.lower.precision_bits ()); std::vector inverse (permutation_size); for (std::size_t destination = 0; destination < permutation_size; ++destination) { const auto source = factors.permutation[destination]; if (source < 1 || source > permutation_size) error_with_id ("mplapack:mp:LuError", "MPLAPACK Rgetrf returned an invalid permutation"); inverse[static_cast (source - 1)] = destination; } for (std::size_t column = 0; column < k; ++column) for (std::size_t row = 0; row < m; ++row) mpfr_set (lower_unpermuted.at (row, column).mpfr_data (), factors.lower.at (inverse[row], column).mpfr_data (), MPFR_RNDN); return ovl (make_mtimes_result (std::move (lower_unpermuted)), make_mtimes_result (std::move (factors.upper))); } if (output_mode == "matrix" || output_mode == "vector") { if (output_mode == "vector") { Matrix permutation_vector = permutation_size == 0 ? Matrix (0, 0) : Matrix (p_dimension, 1); for (std::size_t row = 0; row < permutation_size; ++row) permutation_vector.xelem (static_cast (row), 0) = static_cast (factors.permutation[row]); return ovl (make_mtimes_result (std::move (factors.lower)), make_mtimes_result (std::move (factors.upper)), octave_value (permutation_vector)); } octave_mplapack::MpfrMatrixStorage::checked_element_count ( permutation_size, permutation_size); Matrix permutation_matrix (p_dimension, p_dimension); for (std::size_t destination = 0; destination < permutation_size; ++destination) { const auto source = factors.permutation[destination]; if (source < 1 || source > permutation_size) error_with_id ("mplapack:mp:LuError", "MPLAPACK Rgetrf returned an invalid permutation"); permutation_matrix.xelem ( static_cast (destination), static_cast (source - 1)) = 1.0; } return ovl (make_mtimes_result (std::move (factors.lower)), make_mtimes_result (std::move (factors.upper)), octave_value (permutation_matrix)); } error_with_id ("mplapack:mp:InvalidArguments", "invalid LU output mode"); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { error_with_id ("mplapack:mp:LuError", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:LuError", "%s", exception.what ()); } return ovl (); } octave_value matrix_mtimes_operation (const octave_value& lhs_value, const octave_value& rhs_value) { std::optional lhs_owned; std::optional rhs_owned; const octave_mplapack::MpfrMatrixStorage *lhs = nullptr; const octave_mplapack::MpfrMatrixStorage *rhs = nullptr; if (is_mp_value (lhs_value) && is_matrix_payload (lhs_value)) { const octave_value payload = require_matrix_payload (lhs_value); lhs = &octave_mplapack_mpfr_matrix_internal::checked_value ( payload).storage (); } else if (is_real_double_matrix_operand (lhs_value)) { // The other matrix determines the operation precision. The caller // has already rejected two raw-double matrices before this function. const octave_value payload = require_matrix_payload (rhs_value); const auto& rhs_storage = octave_mplapack_mpfr_matrix_internal::checked_value ( payload).storage (); lhs_owned.emplace (make_double_matrix_storage ( lhs_value, rhs_storage.precision_bits ())); lhs = &*lhs_owned; } else error_with_id ("mplapack:mp:UnsupportedOperand", "matrix multiplication requires a dense mp or real double matrix"); if (is_mp_value (rhs_value) && is_matrix_payload (rhs_value)) { const octave_value payload = require_matrix_payload (rhs_value); rhs = &octave_mplapack_mpfr_matrix_internal::checked_value ( payload).storage (); } else if (is_real_double_matrix_operand (rhs_value)) { if (! lhs) error_with_id ("mplapack:mp:UnsupportedOperand", "matrix multiplication requires an mp operand"); rhs_owned.emplace (make_double_matrix_storage ( rhs_value, lhs->precision_bits ())); rhs = &*rhs_owned; } else error_with_id ("mplapack:mp:UnsupportedOperand", "matrix multiplication requires a dense mp or real double matrix"); const auto& lhs_storage = *lhs; const auto& rhs_storage = *rhs; if (lhs_storage.columns () != rhs_storage.rows ()) error_with_id ("mplapack:mp:DimensionMismatch", "matrix multiplication dimensions must agree"); try { return make_mtimes_result ( octave_mplapack::mplapack_mpfr_matrix_multiply (lhs_storage, rhs_storage)); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:MtimesError", "%s", exception.what ()); } return octave_value (); } octave_value matrix_scale_storage_operation ( const octave_mplapack::MpfrMatrixStorage& matrix, const octave_value& scalar_value) { try { if (is_mp_value (scalar_value)) { const octave_value scalar_payload = require_scalar_payload (scalar_value); const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( scalar_payload).storage (); return make_mtimes_result ( octave_mplapack::mplapack_mpfr_matrix_scale ( matrix, scalar.native_value ())); } return make_mtimes_result ( octave_mplapack::mplapack_mpfr_matrix_scale ( matrix, require_arithmetic_double (scalar_value))); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:MtimesError", "%s", exception.what ()); } return octave_value (); } octave_value matrix_scale_operation (const octave_value& matrix_value, const octave_value& scalar_value) { const octave_value matrix_payload = require_matrix_payload (matrix_value); const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value ( matrix_payload).storage (); return matrix_scale_storage_operation (matrix, scalar_value); } octave_value mp_mtimes_operation (const octave_value& lhs_value, const octave_value& rhs_value) { const bool lhs_is_mp = is_mp_value (lhs_value); const bool rhs_is_mp = is_mp_value (rhs_value); if (! lhs_is_mp && ! rhs_is_mp) error_with_id ("mplapack:mp:UnsupportedOperand", "matrix multiplication requires at least one mp operand"); const bool lhs_is_matrix = lhs_is_mp && is_matrix_payload (lhs_value); const bool rhs_is_matrix = rhs_is_mp && is_matrix_payload (rhs_value); const bool lhs_is_double_matrix = is_double_matrix_operand (lhs_value); const bool rhs_is_double_matrix = is_double_matrix_operand (rhs_value); if (lhs_is_double_matrix && ! lhs_value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex matrix multiplication is not supported"); if (rhs_is_double_matrix && ! rhs_value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex matrix multiplication is not supported"); if (lhs_is_double_matrix || rhs_is_double_matrix) { if (lhs_is_double_matrix && rhs_is_double_matrix) error_with_id ("mplapack:mp:UnsupportedOperand", "matrix multiplication requires at least one mp matrix"); if (lhs_is_matrix || rhs_is_matrix) return matrix_mtimes_operation (lhs_value, rhs_value); if (lhs_is_double_matrix && rhs_is_mp) { const octave_value scalar_payload = require_scalar_payload (rhs_value); const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( scalar_payload).storage (); try { const auto matrix = make_double_matrix_storage ( lhs_value, scalar.precision_bits ()); return make_mtimes_result ( octave_mplapack::mplapack_mpfr_matrix_scale ( matrix, scalar.native_value ())); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:MtimesError", "%s", exception.what ()); } } if (rhs_is_double_matrix && lhs_is_mp) { const octave_value scalar_payload = require_scalar_payload (lhs_value); const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( scalar_payload).storage (); try { const auto matrix = make_double_matrix_storage ( rhs_value, scalar.precision_bits ()); return make_mtimes_result ( octave_mplapack::mplapack_mpfr_matrix_scale ( matrix, scalar.native_value ())); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:MtimesError", "%s", exception.what ()); } } } if (lhs_is_matrix && rhs_is_matrix) return matrix_mtimes_operation (lhs_value, rhs_value); if (lhs_is_matrix) return matrix_scale_operation (lhs_value, rhs_value); if (rhs_is_matrix) return matrix_scale_operation (rhs_value, lhs_value); return scalar_binary_operation (lhs_value, rhs_value, ScalarBinaryOperation::multiply); } long require_integer_power_exponent (const octave_value& value) { if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto& complex = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ().native_value (); if (! mpfr_zero_p (mpc_imagref (complex.mpc_data ()))) error_with_id ("mplapack:mp:InvalidExponent", "matrix power exponent must be a real integer"); if (! mpfr_integer_p (mpc_realref (complex.mpc_data ())) || ! mpfr_fits_slong_p (mpc_realref (complex.mpc_data ()), MPFR_RNDN)) error_with_id ("mplapack:mp:InvalidExponent", "matrix power exponent must fit a native integer"); return mpfr_get_si (mpc_realref (complex.mpc_data ()), MPFR_RNDN); } const auto& real = octave_mplapack_mpfr_scalar_internal::checked_value ( require_scalar_payload (payload)).storage ().native_value (); if (! mpfr_integer_p (real.mpfr_data ()) || ! mpfr_fits_slong_p (real.mpfr_data (), MPFR_RNDN)) error_with_id ("mplapack:mp:InvalidExponent", "matrix power exponent must fit a native integer"); return mpfr_get_si (real.mpfr_data (), MPFR_RNDN); } if (! value.is_double_type () || ! value.is_real_scalar ()) error_with_id ("mplapack:mp:InvalidExponent", "matrix power exponent must be a real integer scalar"); const double exponent = value.double_value (); if (! std::isfinite (exponent) || std::trunc (exponent) != exponent || static_cast (exponent) < static_cast (std::numeric_limits::min ()) || static_cast (exponent) > static_cast (std::numeric_limits::max ())) error_with_id ("mplapack:mp:InvalidExponent", "matrix power exponent must fit a native integer"); return static_cast (exponent); } octave_value mpower_identity (const octave_value& value, std::size_t dimension) { if (is_complex_payload (value)) { const mpfr_prec_t precision = arithmetic_mp_precision (value); octave_mplapack::MpfrMpcPrecisionScope scope (precision); octave_mplapack::MpfrComplexMatrixStorage identity ( dimension, dimension, precision); for (std::size_t index = 0; index < dimension; ++index) mpc_set_ui (identity.at (index, index).mpc_data (), 1, MPC_RND (MPFR_RNDN, MPFR_RNDN)); return make_complex_inspection_result (std::move (identity)); } const mpfr_prec_t precision = arithmetic_mp_precision (value); octave_mplapack::MpfrMatrixStorage identity (dimension, dimension, precision); for (std::size_t index = 0; index < dimension; ++index) mpfr_set_ui (identity.at (index, index).mpfr_data (), 1, MPFR_RNDN); return make_inspection_result (std::move (identity)); } octave_value mpower_operation (const octave_value& lhs_value, const octave_value& rhs_value) { if (! is_mp_value (lhs_value)) error_with_id ("mplapack:mp:InvalidInput", "matrix power requires an mp base"); const octave_value base_payload = require_mp_payload (lhs_value); const bool base_is_matrix = is_matrix_payload (lhs_value); if (! base_is_matrix) return scalar_binary_operation (lhs_value, rhs_value, ScalarBinaryOperation::power); const std::size_t rows = base_payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id () ? octave_mplapack_mpfr_matrix_internal::checked_value (base_payload) .storage ().rows () : octave_mplapack_mpc_matrix_internal::checked_value (base_payload) .storage ().rows (); const std::size_t columns = base_payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id () ? octave_mplapack_mpfr_matrix_internal::checked_value (base_payload) .storage ().columns () : octave_mplapack_mpc_matrix_internal::checked_value (base_payload) .storage ().columns (); if (rows != columns) error_with_id ("mplapack:mp:NonSquareMatrix", "matrix power requires a square matrix"); const long exponent = require_integer_power_exponent (rhs_value); if (exponent == 0) return mpower_identity (lhs_value, rows); octave_value current = exponent < 0 ? mp_inverse_operation (lhs_value) : lhs_value; unsigned long magnitude; if (exponent < 0) { magnitude = 0UL - static_cast (exponent); } else magnitude = static_cast (exponent); octave_value result = mpower_identity (lhs_value, rows); const auto multiply = [&] (const octave_value& lhs, const octave_value& rhs) { if (is_complex_arithmetic_operand (lhs) || is_complex_arithmetic_operand (rhs)) return complex_mtimes_operation (lhs, rhs); return mp_mtimes_operation (lhs, rhs); }; while (magnitude != 0) { if ((magnitude & 1UL) != 0) result = multiply (result, current); magnitude >>= 1; if (magnitude != 0) current = multiply (current, current); } return result; } octave_value mp_mldivide_operation (const octave_value& lhs_value, const octave_value& rhs_value, bool force_rank_revealing = false) { const bool lhs_is_mp = is_mp_value (lhs_value); const bool rhs_is_mp = is_mp_value (rhs_value); if (! lhs_is_mp && ! rhs_is_mp) error_with_id ("mplapack:mp:UnsupportedOperand", "left division requires at least one mp operand"); const bool lhs_is_matrix = lhs_is_mp && is_matrix_payload (lhs_value); const bool rhs_is_matrix = rhs_is_mp && is_matrix_payload (rhs_value); const bool lhs_is_double_matrix = is_double_matrix_operand (lhs_value); const bool rhs_is_double_matrix = is_double_matrix_operand (rhs_value); if (lhs_is_double_matrix && ! lhs_value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex matrix left division is not supported"); if (rhs_is_double_matrix && ! rhs_value.isreal ()) error_with_id ("mplapack:mp:ComplexUnsupported", "complex matrix left division is not supported"); try { // Scalar left division is native MPFR arithmetic, not a one-by-one // LAPACK call. The right-hand matrix remains one native payload. if (! lhs_is_matrix && ! lhs_is_double_matrix) { const double lhs_double = lhs_is_mp ? 0.0 : require_arithmetic_double (lhs_value); std::optional lhs_storage; const octave_mplapack::MpfrScalarStorage *lhs_scalar = nullptr; if (lhs_is_mp) { const octave_value payload = require_scalar_payload (lhs_value); lhs_scalar = &octave_mplapack_mpfr_scalar_internal::checked_value ( payload).storage (); } else { const octave_value rhs_payload = require_mp_payload (rhs_value); mpfr_prec_t precision_bits = 0; if (rhs_payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) precision_bits = octave_mplapack_mpfr_scalar_internal::checked_value ( rhs_payload).storage ().precision_bits (); else precision_bits = octave_mplapack_mpfr_matrix_internal::checked_value ( rhs_payload).storage ().precision_bits (); lhs_storage.emplace (lhs_double, precision_bits); lhs_scalar = &*lhs_storage; } if (rhs_is_matrix) { const octave_value rhs_payload = require_matrix_payload (rhs_value); const auto& rhs = octave_mplapack_mpfr_matrix_internal::checked_value ( rhs_payload).storage (); return make_mldivide_result ( octave_mplapack::mplapack_mpfr_matrix_left_divide ( rhs, lhs_scalar->native_value ())); } if (rhs_is_double_matrix) { const mpfr_prec_t precision_bits = lhs_scalar->precision_bits (); const auto rhs = make_double_matrix_storage ( rhs_value, precision_bits); return make_mldivide_result ( octave_mplapack::mplapack_mpfr_matrix_left_divide ( rhs, lhs_scalar->native_value ())); } const octave_mplapack::MpfrScalarStorage rhs_scalar = [&] () { if (rhs_is_mp) return octave_mplapack_mpfr_scalar_internal::checked_value ( require_scalar_payload (rhs_value)).storage (); const double value = require_arithmetic_double (rhs_value); return octave_mplapack::MpfrScalarStorage ( value, lhs_scalar->precision_bits ()); } (); return make_internal_scalar (rhs_scalar.divide (*lhs_scalar)); } // A non-scalar left operand is a dense matrix. A raw double matrix is // explicitly converted to the other mp operand's precision. const octave_mplapack::MpfrMatrixStorage *lhs = nullptr; std::optional lhs_owned; if (lhs_is_matrix) lhs = &octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (lhs_value)).storage (); else if (lhs_is_double_matrix && (rhs_is_matrix || rhs_is_mp)) { const mpfr_prec_t rhs_precision = rhs_is_matrix ? octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (rhs_value)).storage ().precision_bits () : octave_mplapack_mpfr_scalar_internal::checked_value ( require_scalar_payload (rhs_value)).storage ().precision_bits (); lhs_owned.emplace (make_double_matrix_storage ( lhs_value, rhs_precision)); lhs = &*lhs_owned; } else error_with_id ("mplapack:mp:UnsupportedOperand", "matrix left division requires a dense mp or real double matrix"); const octave_mplapack::MpfrMatrixStorage *rhs = nullptr; std::optional rhs_owned; if (rhs_is_matrix) rhs = &octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (rhs_value)).storage (); else if (rhs_is_double_matrix && lhs) { rhs_owned.emplace (make_double_matrix_storage ( rhs_value, lhs->precision_bits ())); rhs = &*rhs_owned; } else if (lhs && lhs->rows () == 1 && ! rhs_is_matrix && ! rhs_is_double_matrix) { const mpfr_prec_t rhs_precision = rhs_is_mp ? octave_mplapack_mpfr_scalar_internal::checked_value ( require_scalar_payload (rhs_value)).storage ().precision_bits () : lhs->precision_bits (); const mpfr_prec_t operation_precision = std::max (lhs->precision_bits (), rhs_precision); rhs_owned.emplace (1, 1, operation_precision); if (rhs_is_mp) { const auto& scalar = octave_mplapack_mpfr_scalar_internal::checked_value ( require_scalar_payload (rhs_value)).storage (); mpfr_set (rhs_owned->at (0, 0).mpfr_data (), scalar.native_value ().mpfr_data (), MPFR_RNDN); } else mpfr_set_d (rhs_owned->at (0, 0).mpfr_data (), require_arithmetic_double (rhs_value), MPFR_RNDN); rhs = &*rhs_owned; } else error_with_id ("mplapack:mp:UnsupportedOperand", "matrix left division requires a dense mp or real double right-hand side"); if (lhs->rows () != lhs->columns () || force_rank_revealing) return make_mldivide_result ( octave_mplapack::mplapack_mpfr_matrix_rank_revealing_solve ( *lhs, *rhs).solution); return make_mldivide_result ( octave_mplapack::mplapack_mpfr_matrix_solve (*lhs, *rhs)); } catch (const octave_mplapack::MpfrRankRevealingError& exception) { if (exception.kind () == octave_mplapack::MpfrRankRevealingError::Kind::convergence) error_with_id ("mplapack:mp:ConvergenceFailure", "MPLAPACK Rgelss failed to converge (info %d)", exception.info ()); if (exception.kind () == octave_mplapack::MpfrRankRevealingError::Kind::invalid_argument) error_with_id ("mplapack:mp:RankRevealingError", "MPLAPACK Rgelss rejected argument %d", -exception.info ()); error_with_id ("mplapack:mp:RankRevealingInternalError", "%s", exception.what ()); } catch (const octave_mplapack::MpfrRgelsError& exception) { if (exception.kind () == octave_mplapack::MpfrRgelsError::Kind::rank_deficient) error_with_id ("mplapack:mp:RankDeficient", "mp left division: rectangular matrix is rank deficient"); error_with_id ("mplapack:mp:RgelsError", "MPLAPACK Rgels rejected argument %d", -exception.info ()); } catch (const octave_mplapack::MpfrRgesvError& exception) { if (exception.kind () == octave_mplapack::MpfrRgesvError::Kind::singular) error_with_id ("mplapack:mp:SingularMatrix", "mp left division: matrix is singular"); error_with_id ("mplapack:mp:RgesvError", "MPLAPACK Rgesv rejected argument %d", -exception.info ()); } catch (const std::overflow_error& exception) { error_with_id ("mplapack:mp:DimensionOverflow", "%s", exception.what ()); } catch (const std::invalid_argument& exception) { const std::string message = exception.what (); if (message.find ("square") != std::string::npos) error_with_id ("mplapack:mp:NonSquareMatrix", "%s", exception.what ()); if (message.find ("dimensions") != std::string::npos) error_with_id ("mplapack:mp:DimensionMismatch", "%s", exception.what ()); error_with_id ("mplapack:mp:MldivideError", "%s", exception.what ()); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:MldivideError", "%s", exception.what ()); } return octave_value (); } octave_value scalar_negate (const octave_value& value) { if (is_mp_value (value) && is_complex_payload (value)) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return make_internal_complex_scalar ( octave_mplapack::mpc_scalar_negate ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ())); try { return make_complex_inspection_result ( octave_mplapack::mpc_matrix_negate ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage ())); } catch (const std::exception& exception) { error_with_id ("mplapack:ArithmeticError", "%s", exception.what ()); } } if (is_mp_value (value) && is_matrix_payload (value)) { try { auto result = octave_mplapack::mpfr_matrix_negate ( octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (value)).storage ()); if (result.rows () == 1 && result.columns () == 1) return make_internal_scalar ( octave_mplapack::MpfrScalarStorage ( std::move (result.at (0, 0)))); return make_internal_matrix (std::move (result)); } catch (const std::exception& exception) { error_with_id ("mplapack:ArithmeticError", "%s", exception.what ()); } } const octave_value payload = require_arithmetic_mp_payload (value); const auto& native = octave_mplapack_mpfr_scalar_internal::checked_value ( payload).storage (); try { return make_internal_scalar (native.negate ()); } catch (const std::exception& exception) { error_with_id ("mplapack:ArithmeticError", "%s", exception.what ()); } return octave_value (); } octave_value script_unary_operation (const octave_value& value, octave_mplapack::MpScriptUnaryOperation operation) { const octave_value payload = require_mp_payload (value); try { if (is_complex_payload (value)) { if (operation == octave_mplapack::MpScriptUnaryOperation::sign) { if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return make_internal_complex_scalar ( octave_mplapack::mpc_script_unary ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (), operation)); return make_complex_inspection_result ( octave_mplapack::mpc_script_unary ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (), operation)); } if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return make_internal_scalar ( octave_mplapack::mpc_script_real_unary ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (), operation)); return make_inspection_result (octave_mplapack::mpc_script_real_unary ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (), operation)); } if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) return make_internal_scalar (octave_mplapack::mpfr_script_unary ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (), operation)); return make_inspection_result (octave_mplapack::mpfr_script_unary ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (), operation)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:CompatibilityError", "%s", exception.what ()); } return octave_value (); } bool real_elementary_requires_complex (const octave_value& payload, octave_mplapack::MpScriptElementaryOperation operation) { if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) return octave_mplapack::mpfr_script_elementary_requires_complex ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage ().native_value ().mpfr_data (), operation); const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); for (std::size_t index = 0; index < source.numel (); ++index) if (octave_mplapack::mpfr_script_elementary_requires_complex ( source.data ()[index].mpfr_data (), operation)) return true; return false; } octave_value script_elementary_operation ( const octave_value& value, octave_mplapack::MpScriptElementaryOperation operation) { const octave_value payload = require_mp_payload (value); try { if (is_complex_payload (value)) { if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return make_internal_complex_scalar ( octave_mplapack::mpc_script_elementary ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (), operation)); return make_complex_inspection_result ( octave_mplapack::mpc_script_elementary ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (), operation)); } if (real_elementary_requires_complex (payload, operation)) { if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) return make_internal_complex_scalar ( octave_mplapack::mpc_script_elementary ( octave_mplapack::mpfr_script_promote ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage ()), operation)); return make_complex_inspection_result ( octave_mplapack::mpc_script_elementary ( octave_mplapack::mpfr_script_promote ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage ()), operation)); } if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) return make_internal_scalar (octave_mplapack::mpfr_script_elementary ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (), operation)); return make_inspection_result (octave_mplapack::mpfr_script_elementary ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (), operation)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:CompatibilityError", "%s", exception.what ()); } return octave_value (); } struct ParsedScriptOptions { octave_mplapack::MpScriptReductionOptions reduction; octave_mplapack::MpScriptComparisonMethod comparison = octave_mplapack::MpScriptComparisonMethod::automatic; }; std::pair script_shape (const octave_value& value) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id () || payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return {1, 1}; if (payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) { const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); return {source.rows (), source.columns ()}; } const auto& source = octave_mplapack_mpc_matrix_internal::checked_value (payload).storage (); return {source.rows (), source.columns ()}; } std::size_t script_default_dimension (const octave_value& value) { const auto shape = script_shape (value); return shape.first != 1 ? 1 : 2; } std::size_t script_dimension (const octave_value& value) { if (! value.isnumeric () || value.islogical () || ! value.isreal () || ! value.is_real_scalar ()) error_with_id ("mplapack:mp:InvalidDimension", "reduction dimension must be 1 or 2"); const double dimension = value.double_value (); if (! std::isfinite (dimension) || std::trunc (dimension) != dimension || (dimension != 1.0 && dimension != 2.0)) error_with_id ("mplapack:mp:InvalidDimension", "reduction dimension must be 1 or 2"); return static_cast (dimension); } ParsedScriptOptions parse_script_options (const octave_value_list& args, int first, std::size_t default_dimension, bool extremum, bool allow_direction) { ParsedScriptOptions parsed; parsed.reduction.dimension = default_dimension; if (extremum) parsed.reduction.omit_nan = true; for (int index = first; index < args.length (); ++index) { const octave_value& option = args(index); if (option.isnumeric () && option.isempty ()) continue; if (option.isnumeric () && ! option.isempty ()) { parsed.reduction.dimension = script_dimension (option); continue; } if (! option.is_string ()) error_with_id ("mplapack:mp:InvalidOption", "invalid reduction option"); const std::string text = option.string_value (); if (text == "all") { parsed.reduction.all = true; continue; } if (text == "omitnan") { parsed.reduction.omit_nan = true; continue; } if (text == "includenan") { parsed.reduction.omit_nan = false; continue; } if (text == "forward" || text == "reverse") { if (! allow_direction) error_with_id ("mplapack:mp:InvalidOption", "cumulative direction is not valid here"); parsed.reduction.reverse = text == "reverse"; continue; } if (text == "default" || text == "native") continue; if (text == "double") { parsed.reduction.output_double = true; continue; } if (extremum && text == "ComparisonMethod") { if (index + 1 >= args.length () || ! args(index + 1).is_string ()) error_with_id ("mplapack:mp:InvalidOption", "ComparisonMethod requires auto, real, or abs"); const std::string method = args(++index).string_value (); if (method == "auto") parsed.comparison = octave_mplapack::MpScriptComparisonMethod::automatic; else if (method == "real") parsed.comparison = octave_mplapack::MpScriptComparisonMethod::real; else if (method == "abs") parsed.comparison = octave_mplapack::MpScriptComparisonMethod::absolute; else error_with_id ("mplapack:mp:InvalidOption", "ComparisonMethod must be auto, real, or abs"); continue; } error_with_id ("mplapack:mp:InvalidOption", "unknown reduction option: %s", text.c_str ()); } return parsed; } octave_value script_real_matrix_result (octave_mplapack::MpfrMatrixStorage storage, bool output_double) { octave_value result = make_inspection_result (std::move (storage)); if (! output_double) return result; const octave_value payload = require_mp_payload (result); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) return octave_value (mpfr_get_d ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage ().native_value ().mpfr_data (), MPFR_RNDN)); return octave_value (matrix_to_double (result)); } octave_value script_complex_matrix_result ( octave_mplapack::MpfrComplexMatrixStorage storage, bool output_double) { octave_value result = make_complex_inspection_result (std::move (storage)); if (! output_double) return result; const octave_value payload = require_mp_payload (result); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { const auto converted = octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ().to_double (); return octave_value (Complex (converted.real (), converted.imag ())); } return octave_value (complex_matrix_to_double (result)); } octave_value script_indices_result (std::size_t rows, std::size_t columns, const std::vector& indices) { Matrix result (checked_octave_dimension_for_inspection (rows), checked_octave_dimension_for_inspection (columns)); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) result.xelem (static_cast (row), static_cast (column)) = static_cast (indices.at (row + column * rows)); return octave_value (result); } octave_mplapack::MpfrMatrixStorage script_real_matrix_operand (const octave_value& value, mpfr_prec_t precision) { if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (is_complex_payload (value)) error_with_id ("mplapack:mp:ComplexUnsupported", "real reduction operand cannot be complex"); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { octave_mplapack::MpfrMatrixStorage result (1, 1, precision); mpfr_set (result.at (0, 0).mpfr_data (), octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage ().native_value ().mpfr_data (), MPFR_RNDN); return result; } const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); octave_mplapack::MpfrMatrixStorage result (source.rows (), source.columns (), precision); for (std::size_t index = 0; index < source.numel (); ++index) mpfr_set (result.data ()[index].mpfr_data (), source.data ()[index].mpfr_data (), MPFR_RNDN); return result; } if (! value.is_double_type () || ! value.isreal ()) error_with_id ("mplapack:mp:UnsupportedOperand", "reduction operands must be mp or real double values"); if (value.is_real_scalar ()) { octave_mplapack::MpfrMatrixStorage result (1, 1, precision); mpfr_set_d (result.at (0, 0).mpfr_data (), value.double_value (), MPFR_RNDN); return result; } return make_double_matrix_storage (value, precision); } octave_mplapack::MpfrComplexMatrixStorage script_complex_matrix_operand (const octave_value& value, mpfr_prec_t precision) { octave_mplapack::MpfrMpcPrecisionScope scope (precision); if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) { octave_mplapack::MpfrComplexMatrixStorage result (1, 1, precision); mpc_set (result.at (0, 0).mpc_data (), octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ().native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { const auto& source = octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); octave_mplapack::MpfrComplexMatrixStorage result (source.rows (), source.columns (), precision); for (std::size_t index = 0; index < source.numel (); ++index) mpc_set (result.data ()[index].mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& source = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); octave_mplapack::MpfrComplexMatrixStorage result (1, 1, precision); mpc_set_fr (result.at (0, 0).mpc_data (), source.native_value ().mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); octave_mplapack::MpfrComplexMatrixStorage result (source.rows (), source.columns (), precision); for (std::size_t index = 0; index < source.numel (); ++index) mpc_set_fr (result.data ()[index].mpc_data (), source.data ()[index].mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } if (! value.is_double_type ()) error_with_id ("mplapack:mp:UnsupportedOperand", "reduction operands must be mp or double values"); if (value.is_real_scalar () || value.is_complex_scalar ()) { const Complex scalar = value.complex_value (); octave_mplapack::MpfrComplexMatrixStorage result (1, 1, precision); mpc_set_d_d (result.at (0, 0).mpc_data (), scalar.real (), scalar.imag (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } return make_complex_double_matrix_storage (value, precision); } std::int64_t require_signed_structure_integer (const octave_value& value, const char *description) { if (! value.isnumeric () || value.islogical () || value.is_string () || ! value.isreal () || ! value.is_real_scalar ()) error_with_id ("mplapack:mp:InvalidOption", "%s must be a real integer scalar", description); const double supplied = value.double_value (); if (! std::isfinite (supplied) || std::trunc (supplied) != supplied || static_cast (supplied) < static_cast (std::numeric_limits::min ()) || static_cast (supplied) > static_cast (std::numeric_limits::max ())) error_with_id ("mplapack:mp:InvalidOption", "%s must be an integer in the supported range", description); return static_cast (supplied); } std::size_t require_nonnegative_structure_dimension (const octave_value& value, const char *description) { if (! value.isnumeric () || value.islogical () || value.is_string () || ! value.isreal () || ! value.is_real_scalar ()) error_with_id ("mplapack:mp:InvalidDimension", "%s must be a nonnegative integer scalar", description); const double supplied = value.double_value (); if (! std::isfinite (supplied) || std::trunc (supplied) != supplied || supplied < 0.0 || static_cast (supplied) > static_cast ( std::numeric_limits::max ())) error_with_id ("mplapack:mp:InvalidDimension", "%s must be a nonnegative integer scalar", description); return checked_size_dimension (static_cast (supplied)); } std::vector parse_structure_dimensions (const octave_value_list& args, int first, const char *description) { if (first >= args.length ()) error_with_id ("mplapack:mp:InvalidDimension", "%s requires one or two dimensions", description); std::vector dimensions; if (args.length () == first + 1 && args(first).isnumeric () && ! args(first).islogical () && ! args(first).is_string () && ! args(first).is_real_scalar ()) { const octave_value& vector = args(first); if (! vector.isreal () || vector.ndims () != 2 || (vector.rows () != 1 && vector.columns () != 1) || vector.numel () == 0 || vector.numel () > 2) error_with_id ("mplapack:mp:InvalidDimension", "%s dimension vector must contain one or two integers", description); const NDArray values = vector.array_value (); for (octave_idx_type index = 0; index < values.numel (); ++index) dimensions.push_back (require_nonnegative_structure_dimension ( octave_value (values(index)), description)); } else { for (int index = first; index < args.length (); ++index) dimensions.push_back (require_nonnegative_structure_dimension ( args(index), description)); if (dimensions.size () > 2) error_with_id ("mplapack:mp:InvalidDimension", "%s accepts at most two dimensions", description); } if (dimensions.size () == 1) dimensions.push_back (dimensions.front ()); return dimensions; } std::pair parse_repmat_dimensions (const octave_value_list& args, int first) { const auto dimensions = parse_structure_dimensions (args, first, "repmat"); return {dimensions.at (0), dimensions.at (1)}; } octave_value script_structure_operation (const octave_value& value, const std::string& operation, const octave_value_list& args, int first) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "%s requires an mp value", operation.c_str ()); try { const mpfr_prec_t precision = arithmetic_mp_precision (value); if (operation == "diag") { if (args.length () != first && args.length () != first + 1) error_with_id ("mplapack:mp:InvalidArguments", "diag accepts an optional diagonal offset"); const std::int64_t diagonal = args.length () == first ? 0 : require_signed_structure_integer (args(first), "diag offset"); if (is_complex_payload (value)) { const auto source = script_complex_matrix_operand (value, precision); return make_complex_inspection_result ( octave_mplapack::mpc_script_diag ( source, source.rows () == 1 || source.columns () == 1, diagonal)); } const auto source = script_real_matrix_operand (value, precision); return make_inspection_result (octave_mplapack::mpfr_script_diag ( source, source.rows () == 1 || source.columns () == 1, diagonal)); } if (operation == "triu" || operation == "tril") { if (args.length () != first && args.length () != first + 1) error_with_id ("mplapack:mp:InvalidArguments", "%s accepts an optional diagonal offset", operation.c_str ()); const std::int64_t diagonal = args.length () == first ? 0 : require_signed_structure_integer ( args(first), "triangular diagonal offset"); const bool upper = operation == "triu"; if (is_complex_payload (value)) return make_complex_inspection_result ( octave_mplapack::mpc_script_triangular ( script_complex_matrix_operand (value, precision), diagonal, upper)); return make_inspection_result (octave_mplapack::mpfr_script_triangular ( script_real_matrix_operand (value, precision), diagonal, upper)); } if (operation == "repmat") { const auto repetitions = parse_repmat_dimensions (args, first); if (is_complex_payload (value)) return make_complex_inspection_result ( octave_mplapack::mpc_script_repmat ( script_complex_matrix_operand (value, precision), repetitions.first, repetitions.second)); return make_inspection_result (octave_mplapack::mpfr_script_repmat ( script_real_matrix_operand (value, precision), repetitions.first, repetitions.second)); } if (operation == "flip") { if (args.length () != first && args.length () != first + 1) error_with_id ("mplapack:mp:InvalidArguments", "flip accepts an optional dimension"); const int dimension = args.length () == first ? 0 : static_cast (require_signed_structure_integer ( args(first), "flip dimension")); if (dimension != 0 && dimension != 1 && dimension != 2) error_with_id ("mplapack:mp:InvalidDimension", "flip dimension must be 1 or 2"); if (is_complex_payload (value)) { const auto source = script_complex_matrix_operand (value, precision); const int selected = dimension == 0 ? (source.rows () != 1 ? 1 : 2) : dimension; return make_complex_inspection_result ( octave_mplapack::mpc_script_flip (source, selected)); } const auto source = script_real_matrix_operand (value, precision); const int selected = dimension == 0 ? (source.rows () != 1 ? 1 : 2) : dimension; return make_inspection_result ( octave_mplapack::mpfr_script_flip (source, selected)); } if (operation == "rot90") { if (args.length () != first && args.length () != first + 1) error_with_id ("mplapack:mp:InvalidArguments", "rot90 accepts an optional integer count"); const std::int64_t supplied = args.length () == first ? 1 : require_signed_structure_integer (args(first), "rot90 count"); if (supplied < static_cast (std::numeric_limits::min ()) || supplied > static_cast (std::numeric_limits::max ())) error_with_id ("mplapack:mp:InvalidOption", "rot90 count is outside the supported range"); const int turns = static_cast (supplied); if (is_complex_payload (value)) return make_complex_inspection_result ( octave_mplapack::mpc_script_rot90 ( script_complex_matrix_operand (value, precision), turns)); return make_inspection_result (octave_mplapack::mpfr_script_rot90 ( script_real_matrix_operand (value, precision), turns)); } if (operation == "like") { const std::vector dimensions = parse_structure_dimensions (args, first, "like constructor"); const std::size_t rows = dimensions.at (0); const std::size_t columns = dimensions.at (1); const std::string kind = require_string (args(2), "constructor kind"); if (kind != "zeros" && kind != "ones" && kind != "eye" && kind != "nan" && kind != "inf") error_with_id ("mplapack:mp:InvalidOption", "unknown like constructor kind"); if (is_complex_payload (value)) { octave_mplapack::MpfrMpcPrecisionScope scope (precision); octave_mplapack::MpfrComplexMatrixStorage result ( rows, columns, precision); for (std::size_t index = 0; index < result.numel (); ++index) { if (kind == "nan") mpc_set_nan (result.data ()[index].mpc_data ()); else if (kind == "inf") { mpfr_set_inf (mpc_realref ( result.data ()[index].mpc_data ()), 1); mpfr_set_zero (mpc_imagref ( result.data ()[index].mpc_data ()), 0); } else if (kind == "ones") mpc_set_ui (result.data ()[index].mpc_data (), 1, MPC_RND (MPFR_RNDN, MPFR_RNDN)); else mpc_set_ui (result.data ()[index].mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } if (kind == "eye") { for (std::size_t index = 0; index < std::min (rows, columns); ++index) mpc_set_ui (result.at (index, index).mpc_data (), 1, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } return make_complex_inspection_result (std::move (result)); } octave_mplapack::MpfrMatrixStorage result (rows, columns, precision); for (std::size_t index = 0; index < result.numel (); ++index) { if (kind == "nan") mpfr_set_nan (result.data ()[index].mpfr_data ()); else if (kind == "inf") mpfr_set_inf (result.data ()[index].mpfr_data (), 1); else mpfr_set_ui (result.data ()[index].mpfr_data (), kind == "ones" ? 1UL : 0UL, MPFR_RNDN); } if (kind == "eye") { for (std::size_t index = 0; index < std::min (rows, columns); ++index) mpfr_set_ui (result.at (index, index).mpfr_data (), 1, MPFR_RNDN); } return make_inspection_result (std::move (result)); } } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StructureError", "%s", exception.what ()); } return octave_value (); } mpfr_prec_t script_utility_precision (const octave_value_list& args, int first, int last) { mpfr_prec_t precision = MPFR_PREC_MIN; bool has_mp = false; for (int index = first; index < last; ++index) if (is_mp_value (args(index))) { has_mp = true; precision = std::max (precision, arithmetic_mp_precision (args(index))); } if (! has_mp) error_with_id ("mplapack:mp:InvalidInput", "utility operation requires at least one mp operand"); return precision; } octave_mplapack::MpfrScalarStorage script_real_scalar_argument (const octave_value& value, mpfr_prec_t precision, const char *description) { if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (is_complex_payload (value)) error_with_id ("mplapack:mp:ComplexUnsupported", "%s does not accept complex mp values", description); if (payload.type_id () != octave_mplapack_mpfr_scalar_internal::static_type_id ()) error_with_id ("mplapack:mp:MatrixUnsupported", "%s accepts scalar mp values only", description); const auto& source = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage ().native_value (); auto result = octave_mplapack::MpfrScalarStorage::NativeScalar::with_precision ( precision); mpfr_set (result.mpfr_data (), source.mpfr_data (), MPFR_RNDN); return octave_mplapack::MpfrScalarStorage (std::move (result)); } if (! value.isnumeric () || value.islogical () || value.is_string () || ! value.isreal () || ! value.is_real_scalar ()) error_with_id ("mplapack:mp:InvalidInput", "%s expects a real numeric scalar", description); return octave_mplapack::MpfrScalarStorage (value.double_value (), precision); } octave_mplapack::MpfrComplexScalarStorage script_complex_scalar_argument (const octave_value& value, mpfr_prec_t precision, const char *description) { if (is_mp_value (value)) { const octave_value payload = require_mp_payload (value); if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id () || payload.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) error_with_id ("mplapack:mp:MatrixUnsupported", "%s accepts scalar mp values only", description); auto result = octave_mplapack::MpfrComplexScalarStorage::NativeScalar::with_precision ( precision); if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) mpc_set (result.mpc_data (), octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage ().native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else mpc_set_fr (result.mpc_data (), octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage ().native_value ().mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return octave_mplapack::MpfrComplexScalarStorage (std::move (result)); } if (! value.isnumeric () || value.islogical () || value.is_string () || ! value.is_real_scalar () && ! value.is_complex_scalar ()) error_with_id ("mplapack:mp:InvalidInput", "%s expects a numeric scalar", description); const Complex scalar = value.complex_value (); return octave_mplapack::MpfrComplexScalarStorage ( scalar.real (), scalar.imag (), precision); } std::size_t script_utility_count (const octave_value& value, const char *description) { return require_nonnegative_structure_dimension (value, description); } octave_value script_range_operation (const octave_value_list& args) { if (args.length () != 3 && args.length () != 4) error_with_id ("mplapack:mp:InvalidArguments", "colon expects two endpoints or an endpoint and a step"); const mpfr_prec_t precision = script_utility_precision (args, 1, args.length ()); if (is_complex_arithmetic_operand (args(1)) || (args.length () == 4 && is_complex_arithmetic_operand (args(2))) || is_complex_arithmetic_operand (args(args.length () - 1))) error_with_id ("mplapack:mp:ComplexUnsupported", "complex colon ranges are not supported"); const auto first = script_real_scalar_argument (args(1), precision, "colon"); octave_mplapack::MpfrScalarStorage step (1.0, precision); const octave_value& last = args(args.length () - 1); if (args.length () == 4) step = script_real_scalar_argument (args(2), precision, "colon step"); return make_inspection_result (octave_mplapack::mpfr_script_colon ( first, step, script_real_scalar_argument (last, precision, "colon endpoint"))); } octave_value script_linspace_operation (const octave_value_list& args) { if (args.length () != 3 && args.length () != 4) error_with_id ("mplapack:mp:InvalidArguments", "linspace expects two endpoints and an optional count"); const mpfr_prec_t precision = script_utility_precision (args, 1, 3); const std::size_t count = args.length () == 4 ? script_utility_count (args(3), "linspace count") : 100; const bool complex = is_complex_arithmetic_operand (args(1)) || is_complex_arithmetic_operand (args(2)); if (complex) return make_complex_inspection_result (octave_mplapack::mpc_script_linspace ( script_complex_scalar_argument (args(1), precision, "linspace"), script_complex_scalar_argument (args(2), precision, "linspace"), count)); return make_inspection_result (octave_mplapack::mpfr_script_linspace ( script_real_scalar_argument (args(1), precision, "linspace"), script_real_scalar_argument (args(2), precision, "linspace"), count)); } octave_value script_logspace_operation (const octave_value_list& args) { if (args.length () != 3 && args.length () != 4) error_with_id ("mplapack:mp:InvalidArguments", "logspace expects two endpoints and an optional count"); if (is_complex_arithmetic_operand (args(1)) || is_complex_arithmetic_operand (args(2))) error_with_id ("mplapack:mp:ComplexUnsupported", "complex logspace endpoints are not supported"); const mpfr_prec_t precision = script_utility_precision (args, 1, 3); const std::size_t count = args.length () == 4 ? script_utility_count (args(3), "logspace count") : 50; return make_inspection_result (octave_mplapack::mpfr_script_logspace ( script_real_scalar_argument (args(1), precision, "logspace"), script_real_scalar_argument (args(2), precision, "logspace"), count)); } octave_value script_round_operation (const octave_value& value, const std::string& operation) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "%s expects an mp value", operation.c_str ()); if (is_complex_payload (value)) error_with_id ("mplapack:mp:ComplexUnsupported", "%s is implemented for real mp values only", operation.c_str ()); const auto source = script_real_matrix_operand ( value, arithmetic_mp_precision (value)); const auto select = [&] () { if (operation == "floor") return octave_mplapack::MpScriptRoundingOperation::floor; if (operation == "ceil") return octave_mplapack::MpScriptRoundingOperation::ceil; if (operation == "fix") return octave_mplapack::MpScriptRoundingOperation::fix; return octave_mplapack::MpScriptRoundingOperation::round; } (); return make_inspection_result (octave_mplapack::mpfr_script_round (source, select)); } octave_value script_real_binary_utility (const octave_value& lhs, const octave_value& rhs, const std::string& operation) { if (is_complex_arithmetic_operand (lhs) || is_complex_arithmetic_operand (rhs)) error_with_id ("mplapack:mp:ComplexUnsupported", "%s is implemented for real mp values only", operation.c_str ()); const octave_value_list operands = ovl (lhs, rhs); const mpfr_prec_t precision = script_utility_precision (operands, 0, 2); const auto left = script_real_matrix_operand (lhs, precision); const auto right = script_real_matrix_operand (rhs, precision); if (operation == "rem" || operation == "mod") return make_inspection_result (octave_mplapack::mpfr_script_remainder ( left, right, operation == "mod")); if (operation == "hypot") return make_inspection_result (octave_mplapack::mpfr_script_hypot ( left, right)); return make_inspection_result (octave_mplapack::mpfr_script_atan2 ( left, right)); } octave_value script_signbit_operation (const octave_value& value) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "signbit expects an mp value"); if (is_complex_payload (value)) error_with_id ("mplapack:mp:ComplexUnsupported", "signbit is implemented for real mp values only"); const auto source = script_real_matrix_operand ( value, arithmetic_mp_precision (value)); if (source.rows () == 1 && source.columns () == 1) return octave_value (mpfr_signbit (source.at (0, 0).mpfr_data ()) != 0); boolMatrix result (checked_octave_dimension_for_inspection (source.rows ()), checked_octave_dimension_for_inspection (source.columns ())); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) result (static_cast (row), static_cast (column)) = mpfr_signbit (source.at (row, column).mpfr_data ()) != 0; return octave_value (result); } octave_value script_eps_operation (const octave_value& value) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "eps expects an mp value"); if (is_complex_payload (value)) error_with_id ("mplapack:mp:ComplexUnsupported", "eps is implemented for real mp values only"); return make_inspection_result (octave_mplapack::mpfr_script_eps ( script_real_matrix_operand (value, arithmetic_mp_precision (value)))); } struct ParsedStatisticsOptions { octave_mplapack::MpScriptStatisticsOptions statistics; bool output_double = false; }; ParsedStatisticsOptions parse_statistics_options (const octave_value_list& args, int first, const octave_value& value, const std::string& operation) { const bool range_like = operation == "range" || operation == "bounds"; int option_first = first; ParsedStatisticsOptions result; if (operation == "var" || operation == "std") { if (option_first < args.length () && args(option_first).isnumeric ()) { const octave_value weight = args(option_first++); if (! weight.isempty ()) { if (weight.islogical () || ! weight.isreal () || ! weight.is_real_scalar ()) error_with_id ("mplapack:mp:InvalidOption", "%s normalization must be scalar 0 or 1", operation.c_str ()); const double supplied = weight.double_value (); if (! std::isfinite (supplied) || (supplied != 0.0 && supplied != 1.0)) error_with_id ("mplapack:mp:InvalidOption", "%s normalization must be scalar 0 or 1", operation.c_str ()); result.statistics.correction = supplied == 1.0 ? 1U : 0U; } } } const ParsedScriptOptions parsed = parse_script_options (args, option_first, script_default_dimension (value), range_like, false); result.statistics.dimension = parsed.reduction.dimension; result.statistics.all = parsed.reduction.all; result.statistics.omit_nan = parsed.reduction.omit_nan; result.output_double = parsed.reduction.output_double; return result; } octave_value_list script_statistics_operation (const octave_value& value, const std::string& operation, const octave_value_list& args) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "%s requires an mp value", operation.c_str ()); if (operation != "mean" && operation != "median" && operation != "var" && operation != "std" && operation != "range" && operation != "bounds") error_with_id ("mplapack:mp:InvalidOption", "unknown statistics operation: %s", operation.c_str ()); const ParsedStatisticsOptions parsed = parse_statistics_options (args, 3, value, operation); const bool complex = is_complex_arithmetic_operand (value); const mpfr_prec_t precision = arithmetic_mp_precision (value); try { if (complex) { const auto source = script_complex_matrix_operand (value, precision); if (operation == "mean") return ovl (script_complex_matrix_result ( octave_mplapack::mpc_script_mean (source, parsed.statistics), parsed.output_double)); if (operation == "median") return ovl (script_complex_matrix_result ( octave_mplapack::mpc_script_median (source, parsed.statistics), parsed.output_double)); if (operation == "var" || operation == "std") { const auto result = octave_mplapack::mpc_script_variance ( source, parsed.statistics, operation == "std"); return ovl ( script_real_matrix_result (std::move (result.values), parsed.output_double), script_complex_matrix_result (std::move (result.means), parsed.output_double)); } if (operation == "range") return ovl (script_complex_matrix_result ( octave_mplapack::mpc_script_range (source, parsed.statistics), parsed.output_double)); const auto result = octave_mplapack::mpc_script_bounds (source, parsed.statistics); return ovl ( script_complex_matrix_result (std::move (result.lower), parsed.output_double), script_complex_matrix_result (std::move (result.upper), parsed.output_double)); } const auto source = script_real_matrix_operand (value, precision); if (operation == "mean") return ovl (script_real_matrix_result ( octave_mplapack::mpfr_script_mean (source, parsed.statistics), parsed.output_double)); if (operation == "median") return ovl (script_real_matrix_result ( octave_mplapack::mpfr_script_median (source, parsed.statistics), parsed.output_double)); if (operation == "var" || operation == "std") { const auto result = octave_mplapack::mpfr_script_variance ( source, parsed.statistics, operation == "std"); return ovl ( script_real_matrix_result (std::move (result.values), parsed.output_double), script_real_matrix_result (std::move (result.means), parsed.output_double)); } if (operation == "range") return ovl (script_real_matrix_result ( octave_mplapack::mpfr_script_range (source, parsed.statistics), parsed.output_double)); const auto result = octave_mplapack::mpfr_script_bounds (source, parsed.statistics); return ovl ( script_real_matrix_result (std::move (result.lower), parsed.output_double), script_real_matrix_result (std::move (result.upper), parsed.output_double)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:StatisticsError", "%s", exception.what ()); } return ovl (octave_value ()); } octave_value script_reduce_operation ( const octave_value& value, octave_mplapack::MpScriptReductionOperation operation, const octave_value_list& args, int first_option) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "reduction functions require an mp value"); const ParsedScriptOptions parsed = parse_script_options (args, first_option, script_default_dimension (value), false, operation == octave_mplapack::MpScriptReductionOperation::cumsum || operation == octave_mplapack::MpScriptReductionOperation::cumprod); if (parsed.reduction.all && (operation == octave_mplapack::MpScriptReductionOperation::cumsum || operation == octave_mplapack::MpScriptReductionOperation::cumprod)) error_with_id ("mplapack:mp:InvalidOption", "all is not valid for cumulative reductions"); try { const mpfr_prec_t precision = arithmetic_mp_precision (value); if (is_complex_payload (value)) { const auto source = script_complex_matrix_operand (value, precision); if (operation == octave_mplapack::MpScriptReductionOperation::sumsq) return script_real_matrix_result ( octave_mplapack::mpc_script_sumsq (source, parsed.reduction), parsed.reduction.output_double); return script_complex_matrix_result ( octave_mplapack::mpc_script_reduce (source, operation, parsed.reduction), parsed.reduction.output_double); } const auto source = script_real_matrix_operand (value, precision); return script_real_matrix_result ( octave_mplapack::mpfr_script_reduce (source, operation, parsed.reduction), parsed.reduction.output_double); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:CompatibilityError", "%s", exception.what ()); } return octave_value (); } octave_value_list script_extremum_operation (const octave_value& value, const octave_value_list& args, int mode) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "min/max functions require an mp value as the first operand"); const bool has_pair = args.length () > 4 && ! args(4).isempty () && (is_mp_value (args(4)) || args(4).isnumeric ()); const int first_option = has_pair ? 5 : 4; const octave_value& rhs_value = has_pair ? args(4) : value; const bool complex = is_complex_arithmetic_operand (value) || (has_pair && is_complex_arithmetic_operand (rhs_value)); ParsedScriptOptions parsed; if (has_pair) parsed = parse_script_options (args, first_option, 1, true, false); else parsed = parse_script_options (args, first_option, script_default_dimension (value), true, false); if (has_pair && parsed.reduction.all) error_with_id ("mplapack:mp:InvalidOption", "all is not valid for pairwise min/max"); if (has_pair && mode == 1) error_with_id ("mplapack:mp:InvalidOutput", "pairwise min/max does not return indices"); try { mpfr_prec_t precision = arithmetic_mp_precision (value); if (has_pair && is_mp_value (rhs_value)) precision = std::max (precision, arithmetic_mp_precision (rhs_value)); const auto extremum = require_string (args(2), "extremum operation"); const auto operation = extremum == "min" ? octave_mplapack::MpScriptExtremumOperation::minimum : octave_mplapack::MpScriptExtremumOperation::maximum; if (complex) { const auto lhs = script_complex_matrix_operand (value, precision); const auto rhs = script_complex_matrix_operand (rhs_value, precision); octave_mplapack::MpScriptExtremumResultComplex result = has_pair ? octave_mplapack::mpc_script_extremum_pair ( lhs, rhs, operation, octave_mplapack::MpScriptExtremumOptions { parsed.reduction, parsed.comparison }) : octave_mplapack::mpc_script_extremum ( lhs, operation, octave_mplapack::MpScriptExtremumOptions { parsed.reduction, parsed.comparison }); const std::size_t result_rows = result.values.rows (); const std::size_t result_columns = result.values.columns (); const auto indices = result.indices; const octave_value values = script_complex_matrix_result (std::move (result.values), parsed.reduction.output_double); if (mode == 0) return ovl (values); return ovl (values, script_indices_result ( result_rows, result_columns, indices)); } const auto lhs = script_real_matrix_operand (value, precision); const auto rhs = script_real_matrix_operand (rhs_value, precision); octave_mplapack::MpScriptExtremumResultReal result = has_pair ? octave_mplapack::mpfr_script_extremum_pair ( lhs, rhs, operation, octave_mplapack::MpScriptExtremumOptions { parsed.reduction, parsed.comparison }) : octave_mplapack::mpfr_script_extremum ( lhs, operation, octave_mplapack::MpScriptExtremumOptions { parsed.reduction, parsed.comparison }); const std::size_t result_rows = result.values.rows (); const std::size_t result_columns = result.values.columns (); const auto indices = result.indices; const octave_value values = script_real_matrix_result (std::move (result.values), parsed.reduction.output_double); if (mode == 0) return ovl (values); return ovl (values, script_indices_result ( result_rows, result_columns, indices)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:CompatibilityError", "%s", exception.what ()); } return octave_value_list (); } octave_value script_predicate_operation (const octave_value& value, octave_mplapack::MpScriptPredicate predicate) { const octave_value payload = require_mp_payload (value); octave_mplapack::MpScriptPredicateResult result; try { if (is_complex_payload (value)) { if (payload.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) result = octave_mplapack::mpc_script_predicate ( octave_mplapack_mpc_scalar_internal::checked_value (payload) .storage (), predicate); else result = octave_mplapack::mpc_script_predicate ( octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (), predicate); } else if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) result = octave_mplapack::mpfr_script_predicate ( octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (), predicate); else result = octave_mplapack::mpfr_script_predicate ( octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (), predicate); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:CompatibilityError", "%s", exception.what ()); } if (result.rows == 1 && result.columns == 1) return octave_value (result.values.at (0) != 0); boolMatrix logicals (checked_octave_dimension_for_inspection (result.rows), checked_octave_dimension_for_inspection (result.columns)); for (std::size_t column = 0; column < result.columns; ++column) for (std::size_t row = 0; row < result.rows; ++row) logicals (static_cast (row), static_cast (column)) = result.values.at (column * result.rows + row) != 0; return octave_value (logicals); } octave_mplapack::MpScriptLogicalResult script_logical_values_for_mp (const octave_value& value) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "logical script operation requires an mp value"); const mpfr_prec_t precision = arithmetic_mp_precision (value); auto operand = prepare_script_logic_operand ( value, precision, is_complex_payload (value)); return is_complex_payload (value) ? octave_mplapack::mpc_script_logical (operand.complex_view) : octave_mplapack::mpfr_script_logical (operand.real_view); } octave_value script_any_all_operation (const octave_value& value, const std::string& operation, const octave_value_list& args) { if (operation != "any" && operation != "all") error_with_id ("mplapack:mp:InvalidOption", "logical reduction must be any or all"); const ParsedScriptOptions parsed = parse_script_options (args, 3, script_default_dimension (value), false, false); const auto source = script_logical_values_for_mp (value); if (parsed.reduction.all) { bool result = operation == "all"; for (const unsigned char entry : source.values) { if (operation == "any") result = result || entry != 0; else result = result && entry != 0; } return octave_value (result); } const std::size_t rows = parsed.reduction.dimension == 1 ? 1 : source.rows; const std::size_t columns = parsed.reduction.dimension == 1 ? source.columns : 1; boolMatrix result (checked_octave_dimension_for_inspection (rows), checked_octave_dimension_for_inspection (columns)); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) { const std::size_t length = parsed.reduction.dimension == 1 ? source.rows : source.columns; bool accumulated = operation == "all"; for (std::size_t position = 0; position < length; ++position) { const std::size_t source_row = parsed.reduction.dimension == 1 ? position : row; const std::size_t source_column = parsed.reduction.dimension == 1 ? column : position; const bool entry = source.values[source_row + source_column * source.rows] != 0; if (operation == "any") accumulated = accumulated || entry; else accumulated = accumulated && entry; } result (static_cast (row), static_cast (column)) = accumulated; } return octave_value (result); } octave_value script_linear_selection_result (const octave_value& value, const std::vector& indices) { const mpfr_prec_t precision = arithmetic_mp_precision (value); if (is_complex_payload (value)) { const auto source = script_complex_matrix_operand (value, precision); return make_complex_inspection_result ( octave_mplapack::select_complex_linear (source, indices)); } const auto source = script_real_matrix_operand (value, precision); return make_inspection_result ( octave_mplapack::select_linear (source, indices)); } octave_value_list script_find_operation (const octave_value_list& args) { if (args.length () < 3) error_with_id ("mplapack:InvalidArguments", "script_find expects an mp value and output count"); const octave_value& value = args(1); if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "find expects an mp value"); if (! args(2).is_real_scalar ()) error_with_id ("mplapack:mp:OutputCount", "find output count is invalid"); const double supplied_outputs = args(2).double_value (); if (! std::isfinite (supplied_outputs) || std::trunc (supplied_outputs) != supplied_outputs || supplied_outputs < 0.0 || supplied_outputs > 3.0) error_with_id ("mplapack:mp:OutputCount", "find supports zero through three outputs"); const int output_count = std::max (1, static_cast (supplied_outputs)); std::size_t limit = std::numeric_limits::max (); bool last = false; for (int index = 3; index < args.length (); ++index) { const octave_value& option = args(index); if (option.isnumeric () && option.isempty ()) continue; if (option.isnumeric () && option.is_real_scalar ()) { const double supplied = option.double_value (); if (! std::isfinite (supplied) || std::trunc (supplied) != supplied || supplied < 0.0 || supplied > static_cast ( std::numeric_limits::max ())) error_with_id ("mplapack:mp:InvalidOption", "find count must be a nonnegative integer"); limit = static_cast (supplied); continue; } if (option.is_string ()) { const std::string direction = option.string_value (); if (direction == "first") { last = false; continue; } if (direction == "last") { last = true; continue; } } error_with_id ("mplapack:mp:InvalidOption", "find option must be a count, \"first\", or \"last\""); } const auto logical = script_logical_values_for_mp (value); std::vector indices; indices.reserve (logical.values.size ()); for (std::size_t index = 0; index < logical.values.size (); ++index) if (logical.values[index] != 0) indices.push_back (index); if (limit != std::numeric_limits::max () && indices.size () > limit) { if (last) indices.erase (indices.begin (), indices.end () - limit); else indices.resize (limit); } const std::size_t rows = logical.rows; const std::size_t columns = logical.columns; Matrix linear (checked_octave_dimension_for_inspection (indices.size ()), 1); Matrix row_output (checked_octave_dimension_for_inspection (indices.size ()), 1); Matrix column_output (checked_octave_dimension_for_inspection (indices.size ()), 1); for (std::size_t output = 0; output < indices.size (); ++output) { const std::size_t linear_index = indices[output]; linear.xelem (static_cast (output), 0) = static_cast (linear_index + 1); row_output.xelem (static_cast (output), 0) = rows == 0 ? 1.0 : static_cast (linear_index % rows + 1); column_output.xelem (static_cast (output), 0) = rows == 0 ? 1.0 : static_cast (linear_index / rows + 1); } if (output_count == 1) return ovl (octave_value (linear)); if (output_count == 2) return ovl (octave_value (row_output), octave_value (column_output)); return ovl (octave_value (row_output), octave_value (column_output), script_linear_selection_result (value, indices)); } octave_value_list script_sort_operation (const octave_value& value, const octave_value_list& args) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "sort expects an mp value"); std::size_t dimension = script_default_dimension (value); bool dimension_supplied = false; bool descending = false; bool direction_supplied = false; for (int index = 2; index < args.length (); ++index) { const octave_value& option = args(index); if (option.isnumeric () && ! option.islogical () && ! option.is_string () && option.isreal () && option.is_real_scalar ()) { if (dimension_supplied) error_with_id ("mplapack:mp:InvalidOption", "sort dimension was supplied more than once"); const std::int64_t supplied = require_signed_structure_integer (option, "sort dimension"); if (supplied != 1 && supplied != 2) error_with_id ("mplapack:mp:InvalidDimension", "sort dimension must be 1 or 2"); dimension = static_cast (supplied); dimension_supplied = true; continue; } if (option.is_string ()) { if (direction_supplied) error_with_id ("mplapack:mp:InvalidOption", "sort direction was supplied more than once"); const std::string direction = option.string_value (); if (direction == "ascend") descending = false; else if (direction == "descend") descending = true; else error_with_id ("mplapack:mp:InvalidOption", "sort direction must be \"ascend\" or \"descend\""); direction_supplied = true; continue; } error_with_id ("mplapack:mp:InvalidOption", "sort expects a dimension or direction option"); } try { if (is_complex_payload (value)) { auto result = octave_mplapack::mpc_script_sort ( script_complex_matrix_operand (value, arithmetic_mp_precision (value)), dimension, descending); const std::size_t rows = result.values.rows (); const std::size_t columns = result.values.columns (); return ovl (make_complex_inspection_result (std::move (result.values)), script_indices_result (rows, columns, result.indices)); } auto result = octave_mplapack::mpfr_script_sort ( script_real_matrix_operand (value, arithmetic_mp_precision (value)), dimension, descending); const std::size_t rows = result.values.rows (); const std::size_t columns = result.values.columns (); return ovl (make_inspection_result (std::move (result.values)), script_indices_result (rows, columns, result.indices)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:SequenceError", "%s", exception.what ()); } return octave_value_list (); } octave_value script_diff_operation (const octave_value& value, const octave_value_list& args) { if (! is_mp_value (value)) error_with_id ("mplapack:mp:InvalidInput", "diff expects an mp value"); if (args.length () < 2 || args.length () > 4) error_with_id ("mplapack:mp:InvalidArguments", "diff expects an mp value and optional order/dimension"); std::size_t order = 1; std::size_t dimension = script_default_dimension (value); bool dimension_supplied = false; if (args.length () >= 3 && ! args(2).isnumeric () && ! args(2).islogical ()) error_with_id ("mplapack:mp:InvalidOption", "diff order must be a nonnegative integer"); if (args.length () >= 3 && ! args(2).isempty ()) order = require_nonnegative_structure_dimension (args(2), "diff order"); if (args.length () == 4) { const std::int64_t supplied = require_signed_structure_integer (args(3), "diff dimension"); if (supplied != 1 && supplied != 2) error_with_id ("mplapack:mp:InvalidDimension", "diff dimension must be 1 or 2"); dimension = static_cast (supplied); dimension_supplied = true; } try { if (is_complex_payload (value)) { const auto source = script_complex_matrix_operand ( value, arithmetic_mp_precision (value)); if (! dimension_supplied && source.numel () == 1 && order != 0) return make_complex_inspection_result ( octave_mplapack::MpfrComplexMatrixStorage ( 0, 0, source.precision_bits ())); return make_complex_inspection_result ( octave_mplapack::mpc_script_diff (source, order, dimension)); } const auto source = script_real_matrix_operand ( value, arithmetic_mp_precision (value)); if (! dimension_supplied && source.numel () == 1 && order != 0) return make_inspection_result (octave_mplapack::MpfrMatrixStorage ( 0, 0, source.precision_bits ())); return make_inspection_result ( octave_mplapack::mpfr_script_diff (source, order, dimension)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:SequenceError", "%s", exception.what ()); } return octave_value (); } bool script_equal_operation (const octave_value& lhs_value, const octave_value& rhs_value, bool nan_equal) { if (! is_mp_value (lhs_value) || ! is_mp_value (rhs_value)) return false; const octave_value lhs = require_mp_payload (lhs_value); const octave_value rhs = require_mp_payload (rhs_value); if (lhs.type_id () != rhs.type_id ()) return false; if (lhs.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) return octave_mplapack::mpfr_script_equal ( octave_mplapack_mpfr_scalar_internal::checked_value (lhs).storage (), octave_mplapack_mpfr_scalar_internal::checked_value (rhs).storage (), nan_equal); if (lhs.type_id () == octave_mplapack_mpfr_matrix_internal::static_type_id ()) return octave_mplapack::mpfr_script_equal ( octave_mplapack_mpfr_matrix_internal::checked_value (lhs).storage (), octave_mplapack_mpfr_matrix_internal::checked_value (rhs).storage (), nan_equal); if (lhs.type_id () == octave_mplapack_mpc_scalar_internal::static_type_id ()) return octave_mplapack::mpc_script_equal ( octave_mplapack_mpc_scalar_internal::checked_value (lhs).storage (), octave_mplapack_mpc_scalar_internal::checked_value (rhs).storage (), nan_equal); return octave_mplapack::mpc_script_equal ( octave_mplapack_mpc_matrix_internal::checked_value (lhs).storage (), octave_mplapack_mpc_matrix_internal::checked_value (rhs).storage (), nan_equal); } octave_value_list version_info () { const mpfr_class epsilon = Rlamch_mpfr ("E"); const double probe_value = epsilon.get_d (); const bool probe_ok = (std::isfinite (probe_value) && probe_value > 0.0 && probe_value < 1.0); octave_scalar_map info; info.assign ("octave", OCTAVE_VERSION); info.assign ("mplapack", MPLAPACK_STRINGIFY (MPLAPACK_PKG_VERSION)); info.assign ("backend", "mpfr"); info.assign ("mpfr", MPFR_VERSION_STRING); info.assign ("probe_routine", "Rlamch_mpfr(\"E\")"); info.assign ("probe_ok", probe_ok); info.assign ("probe_value", probe_value); return ovl (info); } octave_value_list mp_hess_operation (const octave_value& value) { const auto input = generalized_matrix_payload (value); return std::visit ([] (const auto& matrix) -> octave_value_list { using Matrix = std::decay_t; if constexpr (std::is_same_v) { const auto result = octave_mplapack::mplapack_mpfr_hess (matrix); return ovl (make_inspection_result (result.p), make_inspection_result (result.h)); } else { const auto result = octave_mplapack::mplapack_mpc_hess (matrix); return ovl (make_complex_inspection_result (result.p), make_complex_inspection_result (result.h)); } }, input); } octave_value_list mp_schur_operation (const octave_value& value, bool force_complex) { auto input = generalized_matrix_payload (value); if (force_complex && ! is_complex_payload (value)) input = generalized_matrix_at_precision ( input, generalized_matrix_precision (input), true); return std::visit ([] (const auto& matrix) -> octave_value_list { using Matrix = std::decay_t; if constexpr (std::is_same_v) { const auto result = octave_mplapack::mplapack_mpfr_schur (matrix); return ovl (make_inspection_result (result.u), make_inspection_result (result.s)); } else { const auto result = octave_mplapack::mplapack_mpc_schur (matrix); return ovl (make_complex_inspection_result (result.u), make_complex_inspection_result (result.s)); } }, input); } octave_value mp_balance_operation (const octave_value& value, const std::string& option) { const auto input = generalized_matrix_payload (value); const char *job = "B"; if (option == "noperm" || option == "S") job = "S"; else if (option == "noscal" || option == "P") job = "P"; else if (option != "" && option != "balance" && option != "B") error_with_id ("mplapack:mp:InvalidOption", "balance option must be \"noperm\", \"noscal\", or default"); return std::visit ([job] (const auto& matrix) -> octave_value { using Matrix = std::decay_t; if (matrix.rows () != matrix.columns ()) error_with_id ("mplapack:mp:InvalidInput", "balance expects a square mp matrix"); if constexpr (std::is_same_v) { octave_mplapack::MpfrMatrixStorage result (matrix); octave_mplapack::MpfrMatrixStorage scale ( matrix.rows (), 1, matrix.precision_bits ()); octave_mplapack::MpfrMatrixStorage::MplapackInteger ilo = 0; octave_mplapack::MpfrMatrixStorage::MplapackInteger ihi = 0; octave_mplapack::MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope scope (matrix.precision_bits ()); Rgebal (job, static_cast ( matrix.rows ()), result.data (), result.leading_dimension (), ilo, ihi, scale.data (), info); } if (info != 0) error_with_id ("mplapack:mp:BalanceError", "MPLAPACK Rgebal failed (info %d)", static_cast (info)); return make_inspection_result (std::move (result)); } else { octave_mplapack::MpfrComplexMatrixStorage result (matrix); octave_mplapack::MpfrMatrixStorage scale ( matrix.rows (), 1, matrix.precision_bits ()); octave_mplapack::MpfrComplexMatrixStorage::MplapackInteger ilo = 0; octave_mplapack::MpfrComplexMatrixStorage::MplapackInteger ihi = 0; octave_mplapack::MpfrComplexMatrixStorage::MplapackInteger info = 0; { octave_mplapack::MpfrMpcPrecisionScope scope ( matrix.precision_bits ()); Cgebal (job, static_cast ( matrix.rows ()), result.data (), result.leading_dimension (), ilo, ihi, scale.data (), info); } if (info != 0) error_with_id ("mplapack:mp:BalanceError", "MPLAPACK Cgebal failed (info %d)", static_cast (info)); return make_complex_inspection_result (std::move (result)); } }, input); } octave_value_list mp_qz_operation (const octave_value& value_a, const octave_value& value_b, bool force_complex) { auto a = generalized_matrix_payload (value_a); auto b = generalized_matrix_payload (value_b); if (generalized_matrix_precision (a) != generalized_matrix_precision (b)) error_with_id ("mplapack:mp:PrecisionMismatch", "qz matrix operands must have the same precision"); const bool complex_output = force_complex || is_complex_payload (value_a) || is_complex_payload (value_b); if (complex_output) { a = generalized_matrix_at_precision ( a, generalized_matrix_precision (a), true); b = generalized_matrix_at_precision ( b, generalized_matrix_precision (b), true); } if (! complex_output) { const auto& ar = std::get (a); const auto& br = std::get (b); const auto result = octave_mplapack::mplapack_mpfr_qz (ar, br); return ovl (make_inspection_result (result.aa), make_inspection_result (result.bb), make_inspection_result (result.q), make_inspection_result (result.z)); } const auto& ac = std::get (a); const auto& bc = std::get (b); const auto result = octave_mplapack::mplapack_mpc_qz (ac, bc); return ovl (make_complex_inspection_result (result.aa), make_complex_inspection_result (result.bb), make_complex_inspection_result (result.q), make_complex_inspection_result (result.z)); } } // namespace DEFMETHOD_DLD (__mplapack_core__, interp, args, , "Private native diagnostics for octave-mplapack.") { if (args.length () < 1 || ! args(0).is_string ()) error_with_id ("mplapack:InvalidCommand", "__mplapack_core__ expects a string command"); const bool module_locked = initialize_internal_type (interp); const std::string command = args(0).string_value (); if (command == "version") { require_argument_count (args, 1, command); return version_info (); } if (command == "module_test_locked") { require_argument_count (args, 1, command); return ovl (module_locked); } if (command == "precision_get_bits") { require_argument_count (args, 1, command); return ovl (precision_count_value ( octave_mplapack::default_precision_bits ())); } if (command == "precision_set_bits") { require_argument_count (args, 2, command); const auto requested = require_precision_count ( args(1), "mplapack:mpbits:InvalidPrecision"); if (requested > static_cast (MPFR_PREC_MAX)) error_with_id ("mplapack:mpbits:PrecisionOverflow", "bit precision exceeds MPFR_PREC_MAX"); octave_mplapack::set_default_precision_bits ( static_cast (requested)); return ovl (precision_count_value ( octave_mplapack::default_precision_bits ())); } if (command == "precision_get_digits") { require_argument_count (args, 1, command); return ovl (precision_count_value ( octave_mplapack::decimal_digits_for_bits ( octave_mplapack::default_precision_bits ()))); } if (command == "precision_test_mpfr_global_bits") { require_argument_count (args, 1, command); return ovl (precision_count_value (mpfr_get_default_prec ())); } if (command == "precision_set_digits") { require_argument_count (args, 2, command); const auto requested = require_precision_count ( args(1), "mplapack:mpdigits:InvalidPrecision"); try { const mpfr_prec_t converted = octave_mplapack::bits_for_decimal_digits (requested); octave_mplapack::set_default_precision_bits (converted); return ovl (precision_count_value ( octave_mplapack::decimal_digits_for_bits (converted))); } catch (const std::overflow_error&) { error_with_id ("mplapack:mpdigits:PrecisionOverflow", "decimal precision exceeds the MPFR range"); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } } if (command == "rng_seed") { require_argument_count (args, 2, command); const auto state = octave_mplapack::mp_random_seed ( require_rng_word (args(1), "rng seed")); return ovl (octave_uint64 (state.first), octave_uint64 (state.second)); } if (command == "rng_uniform" || command == "rng_normal") { require_argument_count (args, 5, command); const std::size_t rows = parse_reshape_dimension (args(1), "rng rows"); const std::size_t columns = parse_reshape_dimension (args(2), "rng columns"); auto state = require_rng_state (args(3), args(4)); const mpfr_prec_t precision = octave_mplapack::default_precision_bits (); octave_mplapack::synchronize_current_thread_precision (); try { if (command == "rng_uniform") return make_random_result ( octave_mplapack::mp_random_uniform ( rows, columns, precision, state), state); return make_random_result ( octave_mplapack::mp_random_normal ( rows, columns, precision, state), state); } catch (const std::exception& exception) { error_with_id ("mplapack:rng:GenerationError", "%s", exception.what ()); } } if (command == "rng_integer") { require_argument_count (args, 7, command); const auto lower = require_real_mp_scalar_for_rng (args(1), "rng lower bound"); const auto upper = require_real_mp_scalar_for_rng (args(2), "rng upper bound"); const std::size_t rows = parse_reshape_dimension (args(3), "rng rows"); const std::size_t columns = parse_reshape_dimension (args(4), "rng columns"); auto state = require_rng_state (args(5), args(6)); const mpfr_prec_t precision = octave_mplapack::default_precision_bits (); octave_mplapack::synchronize_current_thread_precision (); try { return make_random_result ( octave_mplapack::mp_random_integer ( rows, columns, precision, lower, upper, state), state); } catch (const std::exception& exception) { error_with_id ("mplapack:rng:GenerationError", "%s", exception.what ()); } } if (command == "matrix_create_double") { require_argument_count (args, 2, command); return ovl (make_matrix_from_double (args(1))); } if (command == "matrix_create_text_cell") { require_argument_count (args, 2, command); return ovl (make_matrix_from_text_cell (args(1))); } if (command == "matrix_create_complex_text_cell") { require_argument_count (args, 2, command); return ovl (make_complex_matrix_from_text_cell (args(1))); } if (command == "serialize") { require_argument_count (args, 2, command); try { return ovl (serialize_mp_value (args(1))); } catch (const std::exception& exception) { error_with_id ("mplapack:SerializationError", "%s", exception.what ()); } } if (command == "deserialize") { require_argument_count (args, 2, command); return ovl (deserialize_mp_value (args(1))); } if (command == "value_shape_info") { require_argument_count (args, 2, command); return ovl (value_shape_info (args(1))); } if (command == "value_is_matrix") { require_argument_count (args, 2, command); return ovl (is_matrix_payload (args(1))); } if (command == "value_is_real") { require_argument_count (args, 2, command); return ovl (! is_complex_payload (args(1))); } if (command == "value_real") { require_argument_count (args, 2, command); if (is_complex_payload (args(1))) return ovl (complex_real_result (args(1))); return ovl (require_mp_payload (args(1))); } if (command == "value_imag") { require_argument_count (args, 2, command); if (is_complex_payload (args(1))) return ovl (complex_imag_result (args(1))); const octave_value payload = require_mp_payload (args(1)); if (payload.type_id () == octave_mplapack_mpfr_scalar_internal::static_type_id ()) { const auto& source = octave_mplapack_mpfr_scalar_internal::checked_value (payload) .storage (); return ovl (make_internal_scalar ( 0.0, source.precision_bits ())); } const auto& source = octave_mplapack_mpfr_matrix_internal::checked_value (payload) .storage (); return ovl (make_internal_matrix ( octave_mplapack::MpfrMatrixStorage ( source.rows (), source.columns (), source.precision_bits ()))); } if (command == "value_conj") { require_argument_count (args, 2, command); if (is_complex_payload (args(1))) return ovl (complex_conj_result (args(1))); return ovl (require_mp_payload (args(1))); } if (command == "script_unary") { require_argument_count (args, 3, command); const std::string operation = require_string (args(2), "unary operation"); if (operation == "abs") return ovl (script_unary_operation ( args(1), octave_mplapack::MpScriptUnaryOperation::absolute)); if (operation == "angle") return ovl (script_unary_operation ( args(1), octave_mplapack::MpScriptUnaryOperation::angle)); if (operation == "sign") return ovl (script_unary_operation ( args(1), octave_mplapack::MpScriptUnaryOperation::sign)); error_with_id ("mplapack:mp:InvalidOption", "unknown script unary operation: %s", operation.c_str ()); } if (command == "script_elementary") { require_argument_count (args, 3, command); const std::string operation = require_string (args(2), "elementary operation"); const auto select_operation = [&] () { if (operation == "sqrt") return octave_mplapack::MpScriptElementaryOperation::sqrt; if (operation == "exp") return octave_mplapack::MpScriptElementaryOperation::exp; if (operation == "expm1") return octave_mplapack::MpScriptElementaryOperation::expm1; if (operation == "log") return octave_mplapack::MpScriptElementaryOperation::log; if (operation == "log1p") return octave_mplapack::MpScriptElementaryOperation::log1p; if (operation == "log10") return octave_mplapack::MpScriptElementaryOperation::log10; if (operation == "log2") return octave_mplapack::MpScriptElementaryOperation::log2; if (operation == "sin") return octave_mplapack::MpScriptElementaryOperation::sin; if (operation == "cos") return octave_mplapack::MpScriptElementaryOperation::cos; if (operation == "tan") return octave_mplapack::MpScriptElementaryOperation::tan; if (operation == "asin") return octave_mplapack::MpScriptElementaryOperation::asin; if (operation == "acos") return octave_mplapack::MpScriptElementaryOperation::acos; if (operation == "atan") return octave_mplapack::MpScriptElementaryOperation::atan; if (operation == "sinh") return octave_mplapack::MpScriptElementaryOperation::sinh; if (operation == "cosh") return octave_mplapack::MpScriptElementaryOperation::cosh; if (operation == "tanh") return octave_mplapack::MpScriptElementaryOperation::tanh; if (operation == "asinh") return octave_mplapack::MpScriptElementaryOperation::asinh; if (operation == "acosh") return octave_mplapack::MpScriptElementaryOperation::acosh; if (operation == "atanh") return octave_mplapack::MpScriptElementaryOperation::atanh; if (operation == "erf") return octave_mplapack::MpScriptElementaryOperation::erf; if (operation == "erfc") return octave_mplapack::MpScriptElementaryOperation::erfc; if (operation == "gamma") return octave_mplapack::MpScriptElementaryOperation::gamma; if (operation == "gammaln" || operation == "lgamma") return octave_mplapack::MpScriptElementaryOperation::lngamma; if (operation == "cbrt") return octave_mplapack::MpScriptElementaryOperation::cbrt; error_with_id ("mplapack:mp:InvalidOption", "unknown elementary operation: %s", operation.c_str ()); return octave_mplapack::MpScriptElementaryOperation::sqrt; } (); return ovl (script_elementary_operation (args(1), select_operation)); } if (command == "script_reduce") { if (args.length () < 3) error_with_id ("mplapack:InvalidArguments", "__mplapack_core__(\"script_reduce\") expects an mp value and operation"); const std::string operation = require_string (args(2), "reduction operation"); const auto select_operation = [&] () { if (operation == "sum") return octave_mplapack::MpScriptReductionOperation::sum; if (operation == "prod") return octave_mplapack::MpScriptReductionOperation::prod; if (operation == "sumsq") return octave_mplapack::MpScriptReductionOperation::sumsq; if (operation == "cumsum") return octave_mplapack::MpScriptReductionOperation::cumsum; if (operation == "cumprod") return octave_mplapack::MpScriptReductionOperation::cumprod; error_with_id ("mplapack:mp:InvalidOption", "unknown reduction operation: %s", operation.c_str ()); return octave_mplapack::MpScriptReductionOperation::sum; } (); return ovl (script_reduce_operation (args(1), select_operation, args, 3)); } if (command == "script_extremum") { if (args.length () < 4) error_with_id ("mplapack:InvalidArguments", "__mplapack_core__(\"script_extremum\") expects an mp value, operation, and output mode"); const std::string operation = require_string (args(2), "extremum operation"); if (operation != "min" && operation != "max") error_with_id ("mplapack:mp:InvalidOption", "extremum operation must be min or max"); const std::string mode = require_string (args(3), "extremum output mode"); if (mode != "value" && mode != "value_index") error_with_id ("mplapack:mp:InvalidOption", "extremum output mode must be value or value_index"); return script_extremum_operation (args(1), args, mode == "value_index"); } if (command == "script_predicate") { require_argument_count (args, 3, command); const std::string predicate = require_string (args(2), "predicate"); if (predicate == "isnan") return ovl (script_predicate_operation ( args(1), octave_mplapack::MpScriptPredicate::isnan)); if (predicate == "isinf") return ovl (script_predicate_operation ( args(1), octave_mplapack::MpScriptPredicate::isinf)); if (predicate == "isfinite") return ovl (script_predicate_operation ( args(1), octave_mplapack::MpScriptPredicate::isfinite)); error_with_id ("mplapack:mp:InvalidOption", "unknown script predicate: %s", predicate.c_str ()); } if (command == "script_compare") { require_argument_count (args, 4, command); const std::string operation = require_string (args(3), "comparison operation"); const auto select_operation = [&] () { if (operation == "eq") return octave_mplapack::MpScriptComparisonOperation::equal; if (operation == "ne") return octave_mplapack::MpScriptComparisonOperation::not_equal; if (operation == "lt") return octave_mplapack::MpScriptComparisonOperation::less; if (operation == "le") return octave_mplapack::MpScriptComparisonOperation::less_equal; if (operation == "gt") return octave_mplapack::MpScriptComparisonOperation::greater; if (operation == "ge") return octave_mplapack::MpScriptComparisonOperation::greater_equal; error_with_id ("mplapack:mp:InvalidOption", "unknown comparison operation: %s", operation.c_str ()); return octave_mplapack::MpScriptComparisonOperation::equal; } (); return ovl (script_compare_operation (args(1), args(2), select_operation)); } if (command == "script_logical") { if (args.length () < 3) error_with_id ("mplapack:InvalidArguments", "script_logical expects one or two operands"); const std::string operation = require_string (args(2), "logical operation"); if (operation == "not") { require_argument_count (args, 3, command); return ovl (script_logical_not_operation (args(1))); } require_argument_count (args, 4, command); const auto select_operation = [&] () { if (operation == "and") return octave_mplapack::MpScriptLogicalOperation::and_op; if (operation == "or") return octave_mplapack::MpScriptLogicalOperation::or_op; if (operation == "xor") return octave_mplapack::MpScriptLogicalOperation::xor_op; error_with_id ("mplapack:mp:InvalidOption", "unknown logical operation: %s", operation.c_str ()); return octave_mplapack::MpScriptLogicalOperation::and_op; } (); return ovl (script_logical_operation (args(1), args(3), select_operation)); } if (command == "script_any_all") { if (args.length () < 3) error_with_id ("mplapack:InvalidArguments", "script_any_all expects an mp value and operation"); return ovl (script_any_all_operation ( args(1), require_string (args(2), "logical reduction operation"), args)); } if (command == "script_find") return script_find_operation (args); if (command == "script_sort") return script_sort_operation (args(1), args); if (command == "script_diff") return ovl (script_diff_operation (args(1), args)); if (command == "script_structure") { if (args.length () < 3) error_with_id ("mplapack:InvalidArguments", "script_structure expects an mp value and operation"); if (args(1).is_string () && args(1).string_value () == "like") { if (args.length () < 5) error_with_id ("mplapack:mp:InvalidArguments", "like constructor expects a kind, template, and dimensions"); return ovl (script_structure_operation ( args(3), "like", args, 4)); } return ovl (script_structure_operation ( args(1), require_string (args(2), "structure operation"), args, 3)); } if (command == "script_range") { try { return ovl (script_range_operation (args)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:RangeError", "%s", exception.what ()); } } if (command == "script_linspace") { try { return ovl (script_linspace_operation (args)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:RangeError", "%s", exception.what ()); } } if (command == "script_logspace") { try { return ovl (script_logspace_operation (args)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:RangeError", "%s", exception.what ()); } } if (command == "script_round") { require_argument_count (args, 3, command); try { const std::string operation = require_string (args(2), "rounding operation"); if (operation != "floor" && operation != "ceil" && operation != "fix" && operation != "round") error_with_id ("mplapack:mp:InvalidOption", "unknown rounding operation: %s", operation.c_str ()); return ovl (script_round_operation (args(1), operation)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:UtilityError", "%s", exception.what ()); } } if (command == "script_binary_utility") { require_argument_count (args, 4, command); const std::string operation = require_string (args(3), "utility operation"); if (operation != "rem" && operation != "mod" && operation != "hypot" && operation != "atan2") error_with_id ("mplapack:mp:InvalidOption", "unknown binary utility operation: %s", operation.c_str ()); try { return ovl (script_real_binary_utility (args(1), args(2), operation)); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:UtilityError", "%s", exception.what ()); } } if (command == "script_signbit") { require_argument_count (args, 2, command); return ovl (script_signbit_operation (args(1))); } if (command == "script_eps") { require_argument_count (args, 2, command); try { return ovl (script_eps_operation (args(1))); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:UtilityError", "%s", exception.what ()); } } if (command == "script_statistics") { if (args.length () < 3) error_with_id ("mplapack:mp:InvalidArguments", "script_statistics expects an mp value and operation"); return script_statistics_operation ( args(1), require_string (args(2), "statistics operation"), args); } if (command == "value_equal") { require_argument_count (args, 4, command); const std::string mode = require_string (args(3), "equality mode"); if (mode != "isequal" && mode != "isequaln") error_with_id ("mplapack:mp:InvalidOption", "equality mode must be isequal or isequaln"); return ovl (script_equal_operation (args(1), args(2), mode == "isequaln")); } if (command == "matrix_subscript") { require_argument_count (args, 4, command); if (is_complex_payload (args(1))) return ovl (complex_matrix_subscript_result ( args(1), args(2), args(3))); return ovl (matrix_subscript_result (args(1), args(2), args(3))); } if (command == "matrix_linear_subscript") { require_argument_count (args, 3, command); if (is_complex_payload (args(1))) return ovl (complex_matrix_linear_subscript_result (args(1), args(2))); return ovl (matrix_linear_subscript_result (args(1), args(2))); } if (command == "matrix_subsasgn") { require_argument_count (args, 5, command); if (is_complex_payload (args(1)) || is_complex_arithmetic_operand (args(4))) return ovl (complex_matrix_assignment_result ( args(1), args(2), args(3), args(4))); return ovl (matrix_two_subscript_assignment_result ( args(1), args(2), args(3), args(4))); } if (command == "matrix_linear_subsasgn") { require_argument_count (args, 4, command); if (is_complex_payload (args(1)) || is_complex_arithmetic_operand (args(3))) return ovl (complex_matrix_linear_assignment_result ( args(1), args(2), args(3))); return ovl (matrix_linear_assignment_result ( args(1), args(2), args(3))); } if (command == "matrix_transpose") { require_argument_count (args, 2, command); return ovl (matrix_transpose_result (args(1))); } if (command == "matrix_ctranspose") { require_argument_count (args, 2, command); return ovl (matrix_ctranspose_result (args(1))); } if (command == "matrix_reshape") { if (args.length () != 3 && args.length () != 4) error_with_id ("mplapack:InvalidArguments", "__mplapack_core__(\"matrix_reshape\") expects two or three arguments"); if (args.length () == 3) return ovl (matrix_reshape_result (args(1), args(2), nullptr)); return ovl (matrix_reshape_result (args(1), args(2), &args(3))); } if (command == "matrix_horzcat" || command == "matrix_vertcat") { if (args.length () < 2) error_with_id ("mplapack:InvalidArguments", "__mplapack_core__(\"%s\") expects at least one operand", command.c_str ()); return ovl (matrix_concatenate_result ( args, command == "matrix_horzcat" ? 1 : 0)); } if (command == "matrix_to_double") { require_argument_count (args, 2, command); if (is_mp_value (args(1)) && is_complex_payload (args(1))) return ovl (complex_matrix_to_double (args(1))); return ovl (matrix_to_double (args(1))); } if (command == "matrix_display_text") { require_argument_count (args, 2, command); try { if (is_complex_payload (args(1))) { const auto& source = octave_mplapack_mpc_matrix_internal::checked_value ( require_matrix_payload (args(1))).storage (); return ovl (octave_mplapack::format_complex_matrix (source)); } return ovl (matrix_display_text (args(1))); } catch (const std::exception& exception) { error_with_id ("mplapack:mp:DisplayError", "%s", exception.what ()); } } if (command == "matrix_test_info") { require_argument_count (args, 2, command); const octave_value payload = require_matrix_payload (args(1)); if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { const auto& matrix = octave_mplapack_mpc_matrix_internal::checked_value (payload); const auto& storage = matrix.storage (); octave_scalar_map info; info.assign ("internal_type", matrix.static_type_name ()); info.assign ("rows", octave_uint64 (storage.rows ())); info.assign ("columns", octave_uint64 (storage.columns ())); info.assign ("numel", octave_uint64 (storage.numel ())); info.assign ("precision_bits", octave_uint64 (storage.precision_bits ())); info.assign ("leading_dimension", octave_int64 (storage.leading_dimension ())); info.assign ("storage_kind", "column_major_contiguous_complex"); info.assign ("all_elements_same_precision", storage.all_elements_have_uniform_precision ()); info.assign ("is_complex", true); return ovl (info); } const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value (payload); const auto& storage = matrix.storage (); octave_scalar_map info; info.assign ("internal_type", matrix.static_type_name ()); info.assign ("rows", octave_uint64 (storage.rows ())); info.assign ("columns", octave_uint64 (storage.columns ())); info.assign ("numel", octave_uint64 (storage.numel ())); info.assign ("precision_bits", octave_uint64 (storage.precision_bits ())); info.assign ("leading_dimension", octave_int64 (storage.leading_dimension ())); info.assign ("storage_kind", "column_major_contiguous"); info.assign ("all_elements_same_precision", storage.all_elements_have_uniform_precision ()); info.assign ("is_complex", false); return ovl (info); } if (command == "matrix_test_element_equal_text") { require_argument_count (args, 5, command); const octave_value payload = require_matrix_payload (args(1)); if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { const auto& storage = octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); try { return ovl (storage.element_exactly_equal_text ( require_matrix_index (args(2)), require_matrix_index (args(3)), require_string (args(4), "matrix test text"))); } catch (const std::out_of_range&) { error_with_id ("mplapack:InvalidArguments", "matrix test index is out of range"); } catch (const std::invalid_argument&) { error_with_id ("mplapack:InvalidScalarText", "invalid complex matrix test text"); } } const auto& storage = octave_mplapack_mpfr_matrix_internal::checked_value ( payload).storage (); const std::size_t row = require_matrix_index (args(2)); const std::size_t column = require_matrix_index (args(3)); const std::string text = require_string (args(4), "matrix test text"); try { return ovl (storage.element_exactly_equal_text (row, column, text)); } catch (const std::out_of_range&) { error_with_id ("mplapack:InvalidArguments", "matrix test index is out of range"); } catch (const std::invalid_argument&) { error_with_id ("mplapack:InvalidScalarText", "invalid matrix test text"); } } if (command == "matrix_test_element_equal_double") { require_argument_count (args, 5, command); const octave_value payload = require_matrix_payload (args(1)); if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { const auto& storage = octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); const std::size_t row = require_matrix_index (args(2)); const std::size_t column = require_matrix_index (args(3)); if (! args(4).is_complex_scalar () && ! args(4).is_real_scalar ()) error_with_id ("mplapack:InvalidArguments", "matrix test value must be a scalar"); return ovl (storage.element_exactly_equal_double ( row, column, args(4).complex_value ())); } const auto& storage = octave_mplapack_mpfr_matrix_internal::checked_value ( payload).storage (); const std::size_t row = require_matrix_index (args(2)); const std::size_t column = require_matrix_index (args(3)); const double value = require_double_scalar (args(4), "matrix test value"); if (row >= storage.rows () || column >= storage.columns ()) error_with_id ("mplapack:InvalidArguments", "matrix test index is out of range"); return ovl (storage.element_exactly_equal_double (row, column, value)); } if (command == "matrix_test_element_double") { require_argument_count (args, 4, command); const octave_value payload = require_matrix_payload (args(1)); if (payload.type_id () == octave_mplapack_mpc_matrix_internal::static_type_id ()) { const auto& storage = octave_mplapack_mpc_matrix_internal::checked_value (payload) .storage (); const std::size_t row = require_matrix_index (args(2)); const std::size_t column = require_matrix_index (args(3)); if (row >= storage.rows () || column >= storage.columns ()) error_with_id ("mplapack:InvalidArguments", "matrix test index is out of range"); return ovl (storage.at (row, column).real_to_double ()); } const auto& storage = octave_mplapack_mpfr_matrix_internal::checked_value ( payload).storage (); const std::size_t row = require_matrix_index (args(2)); const std::size_t column = require_matrix_index (args(3)); if (row >= storage.rows () || column >= storage.columns ()) error_with_id ("mplapack:InvalidArguments", "matrix test index is out of range"); return ovl (mpfr_get_d (storage.at (row, column).mpfr_data (), MPFR_RNDN)); } if (command == "matrix_test_element_equal") { require_argument_count (args, 7, command); const auto& lhs = octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (args(1))).storage (); const auto& rhs = octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (args(4))).storage (); try { return ovl (lhs.element_exactly_equal ( require_matrix_index (args(2)), require_matrix_index (args(3)), rhs, require_matrix_index (args(5)), require_matrix_index (args(6)))); } catch (const std::out_of_range&) { error_with_id ("mplapack:InvalidArguments", "matrix test index is out of range"); } } if (command == "matrix_test_clone") { require_argument_count (args, 2, command); const auto& matrix = octave_mplapack_mpfr_matrix_internal::checked_value ( require_matrix_payload (args(1))); try { return ovl (octave_value (matrix.clone ())); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } } if (command == "mtimes") { require_argument_count (args, 3, command); if (is_complex_arithmetic_operand (args(1)) || is_complex_arithmetic_operand (args(2))) return ovl (complex_mtimes_operation (args(1), args(2))); return ovl (mp_mtimes_operation (args(1), args(2))); } if (command == "power") { require_argument_count (args, 3, command); return ovl (scalar_binary_operation ( args(1), args(2), ScalarBinaryOperation::power)); } if (command == "mpower") { require_argument_count (args, 3, command); return ovl (mpower_operation (args(1), args(2))); } if (command == "mldivide") { require_argument_count (args, 3, command); if (is_complex_arithmetic_operand (args(1)) || is_complex_arithmetic_operand (args(2))) return ovl (complex_mldivide_operation (args(1), args(2))); return ovl (mp_mldivide_operation (args(1), args(2))); } if (command == "mldivide_rank") { require_argument_count (args, 3, command); if (is_complex_arithmetic_operand (args(1)) || is_complex_arithmetic_operand (args(2))) return ovl (complex_mldivide_operation (args(1), args(2), true)); return ovl (mp_mldivide_operation (args(1), args(2), true)); } if (command == "norm") { require_argument_count (args, 3, command); return ovl (mp_norm_operation (args(1), args(2))); } if (command == "det") { require_argument_count (args, 2, command); return ovl (mp_det_operation (args(1))); } if (command == "det_rcond") { require_argument_count (args, 2, command); return mp_det_rcond_operation (args(1)); } if (command == "inv") { require_argument_count (args, 2, command); return ovl (mp_inverse_operation (args(1))); } if (command == "svd") { require_argument_count (args, 4, command); const std::string option = require_string (args(2), "svd option"); const std::string outputs = require_string (args(3), "svd output mode"); if (option != "full" && option != "econ") error_with_id ("mplapack:mp:InvalidOption", "svd option must be \"full\" or \"econ\""); if (outputs != "values" && outputs != "factors") error_with_id ("mplapack:mp:InvalidArguments", "svd output mode is invalid"); return mp_svd_operation (args(1), option == "econ", outputs == "factors"); } if (command == "rank") { if (args.length () != 2 && args.length () != 3) error_with_id ("mplapack:InvalidArguments", "__mplapack_core__(\"rank\") expects one or two arguments"); return ovl (mp_rank_operation (args(1), args.length () == 3 ? &args(2) : nullptr)); } if (command == "eig") { require_argument_count (args, 4, command); return mp_eig_operation ( args(1), require_string (args(2), "eig output mode"), require_string (args(3), "eig balance mode")); } if (command == "geig") { require_argument_count (args, 5, command); return mp_generalized_eig_operation ( args(1), args(2), require_string (args(3), "generalized eig output mode"), require_string (args(4), "generalized eig algorithm")); } if (command == "cond") { require_argument_count (args, 3, command); const std::string option = require_string (args(2), "cond norm"); return ovl (mp_condition_operation (args(1), require_condition_kind (option))); } if (command == "rcond") { require_argument_count (args, 2, command); return ovl (mp_rcond_operation (args(1))); } if (command == "chol") { require_argument_count (args, 3, command); const std::string option = require_string (args(2), "chol option"); if (option != "upper" && option != "lower") error_with_id ("mplapack:mp:InvalidOption", "chol option must be \"upper\" or \"lower\""); return mp_cholesky_operation (args(1), option == "lower"); } if (command == "qr") { require_argument_count (args, 4, command); const std::string option = require_string (args(2), "qr option"); const std::string outputs = require_string (args(3), "qr output mode"); if (option != "full" && option != "econ") error_with_id ("mplapack:mp:InvalidOption", "qr option must be \"full\" or \"econ\""); if (outputs != "r" && outputs != "qr") error_with_id ("mplapack:mp:InvalidArguments", "qr output mode is invalid"); if (is_complex_payload (args(1))) return complex_qr_operation (args(1), option == "econ", outputs == "qr"); return mp_qr_operation (args(1), option == "econ", outputs == "qr"); } if (command == "hess") { require_argument_count (args, 2, command); return mp_hess_operation (args(1)); } if (command == "schur") { require_argument_count (args, 3, command); const std::string option = require_string (args(2), "schur option"); if (option != "real" && option != "complex") error_with_id ("mplapack:mp:InvalidOption", "schur option must be \"real\" or \"complex\""); return mp_schur_operation (args(1), option == "complex"); } if (command == "balance") { require_argument_count (args, 3, command); return ovl (mp_balance_operation (args(1), require_string (args(2), "balance option"))); } if (command == "qz") { require_argument_count (args, 4, command); const std::string option = require_string (args(3), "qz option"); if (option != "real" && option != "complex") error_with_id ("mplapack:mp:InvalidOption", "qz option must be \"real\" or \"complex\""); return mp_qz_operation (args(1), args(2), option == "complex"); } if (command == "qr_pivoted") { require_argument_count (args, 4, command); const std::string option = require_string (args(2), "qr option"); const std::string permutation = require_string (args(3), "qr permutation output"); if (option != "full" && option != "econ") error_with_id ("mplapack:mp:InvalidOption", "pivoted qr option must be \"full\" or \"econ\""); if (permutation != "matrix" && permutation != "vector") error_with_id ("mplapack:mp:InvalidArguments", "pivoted qr permutation output is invalid"); if (is_complex_payload (args(1))) return complex_pivoted_qr_operation (args(1), option == "econ", permutation == "vector"); return mp_pivoted_qr_operation (args(1), option == "econ", permutation == "vector"); } if (command == "lu") { require_argument_count (args, 3, command); const std::string output_mode = require_string (args(2), "lu output mode"); if (output_mode != "packed" && output_mode != "two" && output_mode != "matrix" && output_mode != "vector") error_with_id ("mplapack:mp:InvalidArguments", "lu output mode is invalid"); return mp_lu_operation (args(1), output_mode); } if (command == "scalar_test_create") { require_argument_count (args, 3, command); const std::string text = require_string (args(1), "scalar text"); const mpfr_prec_t precision_bits = require_precision (args(2)); return ovl (make_internal_scalar (text, precision_bits)); } if (command == "scalar_create_text") { require_argument_count (args, 2, command); const std::string text = require_string (args(1), "scalar text"); return ovl (make_internal_scalar ( text, octave_mplapack::default_precision_bits ())); } if (command == "scalar_create_complex_text") { require_argument_count (args, 3, command); const std::string real_text = require_string (args(1), "real text"); const std::string imag_text = require_string (args(2), "imaginary text"); return ovl (make_internal_complex_scalar ( "(" + real_text + "," + imag_text + ")", octave_mplapack::default_precision_bits ())); } if (command == "scalar_create_complex_text_single") { require_argument_count (args, 2, command); const std::string text = require_string (args(1), "complex scalar text"); return ovl (make_internal_complex_scalar ( text, octave_mplapack::default_precision_bits ())); } if (command == "scalar_create_double") { require_argument_count (args, 2, command); const double value = require_double_scalar (args(1), "scalar value"); return ovl (make_internal_scalar ( value, octave_mplapack::default_precision_bits ())); } if (command == "scalar_create_complex_double") { require_argument_count (args, 2, command); if (! args(1).is_complex_scalar ()) error_with_id ("mplapack:InvalidArguments", "complex scalar value is required"); return ovl (make_internal_complex_scalar ( args(1).complex_value (), octave_mplapack::default_precision_bits ())); } if (command == "matrix_create_complex_double") { require_argument_count (args, 2, command); if (! args(1).is_double_type () || args(1).is_real_scalar () || args(1).ndims () != 2) error_with_id ("mplapack:mp:InvalidInput", "complex matrix input must be a two-dimensional array"); const ComplexMatrix input = args(1).complex_matrix_value (); const std::size_t rows = checked_size_dimension (input.rows ()); const std::size_t columns = checked_size_dimension (input.columns ()); std::vector values; values.reserve (octave_mplapack::MpfrComplexMatrixStorage:: checked_element_count (rows, columns)); for (octave_idx_type column = 0; column < input.columns (); ++column) for (octave_idx_type row = 0; row < input.rows (); ++row) values.push_back (input.xelem (row, column)); try { return ovl (make_internal_complex_matrix ( octave_mplapack::MpfrComplexMatrixStorage ( rows, columns, octave_mplapack::default_precision_bits (), values))); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } } if (command == "scalar_default_precision") { require_argument_count (args, 1, command); return ovl (octave_int64 ( octave_mplapack::default_precision_bits ())); } if (command == "scalar_test_info") { require_argument_count (args, 2, command); if (is_mp_value (args(1)) && is_complex_payload (args(1))) { const octave_value payload = require_mp_payload (args(1)); const auto& value = octave_mplapack_mpc_scalar_internal::checked_value (payload); octave_scalar_map info; info.assign ("internal_type", value.static_type_name ()); info.assign ("precision_bits", octave_int64 (value.storage ().precision_bits ())); info.assign ("backend", "mpc"); info.assign ("is_scalar", true); info.assign ("is_complex", true); info.assign ("is_nan", value.storage ().is_nan ()); info.assign ("is_infinite", value.storage ().is_infinite ()); info.assign ("is_zero", value.storage ().is_zero ()); info.assign ("real_signbit", value.storage ().real_signbit ()); info.assign ("imag_signbit", value.storage ().imag_signbit ()); return ovl (info); } const octave_value payload = require_scalar_payload (args(1)); const auto& value = octave_mplapack_mpfr_scalar_internal::checked_value (payload); octave_scalar_map info; info.assign ("internal_type", value.static_type_name ()); info.assign ("precision_bits", octave_int64 (value.storage ().precision_bits ())); info.assign ("backend", "mpfr"); info.assign ("is_scalar", true); info.assign ("is_nan", value.storage ().is_nan ()); info.assign ("is_infinite", value.storage ().is_infinite ()); info.assign ("is_zero", value.storage ().is_zero ()); info.assign ("signbit", value.storage ().signbit ()); info.assign ("is_complex", false); return ovl (info); } if (command == "scalar_to_canonical_text") { require_argument_count (args, 2, command); if (is_mp_value (args(1)) && is_complex_payload (args(1))) { const octave_value payload = require_mp_payload (args(1)); const auto& value = octave_mplapack_mpc_scalar_internal::checked_value (payload); return ovl (value.storage ().to_canonical_string ()); } const octave_value payload = require_scalar_payload (args(1)); const auto& value = octave_mplapack_mpfr_scalar_internal::checked_value (payload); try { return ovl (value.storage ().to_canonical_string ()); } catch (const std::exception& exception) { error_with_id ("mplapack:ConversionError", "%s", exception.what ()); } } if (command == "scalar_to_double") { require_argument_count (args, 2, command); if (is_complex_payload (args(1))) { const octave_value payload = require_mp_payload (args(1)); const auto& value = octave_mplapack_mpc_scalar_internal::checked_value (payload); const std::complex converted = value.storage ().to_double (); return ovl (Complex (converted.real (), converted.imag ())); } const octave_value payload = require_scalar_payload (args(1)); const auto& value = octave_mplapack_mpfr_scalar_internal::checked_value (payload); return ovl (value.storage ().to_double ()); } if (command == "scalar_add") { require_argument_count (args, 3, command); return ovl (scalar_binary_operation ( args(1), args(2), ScalarBinaryOperation::add)); } if (command == "scalar_subtract") { require_argument_count (args, 3, command); return ovl (scalar_binary_operation ( args(1), args(2), ScalarBinaryOperation::subtract)); } if (command == "scalar_multiply") { require_argument_count (args, 3, command); return ovl (scalar_binary_operation ( args(1), args(2), ScalarBinaryOperation::multiply)); } if (command == "scalar_divide") { require_argument_count (args, 3, command); return ovl (scalar_binary_operation ( args(1), args(2), ScalarBinaryOperation::divide)); } if (command == "scalar_negate") { require_argument_count (args, 2, command); return ovl (scalar_negate (args(1))); } if (command == "scalar_test_clone") { require_argument_count (args, 2, command); const auto& value = octave_mplapack_mpfr_scalar_internal::checked_value (args(1)); try { return ovl (octave_value (value.clone ())); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } } if (command == "scalar_test_equal") { require_argument_count (args, 3, command); const octave_value lhs_payload = require_scalar_payload (args(1)); const octave_value rhs_payload = require_scalar_payload (args(2)); const auto& lhs = octave_mplapack_mpfr_scalar_internal::checked_value (lhs_payload); const auto& rhs = octave_mplapack_mpfr_scalar_internal::checked_value (rhs_payload); return ovl (lhs.storage ().exactly_equal (rhs.storage ())); } if (command == "scalar_test_equal_string") { require_argument_count (args, 3, command); const octave_value payload = require_scalar_payload (args(1)); const auto& value = octave_mplapack_mpfr_scalar_internal::checked_value (payload); const std::string text = require_string (args(2), "comparison text"); try { return ovl (value.storage ().exactly_equal_string (text)); } catch (const std::invalid_argument&) { error_with_id ("mplapack:InvalidScalarText", "invalid scalar text"); } catch (const std::exception& exception) { error_with_id ("mplapack:NativeError", "%s", exception.what ()); } } if (command == "scalar_test_equal_double") { require_argument_count (args, 3, command); const octave_value payload = require_scalar_payload (args(1)); const auto& value = octave_mplapack_mpfr_scalar_internal::checked_value (payload); const double expected = require_double_scalar (args(2), "comparison value"); return ovl (value.storage ().exactly_equal_double (expected)); } error_with_id ("mplapack:InvalidCommand", "unknown __mplapack_core__ command: %s", command.c_str ()); return ovl (); } mplapack-interop-0.5.1/src/mp_matrix_assignment.h0000644000230300031750000000224615274353472021437 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_MATRIX_ASSIGNMENT_H #define OCTAVE_MPLAPACK_MP_MATRIX_ASSIGNMENT_H #include #include #include #include "mp_matrix_storage.h" namespace octave_mplapack { // An assignment RHS supplies structural copies of its existing values. The // callback never performs arithmetic or consults the ambient MPFR default. struct MpfrAssignmentOperand { using CopyElement = std::function; std::size_t rows = 0; std::size_t columns = 0; mpfr_prec_t precision_bits = 0; bool has_mp_precision = false; CopyElement copy_element; }; MpfrMatrixStorage mpfr_matrix_assign_two_subscript ( const MpfrMatrixStorage& source, const std::vector& row_indices, const std::vector& column_indices, const MpfrAssignmentOperand& rhs, mpfr_prec_t result_precision); MpfrMatrixStorage mpfr_matrix_assign_linear ( const MpfrMatrixStorage& source, const std::vector& indices, const MpfrAssignmentOperand& rhs, mpfr_prec_t result_precision); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_lapack.cc0000644000230300031750000000615615274353472021027 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_lapack.h" #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_precision.h" namespace octave_mplapack { void require_mplapack_mpc_solve_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& b_work) { if (operation_precision < MPFR_PREC_MIN || operation_precision > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK MPC solve precision is outside the MPFR range"); const auto precision_override = mpfrxx::mpc_precision_override_storage (); const bool matches = mpfrxx::default_precision_bits () == operation_precision && precision_override.active && precision_override.real_precision_bits == operation_precision && precision_override.imag_precision_bits == operation_precision && a_work.precision_bits () == operation_precision && b_work.precision_bits () == operation_precision && a_work.all_elements_have_uniform_precision () && b_work.all_elements_have_uniform_precision (); if (! matches) throw std::runtime_error ( "MPLAPACK complex precision contract mismatch at Cgesv boundary"); } MpfrComplexMatrixStorage mplapack_mpc_matrix_solve (const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs) { if (lhs.rows () != lhs.columns ()) throw std::invalid_argument ( "MPLAPACK Cgesv requires a square coefficient matrix"); if (rhs.rows () != lhs.rows ()) throw std::invalid_argument ("matrix solve dimensions must agree"); const mpfr_prec_t operation_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); auto a_work = mplapack_mpc_matrix_copy_at_precision ( lhs, operation_precision); auto b_work = mplapack_mpc_matrix_copy_at_precision ( rhs, operation_precision); const std::size_t n = lhs.rows (); const std::size_t nrhs = rhs.columns (); if (n == 0 || nrhs == 0) return b_work; std::vector pivots (n); const auto n_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (n); const auto nrhs_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (nrhs); const auto lda = a_work.leading_dimension (); const auto ldb = b_work.leading_dimension (); MpfrComplexMatrixStorage::MplapackInteger info = 0; MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_solve_precision_contract ( operation_precision, a_work, b_work); Cgesv (n_arg, nrhs_arg, a_work.data (), lda, pivots.data (), b_work.data (), ldb, info); require_mplapack_mpc_solve_precision_contract ( operation_precision, a_work, b_work); if (info > 0) throw MpcCgesvError (MpcCgesvError::Kind::singular, info, "MPLAPACK Cgesv reported a singular matrix"); if (info < 0) throw MpcCgesvError (MpcCgesvError::Kind::invalid_argument, info, "MPLAPACK Cgesv rejected an argument"); return b_work; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_random.h0000644000230300031750000000247415274353472017166 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_RANDOM_H #define OCTAVE_MPLAPACK_MP_RANDOM_H #include #include #include "mp_matrix_storage.h" #include "mp_scalar_storage.h" namespace octave_mplapack { struct MpRandomState { std::uint64_t first = 0; std::uint64_t second = 0; }; constexpr std::uint64_t mp_random_algorithm_version = 1; MpRandomState mp_random_seed (std::uint64_t seed) noexcept; MpfrMatrixStorage mp_random_uniform (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, MpRandomState& state); MpfrMatrixStorage mp_random_normal (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, MpRandomState& state); MpfrMatrixStorage mp_random_integer (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const MpfrScalarStorage& lower, const MpfrScalarStorage& upper, MpRandomState& state); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_blas.h0000644000230300031750000000277015274353472020355 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_BLAS_H #define OCTAVE_MPLAPACK_MP_COMPLEX_BLAS_H #include "mp_complex_matrix_storage.h" #include "mp_complex_scalar_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { void require_mplapack_mpc_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexScalarStorage& alpha, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& b_work, const MpfrComplexScalarStorage& beta, const MpfrComplexMatrixStorage& c); MpfrComplexMatrixStorage mplapack_mpc_matrix_copy_at_precision ( const MpfrComplexMatrixStorage& source, mpfr_prec_t precision_bits); MpfrComplexMatrixStorage mplapack_mpc_matrix_from_real ( const MpfrMatrixStorage& source, mpfr_prec_t precision_bits); MpfrComplexScalarStorage mplapack_mpc_scalar_copy_at_precision ( const MpfrComplexScalarStorage& source, mpfr_prec_t precision_bits); MpfrComplexScalarStorage mplapack_mpc_scalar_from_real ( const MpfrScalarStorage& source, mpfr_prec_t precision_bits); MpfrComplexMatrixStorage mplapack_mpc_matrix_multiply ( const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs); MpfrComplexMatrixStorage mplapack_mpc_matrix_scale ( const MpfrComplexMatrixStorage& matrix, const MpfrComplexScalarStorage& scalar); MpfrComplexScalarStorage mplapack_mpc_scalar_multiply ( const MpfrComplexScalarStorage& lhs, const MpfrComplexScalarStorage& rhs); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_svd.cc0000644000230300031750000003300715274353472016634 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_svd.h" #include #include #include #include #include #include #include #include #include "mp_complex_precision.h" #include "mp_complex_blas.h" #include "mp_norm.h" #include "mp_precision.h" namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrScalarStorage; void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ("MPLAPACK SVD precision is outside MPFR limits"); } std::size_t checked_workspace_length (const MpfrScalarStorage::NativeScalar& query, const char *routine) { if (mpfr_nan_p (query.mpfr_data ()) != 0 || mpfr_inf_p (query.mpfr_data ()) != 0 || mpfr_integer_p (query.mpfr_data ()) == 0 || mpfr_sgn (query.mpfr_data ()) <= 0) throw std::runtime_error (std::string (routine) + " returned an invalid workspace query"); mpz_t value; mpz_t max_mplapack; mpz_t max_size; mpz_init (value); mpz_init (max_mplapack); mpz_init (max_size); mpfr_get_z (value, query.mpfr_data (), MPFR_RNDZ); const auto mplapack_max = std::numeric_limits::max (); const auto size_max = std::numeric_limits::max (); mpz_import (max_mplapack, 1, -1, sizeof (mplapack_max), 0, 0, &mplapack_max); mpz_import (max_size, 1, -1, sizeof (size_max), 0, 0, &size_max); const bool fits = mpz_cmp (value, max_mplapack) <= 0 && mpz_cmp (value, max_size) <= 0; if (! fits) { mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); throw std::overflow_error (std::string (routine) + " workspace exceeds allocation limits"); } const auto result = static_cast ( mpfr_get_uj (query.mpfr_data (), MPFR_RNDZ)); mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); return result; } std::size_t checked_complex_workspace_length ( const MpfrComplexMatrixStorage::NativeScalar& query, const char *routine) { if (mpfr_sgn (mpc_imagref (query.mpc_data ())) != 0) throw std::runtime_error (std::string (routine) + " returned a complex workspace query"); auto real_query = MpfrScalarStorage::NativeScalar::with_precision ( query.real_precision ()); mpfr_set (real_query.mpfr_data (), mpc_realref (query.mpc_data ()), MPFR_RNDN); return checked_workspace_length (real_query, routine); } void zero_matrix (MpfrMatrixStorage& matrix) { for (std::size_t index = 0; index < matrix.numel (); ++index) mpfr_set_zero (matrix.data ()[index].mpfr_data (), 1); } void require_real_svd_precision_contract (mpfr_prec_t precision, const MpfrMatrixStorage& a, const MpfrMatrixStorage& s, const MpfrMatrixStorage& u, const MpfrMatrixStorage& vt, const MpfrMatrixStorage& work) { if (mpfrxx::default_precision_bits () != precision || a.precision_bits () != precision || s.precision_bits () != precision || u.precision_bits () != precision || vt.precision_bits () != precision || work.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! s.all_elements_have_uniform_precision () || ! u.all_elements_have_uniform_precision () || ! vt.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rgesvd boundary"); } void require_complex_svd_precision_contract ( mpfr_prec_t precision, const MpfrComplexMatrixStorage& a, const MpfrMatrixStorage& s, const MpfrComplexMatrixStorage& u, const MpfrComplexMatrixStorage& vt, const MpfrComplexMatrixStorage& work, const MpfrMatrixStorage& rwork) { if (mpfrxx::default_precision_bits () != precision || a.precision_bits () != precision || s.precision_bits () != precision || u.precision_bits () != precision || vt.precision_bits () != precision || work.precision_bits () != precision || rwork.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! s.all_elements_have_uniform_precision () || ! u.all_elements_have_uniform_precision () || ! vt.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision () || ! rwork.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPC precision contract mismatch at Cgesvd boundary"); } void fill_real_s (MpfrMatrixStorage& destination, const MpfrMatrixStorage& singular_values) { zero_matrix (destination); for (std::size_t index = 0; index < singular_values.rows (); ++index) mpfr_set (destination.at (index, index).mpfr_data (), singular_values.at (index, 0).mpfr_data (), MPFR_RNDN); } void fill_real_v (MpfrMatrixStorage& v, const MpfrMatrixStorage& vt) { for (std::size_t column = 0; column < v.columns (); ++column) for (std::size_t row = 0; row < v.rows (); ++row) mpfr_set (v.at (row, column).mpfr_data (), vt.at (column, row).mpfr_data (), MPFR_RNDN); } void fill_complex_v (MpfrComplexMatrixStorage& v, const MpfrComplexMatrixStorage& vt) { for (std::size_t column = 0; column < v.columns (); ++column) for (std::size_t row = 0; row < v.rows (); ++row) mpc_conj (v.at (row, column).mpc_data (), vt.at (column, row).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } // namespace namespace octave_mplapack { MpfrSvdResult mplapack_mpfr_matrix_svd (const MpfrMatrixStorage& input, bool economy) { const mpfr_prec_t precision = input.precision_bits (); validate_precision (precision); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); const std::size_t u_columns = economy ? k : m; const std::size_t vt_rows = economy ? k : n; const std::size_t s_rows = economy ? k : m; const std::size_t s_columns = economy ? k : n; MpfrSvdResult result { MpfrMatrixStorage (m, u_columns, precision), MpfrMatrixStorage (s_rows, s_columns, precision), MpfrMatrixStorage (n, economy ? k : n, precision) }; if (m == 0 || n == 0) return result; MpfrMatrixStorage a_work (m, n, precision, input); MpfrMatrixStorage singular_values (k, 1, precision); MpfrMatrixStorage u (m, u_columns, precision); MpfrMatrixStorage vt (vt_rows, n, precision); MpfrMatrixStorage query_work (1, 1, precision); const char *job = economy ? "S" : "A"; MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope scope (precision); require_real_svd_precision_contract ( precision, a_work, singular_values, u, vt, query_work); Rgesvd (job, job, MpfrMatrixStorage::checked_mplapack_dimension (m), MpfrMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), singular_values.data (), u.data (), u.leading_dimension (), vt.data (), vt.leading_dimension (), query_work.data (), -1, info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK MPFR Rgesvd changed the current-thread default precision"); } if (info < 0) throw MpfrSvdError (MpfrSvdError::Kind::invalid_argument, -info, "MPLAPACK Rgesvd rejected a workspace query argument"); if (info > 0) throw MpfrSvdError (MpfrSvdError::Kind::convergence, info, "MPLAPACK Rgesvd workspace query failed"); const std::size_t lwork = checked_workspace_length ( query_work.at (0, 0), "MPLAPACK Rgesvd"); MpfrMatrixStorage work (lwork, 1, precision); a_work = MpfrMatrixStorage (m, n, precision, input); singular_values = MpfrMatrixStorage (k, 1, precision); u = MpfrMatrixStorage (m, u_columns, precision); vt = MpfrMatrixStorage (vt_rows, n, precision); info = 0; { MplapackMpfrPrecisionScope scope (precision); require_real_svd_precision_contract ( precision, a_work, singular_values, u, vt, work); Rgesvd (job, job, MpfrMatrixStorage::checked_mplapack_dimension (m), MpfrMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), singular_values.data (), u.data (), u.leading_dimension (), vt.data (), vt.leading_dimension (), work.data (), static_cast (lwork), info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK MPFR Rgesvd changed the current-thread default precision"); } if (info < 0) throw MpfrSvdError (MpfrSvdError::Kind::invalid_argument, -info, "MPLAPACK Rgesvd rejected an argument"); if (info > 0) throw MpfrSvdError (MpfrSvdError::Kind::convergence, info, "MPLAPACK Rgesvd failed to converge"); result.u = std::move (u); result.s = MpfrMatrixStorage (s_rows, s_columns, precision); fill_real_s (result.s, singular_values); MpfrMatrixStorage v (n, economy ? k : n, precision); fill_real_v (v, vt); result.v = std::move (v); return result; } MpcSvdResult mplapack_mpc_matrix_svd (const MpfrComplexMatrixStorage& input, bool economy) { const mpfr_prec_t precision = input.precision_bits (); validate_precision (precision); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); const std::size_t u_columns = economy ? k : m; const std::size_t vt_rows = economy ? k : n; const std::size_t s_rows = economy ? k : m; const std::size_t s_columns = economy ? k : n; MpcSvdResult result { MpfrComplexMatrixStorage (m, u_columns, precision), MpfrMatrixStorage (s_rows, s_columns, precision), MpfrComplexMatrixStorage (n, economy ? k : n, precision) }; if (m == 0 || n == 0) return result; MpfrComplexMatrixStorage a_work = mplapack_mpc_matrix_copy_at_precision (input, precision); MpfrMatrixStorage singular_values (k, 1, precision); MpfrComplexMatrixStorage u (m, u_columns, precision); MpfrComplexMatrixStorage vt (vt_rows, n, precision); MpfrComplexMatrixStorage query_work (1, 1, precision); MpfrMatrixStorage rwork (5 * k, 1, precision); const char *job = economy ? "S" : "A"; MpfrComplexMatrixStorage::MplapackInteger info = 0; { MpfrMpcPrecisionScope scope (precision); require_complex_svd_precision_contract ( precision, a_work, singular_values, u, vt, query_work, rwork); Cgesvd (job, job, MpfrComplexMatrixStorage::checked_mplapack_dimension (m), MpfrComplexMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), singular_values.data (), u.data (), u.leading_dimension (), vt.data (), vt.leading_dimension (), query_work.data (), -1, rwork.data (), info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK MPC Cgesvd changed the current-thread default precision"); } if (info < 0) throw MpcSvdError (MpcSvdError::Kind::invalid_argument, -info, "MPLAPACK Cgesvd rejected a workspace query argument"); if (info > 0) throw MpcSvdError (MpcSvdError::Kind::convergence, info, "MPLAPACK Cgesvd workspace query failed"); const std::size_t lwork = checked_complex_workspace_length ( query_work.at (0, 0), "MPLAPACK Cgesvd"); MpfrComplexMatrixStorage work (lwork, 1, precision); a_work = mplapack_mpc_matrix_copy_at_precision (input, precision); singular_values = MpfrMatrixStorage (k, 1, precision); u = MpfrComplexMatrixStorage (m, u_columns, precision); vt = MpfrComplexMatrixStorage (vt_rows, n, precision); rwork = MpfrMatrixStorage (5 * k, 1, precision); info = 0; { MpfrMpcPrecisionScope scope (precision); require_complex_svd_precision_contract ( precision, a_work, singular_values, u, vt, work, rwork); Cgesvd (job, job, MpfrComplexMatrixStorage::checked_mplapack_dimension (m), MpfrComplexMatrixStorage::checked_mplapack_dimension (n), a_work.data (), a_work.leading_dimension (), singular_values.data (), u.data (), u.leading_dimension (), vt.data (), vt.leading_dimension (), work.data (), static_cast ( lwork), rwork.data (), info); if (mpfrxx::default_precision_bits () != precision) throw std::runtime_error ( "MPLAPACK MPC Cgesvd changed the current-thread default precision"); } if (info < 0) throw MpcSvdError (MpcSvdError::Kind::invalid_argument, -info, "MPLAPACK Cgesvd rejected an argument"); if (info > 0) throw MpcSvdError (MpcSvdError::Kind::convergence, info, "MPLAPACK Cgesvd failed to converge"); result.u = std::move (u); result.s = MpfrMatrixStorage (s_rows, s_columns, precision); fill_real_s (result.s, singular_values); MpfrComplexMatrixStorage v (n, economy ? k : n, precision); fill_complex_v (v, vt); result.v = std::move (v); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_arithmetic.cc0000644000230300031750000001550415274353472021722 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_arithmetic.h" #include #include #include #include #include "mp_complex_precision.h" namespace { std::size_t compatible_dimension (std::size_t lhs, std::size_t rhs, const char *dimension_name) { if (lhs == rhs) return lhs; if (lhs == 1) return rhs; if (rhs == 1) return lhs; throw std::invalid_argument (std::string ("nonconformant ") + dimension_name + " dimensions for element-wise operation"); } std::size_t broadcast_index (std::size_t result_index, std::size_t source_dimension) { return source_dimension == 1 ? 0 : result_index; } void apply_binary (mpc_ptr destination, mpc_srcptr lhs, mpc_srcptr rhs, octave_mplapack::MpcElementwiseBinaryOperation operation) { const mpc_rnd_t rounding = MPC_RND (MPFR_RNDN, MPFR_RNDN); switch (operation) { case octave_mplapack::MpcElementwiseBinaryOperation::add: mpc_add (destination, lhs, rhs, rounding); return; case octave_mplapack::MpcElementwiseBinaryOperation::subtract: mpc_sub (destination, lhs, rhs, rounding); return; case octave_mplapack::MpcElementwiseBinaryOperation::multiply: mpc_mul (destination, lhs, rhs, rounding); return; case octave_mplapack::MpcElementwiseBinaryOperation::divide: mpc_div (destination, lhs, rhs, rounding); return; case octave_mplapack::MpcElementwiseBinaryOperation::power: mpc_pow (destination, lhs, rhs, rounding); return; } throw std::logic_error ("unknown complex element-wise operation"); } } // namespace namespace octave_mplapack { MpcElementwiseOperand MpcElementwiseOperand::from_real_scalar ( const MpfrScalarStorage& value) noexcept { return {&value, nullptr, nullptr, nullptr}; } MpcElementwiseOperand MpcElementwiseOperand::from_real_matrix ( const MpfrMatrixStorage& value) noexcept { return {nullptr, &value, nullptr, nullptr}; } MpcElementwiseOperand MpcElementwiseOperand::from_complex_scalar ( const MpfrComplexScalarStorage& value) noexcept { return {nullptr, nullptr, &value, nullptr}; } MpcElementwiseOperand MpcElementwiseOperand::from_complex_matrix ( const MpfrComplexMatrixStorage& value) noexcept { return {nullptr, nullptr, nullptr, &value}; } bool MpcElementwiseOperand::is_scalar () const noexcept { return real_scalar || complex_scalar; } bool MpcElementwiseOperand::is_complex () const noexcept { return complex_scalar || complex_matrix; } mpfr_prec_t MpcElementwiseOperand::precision_bits () const { if (real_scalar) return real_scalar->precision_bits (); if (real_matrix) return real_matrix->precision_bits (); if (complex_scalar) return complex_scalar->precision_bits (); if (complex_matrix) return complex_matrix->precision_bits (); throw std::invalid_argument ("empty complex element-wise operand"); } std::size_t MpcElementwiseOperand::rows () const { if (is_scalar ()) return 1; if (real_matrix) return real_matrix->rows (); if (complex_matrix) return complex_matrix->rows (); throw std::invalid_argument ("empty complex element-wise operand"); } std::size_t MpcElementwiseOperand::columns () const { if (is_scalar ()) return 1; if (real_matrix) return real_matrix->columns (); if (complex_matrix) return complex_matrix->columns (); throw std::invalid_argument ("empty complex element-wise operand"); } void MpcElementwiseOperand::copy_to ( MpfrComplexMatrixStorage::NativeScalar& destination, std::size_t row, std::size_t column) const { if (complex_scalar) { mpc_set (destination.mpc_data (), complex_scalar->native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return; } if (complex_matrix) { mpc_set (destination.mpc_data (), complex_matrix->at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return; } if (real_scalar) { mpc_set_fr (destination.mpc_data (), real_scalar->native_value ().mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return; } if (real_matrix) { mpc_set_fr (destination.mpc_data (), real_matrix->at (row, column).mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return; } throw std::invalid_argument ("empty complex element-wise operand"); } MpfrComplexMatrixStorage mpc_matrix_elementwise_binary ( const MpcElementwiseOperand& lhs, const MpcElementwiseOperand& rhs, MpcElementwiseBinaryOperation operation) { const std::size_t result_rows = compatible_dimension (lhs.rows (), rhs.rows (), "row"); const std::size_t result_columns = compatible_dimension (lhs.columns (), rhs.columns (), "column"); const mpfr_prec_t result_precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); MpfrMpcPrecisionScope scope (result_precision); MpfrComplexMatrixStorage result (result_rows, result_columns, result_precision); auto lhs_value = MpfrComplexMatrixStorage::NativeScalar::with_precision ( result_precision); auto rhs_value = MpfrComplexMatrixStorage::NativeScalar::with_precision ( result_precision); for (std::size_t column = 0; column < result_columns; ++column) for (std::size_t row = 0; row < result_rows; ++row) { lhs.copy_to (lhs_value, broadcast_index (row, lhs.rows ()) , broadcast_index (column, lhs.columns ())); rhs.copy_to (rhs_value, broadcast_index (row, rhs.rows ()) , broadcast_index (column, rhs.columns ())); apply_binary (result.at (row, column).mpc_data (), lhs_value.mpc_data (), rhs_value.mpc_data (), operation); } return result; } MpfrComplexMatrixStorage mpc_matrix_negate (const MpfrComplexMatrixStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) mpc_neg (result.data ()[index].mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrComplexScalarStorage mpc_scalar_negate (const MpfrComplexScalarStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexScalarStorage::NativeScalar result = MpfrComplexScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); mpc_neg (result.mpc_data (), source.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return MpfrComplexScalarStorage (std::move (result)); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_script_logic.cc0000644000230300031750000002223515274353472020522 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_script_logic.h" #include #include #include namespace { std::size_t compatible_dimension (std::size_t lhs, std::size_t rhs, const char *axis) { if (lhs != rhs && lhs != 1 && rhs != 1) throw std::invalid_argument (std::string ("nonconformant ") + axis + " dimensions for logical operation"); return std::max (lhs, rhs); } std::size_t broadcast_index (std::size_t index, std::size_t dimension) { return dimension == 1 ? 0 : index; } octave_mplapack::MpScriptLogicalResult make_result (std::size_t rows, std::size_t columns) { octave_mplapack::MpScriptLogicalResult result; result.rows = rows; result.columns = columns; result.values.assign (rows * columns, 0); return result; } bool compare_real (mpfr_srcptr lhs, mpfr_srcptr rhs, octave_mplapack::MpScriptComparisonOperation operation) { const bool nan = mpfr_nan_p (lhs) != 0 || mpfr_nan_p (rhs) != 0; if (nan) return operation == octave_mplapack::MpScriptComparisonOperation::not_equal; const int comparison = mpfr_cmp (lhs, rhs); switch (operation) { case octave_mplapack::MpScriptComparisonOperation::equal: return comparison == 0; case octave_mplapack::MpScriptComparisonOperation::not_equal: return comparison != 0; case octave_mplapack::MpScriptComparisonOperation::less: return comparison < 0; case octave_mplapack::MpScriptComparisonOperation::less_equal: return comparison <= 0; case octave_mplapack::MpScriptComparisonOperation::greater: return comparison > 0; case octave_mplapack::MpScriptComparisonOperation::greater_equal: return comparison >= 0; } throw std::logic_error ("unknown MPFR comparison operation"); } bool complex_equal (const mpc_ptr lhs, const mpc_ptr rhs) { const bool nan = mpfr_nan_p (mpc_realref (lhs)) != 0 || mpfr_nan_p (mpc_imagref (lhs)) != 0 || mpfr_nan_p (mpc_realref (rhs)) != 0 || mpfr_nan_p (mpc_imagref (rhs)) != 0; if (nan) return false; return mpfr_cmp (mpc_realref (lhs), mpc_realref (rhs)) == 0 && mpfr_cmp (mpc_imagref (lhs), mpc_imagref (rhs)) == 0; } bool complex_nonzero (const mpc_ptr value) { return mpfr_zero_p (mpc_realref (value)) == 0 || mpfr_zero_p (mpc_imagref (value)) == 0; } } // namespace namespace octave_mplapack { MpScriptLogicalResult mpfr_script_compare (const MpfrElementwiseOperand& lhs, const MpfrElementwiseOperand& rhs, MpScriptComparisonOperation operation) { const std::size_t rows = compatible_dimension (lhs.rows (), rhs.rows (), "row"); const std::size_t columns = compatible_dimension (lhs.columns (), rhs.columns (), "column"); MpScriptLogicalResult result = make_result (rows, columns); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) result.values[row + column * rows] = compare_real ( lhs.at (broadcast_index (row, lhs.rows ()), broadcast_index (column, lhs.columns ())).mpfr_data (), rhs.at (broadcast_index (row, rhs.rows ()), broadcast_index (column, rhs.columns ())).mpfr_data (), operation); return result; } MpScriptLogicalResult mpc_script_compare (const MpcElementwiseOperand& lhs, const MpcElementwiseOperand& rhs, MpScriptComparisonOperation operation) { if (operation != MpScriptComparisonOperation::equal && operation != MpScriptComparisonOperation::not_equal) throw std::invalid_argument ( "ordered comparison is undefined for complex mp values"); const std::size_t rows = compatible_dimension (lhs.rows (), rhs.rows (), "row"); const std::size_t columns = compatible_dimension (lhs.columns (), rhs.columns (), "column"); const mpfr_prec_t precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); MpScriptLogicalResult result = make_result (rows, columns); auto lhs_value = MpfrComplexMatrixStorage::NativeScalar::with_precision ( precision); auto rhs_value = MpfrComplexMatrixStorage::NativeScalar::with_precision ( precision); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) { lhs.copy_to (lhs_value, broadcast_index (row, lhs.rows ()), broadcast_index (column, lhs.columns ())); rhs.copy_to (rhs_value, broadcast_index (row, rhs.rows ()), broadcast_index (column, rhs.columns ())); const bool equal = complex_equal (lhs_value.mpc_data (), rhs_value.mpc_data ()); result.values[row + column * rows] = operation == MpScriptComparisonOperation::equal ? equal : ! equal; } return result; } MpScriptLogicalResult mpfr_script_logical (const MpfrElementwiseOperand& source) { MpScriptLogicalResult result = make_result (source.rows (), source.columns ()); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) result.values[row + column * result.rows] = mpfr_zero_p (source.at (row, column).mpfr_data ()) == 0; return result; } MpScriptLogicalResult mpc_script_logical (const MpcElementwiseOperand& source) { const mpfr_prec_t precision = source.precision_bits (); MpScriptLogicalResult result = make_result (source.rows (), source.columns ()); auto value = MpfrComplexMatrixStorage::NativeScalar::with_precision (precision); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) { source.copy_to (value, row, column); result.values[row + column * result.rows] = complex_nonzero (value.mpc_data ()); } return result; } MpScriptLogicalResult mpfr_script_logical_binary (const MpfrElementwiseOperand& lhs, const MpfrElementwiseOperand& rhs, MpScriptLogicalOperation operation) { const std::size_t rows = compatible_dimension (lhs.rows (), rhs.rows (), "row"); const std::size_t columns = compatible_dimension (lhs.columns (), rhs.columns (), "column"); MpScriptLogicalResult result = make_result (rows, columns); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) { const bool left = mpfr_zero_p ( lhs.at (broadcast_index (row, lhs.rows ()), broadcast_index (column, lhs.columns ())).mpfr_data ()) == 0; const bool right = mpfr_zero_p ( rhs.at (broadcast_index (row, rhs.rows ()), broadcast_index (column, rhs.columns ())).mpfr_data ()) == 0; bool value = false; if (operation == MpScriptLogicalOperation::and_op) value = left && right; else if (operation == MpScriptLogicalOperation::or_op) value = left || right; else value = left != right; result.values[row + column * rows] = value; } return result; } MpScriptLogicalResult mpc_script_logical_binary (const MpcElementwiseOperand& lhs, const MpcElementwiseOperand& rhs, MpScriptLogicalOperation operation) { const std::size_t rows = compatible_dimension (lhs.rows (), rhs.rows (), "row"); const std::size_t columns = compatible_dimension (lhs.columns (), rhs.columns (), "column"); const mpfr_prec_t precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); MpScriptLogicalResult result = make_result (rows, columns); auto lhs_value = MpfrComplexMatrixStorage::NativeScalar::with_precision ( precision); auto rhs_value = MpfrComplexMatrixStorage::NativeScalar::with_precision ( precision); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) { lhs.copy_to (lhs_value, broadcast_index (row, lhs.rows ()), broadcast_index (column, lhs.columns ())); rhs.copy_to (rhs_value, broadcast_index (row, rhs.rows ()), broadcast_index (column, rhs.columns ())); const bool left = complex_nonzero (lhs_value.mpc_data ()); const bool right = complex_nonzero (rhs_value.mpc_data ()); bool value = false; if (operation == MpScriptLogicalOperation::and_op) value = left && right; else if (operation == MpScriptLogicalOperation::or_op) value = left || right; else value = left != right; result.values[row + column * rows] = value; } return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_norm.h0000644000230300031750000000227115274353472016654 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_NORM_H #define OCTAVE_MPLAPACK_MP_NORM_H #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" #include "mp_scalar_storage.h" namespace octave_mplapack { struct MpfrNormRequest { enum class Kind { one, two, infinity, negative_infinity, frobenius, zero, finite }; Kind kind; double exponent = 2.0; }; class MpfrNormError : public std::runtime_error { public: explicit MpfrNormError (const char *message) : std::runtime_error (message) { } }; MpfrScalarStorage mplapack_mpfr_norm ( const MpfrMatrixStorage& input, const MpfrNormRequest& request); MpfrScalarStorage mplapack_mpc_norm ( const MpfrComplexMatrixStorage& input, const MpfrNormRequest& request); // This is intentionally a private backend-facing helper. N02 reuses it to // implement the public SVD API without introducing a second matrix-2-norm // implementation. MpfrMatrixStorage mplapack_mpfr_singular_values ( const MpfrMatrixStorage& input); MpfrMatrixStorage mplapack_mpc_singular_values ( const MpfrComplexMatrixStorage& input); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_script_statistics.cc0000644000230300031750000005775215274353472021633 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_script_statistics.h" #include #include #include #include #include #include "mp_complex_precision.h" namespace { using namespace octave_mplapack; using Real = MpfrScalarStorage::NativeScalar; using Complex = MpfrComplexScalarStorage::NativeScalar; bool real_nan (const Real& value) noexcept { return mpfr_nan_p (value.mpfr_data ()) != 0; } bool complex_nan (const Complex& value) noexcept { return mpfr_nan_p (mpc_realref (value.mpc_data ())) || mpfr_nan_p (mpc_imagref (value.mpc_data ())); } std::pair result_shape (std::size_t rows, std::size_t columns, const MpScriptStatisticsOptions& options) { if (options.all) return {1, 1}; if (options.dimension == 1) return {1, columns}; if (options.dimension == 2) return {rows, 1}; throw std::invalid_argument ("statistics dimension must be 1 or 2"); } std::size_t slice_count (std::size_t rows, std::size_t columns, const MpScriptStatisticsOptions& options) { return options.all ? 1 : options.dimension == 1 ? columns : rows; } std::vector slice_indices (std::size_t rows, std::size_t columns, const MpScriptStatisticsOptions& options, std::size_t fixed) { if (options.all) { std::vector result; result.reserve (rows * columns); for (std::size_t index = 0; index < rows * columns; ++index) result.push_back (index); return result; } const std::size_t length = options.dimension == 1 ? rows : columns; std::vector result; result.reserve (length); for (std::size_t position = 0; position < length; ++position) result.push_back (options.dimension == 1 ? position + fixed * rows : fixed + position * rows); return result; } void divide_by_count (mpfr_ptr value, std::size_t count) { if (count > std::numeric_limits::max ()) throw std::overflow_error ("statistics count exceeds MPFR divisor range"); mpfr_div_ui (value, value, static_cast (count), MPFR_RNDN); } void divide_complex_by_count (mpc_ptr value, std::size_t count) { if (count > std::numeric_limits::max ()) throw std::overflow_error ("statistics count exceeds MPC divisor range"); mpc_div_ui (value, value, static_cast (count), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } bool select_nan_policy_real (const MpfrMatrixStorage& source, const std::vector& indices, const MpScriptStatisticsOptions& options, std::size_t& used) { used = 0; for (const std::size_t index : indices) { if (real_nan (source.data ()[index])) { if (! options.omit_nan) return true; } else ++used; } return false; } bool select_nan_policy_complex (const MpfrComplexMatrixStorage& source, const std::vector& indices, const MpScriptStatisticsOptions& options, std::size_t& used) { used = 0; for (const std::size_t index : indices) { if (complex_nan (source.data ()[index])) { if (! options.omit_nan) return true; } else ++used; } return false; } void set_real_nan (mpfr_ptr value) { mpfr_set_nan (value); } void set_complex_nan (mpc_ptr value) { mpc_set_nan (value); } Real real_slice_mean (const MpfrMatrixStorage& source, const std::vector& indices, const MpScriptStatisticsOptions& options, std::size_t& used) { Real result = Real::with_precision (source.precision_bits ()); if (select_nan_policy_real (source, indices, options, used)) { set_real_nan (result.mpfr_data ()); return result; } mpfr_set_zero (result.mpfr_data (), 1); if (used == 0) { set_real_nan (result.mpfr_data ()); return result; } for (const std::size_t index : indices) if (! real_nan (source.data ()[index])) mpfr_add (result.mpfr_data (), result.mpfr_data (), source.data ()[index].mpfr_data (), MPFR_RNDN); divide_by_count (result.mpfr_data (), used); return result; } Complex complex_slice_mean (const MpfrComplexMatrixStorage& source, const std::vector& indices, const MpScriptStatisticsOptions& options, std::size_t& used) { Complex result = Complex::with_precision (source.precision_bits ()); if (select_nan_policy_complex (source, indices, options, used)) { set_complex_nan (result.mpc_data ()); return result; } mpc_set_ui (result.mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); if (used == 0) { set_complex_nan (result.mpc_data ()); return result; } for (const std::size_t index : indices) if (! complex_nan (source.data ()[index])) mpc_add (result.mpc_data (), result.mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); divide_complex_by_count (result.mpc_data (), used); return result; } int compare_complex (const Complex& lhs, const Complex& rhs) { const mpfr_prec_t precision = std::max (mpfr_get_prec (mpc_realref (lhs.mpc_data ())), mpfr_get_prec (mpc_realref (rhs.mpc_data ()))); mpfr_t left_key; mpfr_t right_key; mpfr_init2 (left_key, precision); mpfr_init2 (right_key, precision); mpc_abs (left_key, lhs.mpc_data (), MPFR_RNDN); mpc_abs (right_key, rhs.mpc_data (), MPFR_RNDN); int result = mpfr_cmp (left_key, right_key); if (result == 0) { mpfr_atan2 (left_key, mpc_imagref (lhs.mpc_data ()), mpc_realref (lhs.mpc_data ()), MPFR_RNDN); mpfr_atan2 (right_key, mpc_imagref (rhs.mpc_data ()), mpc_realref (rhs.mpc_data ()), MPFR_RNDN); result = mpfr_cmp (left_key, right_key); } mpfr_clear (left_key); mpfr_clear (right_key); return result; } template std::vector filtered_indices (const Storage& source, const std::vector& indices, const MpScriptStatisticsOptions& options); template <> std::vector filtered_indices (const MpfrMatrixStorage& source, const std::vector& indices, const MpScriptStatisticsOptions& options) { std::vector result; result.reserve (indices.size ()); for (const std::size_t index : indices) if (! options.omit_nan || ! real_nan (source.data ()[index])) result.push_back (index); return result; } template <> std::vector filtered_indices (const MpfrComplexMatrixStorage& source, const std::vector& indices, const MpScriptStatisticsOptions& options) { std::vector result; result.reserve (indices.size ()); for (const std::size_t index : indices) if (! options.omit_nan || ! complex_nan (source.data ()[index])) result.push_back (index); return result; } template bool has_nan (const Storage& source, const std::vector& indices); template <> bool has_nan (const MpfrMatrixStorage& source, const std::vector& indices) { for (const std::size_t index : indices) if (real_nan (source.data ()[index])) return true; return false; } template <> bool has_nan (const MpfrComplexMatrixStorage& source, const std::vector& indices) { for (const std::size_t index : indices) if (complex_nan (source.data ()[index])) return true; return false; } } // namespace namespace octave_mplapack { MpfrMatrixStorage mpfr_script_mean (const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options) { const auto shape = result_shape (source.rows (), source.columns (), options); MpfrMatrixStorage result (shape.first, shape.second, source.precision_bits ()); const std::size_t slices = slice_count (source.rows (), source.columns (), options); for (std::size_t fixed = 0; fixed < slices; ++fixed) { const auto indices = slice_indices (source.rows (), source.columns (), options, fixed); std::size_t used = 0; const Real value = real_slice_mean (source, indices, options, used); const std::size_t row = options.all ? 0 : options.dimension == 1 ? 0 : fixed; const std::size_t column = options.all ? 0 : options.dimension == 1 ? fixed : 0; mpfr_set (result.at (row, column).mpfr_data (), value.mpfr_data (), MPFR_RNDN); } return result; } MpfrComplexMatrixStorage mpc_script_mean (const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options) { MpfrMpcPrecisionScope scope (source.precision_bits ()); const auto shape = result_shape (source.rows (), source.columns (), options); MpfrComplexMatrixStorage result (shape.first, shape.second, source.precision_bits ()); const std::size_t slices = slice_count (source.rows (), source.columns (), options); for (std::size_t fixed = 0; fixed < slices; ++fixed) { const auto indices = slice_indices (source.rows (), source.columns (), options, fixed); std::size_t used = 0; const Complex value = complex_slice_mean (source, indices, options, used); const std::size_t row = options.all ? 0 : options.dimension == 1 ? 0 : fixed; const std::size_t column = options.all ? 0 : options.dimension == 1 ? fixed : 0; mpc_set (result.at (row, column).mpc_data (), value.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } return result; } MpfrMatrixStorage mpfr_script_median (const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options) { const auto shape = result_shape (source.rows (), source.columns (), options); MpfrMatrixStorage result (shape.first, shape.second, source.precision_bits ()); const std::size_t slices = slice_count (source.rows (), source.columns (), options); for (std::size_t fixed = 0; fixed < slices; ++fixed) { const auto original = slice_indices (source.rows (), source.columns (), options, fixed); const bool nan = has_nan (source, original); auto indices = filtered_indices (source, original, options); const std::size_t row = options.all ? 0 : options.dimension == 1 ? 0 : fixed; const std::size_t column = options.all ? 0 : options.dimension == 1 ? fixed : 0; auto& output = result.at (row, column); if ((nan && ! options.omit_nan) || indices.empty ()) { set_real_nan (output.mpfr_data ()); continue; } std::stable_sort (indices.begin (), indices.end (), [&] (std::size_t lhs, std::size_t rhs) { return mpfr_cmp (source.data ()[lhs].mpfr_data (), source.data ()[rhs].mpfr_data ()) < 0; }); const std::size_t middle = indices.size () / 2; if (indices.size () % 2 != 0) mpfr_set (output.mpfr_data (), source.data ()[indices[middle]].mpfr_data (), MPFR_RNDN); else { mpfr_add (output.mpfr_data (), source.data ()[indices[middle - 1]].mpfr_data (), source.data ()[indices[middle]].mpfr_data (), MPFR_RNDN); divide_by_count (output.mpfr_data (), 2); } } return result; } MpfrComplexMatrixStorage mpc_script_median (const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options) { MpfrMpcPrecisionScope scope (source.precision_bits ()); const auto shape = result_shape (source.rows (), source.columns (), options); MpfrComplexMatrixStorage result (shape.first, shape.second, source.precision_bits ()); const std::size_t slices = slice_count (source.rows (), source.columns (), options); for (std::size_t fixed = 0; fixed < slices; ++fixed) { const auto original = slice_indices (source.rows (), source.columns (), options, fixed); const bool nan = has_nan (source, original); auto indices = filtered_indices (source, original, options); const std::size_t row = options.all ? 0 : options.dimension == 1 ? 0 : fixed; const std::size_t column = options.all ? 0 : options.dimension == 1 ? fixed : 0; auto& output = result.at (row, column); if ((nan && ! options.omit_nan) || indices.empty ()) { set_complex_nan (output.mpc_data ()); continue; } std::stable_sort (indices.begin (), indices.end (), [&] (std::size_t lhs, std::size_t rhs) { return compare_complex (source.data ()[lhs], source.data ()[rhs]) < 0; }); const std::size_t middle = indices.size () / 2; if (indices.size () % 2 != 0) mpc_set (output.mpc_data (), source.data ()[indices[middle]].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else { mpc_add (output.mpc_data (), source.data ()[indices[middle - 1]].mpc_data (), source.data ()[indices[middle]].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); divide_complex_by_count (output.mpc_data (), 2); } } return result; } MpScriptVarianceRealResult mpfr_script_variance (const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options, bool standard_deviation) { const auto shape = result_shape (source.rows (), source.columns (), options); MpfrMatrixStorage values (shape.first, shape.second, source.precision_bits ()); MpfrMatrixStorage means (shape.first, shape.second, source.precision_bits ()); const std::size_t slices = slice_count (source.rows (), source.columns (), options); for (std::size_t fixed = 0; fixed < slices; ++fixed) { const auto indices = slice_indices (source.rows (), source.columns (), options, fixed); std::size_t used = 0; const Real mean = real_slice_mean (source, indices, options, used); const std::size_t row = options.all ? 0 : options.dimension == 1 ? 0 : fixed; const std::size_t column = options.all ? 0 : options.dimension == 1 ? fixed : 0; auto& output_mean = means.at (row, column); mpfr_set (output_mean.mpfr_data (), mean.mpfr_data (), MPFR_RNDN); auto& output = values.at (row, column); if (mpfr_nan_p (mean.mpfr_data ()) || used == 0) { set_real_nan (output.mpfr_data ()); continue; } if (used == 1) { mpfr_set_zero (output.mpfr_data (), 1); continue; } Real sum = Real::with_precision (source.precision_bits ()); Real delta = Real::with_precision (source.precision_bits ()); mpfr_set_zero (sum.mpfr_data (), 1); for (const std::size_t index : indices) if (! real_nan (source.data ()[index])) { mpfr_sub (delta.mpfr_data (), source.data ()[index].mpfr_data (), mean.mpfr_data (), MPFR_RNDN); mpfr_fma (sum.mpfr_data (), delta.mpfr_data (), delta.mpfr_data (), sum.mpfr_data (), MPFR_RNDN); } const std::size_t denominator = options.correction == 0 ? used - 1 : used; if (denominator == 0) set_real_nan (output.mpfr_data ()); else { mpfr_set (output.mpfr_data (), sum.mpfr_data (), MPFR_RNDN); divide_by_count (output.mpfr_data (), denominator); if (standard_deviation) mpfr_sqrt (output.mpfr_data (), output.mpfr_data (), MPFR_RNDN); } } return {std::move (values), std::move (means)}; } MpScriptVarianceComplexResult mpc_script_variance (const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options, bool standard_deviation) { MpfrMpcPrecisionScope scope (source.precision_bits ()); const auto shape = result_shape (source.rows (), source.columns (), options); MpfrMatrixStorage values (shape.first, shape.second, source.precision_bits ()); MpfrComplexMatrixStorage means (shape.first, shape.second, source.precision_bits ()); const std::size_t slices = slice_count (source.rows (), source.columns (), options); for (std::size_t fixed = 0; fixed < slices; ++fixed) { const auto indices = slice_indices (source.rows (), source.columns (), options, fixed); std::size_t used = 0; const Complex mean = complex_slice_mean (source, indices, options, used); const std::size_t row = options.all ? 0 : options.dimension == 1 ? 0 : fixed; const std::size_t column = options.all ? 0 : options.dimension == 1 ? fixed : 0; mpc_set (means.at (row, column).mpc_data (), mean.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); auto& output = values.at (row, column); if (mpfr_nan_p (mpc_realref (mean.mpc_data ())) || mpfr_nan_p (mpc_imagref (mean.mpc_data ())) || used == 0) { set_real_nan (output.mpfr_data ()); continue; } if (used == 1) { mpfr_set_zero (output.mpfr_data (), 1); continue; } Real sum = Real::with_precision (source.precision_bits ()); Real delta = Real::with_precision (source.precision_bits ()); Real magnitude = Real::with_precision (source.precision_bits ()); mpfr_set_zero (sum.mpfr_data (), 1); Complex difference = Complex::with_precision (source.precision_bits ()); for (const std::size_t index : indices) if (! complex_nan (source.data ()[index])) { mpc_sub (difference.mpc_data (), source.data ()[index].mpc_data (), mean.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); mpc_abs (magnitude.mpfr_data (), difference.mpc_data (), MPFR_RNDN); mpfr_mul (delta.mpfr_data (), magnitude.mpfr_data (), magnitude.mpfr_data (), MPFR_RNDN); mpfr_add (sum.mpfr_data (), sum.mpfr_data (), delta.mpfr_data (), MPFR_RNDN); } const std::size_t denominator = options.correction == 0 ? used - 1 : used; if (denominator == 0) set_real_nan (output.mpfr_data ()); else { mpfr_set (output.mpfr_data (), sum.mpfr_data (), MPFR_RNDN); divide_by_count (output.mpfr_data (), denominator); if (standard_deviation) mpfr_sqrt (output.mpfr_data (), output.mpfr_data (), MPFR_RNDN); } } return {std::move (values), std::move (means)}; } MpfrMatrixStorage mpfr_script_range (const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options) { const auto bounds = mpfr_script_bounds (source, options); MpfrMatrixStorage result (bounds.lower.rows (), bounds.lower.columns (), source.precision_bits ()); for (std::size_t index = 0; index < result.numel (); ++index) mpfr_sub (result.data ()[index].mpfr_data (), bounds.upper.data ()[index].mpfr_data (), bounds.lower.data ()[index].mpfr_data (), MPFR_RNDN); return result; } MpfrComplexMatrixStorage mpc_script_range (const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options) { const auto bounds = mpc_script_bounds (source, options); MpfrComplexMatrixStorage result (bounds.lower.rows (), bounds.lower.columns (), source.precision_bits ()); MpfrMpcPrecisionScope scope (source.precision_bits ()); for (std::size_t index = 0; index < result.numel (); ++index) mpc_sub (result.data ()[index].mpc_data (), bounds.upper.data ()[index].mpc_data (), bounds.lower.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpScriptBoundsRealResult mpfr_script_bounds (const MpfrMatrixStorage& source, const MpScriptStatisticsOptions& options) { const auto shape = result_shape (source.rows (), source.columns (), options); MpfrMatrixStorage lower (shape.first, shape.second, source.precision_bits ()); MpfrMatrixStorage upper (shape.first, shape.second, source.precision_bits ()); const std::size_t slices = slice_count (source.rows (), source.columns (), options); for (std::size_t fixed = 0; fixed < slices; ++fixed) { const auto original = slice_indices (source.rows (), source.columns (), options, fixed); const bool nan = has_nan (source, original); const auto indices = filtered_indices (source, original, options); const std::size_t row = options.all ? 0 : options.dimension == 1 ? 0 : fixed; const std::size_t column = options.all ? 0 : options.dimension == 1 ? fixed : 0; auto& lo = lower.at (row, column); auto& hi = upper.at (row, column); if ((nan && ! options.omit_nan) || indices.empty ()) { set_real_nan (lo.mpfr_data ()); set_real_nan (hi.mpfr_data ()); continue; } mpfr_set (lo.mpfr_data (), source.data ()[indices.front ()].mpfr_data (), MPFR_RNDN); mpfr_set (hi.mpfr_data (), lo.mpfr_data (), MPFR_RNDN); for (const std::size_t index : indices) { if (mpfr_cmp (source.data ()[index].mpfr_data (), lo.mpfr_data ()) < 0) mpfr_set (lo.mpfr_data (), source.data ()[index].mpfr_data (), MPFR_RNDN); if (mpfr_cmp (source.data ()[index].mpfr_data (), hi.mpfr_data ()) > 0) mpfr_set (hi.mpfr_data (), source.data ()[index].mpfr_data (), MPFR_RNDN); } } return {std::move (lower), std::move (upper)}; } MpScriptBoundsComplexResult mpc_script_bounds (const MpfrComplexMatrixStorage& source, const MpScriptStatisticsOptions& options) { MpfrMpcPrecisionScope scope (source.precision_bits ()); const auto shape = result_shape (source.rows (), source.columns (), options); MpfrComplexMatrixStorage lower (shape.first, shape.second, source.precision_bits ()); MpfrComplexMatrixStorage upper (shape.first, shape.second, source.precision_bits ()); const std::size_t slices = slice_count (source.rows (), source.columns (), options); for (std::size_t fixed = 0; fixed < slices; ++fixed) { const auto original = slice_indices (source.rows (), source.columns (), options, fixed); const bool nan = has_nan (source, original); const auto indices = filtered_indices (source, original, options); const std::size_t row = options.all ? 0 : options.dimension == 1 ? 0 : fixed; const std::size_t column = options.all ? 0 : options.dimension == 1 ? fixed : 0; auto& lo = lower.at (row, column); auto& hi = upper.at (row, column); if ((nan && ! options.omit_nan) || indices.empty ()) { set_complex_nan (lo.mpc_data ()); set_complex_nan (hi.mpc_data ()); continue; } mpc_set (lo.mpc_data (), source.data ()[indices.front ()].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); mpc_set (hi.mpc_data (), lo.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); for (const std::size_t index : indices) { if (compare_complex (source.data ()[index], lo) < 0) mpc_set (lo.mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); if (compare_complex (source.data ()[index], hi) > 0) mpc_set (hi.mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } return {std::move (lower), std::move (upper)}; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_cholesky.h0000644000230300031750000000221615274353472021250 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_CHOLESKY_H #define OCTAVE_MPLAPACK_MP_COMPLEX_CHOLESKY_H #include #include "mp_complex_matrix_storage.h" namespace octave_mplapack { class MpcCpotrfError : public std::runtime_error { public: enum class Kind { invalid_argument, internal }; MpcCpotrfError (Kind kind, MpfrComplexMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrComplexMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrComplexMatrixStorage::MplapackInteger m_info; }; struct MpcCholeskyResult { MpfrComplexMatrixStorage factor; MpfrComplexMatrixStorage::MplapackInteger info; }; void require_mplapack_mpc_cpotrf_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work); MpcCholeskyResult mplapack_mpc_matrix_cholesky ( const MpfrComplexMatrixStorage& input, bool lower); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_precision.cc0000644000230300031750000000271115274353472021560 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_precision.h" #include namespace octave_mplapack { MpfrMpcPrecisionScope::MpfrMpcPrecisionScope (mpfr_prec_t precision_bits) : m_mpfr_precision (mpfrxx::default_precision_bits ()), m_mpfr_rounding (mpfrxx::default_rounding_mode ()), m_mpc_precision (mpfrxx::mpc_precision_override_storage ()), m_mpc_rounding (mpfrxx::mpc_rounding_override_storage ()) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ("complex operation precision is outside MPFR limits"); mpfrxx::set_default_precision_bits (precision_bits); mpfrxx::set_default_rounding_mode (MPFR_RNDN); mpfrxx::set_default_mpc_precision_bits (precision_bits, precision_bits); mpfrxx::set_default_mpc_rounding_mode (MPFR_RNDN, MPFR_RNDN); } MpfrMpcPrecisionScope::~MpfrMpcPrecisionScope () noexcept { mpfrxx::set_default_precision_bits (m_mpfr_precision); mpfrxx::set_default_rounding_mode (m_mpfr_rounding); if (m_mpc_precision.active) mpfrxx::set_default_mpc_precision_bits ( m_mpc_precision.real_precision_bits, m_mpc_precision.imag_precision_bits); else mpfrxx::clear_mpc_precision_override (); if (m_mpc_rounding.active) mpfrxx::set_default_mpc_rounding_mode ( m_mpc_rounding.real_rounding_mode, m_mpc_rounding.imag_rounding_mode); else mpfrxx::clear_mpc_rounding_override (); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_scalar_storage.h0000644000230300031750000000326315274353472022423 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_SCALAR_STORAGE_H #define OCTAVE_MPLAPACK_MP_COMPLEX_SCALAR_STORAGE_H #include #include #include #include namespace octave_mplapack { class MpfrComplexScalarStorage { public: using NativeScalar = mpfrxx::mpc_class; MpfrComplexScalarStorage (const std::string& text, mpfr_prec_t precision_bits); MpfrComplexScalarStorage (double real, double imag, mpfr_prec_t precision_bits); MpfrComplexScalarStorage (const std::complex& value, mpfr_prec_t precision_bits); explicit MpfrComplexScalarStorage (NativeScalar value); MpfrComplexScalarStorage (const MpfrComplexScalarStorage&) = default; MpfrComplexScalarStorage (MpfrComplexScalarStorage&&) noexcept = default; ~MpfrComplexScalarStorage () = default; MpfrComplexScalarStorage& operator= (MpfrComplexScalarStorage other) noexcept; void swap (MpfrComplexScalarStorage& other) noexcept; mpfr_prec_t precision_bits () const noexcept; bool exactly_equal (const MpfrComplexScalarStorage& other) const noexcept; bool is_nan () const noexcept; bool is_infinite () const noexcept; bool is_zero () const noexcept; bool real_signbit () const noexcept; bool imag_signbit () const noexcept; std::string to_canonical_string () const; std::complex to_double () const; const NativeScalar& native_value () const noexcept; private: NativeScalar m_value; }; void swap (MpfrComplexScalarStorage& lhs, MpfrComplexScalarStorage& rhs) noexcept; } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_svd.h0000644000230300031750000000333315274353472016475 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_SVD_H #define OCTAVE_MPLAPACK_MP_SVD_H #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { class MpfrSvdError : public std::runtime_error { public: enum class Kind { convergence, invalid_argument, internal }; MpfrSvdError (Kind kind, MpfrMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrMatrixStorage::MplapackInteger m_info; }; class MpcSvdError : public std::runtime_error { public: enum class Kind { convergence, invalid_argument, internal }; MpcSvdError (Kind kind, MpfrComplexMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrComplexMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrComplexMatrixStorage::MplapackInteger m_info; }; struct MpfrSvdResult { MpfrMatrixStorage u; MpfrMatrixStorage s; MpfrMatrixStorage v; }; struct MpcSvdResult { MpfrComplexMatrixStorage u; MpfrMatrixStorage s; MpfrComplexMatrixStorage v; }; MpfrSvdResult mplapack_mpfr_matrix_svd (const MpfrMatrixStorage& input, bool economy); MpcSvdResult mplapack_mpc_matrix_svd ( const MpfrComplexMatrixStorage& input, bool economy); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_matrix_structure.h0000644000230300031750000000166615274353472021334 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_MATRIX_STRUCTURE_H #define OCTAVE_MPLAPACK_MP_MATRIX_STRUCTURE_H #include "mp_matrix_storage.h" #include "mp_complex_matrix_storage.h" namespace octave_mplapack { MpfrMatrixStorage mpfr_matrix_transpose ( const MpfrMatrixStorage& source); MpfrMatrixStorage mpfr_matrix_reshape ( const MpfrMatrixStorage& source, std::size_t rows, std::size_t columns); MpfrMatrixStorage mpfr_complex_matrix_real ( const MpfrComplexMatrixStorage& source); MpfrMatrixStorage mpfr_complex_matrix_imag ( const MpfrComplexMatrixStorage& source); MpfrComplexMatrixStorage mpfr_complex_matrix_conj ( const MpfrComplexMatrixStorage& source); MpfrComplexMatrixStorage mpfr_complex_matrix_transpose ( const MpfrComplexMatrixStorage& source); MpfrComplexMatrixStorage mpfr_complex_matrix_ctranspose ( const MpfrComplexMatrixStorage& source); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_qr.cc0000644000230300031750000003437215274353472020217 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_qr.h" #include #include #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_precision.h" namespace octave_mplapack { namespace { mplapackint checked_workspace_length (const mpfrxx::mpc_class& query, const char *routine) { const mpfr_prec_t precision = query.real_precision (); if (precision < MPFR_PREC_MIN || precision > MPFR_PREC_MAX) throw std::runtime_error (std::string (routine) + " returned an invalid workspace precision"); if (mpfr_sgn (mpc_imagref (query.mpc_data ())) != 0 || mpfr_sgn (mpc_realref (query.mpc_data ())) < 0 || ! mpfr_integer_p (mpc_realref (query.mpc_data ()))) throw std::runtime_error (std::string (routine) + " returned a non-integral workspace size"); const unsigned long value = mpfr_get_ui (mpc_realref (query.mpc_data ()), MPFR_RNDZ); if (value == 0 || static_cast (value) > static_cast ( std::numeric_limits::max ())) throw std::overflow_error (std::string (routine) + " workspace size is out of range"); return static_cast (value); } MpcQrResult make_qr_result_from_factorization (MpfrComplexMatrixStorage a_fact, MpfrComplexMatrixStorage tau, bool economy, bool want_q) { const mpfr_prec_t operation_precision = a_fact.precision_bits (); const std::size_t m = a_fact.rows (); const std::size_t n = a_fact.columns (); const std::size_t k = std::min (m, n); const bool tall_economy = economy && m > n; const std::size_t q_columns = tall_economy ? n : m; const std::size_t r_rows = tall_economy ? n : m; MpfrComplexMatrixStorage r (r_rows, n, operation_precision); for (std::size_t column = 0; column < n; ++column) for (std::size_t row = 0; row < r_rows; ++row) { if (row < k && row <= column) mpc_set (r.at (row, column).mpc_data (), a_fact.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else mpc_set_ui (r.at (row, column).mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } if (! want_q) return {MpfrComplexMatrixStorage (0, 0, operation_precision), std::move (r)}; const auto m_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (m); const auto k_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (k); const auto q_columns_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (q_columns); MpfrComplexMatrixStorage query_q (m, q_columns, operation_precision); for (std::size_t column = 0; column < q_columns; ++column) for (std::size_t row = 0; row < m; ++row) { if (column < n) mpc_set (query_q.at (row, column).mpc_data (), a_fact.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else mpc_set_ui (query_q.at (row, column).mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } MpfrComplexMatrixStorage query_tau (tau); MpfrComplexMatrixStorage query_work (1, 1, operation_precision); MpfrComplexMatrixStorage::MplapackInteger query_info = 0; { MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_qr_precision_contract ( operation_precision, query_q, query_tau, query_work); Cungqr (m_arg, q_columns_arg, k_arg, query_q.data (), query_q.leading_dimension (), query_tau.data (), query_work.data (), -1, query_info); require_mplapack_mpc_qr_precision_contract ( operation_precision, query_q, query_tau, query_work); } if (query_info != 0) throw MpcQrError (MpcQrError::Kind::invalid_argument, query_info, "MPLAPACK Cungqr rejected a workspace query argument"); const auto cungqr_lwork = checked_workspace_length (query_work.at (0, 0), "Cungqr"); MpfrComplexMatrixStorage q (std::move (query_q)); MpfrComplexMatrixStorage q_tau (std::move (query_tau)); MpfrComplexMatrixStorage cungqr_work ( static_cast (cungqr_lwork), 1, operation_precision); MpfrComplexMatrixStorage::MplapackInteger info = 0; { MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_qr_precision_contract ( operation_precision, q, q_tau, cungqr_work); Cungqr (m_arg, q_columns_arg, k_arg, q.data (), q.leading_dimension (), q_tau.data (), cungqr_work.data (), cungqr_lwork, info); require_mplapack_mpc_qr_precision_contract ( operation_precision, q, q_tau, cungqr_work); } if (info < 0) throw MpcQrError (MpcQrError::Kind::invalid_argument, info, "MPLAPACK Cungqr rejected an argument"); if (info > 0) throw MpcQrError (MpcQrError::Kind::internal, info, "MPLAPACK Cungqr failed"); return {std::move (q), std::move (r)}; } } // namespace void require_mplapack_mpc_qr_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& tau, const MpfrComplexMatrixStorage& work) { if (operation_precision < MPFR_PREC_MIN || operation_precision > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK MPC QR precision is outside the MPFR range"); const auto precision_override = mpfrxx::mpc_precision_override_storage (); const bool matches = mpfrxx::default_precision_bits () == operation_precision && precision_override.active && precision_override.real_precision_bits == operation_precision && precision_override.imag_precision_bits == operation_precision && a_work.precision_bits () == operation_precision && tau.precision_bits () == operation_precision && work.precision_bits () == operation_precision && a_work.all_elements_have_uniform_precision () && tau.all_elements_have_uniform_precision () && work.all_elements_have_uniform_precision (); if (! matches) throw std::runtime_error ( "MPLAPACK complex precision contract mismatch at QR boundary"); } MpcQrResult mplapack_mpc_matrix_qr (const MpfrComplexMatrixStorage& input, bool economy, bool want_q) { const mpfr_prec_t operation_precision = input.precision_bits (); if (operation_precision < MPFR_PREC_MIN || operation_precision > MPFR_PREC_MAX) throw std::invalid_argument ( "complex QR precision is outside the MPFR range"); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); const bool tall_economy = economy && m > n; const std::size_t q_columns = tall_economy ? n : m; const std::size_t r_rows = tall_economy ? n : m; if (m == 0 || n == 0) return {MpfrComplexMatrixStorage (m, q_columns, operation_precision), MpfrComplexMatrixStorage (r_rows, n, operation_precision)}; const auto m_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (m); const auto n_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (n); MpfrComplexMatrixStorage query_a = mplapack_mpc_matrix_copy_at_precision (input, operation_precision); MpfrComplexMatrixStorage query_tau (k, 1, operation_precision); MpfrComplexMatrixStorage query_work (1, 1, operation_precision); MpfrComplexMatrixStorage::MplapackInteger query_info = 0; { MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_qr_precision_contract ( operation_precision, query_a, query_tau, query_work); Cgeqrf (m_arg, n_arg, query_a.data (), query_a.leading_dimension (), query_tau.data (), query_work.data (), -1, query_info); require_mplapack_mpc_qr_precision_contract ( operation_precision, query_a, query_tau, query_work); } if (query_info != 0) throw MpcQrError (MpcQrError::Kind::invalid_argument, query_info, "MPLAPACK Cgeqrf rejected a workspace query argument"); const auto cgeqrf_lwork = checked_workspace_length (query_work.at (0, 0), "Cgeqrf"); MpfrComplexMatrixStorage a_fact = mplapack_mpc_matrix_copy_at_precision (input, operation_precision); MpfrComplexMatrixStorage tau (k, 1, operation_precision); MpfrComplexMatrixStorage cgeqrf_work ( static_cast (cgeqrf_lwork), 1, operation_precision); MpfrComplexMatrixStorage::MplapackInteger info = 0; { MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_qr_precision_contract ( operation_precision, a_fact, tau, cgeqrf_work); Cgeqrf (m_arg, n_arg, a_fact.data (), a_fact.leading_dimension (), tau.data (), cgeqrf_work.data (), cgeqrf_lwork, info); require_mplapack_mpc_qr_precision_contract ( operation_precision, a_fact, tau, cgeqrf_work); } if (info < 0) throw MpcQrError (MpcQrError::Kind::invalid_argument, info, "MPLAPACK Cgeqrf rejected an argument"); if (info > 0) throw MpcQrError (MpcQrError::Kind::internal, info, "MPLAPACK Cgeqrf failed"); return make_qr_result_from_factorization ( std::move (a_fact), std::move (tau), economy, want_q); } void require_mplapack_mpc_pivoted_qr_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& tau, const MpfrComplexMatrixStorage& work, const MpfrMatrixStorage& rwork) { require_mplapack_mpc_qr_precision_contract ( operation_precision, a_work, tau, work); if (rwork.precision_bits () != operation_precision || ! rwork.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK complex precision contract mismatch at Cgeqp3 real workspace boundary"); } MpcPivotedQrResult mplapack_mpc_matrix_pivoted_qr (const MpfrComplexMatrixStorage& input, bool economy, bool want_q) { const mpfr_prec_t operation_precision = input.precision_bits (); if (operation_precision < MPFR_PREC_MIN || operation_precision > MPFR_PREC_MAX) throw std::invalid_argument ( "complex pivoted QR precision is outside the MPFR range"); const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); const bool tall_economy = economy && m > n; const std::size_t q_columns = tall_economy ? n : m; const std::size_t r_rows = tall_economy ? n : m; std::vector permutation (n); for (std::size_t column = 0; column < n; ++column) permutation[column] = static_cast (column + 1); if (m == 0 || n == 0) return {MpfrComplexMatrixStorage (m, q_columns, operation_precision), MpfrComplexMatrixStorage (r_rows, n, operation_precision), std::move (permutation)}; const auto m_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (m); const auto n_arg = MpfrComplexMatrixStorage::checked_mplapack_dimension (n); MpfrComplexMatrixStorage query_a = mplapack_mpc_matrix_copy_at_precision (input, operation_precision); MpfrComplexMatrixStorage query_tau (k, 1, operation_precision); MpfrComplexMatrixStorage query_work (1, 1, operation_precision); MpfrMatrixStorage query_rwork (2, n, operation_precision); std::vector query_jpvt (n, 0); MpfrComplexMatrixStorage::MplapackInteger query_info = 0; { MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_pivoted_qr_precision_contract ( operation_precision, query_a, query_tau, query_work, query_rwork); Cgeqp3 (m_arg, n_arg, query_a.data (), query_a.leading_dimension (), query_jpvt.data (), query_tau.data (), query_work.data (), -1, query_rwork.data (), query_info); require_mplapack_mpc_pivoted_qr_precision_contract ( operation_precision, query_a, query_tau, query_work, query_rwork); } if (query_info != 0) throw MpcQrError (MpcQrError::Kind::invalid_argument, query_info, "MPLAPACK Cgeqp3 rejected a workspace query argument"); const auto cgeqp3_lwork = checked_workspace_length (query_work.at (0, 0), "Cgeqp3"); MpfrComplexMatrixStorage a_fact = mplapack_mpc_matrix_copy_at_precision (input, operation_precision); MpfrComplexMatrixStorage tau (k, 1, operation_precision); MpfrComplexMatrixStorage cgeqp3_work ( static_cast (cgeqp3_lwork), 1, operation_precision); MpfrMatrixStorage cgeqp3_rwork (2, n, operation_precision); std::fill (permutation.begin (), permutation.end (), 0); MpfrComplexMatrixStorage::MplapackInteger info = 0; { MpfrMpcPrecisionScope scope (operation_precision); require_mplapack_mpc_pivoted_qr_precision_contract ( operation_precision, a_fact, tau, cgeqp3_work, cgeqp3_rwork); Cgeqp3 (m_arg, n_arg, a_fact.data (), a_fact.leading_dimension (), permutation.data (), tau.data (), cgeqp3_work.data (), cgeqp3_lwork, cgeqp3_rwork.data (), info); require_mplapack_mpc_pivoted_qr_precision_contract ( operation_precision, a_fact, tau, cgeqp3_work, cgeqp3_rwork); } if (info < 0) throw MpcQrError (MpcQrError::Kind::invalid_argument, info, "MPLAPACK Cgeqp3 rejected an argument"); if (info > 0) throw MpcQrError (MpcQrError::Kind::internal, info, "MPLAPACK Cgeqp3 failed"); std::vector seen (n, false); for (std::size_t column = 0; column < n; ++column) { const auto pivot = permutation[column]; if (pivot < 1 || pivot > n_arg) throw MpcQrError (MpcQrError::Kind::internal, 0, "MPLAPACK Cgeqp3 returned an invalid permutation"); const std::size_t source = static_cast (pivot - 1); if (seen[source]) throw MpcQrError (MpcQrError::Kind::internal, 0, "MPLAPACK Cgeqp3 returned duplicate pivots"); seen[source] = true; } const auto result = make_qr_result_from_factorization ( std::move (a_fact), std::move (tau), economy, want_q); return {std::move (result.q), std::move (result.r), std::move (permutation)}; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/Makefile0000644000230300031750000007740415274353472016506 0ustar rafaelrafaelMKOCTFILE ?= mkoctfile PKG_CONFIG ?= pkg-config MPLAPACK_PC ?= mplapack_mpfr CXX ?= c++ TARGET = __mplapack_core__.oct SOURCE = octave_bridge.cc mp_value.cc mp_matrix_value.cc mp_blas.cc mp_lapack.cc \ mp_scalar_storage.cc mp_matrix_storage.cc mp_matrix_inspection.cc \ mp_matrix_arithmetic.cc mp_matrix_structure.cc mp_matrix_concat.cc \ mp_matrix_assignment.cc \ mp_arithmetic.cc mp_precision.cc mp_complex_precision.cc \ mp_complex_scalar_storage.cc mp_complex_matrix_storage.cc \ mp_complex_value.cc mp_complex_matrix_value.cc mp_complex_structure.cc \ mp_complex_arithmetic.cc mp_complex_blas.cc mp_complex_lapack.cc \ mp_complex_rank.cc mp_complex_cholesky.cc mp_complex_qr.cc \ mp_complex_lu.cc mp_complex_matrix_concat.cc mp_norm.cc mp_det_inv.cc \ mp_svd.cc mp_rank_condition.cc mp_structured_eig.cc mp_general_eig.cc \ mp_generalized_eig.cc mp_script_compat.cc mp_script_reductions.cc \ mp_schur_qz.cc \ mp_script_logic.cc mp_script_structure.cc mp_script_ranges.cc \ mp_script_statistics.cc mp_script_sequence.cc mp_native_serialization.cc \ mp_random.cc HEADERS = mp_value.h mp_matrix_value.h mp_scalar_storage.h \ mp_matrix_storage.h mp_matrix_inspection.h mp_matrix_arithmetic.h \ mp_matrix_structure.h mp_matrix_concat.h \ mp_matrix_assignment.h \ mp_precision.h mp_blas.h \ mp_lapack.h mp_complex_precision.h mp_complex_scalar_storage.h \ mp_complex_matrix_storage.h mp_complex_value.h mp_complex_matrix_value.h \ mp_complex_structure.h mp_complex_arithmetic.h mp_complex_blas.h \ mp_complex_lapack.h mp_complex_rank.h mp_complex_cholesky.h mp_complex_qr.h \ mp_complex_lu.h mp_complex_matrix_concat.h mp_norm.h mp_det_inv.h mp_svd.h \ mp_rank_condition.h mp_structured_eig.h mp_general_eig.h \ mp_generalized_eig.h mp_script_compat.h mp_script_reductions.h \ mp_schur_qz.h \ mp_script_logic.h mp_script_structure.h mp_script_ranges.h \ mp_script_statistics.h mp_script_sequence.h mp_native_serialization.h \ mp_random.h STORAGE_TEST = .build-m02/mp_scalar_storage_test ARITHMETIC_TEST = .build-m06/mp_scalar_arithmetic_test MATRIX_TEST = .build-m07/mp_matrix_storage_test BLAS_TEST = .build-m08/mp_blas_test LAPACK_TEST = .build-m09/mp_lapack_test INSPECTION_TEST = .build-m10/mp_matrix_inspection_test ELEMENTWISE_TEST = .build-m11/mp_matrix_arithmetic_test STRUCTURE_TEST = .build-m12/mp_matrix_structure_test CONCAT_TEST = .build-m13/mp_matrix_concat_test ASSIGNMENT_TEST = .build-m14/mp_matrix_assignment_test RGELS_TEST = .build-m15/mp_lapack_rgels_test RANK_TEST = .build-m16/mp_lapack_rank_test CHOLESKY_TEST = .build-m17/mp_lapack_cholesky_test QR_TEST = .build-m18/mp_lapack_qr_test PIVOTED_QR_TEST = .build-m19/mp_lapack_pivoted_qr_test LU_TEST = .build-m21/mp_lapack_lu_test DEPENDENCY_TEST = .build-m22/m22_dependency_probe CPLX_STORAGE_TEST = .build-c00/mp_complex_storage_test CPLX_STRUCTURE_TEST = .build-c03/mp_complex_structure_test CPLX_ARITHMETIC_TEST = .build-c04/mp_complex_arithmetic_test CPLX_BLAS_TEST = .build-c05/mp_complex_blas_test CPLX_LAPACK_TEST = .build-c06/mp_complex_lapack_test CPLX_LU_TEST = .build-c11l/mp_complex_lu_test NORM_TEST = .build-n00/mp_norm_test DET_INV_TEST = .build-n01/mp_det_inv_test SVD_TEST = .build-n02/mp_svd_test RANK_CONDITION_TEST = .build-n03/mp_rank_condition_test STRUCTURED_EIG_TEST = .build-n04/mp_structured_eig_test GENERAL_EIG_TEST = .build-n05/mp_general_eig_test GENERALIZED_EIG_TEST = .build-n06/mp_generalized_eig_test SCRIPT_SEQUENCE_TEST = .build-s08/mp_script_sequence_test MPLAPACK_VERSION := $(shell $(PKG_CONFIG) --modversion $(MPLAPACK_PC) 2>/dev/null) MPLAPACK_CFLAGS ?= $(shell $(PKG_CONFIG) --cflags $(MPLAPACK_PC) 2>/dev/null) MPLAPACK_LIBS ?= $(shell $(PKG_CONFIG) --libs $(MPLAPACK_PC) 2>/dev/null) PACKAGE_CXXFLAGS = -std=c++17 -DMPLAPACK_PKG_VERSION=$(MPLAPACK_VERSION) SANITIZER_FLAGS = -fsanitize=address,undefined -fno-omit-frame-pointer .PHONY: all check-deps check-dependency check-storage-sanitized \ check-arithmetic-sanitized check-matrix-sanitized check-blas \ check-lapack check-inspection check-elementwise check-structure \ check-concat check-assignment check-rgels check-rank check-cholesky check-qr \ check-pivoted-qr check-lu check-complex-storage check-complex-structure \ check-complex-arithmetic check-complex-blas check-complex-lapack \ check-complex-rank check-complex-cholesky check-complex-qr \ check-complex-pivoted-qr check-complex-concat check-complex-lu check-norm \ check-det-inv check-svd check-rank-condition check-structured-eig \ check-general-eig check-generalized-eig check-schur-qz check-script-sequence clean .DELETE_ON_ERROR: all: $(TARGET) $(RM) -r .build-m22 $(TARGET): $(SOURCE) $(HEADERS) | check-dependency @echo "Building $(TARGET) with MKOCTFILE=$(MKOCTFILE)" $(MKOCTFILE) $(PACKAGE_CXXFLAGS) $(MPLAPACK_CFLAGS) $(SOURCE) \ $(MPLAPACK_LIBS) -o $@ $(STORAGE_TEST): ../test/mp_scalar_storage_test.cc \ mp_scalar_storage.cc mp_scalar_storage.h mp_precision.cc mp_precision.h \ | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_scalar_storage_test.cc \ mp_scalar_storage.cc mp_precision.cc $(MPLAPACK_LIBS) -o $@ $(ARITHMETIC_TEST): ../test/mp_scalar_arithmetic_test.cc \ mp_scalar_storage.cc mp_scalar_storage.h mp_arithmetic.cc \ mp_precision.cc mp_precision.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_scalar_arithmetic_test.cc \ mp_scalar_storage.cc mp_arithmetic.cc mp_precision.cc \ $(MPLAPACK_LIBS) -o $@ check-storage-sanitized: $(STORAGE_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(STORAGE_TEST) check-arithmetic-sanitized: $(ARITHMETIC_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(ARITHMETIC_TEST) $(MATRIX_TEST): ../test/mp_matrix_storage_test.cc \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_matrix_storage_test.cc \ mp_matrix_storage.cc $(MPLAPACK_LIBS) -o $@ check-matrix-sanitized: $(MATRIX_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(MATRIX_TEST) $(BLAS_TEST): ../test/mp_blas_test.cc mp_blas.cc mp_blas.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_blas_test.cc mp_blas.cc \ mp_matrix_storage.cc $(MPLAPACK_LIBS) -o $@ check-blas: $(BLAS_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(BLAS_TEST) $(LAPACK_TEST): ../test/mp_lapack_test.cc mp_lapack.cc mp_lapack.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_lapack_test.cc mp_lapack.cc \ mp_matrix_storage.cc $(MPLAPACK_LIBS) -o $@ check-lapack: $(LAPACK_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(LAPACK_TEST) $(INSPECTION_TEST): ../test/mp_matrix_inspection_test.cc \ mp_matrix_inspection.cc mp_matrix_inspection.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_matrix_inspection_test.cc \ mp_matrix_inspection.cc mp_matrix_storage.cc mp_scalar_storage.cc \ mp_complex_matrix_storage.cc mp_complex_scalar_storage.cc \ mp_complex_precision.cc \ $(MPLAPACK_LIBS) -o $@ check-inspection: $(INSPECTION_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(INSPECTION_TEST) $(ELEMENTWISE_TEST): ../test/mp_matrix_arithmetic_test.cc \ mp_matrix_arithmetic.cc mp_matrix_arithmetic.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_matrix_arithmetic_test.cc \ mp_matrix_arithmetic.cc mp_matrix_storage.cc mp_scalar_storage.cc \ $(MPLAPACK_LIBS) -o $@ check-elementwise: $(ELEMENTWISE_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(ELEMENTWISE_TEST) $(STRUCTURE_TEST): ../test/mp_matrix_structure_test.cc \ mp_matrix_structure.cc mp_matrix_structure.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_matrix_structure_test.cc \ mp_matrix_structure.cc mp_matrix_storage.cc mp_scalar_storage.cc \ mp_complex_matrix_storage.cc mp_complex_scalar_storage.cc \ mp_complex_precision.cc \ $(MPLAPACK_LIBS) -o $@ check-structure: $(STRUCTURE_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(STRUCTURE_TEST) $(CONCAT_TEST): ../test/mp_matrix_concat_test.cc \ mp_matrix_concat.cc mp_matrix_concat.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_matrix_concat_test.cc \ mp_matrix_concat.cc mp_matrix_storage.cc mp_scalar_storage.cc \ $(MPLAPACK_LIBS) -o $@ check-concat: $(CONCAT_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CONCAT_TEST) $(ASSIGNMENT_TEST): ../test/mp_matrix_assignment_test.cc \ mp_matrix_assignment.cc mp_matrix_assignment.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_matrix_assignment_test.cc \ mp_matrix_assignment.cc mp_matrix_storage.cc mp_scalar_storage.cc \ $(MPLAPACK_LIBS) -o $@ check-assignment: $(ASSIGNMENT_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(ASSIGNMENT_TEST) $(RGELS_TEST): ../test/mp_lapack_rgels_test.cc mp_lapack.cc mp_lapack.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_lapack_rgels_test.cc mp_lapack.cc \ mp_matrix_storage.cc $(MPLAPACK_LIBS) -o $@ check-rgels: $(RGELS_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(RGELS_TEST) $(RANK_TEST): ../test/mp_lapack_rank_test.cc mp_lapack.cc mp_lapack.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_lapack_rank_test.cc mp_lapack.cc \ mp_matrix_storage.cc $(MPLAPACK_LIBS) -o $@ check-rank: $(RANK_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(RANK_TEST) $(CHOLESKY_TEST): ../test/mp_lapack_cholesky_test.cc mp_lapack.cc mp_lapack.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_lapack_cholesky_test.cc mp_lapack.cc \ mp_matrix_storage.cc $(MPLAPACK_LIBS) -o $@ check-cholesky: $(CHOLESKY_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CHOLESKY_TEST) $(QR_TEST): ../test/mp_lapack_qr_test.cc mp_lapack.cc mp_lapack.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_lapack_qr_test.cc mp_lapack.cc \ mp_matrix_storage.cc $(MPLAPACK_LIBS) -o $@ check-qr: $(QR_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(QR_TEST) $(PIVOTED_QR_TEST): ../test/mp_lapack_pivoted_qr_test.cc mp_lapack.cc mp_lapack.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_lapack_pivoted_qr_test.cc mp_lapack.cc \ mp_matrix_storage.cc $(MPLAPACK_LIBS) -o $@ check-pivoted-qr: $(PIVOTED_QR_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(PIVOTED_QR_TEST) $(LU_TEST): ../test/mp_lapack_lu_test.cc mp_lapack.cc mp_lapack.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_lapack_lu_test.cc mp_lapack.cc \ mp_matrix_storage.cc $(MPLAPACK_LIBS) -o $@ check-lu: $(LU_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(LU_TEST) $(DEPENDENCY_TEST): ../test/m22_dependency_probe.cc | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread \ $(MPLAPACK_CFLAGS) -I. ../test/m22_dependency_probe.cc \ $(MPLAPACK_LIBS) -o $@ check-dependency: $(DEPENDENCY_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(DEPENDENCY_TEST) $(CPLX_STORAGE_TEST): ../test/mp_complex_storage_test.cc \ mp_complex_precision.cc mp_complex_precision.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_storage_test.cc \ mp_complex_precision.cc mp_complex_scalar_storage.cc \ mp_complex_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-complex-storage: $(CPLX_STORAGE_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_STORAGE_TEST) $(CPLX_STRUCTURE_TEST): ../test/mp_complex_structure_test.cc \ mp_complex_structure.cc mp_complex_structure.h mp_matrix_structure.cc \ mp_matrix_structure.h mp_complex_matrix_storage.cc \ mp_complex_matrix_storage.h mp_complex_scalar_storage.cc \ mp_complex_scalar_storage.h mp_complex_precision.cc \ mp_complex_precision.h mp_matrix_storage.cc mp_matrix_storage.h \ mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_structure_test.cc \ mp_complex_structure.cc mp_matrix_structure.cc \ mp_complex_matrix_storage.cc mp_complex_scalar_storage.cc \ mp_complex_precision.cc mp_matrix_storage.cc mp_scalar_storage.cc \ $(MPLAPACK_LIBS) -o $@ check-complex-structure: $(CPLX_STRUCTURE_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_STRUCTURE_TEST) $(CPLX_ARITHMETIC_TEST): ../test/mp_complex_arithmetic_test.cc \ mp_complex_arithmetic.cc mp_complex_arithmetic.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h \ mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_arithmetic_test.cc \ mp_complex_arithmetic.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc \ mp_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-complex-arithmetic: $(CPLX_ARITHMETIC_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_ARITHMETIC_TEST) $(CPLX_BLAS_TEST): ../test/mp_complex_blas_test.cc \ mp_complex_blas.cc mp_complex_blas.h mp_complex_matrix_storage.cc \ mp_complex_matrix_storage.h mp_complex_scalar_storage.cc \ mp_complex_scalar_storage.h mp_complex_precision.cc \ mp_complex_precision.h mp_matrix_storage.cc mp_matrix_storage.h \ mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_blas_test.cc \ mp_complex_blas.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc \ mp_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-complex-blas: $(CPLX_BLAS_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_BLAS_TEST) $(CPLX_LAPACK_TEST): ../test/mp_complex_lapack_test.cc \ mp_complex_lapack.cc mp_complex_lapack.h mp_complex_blas.cc \ mp_complex_blas.h mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_lapack_test.cc \ mp_complex_lapack.cc mp_complex_blas.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc mp_matrix_storage.cc \ mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-complex-lapack: $(CPLX_LAPACK_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_LAPACK_TEST) CPLX_RANK_TEST = .build-c07/mp_complex_rank_test $(CPLX_RANK_TEST): ../test/mp_complex_rank_test.cc \ mp_complex_rank.cc mp_complex_rank.h mp_complex_blas.cc mp_complex_blas.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_rank_test.cc mp_complex_rank.cc \ mp_complex_blas.cc mp_complex_matrix_storage.cc mp_complex_scalar_storage.cc \ mp_complex_precision.cc mp_matrix_storage.cc mp_scalar_storage.cc \ $(MPLAPACK_LIBS) -o $@ check-complex-rank: $(CPLX_RANK_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_RANK_TEST) CPLX_CHOLESKY_TEST = .build-c08/mp_complex_cholesky_test $(CPLX_CHOLESKY_TEST): ../test/mp_complex_cholesky_test.cc \ mp_complex_cholesky.cc mp_complex_cholesky.h mp_complex_blas.cc \ mp_complex_blas.h mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_cholesky_test.cc \ mp_complex_cholesky.cc mp_complex_blas.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc mp_matrix_storage.cc \ mp_scalar_storage.cc \ $(MPLAPACK_LIBS) -o $@ check-complex-cholesky: $(CPLX_CHOLESKY_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_CHOLESKY_TEST) CPLX_QR_TEST = .build-c09/mp_complex_qr_test $(CPLX_QR_TEST): ../test/mp_complex_qr_test.cc \ mp_complex_qr.cc mp_complex_qr.h mp_complex_blas.cc mp_complex_blas.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_qr_test.cc mp_complex_qr.cc \ mp_complex_blas.cc mp_complex_matrix_storage.cc mp_complex_scalar_storage.cc \ mp_complex_precision.cc mp_matrix_storage.cc mp_scalar_storage.cc \ $(MPLAPACK_LIBS) -o $@ check-complex-qr: $(CPLX_QR_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_QR_TEST) CPLX_PIVOTED_QR_TEST = .build-c10/mp_complex_pivoted_qr_test $(CPLX_PIVOTED_QR_TEST): ../test/mp_complex_pivoted_qr_test.cc \ mp_complex_qr.cc mp_complex_qr.h mp_complex_blas.cc mp_complex_blas.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_pivoted_qr_test.cc \ mp_complex_qr.cc mp_complex_blas.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc mp_matrix_storage.cc \ mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-complex-pivoted-qr: $(CPLX_PIVOTED_QR_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_PIVOTED_QR_TEST) CPLX_CONCAT_TEST = .build-c11/mp_complex_matrix_concat_test $(CPLX_CONCAT_TEST): ../test/mp_complex_matrix_concat_test.cc \ mp_complex_matrix_concat.cc mp_complex_matrix_concat.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_matrix_concat_test.cc \ mp_complex_matrix_concat.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc mp_matrix_storage.cc \ mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-complex-concat: $(CPLX_CONCAT_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_CONCAT_TEST) $(CPLX_LU_TEST): ../test/mp_complex_lu_test.cc \ mp_complex_lu.cc mp_complex_lu.h mp_complex_blas.cc mp_complex_blas.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_complex_lu_test.cc mp_complex_lu.cc \ mp_complex_blas.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc mp_matrix_storage.cc \ mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-complex-lu: $(CPLX_LU_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(CPLX_LU_TEST) $(NORM_TEST): ../test/mp_norm_test.cc mp_norm.cc mp_norm.h \ mp_complex_blas.cc mp_complex_blas.h mp_complex_matrix_storage.cc \ mp_complex_matrix_storage.h mp_complex_scalar_storage.cc \ mp_complex_scalar_storage.h mp_complex_precision.cc mp_complex_precision.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.cc \ mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_norm_test.cc mp_norm.cc \ mp_complex_blas.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc \ mp_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-norm: $(NORM_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(NORM_TEST) $(DET_INV_TEST): ../test/mp_det_inv_test.cc mp_det_inv.cc mp_det_inv.h \ mp_complex_blas.cc mp_complex_blas.h mp_complex_matrix_storage.cc \ mp_complex_matrix_storage.h mp_complex_scalar_storage.cc \ mp_complex_scalar_storage.h mp_complex_precision.cc mp_complex_precision.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.cc \ mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_det_inv_test.cc mp_det_inv.cc \ mp_complex_blas.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc \ mp_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-det-inv: $(DET_INV_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(DET_INV_TEST) $(SVD_TEST): ../test/mp_svd_test.cc mp_svd.cc mp_svd.h mp_norm.cc mp_norm.h \ mp_complex_blas.cc mp_complex_blas.h mp_complex_matrix_storage.cc \ mp_complex_matrix_storage.h mp_complex_scalar_storage.cc \ mp_complex_scalar_storage.h mp_complex_precision.cc mp_complex_precision.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.cc \ mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_svd_test.cc mp_svd.cc mp_norm.cc \ mp_complex_blas.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc \ mp_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-svd: $(SVD_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(SVD_TEST) $(RANK_CONDITION_TEST): ../test/mp_rank_condition_test.cc \ mp_rank_condition.cc mp_rank_condition.h mp_svd.cc mp_svd.h mp_norm.cc \ mp_norm.h mp_complex_blas.cc mp_complex_blas.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_complex_precision.cc mp_complex_precision.h mp_matrix_storage.cc \ mp_matrix_storage.h mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_rank_condition_test.cc \ mp_rank_condition.cc mp_svd.cc mp_norm.cc mp_complex_blas.cc \ mp_complex_matrix_storage.cc mp_complex_scalar_storage.cc \ mp_complex_precision.cc mp_matrix_storage.cc mp_scalar_storage.cc \ $(MPLAPACK_LIBS) -o $@ check-rank-condition: $(RANK_CONDITION_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(RANK_CONDITION_TEST) $(STRUCTURED_EIG_TEST): ../test/mp_structured_eig_test.cc \ mp_structured_eig.cc mp_structured_eig.h mp_complex_precision.cc \ mp_complex_precision.h mp_complex_matrix_storage.cc \ mp_complex_matrix_storage.h mp_complex_scalar_storage.cc \ mp_complex_scalar_storage.h mp_matrix_storage.cc mp_matrix_storage.h \ mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_structured_eig_test.cc \ mp_structured_eig.cc mp_complex_precision.cc \ mp_complex_matrix_storage.cc mp_complex_scalar_storage.cc \ mp_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-structured-eig: $(STRUCTURED_EIG_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(STRUCTURED_EIG_TEST) $(GENERAL_EIG_TEST): ../test/mp_general_eig_test.cc \ mp_general_eig.cc mp_general_eig.h mp_complex_precision.cc \ mp_complex_precision.h mp_complex_matrix_storage.cc \ mp_complex_matrix_storage.h mp_complex_scalar_storage.cc \ mp_complex_scalar_storage.h mp_matrix_storage.cc mp_matrix_storage.h \ mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_general_eig_test.cc \ mp_general_eig.cc mp_complex_precision.cc \ mp_complex_matrix_storage.cc mp_complex_scalar_storage.cc \ mp_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-general-eig: $(GENERAL_EIG_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(GENERAL_EIG_TEST) $(GENERALIZED_EIG_TEST): ../test/mp_generalized_eig_test.cc \ mp_generalized_eig.cc mp_generalized_eig.h mp_structured_eig.cc \ mp_structured_eig.h mp_complex_precision.cc mp_complex_precision.h \ mp_complex_matrix_storage.cc mp_complex_matrix_storage.h \ mp_complex_scalar_storage.cc mp_complex_scalar_storage.h \ mp_matrix_storage.cc mp_matrix_storage.h mp_scalar_storage.cc \ mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_generalized_eig_test.cc \ mp_generalized_eig.cc mp_structured_eig.cc mp_complex_precision.cc \ mp_complex_matrix_storage.cc mp_complex_scalar_storage.cc \ mp_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-generalized-eig: $(GENERALIZED_EIG_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(GENERALIZED_EIG_TEST) $(SCRIPT_SEQUENCE_TEST): ../test/mp_script_sequence_test.cc \ mp_script_sequence.cc mp_script_sequence.h mp_complex_matrix_storage.cc \ mp_complex_matrix_storage.h mp_complex_scalar_storage.cc \ mp_complex_scalar_storage.h mp_complex_precision.cc \ mp_complex_precision.h mp_matrix_storage.cc mp_matrix_storage.h \ mp_scalar_storage.cc mp_scalar_storage.h | check-deps mkdir -p $(dir $@) $(CXX) -std=c++17 -Wall -Wextra -Wpedantic -pthread $(SANITIZER_FLAGS) \ $(MPLAPACK_CFLAGS) -I. ../test/mp_script_sequence_test.cc \ mp_script_sequence.cc mp_complex_matrix_storage.cc \ mp_complex_scalar_storage.cc mp_complex_precision.cc \ mp_matrix_storage.cc mp_scalar_storage.cc $(MPLAPACK_LIBS) -o $@ check-script-sequence: $(SCRIPT_SEQUENCE_TEST) ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 $(SCRIPT_SEQUENCE_TEST) check-deps: @$(MKOCTFILE) --help >/dev/null 2>&1 || { \ echo "FAIL: mkoctfile command not found: $(MKOCTFILE)" >&2; exit 1; } @command -v "$(PKG_CONFIG)" >/dev/null 2>&1 || { \ echo "FAIL: pkg-config command not found: $(PKG_CONFIG)" >&2; exit 1; } @$(PKG_CONFIG) --atleast-version=3.0.0 "$(MPLAPACK_PC)" || { \ echo "FAIL: $(MPLAPACK_PC) >= 3.0.0 is required" >&2; exit 1; } @test -n "$(MPLAPACK_CFLAGS)" || { \ echo "FAIL: $(MPLAPACK_PC) --cflags failed; inspect its dependency metadata" >&2; \ $(PKG_CONFIG) --cflags "$(MPLAPACK_PC)"; exit 1; } @test -n "$(MPLAPACK_LIBS)" || { \ echo "FAIL: $(MPLAPACK_PC) --libs failed; inspect its dependency metadata" >&2; \ $(PKG_CONFIG) --libs "$(MPLAPACK_PC)"; exit 1; } @test -f "$$($(PKG_CONFIG) --variable=includedir $(MPLAPACK_PC))/mplapack_mpfr_precision.h" || { \ echo "FAIL: installed MPLAPACK MPFR precision scope header is required" >&2; exit 1; } @case "$(MPLAPACK_VERSION)" in \ ''|*[!A-Za-z0-9._+-]*) \ echo "FAIL: unsafe $(MPLAPACK_PC) version: $(MPLAPACK_VERSION)" >&2; \ exit 1;; \ esac @echo "PASS: $(MPLAPACK_PC) $(MPLAPACK_VERSION)" clean: $(RM) $(TARGET) *.o *.lo $(RM) -r .libs .deps .build-m02 .build-m06 .build-m07 .build-m08 .build-m09 .build-m10 .build-m11 .build-m12 .build-m13 .build-m14 .build-m15 .build-m16 .build-m17 .build-m18 .build-m19 .build-m21 .build-m22 .build-c00 .build-c06 .build-c07 .build-c08 .build-c09 .build-c10 .build-c11 .build-c11l .build-n00 .build-n01 .build-n02 .build-n03 .build-n04 .build-n05 .build-n06 .build-s08 mplapack-interop-0.5.1/src/mp_matrix_value.h0000644000230300031750000000324115274353472020377 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_MATRIX_VALUE_H #define OCTAVE_MPLAPACK_MP_MATRIX_VALUE_H #include #include #include "mp_matrix_storage.h" class octave_value; class octave_mplapack_mpfr_matrix_internal : public octave_base_dld_value { public: octave_mplapack_mpfr_matrix_internal (); explicit octave_mplapack_mpfr_matrix_internal ( octave_mplapack::MpfrMatrixStorage storage); octave_mplapack_mpfr_matrix_internal ( const octave_mplapack_mpfr_matrix_internal&) = default; ~octave_mplapack_mpfr_matrix_internal () override = default; octave_base_value * clone () const override; octave_base_value * empty_clone () const override; dim_vector dims () const override; bool is_defined () const override; bool is_storable () const override; bool is_real_matrix () const override; bool isreal () const override; bool is_matrix_type () const override; bool save_ascii (std::ostream& os) override; bool load_ascii (std::istream& is) override; bool save_binary (std::ostream& os, bool save_as_floats) override; bool load_binary (std::istream& is, bool swap, octave::mach_info::float_format fmt) override; void print (std::ostream& os, bool pr_as_read_syntax = false) override; void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const override; const octave_mplapack::MpfrMatrixStorage& storage () const noexcept; static const octave_mplapack_mpfr_matrix_internal& checked_value (const octave_value& value); DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA private: octave_mplapack::MpfrMatrixStorage m_storage; }; #endif mplapack-interop-0.5.1/src/mp_complex_qr.h0000644000230300031750000000337315274353472020056 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_QR_H #define OCTAVE_MPLAPACK_MP_COMPLEX_QR_H #include #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { class MpcQrError : public std::runtime_error { public: enum class Kind { invalid_argument, internal }; MpcQrError (Kind kind, MpfrComplexMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrComplexMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrComplexMatrixStorage::MplapackInteger m_info; }; struct MpcQrResult { MpfrComplexMatrixStorage q; MpfrComplexMatrixStorage r; }; struct MpcPivotedQrResult { MpfrComplexMatrixStorage q; MpfrComplexMatrixStorage r; std::vector permutation; }; void require_mplapack_mpc_qr_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& tau, const MpfrComplexMatrixStorage& work); void require_mplapack_mpc_pivoted_qr_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& tau, const MpfrComplexMatrixStorage& work, const MpfrMatrixStorage& rwork); MpcQrResult mplapack_mpc_matrix_qr (const MpfrComplexMatrixStorage& input, bool economy, bool want_q); MpcPivotedQrResult mplapack_mpc_matrix_pivoted_qr ( const MpfrComplexMatrixStorage& input, bool economy, bool want_q); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_convert.cc0000644000230300031750000000017115274353472017514 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause // Scalar conversion lives in MpfrScalarStorage. Matrix conversion follows M07. mplapack-interop-0.5.1/src/mp_matrix_structure.cc0000644000230300031750000001020215274353472021454 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_structure.h" #include #include "mp_complex_precision.h" namespace octave_mplapack { MpfrMatrixStorage mpfr_matrix_transpose (const MpfrMatrixStorage& source) { MpfrMatrixStorage result (source.columns (), source.rows (), source.precision_bits ()); // Structural copies preserve the source precision; ambient defaults are // intentionally irrelevant. for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) mpfr_set (result.at (column, row).mpfr_data (), source.at (row, column).mpfr_data (), MPFR_RNDN); return result; } MpfrMatrixStorage mpfr_matrix_reshape (const MpfrMatrixStorage& source, std::size_t rows, std::size_t columns) { if (MpfrMatrixStorage::checked_element_count (rows, columns) != source.numel ()) throw std::invalid_argument ("reshape element count does not match"); MpfrMatrixStorage result (rows, columns, source.precision_bits ()); // Reshape keeps the existing contiguous column-major linear order. for (std::size_t index = 0; index < source.numel (); ++index) mpfr_set (result.data ()[index].mpfr_data (), source.data ()[index].mpfr_data (), MPFR_RNDN); return result; } MpfrMatrixStorage mpfr_complex_matrix_real (const MpfrComplexMatrixStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) mpfr_set (result.at (row, column).mpfr_data (), mpc_realref (source.at (row, column).mpc_data ()), MPFR_RNDN); return result; } MpfrMatrixStorage mpfr_complex_matrix_imag (const MpfrComplexMatrixStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) mpfr_set (result.at (row, column).mpfr_data (), mpc_imagref (source.at (row, column).mpc_data ()), MPFR_RNDN); return result; } MpfrComplexMatrixStorage mpfr_complex_matrix_conj (const MpfrComplexMatrixStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) mpc_conj (result.data ()[index].mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrComplexMatrixStorage mpfr_complex_matrix_transpose (const MpfrComplexMatrixStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (source.columns (), source.rows (), source.precision_bits ()); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) mpc_set (result.at (column, row).mpc_data (), source.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } MpfrComplexMatrixStorage mpfr_complex_matrix_ctranspose (const MpfrComplexMatrixStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (source.columns (), source.rows (), source.precision_bits ()); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) mpc_conj (result.at (column, row).mpc_data (), source.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_rank_condition.cc0000644000230300031750000004052115274353472021040 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_rank_condition.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_precision.h" #include "mp_norm.h" namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrConditionKind; using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrScalarStorage; void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK rank/condition precision is outside MPFR limits"); } MpfrMatrixStorage copy_real_at_precision (const MpfrMatrixStorage& source, mpfr_prec_t precision_bits) { validate_precision (precision_bits); MpfrMatrixStorage result (source.rows (), source.columns (), precision_bits); for (std::size_t index = 0; index < source.numel (); ++index) mpfr_set (result.data ()[index].mpfr_data (), source.data ()[index].mpfr_data (), MPFR_RNDN); return result; } MpfrScalarStorage::NativeScalar make_zero (mpfr_prec_t precision_bits) { auto result = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); mpfr_set_zero (result.mpfr_data (), 1); return result; } MpfrScalarStorage::NativeScalar make_infinity (mpfr_prec_t precision_bits) { auto result = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); mpfr_set_inf (result.mpfr_data (), 1); return result; } void set_nonnegative_product (mpfrxx::mpfr_class& result, std::size_t dimension, const mpfrxx::mpfr_class& sigma_max, const mpfrxx::mpfr_class& epsilon) { mpfr_set_ui (result.mpfr_data (), static_cast (dimension), MPFR_RNDN); mpfr_mul (result.mpfr_data (), result.mpfr_data (), sigma_max.mpfr_data (), MPFR_RNDN); mpfr_mul (result.mpfr_data (), result.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); } template MpfrScalarStorage condition_from_singular_values (const Matrix& input, MpfrConditionKind kind, const MpfrMatrixStorage& singular_values) { const mpfr_prec_t precision_bits = input.precision_bits (); if (input.rows () == 0 || input.columns () == 0) return MpfrScalarStorage (make_zero (precision_bits)); if (kind == MpfrConditionKind::two) { auto result = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); mpfr_set (result.mpfr_data (), singular_values.at (0, 0).mpfr_data (), MPFR_RNDN); const auto last = std::min (input.rows (), input.columns ()) - 1; if (mpfr_zero_p (singular_values.at (last, 0).mpfr_data ()) != 0) mpfr_set_inf (result.mpfr_data (), 1); else mpfr_div (result.mpfr_data (), result.mpfr_data (), singular_values.at (last, 0).mpfr_data (), MPFR_RNDN); return MpfrScalarStorage (std::move (result)); } if (kind != MpfrConditionKind::frobenius) throw std::invalid_argument ("singular values do not provide this norm"); auto left = MpfrScalarStorage::NativeScalar::with_precision (precision_bits); auto right = MpfrScalarStorage::NativeScalar::with_precision (precision_bits); mpfr_set_zero (left.mpfr_data (), 1); mpfr_set_zero (right.mpfr_data (), 1); for (std::size_t index = 0; index < singular_values.rows (); ++index) { const auto& sigma = singular_values.at (index, 0); if (mpfr_zero_p (sigma.mpfr_data ()) != 0) return MpfrScalarStorage (make_infinity (precision_bits)); mpfr_fma (left.mpfr_data (), sigma.mpfr_data (), sigma.mpfr_data (), left.mpfr_data (), MPFR_RNDN); auto reciprocal = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); mpfr_ui_div (reciprocal.mpfr_data (), 1, sigma.mpfr_data (), MPFR_RNDN); mpfr_fma (right.mpfr_data (), reciprocal.mpfr_data (), reciprocal.mpfr_data (), right.mpfr_data (), MPFR_RNDN); } mpfr_sqrt (left.mpfr_data (), left.mpfr_data (), MPFR_RNDN); mpfr_sqrt (right.mpfr_data (), right.mpfr_data (), MPFR_RNDN); mpfr_mul (left.mpfr_data (), left.mpfr_data (), right.mpfr_data (), MPFR_RNDN); return MpfrScalarStorage (std::move (left)); } template MpfrMatrixStorage::MplapackInteger rank_from_singular_values (const Matrix& input, const MpfrScalarStorage *tolerance, const MpfrMatrixStorage& singular_values) { const mpfr_prec_t precision_bits = singular_values.precision_bits (); auto threshold = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); if (tolerance) mpfr_set (threshold.mpfr_data (), tolerance->native_value ().mpfr_data (), MPFR_RNDN); else { auto epsilon = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); { MplapackMpfrPrecisionScope scope (precision_bits); auto native_epsilon = Rlamch_mpfr ("E"); mpfr_set (epsilon.mpfr_data (), native_epsilon.mpfr_data (), MPFR_RNDN); } set_nonnegative_product (threshold, std::max (input.rows (), input.columns ()), singular_values.rows () == 0 ? epsilon : singular_values.at (0, 0), epsilon); } MpfrMatrixStorage::MplapackInteger result = 0; for (std::size_t index = 0; index < singular_values.rows (); ++index) if (mpfr_cmp (singular_values.at (index, 0).mpfr_data (), threshold.mpfr_data ()) > 0) ++result; return result; } MpfrScalarStorage real_gecon (const MpfrMatrixStorage& input, char norm_code) { if (input.rows () != input.columns ()) throw std::invalid_argument ( "condition number norm requires a square matrix"); const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); const std::size_t n = input.rows (); if (n == 0) return MpfrScalarStorage (make_infinity (precision_bits)); auto factors = copy_real_at_precision (input, precision_bits); std::vector pivots (n); MpfrMatrixStorage::MplapackInteger factor_info = 0; MpfrMatrixStorage norm_work (std::max (n, 1), 1, precision_bits); auto anorm = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); { MplapackMpfrPrecisionScope scope (precision_bits); anorm = Rlange (&norm_code, MpfrMatrixStorage::checked_mplapack_dimension (n), MpfrMatrixStorage::checked_mplapack_dimension (n), factors.data (), factors.leading_dimension (), norm_work.data ()); } factors = copy_real_at_precision (input, precision_bits); { MplapackMpfrPrecisionScope scope (precision_bits); Rgetrf (MpfrMatrixStorage::checked_mplapack_dimension (n), MpfrMatrixStorage::checked_mplapack_dimension (n), factors.data (), factors.leading_dimension (), pivots.data (), factor_info); if (mpfrxx::default_precision_bits () != precision_bits) throw std::runtime_error ("MPLAPACK Rgetrf changed current precision"); } if (factor_info < 0) throw octave_mplapack::MpfrRankConditionError ( octave_mplapack::MpfrRankConditionError::Kind::invalid_argument, factor_info, "MPLAPACK Rgetrf rejected a condition-number argument"); // Rgecon's Rlacn2 vector, RHS vector, and two triangular-solve column-norm // areas occupy four contiguous blocks of n real values. MpfrMatrixStorage work (4 * n, 1, precision_bits); std::vector iwork (n); auto rcond = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope scope (precision_bits); Rgecon (&norm_code, MpfrMatrixStorage::checked_mplapack_dimension (n), factors.data (), factors.leading_dimension (), anorm, rcond, work.data (), iwork.data (), info); if (mpfrxx::default_precision_bits () != precision_bits) throw std::runtime_error ("MPLAPACK Rgecon changed current precision"); } if (info < 0) throw octave_mplapack::MpfrRankConditionError ( octave_mplapack::MpfrRankConditionError::Kind::invalid_argument, info, "MPLAPACK Rgecon rejected a condition-number argument"); return MpfrScalarStorage (std::move (rcond)); } MpfrScalarStorage complex_gecon (const MpfrComplexMatrixStorage& input, char norm_code) { if (input.rows () != input.columns ()) throw std::invalid_argument ( "condition number norm requires a square matrix"); const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); const std::size_t n = input.rows (); if (n == 0) return MpfrScalarStorage (make_infinity (precision_bits)); auto factors = octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( input, precision_bits); std::vector pivots (n); MpfrComplexMatrixStorage::MplapackInteger factor_info = 0; MpfrMatrixStorage norm_work (std::max (n, 1), 1, precision_bits); auto anorm = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); { octave_mplapack::MpfrMpcPrecisionScope scope (precision_bits); anorm = Clange (&norm_code, MpfrComplexMatrixStorage::checked_mplapack_dimension (n), MpfrComplexMatrixStorage::checked_mplapack_dimension (n), factors.data (), factors.leading_dimension (), norm_work.data ()); } factors = octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( input, precision_bits); { octave_mplapack::MpfrMpcPrecisionScope scope (precision_bits); Cgetrf (MpfrComplexMatrixStorage::checked_mplapack_dimension (n), MpfrComplexMatrixStorage::checked_mplapack_dimension (n), factors.data (), factors.leading_dimension (), pivots.data (), factor_info); if (mpfrxx::default_precision_bits () != precision_bits) throw std::runtime_error ("MPLAPACK Cgetrf changed current precision"); } if (factor_info < 0) throw octave_mplapack::MpcRankConditionError ( octave_mplapack::MpcRankConditionError::Kind::invalid_argument, factor_info, "MPLAPACK Cgetrf rejected a condition-number argument"); MpfrComplexMatrixStorage work (2 * n, 1, precision_bits); MpfrMatrixStorage rwork (2 * n, 1, precision_bits); auto rcond = MpfrScalarStorage::NativeScalar::with_precision ( precision_bits); MpfrComplexMatrixStorage::MplapackInteger info = 0; { octave_mplapack::MpfrMpcPrecisionScope scope (precision_bits); Cgecon (&norm_code, MpfrComplexMatrixStorage::checked_mplapack_dimension (n), factors.data (), factors.leading_dimension (), anorm, rcond, work.data (), rwork.data (), info); if (mpfrxx::default_precision_bits () != precision_bits) throw std::runtime_error ("MPLAPACK Cgecon changed current precision"); } if (info < 0) throw octave_mplapack::MpcRankConditionError ( octave_mplapack::MpcRankConditionError::Kind::invalid_argument, info, "MPLAPACK Cgecon rejected a condition-number argument"); return MpfrScalarStorage (std::move (rcond)); } template MpfrScalarStorage reciprocal_to_condition (const MpfrScalarStorage& reciprocal, const Matrix& input) { auto result = MpfrScalarStorage::NativeScalar::with_precision ( input.precision_bits ()); if (mpfr_zero_p (reciprocal.native_value ().mpfr_data ()) != 0) mpfr_set_inf (result.mpfr_data (), 1); else mpfr_ui_div (result.mpfr_data (), 1, reciprocal.native_value ().mpfr_data (), MPFR_RNDN); return MpfrScalarStorage (std::move (result)); } } // namespace namespace octave_mplapack { MpfrMatrixStorage::MplapackInteger mplapack_mpfr_matrix_rank (const MpfrMatrixStorage& input, const MpfrScalarStorage *tolerance) { const mpfr_prec_t operation_precision = std::max (input.precision_bits (), tolerance ? tolerance->precision_bits () : MPFR_PREC_MIN); validate_precision (operation_precision); auto work = copy_real_at_precision (input, operation_precision); std::optional promoted_tolerance; if (tolerance) { auto native = MpfrScalarStorage::NativeScalar::with_precision ( operation_precision); mpfr_set (native.mpfr_data (), tolerance->native_value ().mpfr_data (), MPFR_RNDN); promoted_tolerance.emplace (std::move (native)); } const auto singular_values = mplapack_mpfr_singular_values (work); return rank_from_singular_values (work, promoted_tolerance ? &*promoted_tolerance : nullptr, singular_values); } MpfrComplexMatrixStorage::MplapackInteger mplapack_mpc_matrix_rank (const MpfrComplexMatrixStorage& input, const MpfrScalarStorage *tolerance) { const mpfr_prec_t operation_precision = std::max (input.precision_bits (), tolerance ? tolerance->precision_bits () : MPFR_PREC_MIN); validate_precision (operation_precision); auto work = mplapack_mpc_matrix_copy_at_precision ( input, operation_precision); std::optional promoted_tolerance; if (tolerance) { auto native = MpfrScalarStorage::NativeScalar::with_precision ( operation_precision); mpfr_set (native.mpfr_data (), tolerance->native_value ().mpfr_data (), MPFR_RNDN); promoted_tolerance.emplace (std::move (native)); } const auto singular_values = mplapack_mpc_singular_values (work); return rank_from_singular_values (work, promoted_tolerance ? &*promoted_tolerance : nullptr, singular_values); } MpfrScalarStorage mplapack_mpfr_matrix_condition (const MpfrMatrixStorage& input, MpfrConditionKind kind) { if ((kind == MpfrConditionKind::one || kind == MpfrConditionKind::infinity) && input.rows () != input.columns ()) throw std::invalid_argument ( "condition number norm requires a square matrix"); if (kind == MpfrConditionKind::frobenius && input.rows () != input.columns ()) throw std::invalid_argument ( "Frobenius condition number requires a square matrix"); if (kind == MpfrConditionKind::one || kind == MpfrConditionKind::infinity) { auto reciprocal = real_gecon (input, kind == MpfrConditionKind::one ? '1' : 'I'); return reciprocal_to_condition (reciprocal, input); } return condition_from_singular_values ( input, kind, mplapack_mpfr_singular_values (input)); } MpfrScalarStorage mplapack_mpc_matrix_condition (const MpfrComplexMatrixStorage& input, MpfrConditionKind kind) { if ((kind == MpfrConditionKind::one || kind == MpfrConditionKind::infinity) && input.rows () != input.columns ()) throw std::invalid_argument ( "condition number norm requires a square matrix"); if (kind == MpfrConditionKind::frobenius && input.rows () != input.columns ()) throw std::invalid_argument ( "Frobenius condition number requires a square matrix"); if (kind == MpfrConditionKind::one || kind == MpfrConditionKind::infinity) { auto reciprocal = complex_gecon ( input, kind == MpfrConditionKind::one ? '1' : 'I'); return reciprocal_to_condition (reciprocal, input); } return condition_from_singular_values ( input, kind, mplapack_mpc_singular_values (input)); } MpfrScalarStorage mplapack_mpfr_matrix_rcond (const MpfrMatrixStorage& input) { return real_gecon (input, '1'); } MpfrScalarStorage mplapack_mpc_matrix_rcond (const MpfrComplexMatrixStorage& input) { return complex_gecon (input, '1'); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_generalized_eig.cc0000644000230300031750000006507615274353472021170 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_generalized_eig.h" #include #include #include #include #include #include #include #include #include #include #include "mp_complex_precision.h" #include "mp_structured_eig.h" namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpGeneralizedEigResult; using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrScalarStorage; void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK generalized eig precision is outside MPFR limits"); } std::size_t checked_workspace_length (const MpfrScalarStorage::NativeScalar& query, const char *routine) { if (mpfr_nan_p (query.mpfr_data ()) != 0 || mpfr_inf_p (query.mpfr_data ()) != 0 || mpfr_integer_p (query.mpfr_data ()) == 0 || mpfr_sgn (query.mpfr_data ()) <= 0) throw std::runtime_error (std::string (routine) + " returned an invalid workspace query"); mpz_t value; mpz_t max_mplapack; mpz_t max_size; mpz_init (value); mpz_init (max_mplapack); mpz_init (max_size); mpfr_get_z (value, query.mpfr_data (), MPFR_RNDZ); const auto mplapack_max = std::numeric_limits::max (); const auto size_max = std::numeric_limits::max (); mpz_import (max_mplapack, 1, -1, sizeof (mplapack_max), 0, 0, &mplapack_max); mpz_import (max_size, 1, -1, sizeof (size_max), 0, 0, &size_max); const bool fits = mpz_cmp (value, max_mplapack) <= 0 && mpz_cmp (value, max_size) <= 0; if (! fits) { mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); throw std::overflow_error (std::string (routine) + " workspace exceeds allocation limits"); } const auto result = static_cast ( mpfr_get_uj (query.mpfr_data (), MPFR_RNDZ)); mpz_clear (value); mpz_clear (max_mplapack); mpz_clear (max_size); return result; } std::size_t checked_complex_workspace_length ( const MpfrComplexMatrixStorage::NativeScalar& query, const char *routine) { if (mpfr_sgn (mpc_imagref (query.mpc_data ())) != 0) throw std::runtime_error (std::string (routine) + " returned a complex workspace query"); auto real_query = MpfrScalarStorage::NativeScalar::with_precision ( query.real_precision ()); mpfr_set (real_query.mpfr_data (), mpc_realref (query.mpc_data ()), MPFR_RNDN); return checked_workspace_length (real_query, routine); } std::size_t checked_integer_workspace_length (MpfrMatrixStorage::MplapackInteger value, const char *routine) { if (value <= 0) throw std::runtime_error (std::string (routine) + " returned an invalid integer workspace query"); return static_cast (value); } std::size_t checked_eight_times (std::size_t value, const char *routine) { if (value > std::numeric_limits::max () / 8) throw std::overflow_error (std::string (routine) + " workspace size overflows allocation"); return std::max (1, 8 * value); } void fill_real_diagonal (MpfrMatrixStorage& diagonal, const MpfrMatrixStorage& eigenvalues) { for (std::size_t column = 0; column < diagonal.columns (); ++column) for (std::size_t row = 0; row < diagonal.rows (); ++row) { if (row == column) mpfr_set (diagonal.at (row, column).mpfr_data (), eigenvalues.at (row, 0).mpfr_data (), MPFR_RNDN); else mpfr_set_zero (diagonal.at (row, column).mpfr_data (), 1); } } void fill_complex_diagonal (MpfrComplexMatrixStorage& diagonal, const MpfrComplexMatrixStorage& eigenvalues) { for (std::size_t column = 0; column < diagonal.columns (); ++column) for (std::size_t row = 0; row < diagonal.rows (); ++row) { if (row == column) mpc_set (diagonal.at (row, column).mpc_data (), eigenvalues.at (row, 0).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); else mpc_set_ui (diagonal.at (row, column).mpc_data (), 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } void set_complex_from_real (MpfrComplexMatrixStorage::NativeScalar& destination, const MpfrMatrixStorage::NativeScalar& real, const MpfrMatrixStorage::NativeScalar& imag) { mpfr_set (mpc_realref (destination.mpc_data ()), real.mpfr_data (), MPFR_RNDN); mpfr_set (mpc_imagref (destination.mpc_data ()), imag.mpfr_data (), MPFR_RNDN); } void set_complex_from_real (MpfrComplexMatrixStorage::NativeScalar& destination, const MpfrMatrixStorage::NativeScalar& real) { mpfr_set (mpc_realref (destination.mpc_data ()), real.mpfr_data (), MPFR_RNDN); mpfr_set_zero (mpc_imagref (destination.mpc_data ()), 1); } void set_generalized_real_eigenvalue ( MpfrComplexMatrixStorage::NativeScalar& destination, const MpfrMatrixStorage::NativeScalar& alphar, const MpfrMatrixStorage::NativeScalar& alphai, const MpfrMatrixStorage::NativeScalar& beta) { mpfr_div (mpc_realref (destination.mpc_data ()), alphar.mpfr_data (), beta.mpfr_data (), MPFR_RNDN); mpfr_div (mpc_imagref (destination.mpc_data ()), alphai.mpfr_data (), beta.mpfr_data (), MPFR_RNDN); } void convert_real_generalized_vectors (MpfrComplexMatrixStorage& destination, const MpfrMatrixStorage& source, const MpfrMatrixStorage& alphai) { const std::size_t n = source.columns (); std::size_t column = 0; while (column < n) { const int sign = mpfr_sgn (alphai.at (column, 0).mpfr_data ()); if (sign > 0 && column + 1 < n && mpfr_sgn (alphai.at (column + 1, 0).mpfr_data ()) < 0) { for (std::size_t row = 0; row < source.rows (); ++row) { auto& first = destination.at (row, column); set_complex_from_real (first, source.at (row, column), source.at (row, column + 1)); auto& second = destination.at (row, column + 1); set_complex_from_real (second, source.at (row, column), source.at (row, column + 1)); mpfr_neg (mpc_imagref (second.mpc_data ()), mpc_imagref (second.mpc_data ()), MPFR_RNDN); } column += 2; } else if (sign < 0 && column > 0 && mpfr_sgn (alphai.at (column - 1, 0).mpfr_data ()) > 0) ++column; else { for (std::size_t row = 0; row < source.rows (); ++row) set_complex_from_real (destination.at (row, column), source.at (row, column)); ++column; } } } void require_real_uniform (mpfr_prec_t precision, const MpfrMatrixStorage& a, const MpfrMatrixStorage& b, const MpfrMatrixStorage& alpha, const MpfrMatrixStorage& beta, const MpfrMatrixStorage& vl, const MpfrMatrixStorage& vr, const MpfrMatrixStorage& work) { if (mpfrxx::default_precision_bits () != precision || a.precision_bits () != precision || b.precision_bits () != precision || alpha.precision_bits () != precision || beta.precision_bits () != precision || vl.precision_bits () != precision || vr.precision_bits () != precision || work.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! b.all_elements_have_uniform_precision () || ! alpha.all_elements_have_uniform_precision () || ! beta.all_elements_have_uniform_precision () || ! vl.all_elements_have_uniform_precision () || ! vr.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at generalized Rggev boundary"); } void require_complex_uniform (mpfr_prec_t precision, const MpfrComplexMatrixStorage& a, const MpfrComplexMatrixStorage& b, const MpfrComplexMatrixStorage& alpha, const MpfrComplexMatrixStorage& beta, const MpfrComplexMatrixStorage& vl, const MpfrComplexMatrixStorage& vr, const MpfrComplexMatrixStorage& work, const MpfrMatrixStorage& rwork) { const auto state = mpfrxx::mpc_precision_override_storage (); if (mpfrxx::default_precision_bits () != precision || ! state.active || state.real_precision_bits != precision || state.imag_precision_bits != precision || a.precision_bits () != precision || b.precision_bits () != precision || alpha.precision_bits () != precision || beta.precision_bits () != precision || vl.precision_bits () != precision || vr.precision_bits () != precision || work.precision_bits () != precision || rwork.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! b.all_elements_have_uniform_precision () || ! alpha.all_elements_have_uniform_precision () || ! beta.all_elements_have_uniform_precision () || ! vl.all_elements_have_uniform_precision () || ! vr.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision () || ! rwork.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPC precision contract mismatch at generalized Cggev boundary"); } void require_real_definite_uniform (mpfr_prec_t precision, const MpfrMatrixStorage& a, const MpfrMatrixStorage& b, const MpfrMatrixStorage& w, const MpfrMatrixStorage& work) { if (mpfrxx::default_precision_bits () != precision || a.precision_bits () != precision || b.precision_bits () != precision || w.precision_bits () != precision || work.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! b.all_elements_have_uniform_precision () || ! w.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at generalized Rsygvd boundary"); } void require_complex_definite_uniform (mpfr_prec_t precision, const MpfrComplexMatrixStorage& a, const MpfrComplexMatrixStorage& b, const MpfrMatrixStorage& w, const MpfrComplexMatrixStorage& work, const MpfrMatrixStorage& rwork) { const auto state = mpfrxx::mpc_precision_override_storage (); if (mpfrxx::default_precision_bits () != precision || ! state.active || state.real_precision_bits != precision || state.imag_precision_bits != precision || a.precision_bits () != precision || b.precision_bits () != precision || w.precision_bits () != precision || work.precision_bits () != precision || rwork.precision_bits () != precision || ! a.all_elements_have_uniform_precision () || ! b.all_elements_have_uniform_precision () || ! w.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision () || ! rwork.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPC precision contract mismatch at generalized Chegvd boundary"); } MpGeneralizedEigResult run_real_definite (const MpfrMatrixStorage& input_a, const MpfrMatrixStorage& input_b) { using Integer = MpfrMatrixStorage::MplapackInteger; const auto precision = input_a.precision_bits (); const std::size_t n = input_a.rows (); MpfrMatrixStorage a (n, n, precision, input_a); MpfrMatrixStorage b (n, n, precision, input_b); MpfrMatrixStorage w (n, 1, precision); MpfrMatrixStorage query_work (1, 1, precision); std::vector query_iwork (1); Integer info = 0; { MplapackMpfrPrecisionScope scope (precision); require_real_definite_uniform (precision, a, b, w, query_work); Rsygvd (1, "V", "U", static_cast (n), a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), w.data (), query_work.data (), -1, query_iwork.data (), -1, info); } if (info != 0) throw octave_mplapack::MpGeneralizedEigError ( static_cast (info), "MPLAPACK Rsygvd workspace query failed"); const auto lwork = checked_workspace_length (query_work.at (0, 0), "MPLAPACK Rsygvd"); const auto liwork = checked_integer_workspace_length ( query_iwork.at (0), "MPLAPACK Rsygvd"); MpfrMatrixStorage work (lwork, 1, precision); std::vector iwork (liwork); a = MpfrMatrixStorage (n, n, precision, input_a); b = MpfrMatrixStorage (n, n, precision, input_b); w = MpfrMatrixStorage (n, 1, precision); info = 0; { MplapackMpfrPrecisionScope scope (precision); require_real_definite_uniform (precision, a, b, w, work); Rsygvd (1, "V", "U", static_cast (n), a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), w.data (), work.data (), static_cast (lwork), iwork.data (), static_cast (liwork), info); } if (info != 0) throw octave_mplapack::MpGeneralizedEigError ( static_cast (info), info > static_cast (n) ? "MPLAPACK Rsygvd found B not positive definite" : "MPLAPACK Rsygvd failed to converge"); MpfrMatrixStorage diagonal (n, n, precision); fill_real_diagonal (diagonal, w); MpfrMatrixStorage vectors (n, n, precision, a); return octave_mplapack::MpGeneralizedRealDefiniteEigResult { std::move (w), std::move (a), std::move (vectors), std::move (diagonal)}; } MpGeneralizedEigResult run_complex_definite (const MpfrComplexMatrixStorage& input_a, const MpfrComplexMatrixStorage& input_b) { using Integer = MpfrComplexMatrixStorage::MplapackInteger; const auto precision = input_a.precision_bits (); const std::size_t n = input_a.rows (); MpfrComplexMatrixStorage a (n, n, precision); MpfrComplexMatrixStorage b (n, n, precision); a = input_a; b = input_b; MpfrMatrixStorage w (n, 1, precision); MpfrComplexMatrixStorage query_work (1, 1, precision); MpfrMatrixStorage query_rwork (1, 1, precision); std::vector query_iwork (1); Integer info = 0; { octave_mplapack::MpfrMpcPrecisionScope scope (precision); require_complex_definite_uniform (precision, a, b, w, query_work, query_rwork); Chegvd (1, "V", "U", static_cast (n), a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), w.data (), query_work.data (), -1, query_rwork.data (), -1, query_iwork.data (), -1, info); } if (info != 0) throw octave_mplapack::MpGeneralizedEigError ( static_cast (info), "MPLAPACK Chegvd workspace query failed"); const auto lwork = checked_complex_workspace_length ( query_work.at (0, 0), "MPLAPACK Chegvd"); const auto lrwork = checked_workspace_length (query_rwork.at (0, 0), "MPLAPACK Chegvd"); const auto liwork = checked_integer_workspace_length ( query_iwork.at (0), "MPLAPACK Chegvd"); MpfrComplexMatrixStorage work (lwork, 1, precision); MpfrMatrixStorage rwork (lrwork, 1, precision); std::vector iwork (liwork); a = input_a; b = input_b; w = MpfrMatrixStorage (n, 1, precision); info = 0; { octave_mplapack::MpfrMpcPrecisionScope scope (precision); require_complex_definite_uniform (precision, a, b, w, work, rwork); Chegvd (1, "V", "U", static_cast (n), a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), w.data (), work.data (), static_cast (lwork), rwork.data (), static_cast (lrwork), iwork.data (), static_cast (liwork), info); } if (info != 0) throw octave_mplapack::MpGeneralizedEigError ( static_cast (info), info > static_cast (n) ? "MPLAPACK Chegvd found B not positive definite" : "MPLAPACK Chegvd failed to converge"); MpfrMatrixStorage diagonal (n, n, precision); fill_real_diagonal (diagonal, w); MpfrComplexMatrixStorage vectors = a; return octave_mplapack::MpGeneralizedComplexDefiniteEigResult { std::move (w), std::move (a), std::move (vectors), std::move (diagonal)}; } MpGeneralizedEigResult run_real_qz (const MpfrMatrixStorage& input_a, const MpfrMatrixStorage& input_b) { using Integer = MpfrMatrixStorage::MplapackInteger; const auto precision = input_a.precision_bits (); const std::size_t n = input_a.rows (); MpfrMatrixStorage a (n, n, precision, input_a); MpfrMatrixStorage b (n, n, precision, input_b); MpfrMatrixStorage alphar (n, 1, precision); MpfrMatrixStorage alphai (n, 1, precision); MpfrMatrixStorage beta (n, 1, precision); MpfrMatrixStorage vl (n, n, precision); MpfrMatrixStorage vr (n, n, precision); MpfrMatrixStorage query_work (1, 1, precision); Integer info = 0; { MplapackMpfrPrecisionScope scope (precision); require_real_uniform (precision, a, b, alphar, beta, vl, vr, query_work); Rggev ("V", "V", static_cast (n), a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), alphar.data (), alphai.data (), beta.data (), vl.data (), vl.leading_dimension (), vr.data (), vr.leading_dimension (), query_work.data (), -1, info); } if (info != 0) throw octave_mplapack::MpGeneralizedEigError ( static_cast (info), "MPLAPACK Rggev workspace query failed"); const auto lwork = checked_workspace_length (query_work.at (0, 0), "MPLAPACK Rggev"); MpfrMatrixStorage work (lwork, 1, precision); a = MpfrMatrixStorage (n, n, precision, input_a); b = MpfrMatrixStorage (n, n, precision, input_b); alphar = MpfrMatrixStorage (n, 1, precision); alphai = MpfrMatrixStorage (n, 1, precision); beta = MpfrMatrixStorage (n, 1, precision); vl = MpfrMatrixStorage (n, n, precision); vr = MpfrMatrixStorage (n, n, precision); info = 0; { MplapackMpfrPrecisionScope scope (precision); require_real_uniform (precision, a, b, alphar, beta, vl, vr, work); Rggev ("V", "V", static_cast (n), a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), alphar.data (), alphai.data (), beta.data (), vl.data (), vl.leading_dimension (), vr.data (), vr.leading_dimension (), work.data (), static_cast (lwork), info); } if (info != 0) throw octave_mplapack::MpGeneralizedEigError ( static_cast (info), info < 0 ? "MPLAPACK Rggev rejected an argument" : "MPLAPACK Rggev failed to converge"); MpfrComplexMatrixStorage eigenvalues (n, 1, precision); MpfrComplexMatrixStorage left (n, n, precision); MpfrComplexMatrixStorage right (n, n, precision); for (std::size_t index = 0; index < n; ++index) set_generalized_real_eigenvalue (eigenvalues.at (index, 0), alphar.at (index, 0), alphai.at (index, 0), beta.at (index, 0)); convert_real_generalized_vectors (right, vr, alphai); convert_real_generalized_vectors (left, vl, alphai); MpfrComplexMatrixStorage diagonal (n, n, precision); fill_complex_diagonal (diagonal, eigenvalues); return octave_mplapack::MpGeneralizedQzEigResult { std::move (eigenvalues), std::move (right), std::move (left), std::move (diagonal)}; } MpGeneralizedEigResult run_complex_qz (const MpfrComplexMatrixStorage& input_a, const MpfrComplexMatrixStorage& input_b) { using Integer = MpfrComplexMatrixStorage::MplapackInteger; const auto precision = input_a.precision_bits (); const std::size_t n = input_a.rows (); MpfrComplexMatrixStorage a = input_a; MpfrComplexMatrixStorage b = input_b; MpfrComplexMatrixStorage alpha (n, 1, precision); MpfrComplexMatrixStorage beta (n, 1, precision); MpfrComplexMatrixStorage vl (n, n, precision); MpfrComplexMatrixStorage vr (n, n, precision); MpfrComplexMatrixStorage query_work (1, 1, precision); MpfrMatrixStorage rwork (checked_eight_times (n, "MPLAPACK Cggev"), 1, precision); Integer info = 0; { octave_mplapack::MpfrMpcPrecisionScope scope (precision); require_complex_uniform (precision, a, b, alpha, beta, vl, vr, query_work, rwork); Cggev ("V", "V", static_cast (n), a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), alpha.data (), beta.data (), vl.data (), vl.leading_dimension (), vr.data (), vr.leading_dimension (), query_work.data (), -1, rwork.data (), info); } if (info != 0) throw octave_mplapack::MpGeneralizedEigError ( static_cast (info), "MPLAPACK Cggev workspace query failed"); const auto lwork = checked_complex_workspace_length ( query_work.at (0, 0), "MPLAPACK Cggev"); MpfrComplexMatrixStorage work (lwork, 1, precision); a = input_a; b = input_b; alpha = MpfrComplexMatrixStorage (n, 1, precision); beta = MpfrComplexMatrixStorage (n, 1, precision); vl = MpfrComplexMatrixStorage (n, n, precision); vr = MpfrComplexMatrixStorage (n, n, precision); rwork = MpfrMatrixStorage (checked_eight_times (n, "MPLAPACK Cggev"), 1, precision); info = 0; { octave_mplapack::MpfrMpcPrecisionScope scope (precision); require_complex_uniform (precision, a, b, alpha, beta, vl, vr, work, rwork); Cggev ("V", "V", static_cast (n), a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), alpha.data (), beta.data (), vl.data (), vl.leading_dimension (), vr.data (), vr.leading_dimension (), work.data (), static_cast (lwork), rwork.data (), info); } if (info != 0) throw octave_mplapack::MpGeneralizedEigError ( static_cast (info), info < 0 ? "MPLAPACK Cggev rejected an argument" : "MPLAPACK Cggev failed to converge"); MpfrComplexMatrixStorage eigenvalues (n, 1, precision); for (std::size_t index = 0; index < n; ++index) mpc_div (eigenvalues.at (index, 0).mpc_data (), alpha.at (index, 0).mpc_data (), beta.at (index, 0).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); MpfrComplexMatrixStorage diagonal (n, n, precision); fill_complex_diagonal (diagonal, eigenvalues); return octave_mplapack::MpGeneralizedQzEigResult { std::move (eigenvalues), std::move (vr), std::move (vl), std::move (diagonal)}; } } // namespace namespace octave_mplapack { MpGeneralizedEigResult mplapack_mpfr_matrix_generalized_eig (const MpfrMatrixStorage& a, const MpfrMatrixStorage& b, GeneralizedEigAlgorithm algorithm) { if (a.rows () != a.columns () || b.rows () != b.columns () || a.rows () != b.rows ()) throw std::invalid_argument ( "generalized eig requires equally sized square real matrices"); const auto precision = a.precision_bits (); if (b.precision_bits () != precision) throw std::invalid_argument ( "generalized eig inputs must have one operation precision"); validate_precision (precision); const std::size_t n = a.rows (); if (n == 0) return MpGeneralizedQzEigResult { MpfrComplexMatrixStorage (0, 1, precision), MpfrComplexMatrixStorage (0, 0, precision), MpfrComplexMatrixStorage (0, 0, precision), MpfrComplexMatrixStorage (0, 0, precision)}; const bool structured = mplapack_mpfr_matrix_is_exactly_symmetric (a) && mplapack_mpfr_matrix_is_exactly_symmetric (b); if (algorithm == GeneralizedEigAlgorithm::chol && ! structured) throw std::invalid_argument ( "generalized eig chol requires exactly symmetric real A and B"); if (structured && algorithm != GeneralizedEigAlgorithm::qz) { try { return run_real_definite (a, b); } catch (const MpGeneralizedEigError& exception) { if (algorithm == GeneralizedEigAlgorithm::chol || exception.info () <= static_cast (n)) throw; } } return run_real_qz (a, b); } MpGeneralizedEigResult mplapack_mpc_matrix_generalized_eig (const MpfrComplexMatrixStorage& a, const MpfrComplexMatrixStorage& b, GeneralizedEigAlgorithm algorithm) { if (a.rows () != a.columns () || b.rows () != b.columns () || a.rows () != b.rows ()) throw std::invalid_argument ( "generalized eig requires equally sized square complex matrices"); const auto precision = a.precision_bits (); if (b.precision_bits () != precision) throw std::invalid_argument ( "generalized eig inputs must have one operation precision"); validate_precision (precision); const std::size_t n = a.rows (); if (n == 0) return MpGeneralizedQzEigResult { MpfrComplexMatrixStorage (0, 1, precision), MpfrComplexMatrixStorage (0, 0, precision), MpfrComplexMatrixStorage (0, 0, precision), MpfrComplexMatrixStorage (0, 0, precision)}; const bool structured = mplapack_mpc_matrix_is_exactly_hermitian (a) && mplapack_mpc_matrix_is_exactly_hermitian (b); if (algorithm == GeneralizedEigAlgorithm::chol && ! structured) throw std::invalid_argument ( "generalized eig chol requires exactly Hermitian complex A and B"); if (structured && algorithm != GeneralizedEigAlgorithm::qz) { try { return run_complex_definite (a, b); } catch (const MpGeneralizedEigError& exception) { if (algorithm == GeneralizedEigAlgorithm::chol || exception.info () <= static_cast (n)) throw; } } return run_complex_qz (a, b); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_structure.h0000644000230300031750000000164615274353472021475 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_STRUCTURE_H #define OCTAVE_MPLAPACK_MP_COMPLEX_STRUCTURE_H #include "mp_complex_matrix_storage.h" #include "mp_complex_scalar_storage.h" #include "mp_scalar_storage.h" namespace octave_mplapack { MpfrScalarStorage mpfr_complex_scalar_real ( const MpfrComplexScalarStorage& source); MpfrScalarStorage mpfr_complex_scalar_imag ( const MpfrComplexScalarStorage& source); MpfrComplexScalarStorage mpfr_complex_scalar_conj ( const MpfrComplexScalarStorage& source); MpfrComplexScalarStorage mpfr_complex_scalar_transpose ( const MpfrComplexScalarStorage& source); MpfrComplexScalarStorage mpfr_complex_scalar_ctranspose ( const MpfrComplexScalarStorage& source); MpfrComplexMatrixStorage mpfr_complex_matrix_reshape ( const MpfrComplexMatrixStorage& source, std::size_t rows, std::size_t columns); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_rank.h0000644000230300031750000000255215274353472020365 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_RANK_H #define OCTAVE_MPLAPACK_MP_COMPLEX_RANK_H #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { class MpcCgelsyError : public std::runtime_error { public: enum class Kind { convergence, invalid_argument, internal }; MpcCgelsyError (Kind kind, MpfrComplexMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrComplexMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrComplexMatrixStorage::MplapackInteger m_info; }; struct MpcRankRevealingSolveResult { MpfrComplexMatrixStorage solution; MpfrComplexMatrixStorage::MplapackInteger rank; }; void require_mplapack_mpc_rank_precision_contract ( mpfr_prec_t operation_precision, const MpfrComplexMatrixStorage& a_work, const MpfrComplexMatrixStorage& b_work, const mpfrxx::mpfr_class& rcond, const MpfrComplexMatrixStorage& work, const MpfrMatrixStorage& rwork); MpcRankRevealingSolveResult mplapack_mpc_matrix_rank_solve ( const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_blas.h0000644000230300031750000000160715274353472016624 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_BLAS_H #define OCTAVE_MPLAPACK_MP_BLAS_H #include #include #include #include "mp_matrix_storage.h" namespace octave_mplapack { void require_mplapack_mpfr_precision_contract ( mpfr_prec_t operation_precision, const mpfrxx::mpfr_class& alpha, const MpfrMatrixStorage& a_work, const MpfrMatrixStorage& b_work, const mpfrxx::mpfr_class& beta, const MpfrMatrixStorage& c); MpfrMatrixStorage mplapack_mpfr_matrix_multiply ( const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs); MpfrMatrixStorage mplapack_mpfr_matrix_scale ( const MpfrMatrixStorage& matrix, const mpfrxx::mpfr_class& scalar); MpfrMatrixStorage mplapack_mpfr_matrix_scale ( const MpfrMatrixStorage& matrix, double scalar); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_rank_condition.h0000644000230300031750000000424015274353472020700 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_RANK_CONDITION_H #define OCTAVE_MPLAPACK_MP_RANK_CONDITION_H #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" #include "mp_scalar_storage.h" namespace octave_mplapack { enum class MpfrConditionKind { one, two, infinity, frobenius }; class MpfrRankConditionError : public std::runtime_error { public: enum class Kind { invalid_argument, internal }; MpfrRankConditionError (Kind kind, MpfrMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrMatrixStorage::MplapackInteger m_info; }; class MpcRankConditionError : public std::runtime_error { public: enum class Kind { invalid_argument, internal }; MpcRankConditionError (Kind kind, MpfrComplexMatrixStorage::MplapackInteger info, const char *message) : std::runtime_error (message), m_kind (kind), m_info (info) { } Kind kind () const noexcept { return m_kind; } MpfrComplexMatrixStorage::MplapackInteger info () const noexcept { return m_info; } private: Kind m_kind; MpfrComplexMatrixStorage::MplapackInteger m_info; }; MpfrMatrixStorage::MplapackInteger mplapack_mpfr_matrix_rank ( const MpfrMatrixStorage& input, const MpfrScalarStorage *tolerance = nullptr); MpfrComplexMatrixStorage::MplapackInteger mplapack_mpc_matrix_rank ( const MpfrComplexMatrixStorage& input, const MpfrScalarStorage *tolerance = nullptr); MpfrScalarStorage mplapack_mpfr_matrix_condition ( const MpfrMatrixStorage& input, MpfrConditionKind kind); MpfrScalarStorage mplapack_mpc_matrix_condition ( const MpfrComplexMatrixStorage& input, MpfrConditionKind kind); MpfrScalarStorage mplapack_mpfr_matrix_rcond ( const MpfrMatrixStorage& input); MpfrScalarStorage mplapack_mpc_matrix_rcond ( const MpfrComplexMatrixStorage& input); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_det_inv.cc0000644000230300031750000003765515274353472017505 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_det_inv.h" #include #include #include #include #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_precision.h" namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ( "MPLAPACK determinant/inverse precision is outside MPFR limits"); } std::size_t checked_workspace_length (const mpfrxx::mpfr_class& query) { if (mpfr_nan_p (query.mpfr_data ()) != 0 || mpfr_inf_p (query.mpfr_data ()) != 0 || mpfr_integer_p (query.mpfr_data ()) == 0 || mpfr_sgn (query.mpfr_data ()) <= 0) throw std::runtime_error ( "MPLAPACK inverse returned an invalid workspace query"); mpz_t value; mpz_t maximum; mpz_init (value); mpz_init (maximum); mpfr_get_z (value, query.mpfr_data (), MPFR_RNDZ); const auto limit = std::numeric_limits::max (); mpz_import (maximum, 1, -1, sizeof (limit), 0, 0, &limit); const bool fits = mpz_cmp (value, maximum) <= 0; if (! fits) { mpz_clear (value); mpz_clear (maximum); throw std::overflow_error ( "MPLAPACK inverse workspace exceeds allocation limits"); } const auto result = static_cast ( mpfr_get_uj (query.mpfr_data (), MPFR_RNDZ)); mpz_clear (value); mpz_clear (maximum); return result; } struct RealFactorization { MpfrMatrixStorage factors; std::vector pivots; MpfrMatrixStorage::MplapackInteger info; }; RealFactorization factor_real (const MpfrMatrixStorage& input) { const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); const std::size_t n = input.rows (); MpfrMatrixStorage factors (n, n, precision_bits, input); std::vector pivots (n); MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope scope (precision_bits); if (mpfrxx::default_precision_bits () != precision_bits || factors.precision_bits () != precision_bits || ! factors.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rgetrf boundary"); Rgetrf (MpfrMatrixStorage::checked_mplapack_dimension (n), MpfrMatrixStorage::checked_mplapack_dimension (n), factors.data (), factors.leading_dimension (), pivots.data (), info); if (mpfrxx::default_precision_bits () != precision_bits) throw std::runtime_error ( "MPLAPACK Rgetrf changed the current-thread default precision"); } if (info < 0) throw octave_mplapack::MpfrDetInvError ( octave_mplapack::MpfrDetInvError::Kind::invalid_argument, info, "MPLAPACK Rgetrf rejected an argument"); if (info > static_cast (n)) throw octave_mplapack::MpfrDetInvError ( octave_mplapack::MpfrDetInvError::Kind::internal, info, "MPLAPACK Rgetrf returned an invalid INFO value"); return {std::move (factors), std::move (pivots), info}; } struct ComplexFactorization { MpfrComplexMatrixStorage factors; std::vector pivots; MpfrComplexMatrixStorage::MplapackInteger info; }; ComplexFactorization factor_complex (const MpfrComplexMatrixStorage& input) { const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); const std::size_t n = input.rows (); auto factors = octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( input, precision_bits); std::vector pivots (n); MpfrComplexMatrixStorage::MplapackInteger info = 0; { octave_mplapack::MpfrMpcPrecisionScope scope (precision_bits); const auto override_state = mpfrxx::mpc_precision_override_storage (); if (mpfrxx::default_precision_bits () != precision_bits || ! override_state.active || override_state.real_precision_bits != precision_bits || override_state.imag_precision_bits != precision_bits || factors.precision_bits () != precision_bits || ! factors.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPC precision contract mismatch at Cgetrf boundary"); Cgetrf (MpfrComplexMatrixStorage::checked_mplapack_dimension (n), MpfrComplexMatrixStorage::checked_mplapack_dimension (n), factors.data (), factors.leading_dimension (), pivots.data (), info); const auto after = mpfrxx::mpc_precision_override_storage (); if (mpfrxx::default_precision_bits () != precision_bits || ! after.active || after.real_precision_bits != precision_bits || after.imag_precision_bits != precision_bits) throw std::runtime_error ( "MPLAPACK Cgetrf changed the current-thread precision"); } if (info < 0) throw octave_mplapack::MpcDetInvError ( octave_mplapack::MpcDetInvError::Kind::invalid_argument, info, "MPLAPACK Cgetrf rejected an argument"); if (info > static_cast (n)) throw octave_mplapack::MpcDetInvError ( octave_mplapack::MpcDetInvError::Kind::internal, info, "MPLAPACK Cgetrf returned an invalid INFO value"); return {std::move (factors), std::move (pivots), info}; } void require_real_inverse_contract (mpfr_prec_t precision_bits, const MpfrMatrixStorage& factors, const MpfrMatrixStorage& work) { if (mpfrxx::default_precision_bits () != precision_bits || factors.precision_bits () != precision_bits || work.precision_bits () != precision_bits || ! factors.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPFR precision contract mismatch at Rgetri boundary"); } void require_complex_inverse_contract (mpfr_prec_t precision_bits, const MpfrComplexMatrixStorage& factors, const MpfrComplexMatrixStorage& work) { const auto state = mpfrxx::mpc_precision_override_storage (); if (mpfrxx::default_precision_bits () != precision_bits || ! state.active || state.real_precision_bits != precision_bits || state.imag_precision_bits != precision_bits || factors.precision_bits () != precision_bits || work.precision_bits () != precision_bits || ! factors.all_elements_have_uniform_precision () || ! work.all_elements_have_uniform_precision ()) throw std::runtime_error ( "MPLAPACK MPC precision contract mismatch at Cgetri boundary"); } std::size_t checked_complex_workspace_length ( const MpfrComplexMatrixStorage::NativeScalar& query, mpfr_prec_t precision_bits) { if (mpfr_nan_p (mpc_imagref (query.mpc_data ())) != 0 || mpfr_zero_p (mpc_imagref (query.mpc_data ())) == 0) throw std::runtime_error ( "MPLAPACK complex inverse returned a non-real workspace query"); auto real_query = mpfrxx::mpfr_class::with_precision (precision_bits); mpfr_set (real_query.mpfr_data (), mpc_realref (query.mpc_data ()), MPFR_RNDN); return checked_workspace_length (real_query); } void set_real_one (mpfrxx::mpfr_class& value) { mpfr_set_ui (value.mpfr_data (), 1, MPFR_RNDN); } void set_complex_one (mpfrxx::mpc_class& value) { mpc_set_ui_ui (value.mpc_data (), 1, 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } // namespace namespace octave_mplapack { MpfrScalarStorage mplapack_mpfr_matrix_det (const MpfrMatrixStorage& input) { if (input.rows () != input.columns ()) throw std::invalid_argument ("det requires a square matrix"); const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); if (input.rows () == 0) { auto value = mpfrxx::mpfr_class::with_precision (precision_bits); set_real_one (value); return MpfrScalarStorage (std::move (value)); } const auto factorization = factor_real (input); auto determinant = mpfrxx::mpfr_class::with_precision (precision_bits); if (factorization.info > 0) mpfr_set_zero (determinant.mpfr_data (), 1); else { set_real_one (determinant); const std::size_t n = input.rows (); for (std::size_t index = 0; index < n; ++index) mpfr_mul (determinant.mpfr_data (), determinant.mpfr_data (), factorization.factors.at (index, index).mpfr_data (), MPFR_RNDN); bool odd = false; for (std::size_t index = 0; index < n; ++index) if (factorization.pivots[index] != static_cast (index + 1)) odd = ! odd; if (odd) mpfr_neg (determinant.mpfr_data (), determinant.mpfr_data (), MPFR_RNDN); } return MpfrScalarStorage (std::move (determinant)); } MpfrMatrixStorage mplapack_mpfr_matrix_inverse (const MpfrMatrixStorage& input) { if (input.rows () != input.columns ()) throw std::invalid_argument ("inv requires a square matrix"); const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); const std::size_t n = input.rows (); if (n == 0) return MpfrMatrixStorage (0, 0, precision_bits); auto first = factor_real (input); if (first.info > 0) throw MpfrDetInvError (MpfrDetInvError::Kind::singular, first.info, "MPLAPACK Rgetrf reported a singular matrix"); MpfrMatrixStorage query_work (1, 1, precision_bits); MpfrMatrixStorage::MplapackInteger query_info = 0; { MplapackMpfrPrecisionScope scope (precision_bits); require_real_inverse_contract (precision_bits, first.factors, query_work); Rgetri (MpfrMatrixStorage::checked_mplapack_dimension (n), first.factors.data (), first.factors.leading_dimension (), first.pivots.data (), query_work.data (), -1, query_info); require_real_inverse_contract (precision_bits, first.factors, query_work); } if (query_info != 0) throw MpfrDetInvError (query_info < 0 ? MpfrDetInvError::Kind::invalid_argument : MpfrDetInvError::Kind::internal, query_info, "MPLAPACK Rgetri workspace query failed"); const std::size_t lwork = checked_workspace_length (query_work.at (0, 0)); // Re-factor after the query because LAPACK work-query calls are not part of // the public operation and are not relied upon to preserve factor storage. auto factorization = factor_real (input); MpfrMatrixStorage work (lwork, 1, precision_bits); MpfrMatrixStorage::MplapackInteger info = 0; { MplapackMpfrPrecisionScope scope (precision_bits); require_real_inverse_contract (precision_bits, factorization.factors, work); Rgetri (MpfrMatrixStorage::checked_mplapack_dimension (n), factorization.factors.data (), factorization.factors.leading_dimension (), factorization.pivots.data (), work.data (), static_cast (lwork), info); require_real_inverse_contract (precision_bits, factorization.factors, work); } if (info > 0) throw MpfrDetInvError (MpfrDetInvError::Kind::singular, info, "MPLAPACK Rgetri reported a singular matrix"); if (info < 0) throw MpfrDetInvError (MpfrDetInvError::Kind::invalid_argument, info, "MPLAPACK Rgetri rejected an argument"); return std::move (factorization.factors); } MpfrComplexScalarStorage mplapack_mpc_matrix_det (const MpfrComplexMatrixStorage& input) { if (input.rows () != input.columns ()) throw std::invalid_argument ("det requires a square matrix"); const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); if (input.rows () == 0) { auto value = mpfrxx::mpc_class::with_precision (precision_bits); set_complex_one (value); return MpfrComplexScalarStorage (std::move (value)); } const auto factorization = factor_complex (input); auto determinant = mpfrxx::mpc_class::with_precision (precision_bits); if (factorization.info > 0) mpc_set_ui_ui (determinant.mpc_data (), 0, 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); else { set_complex_one (determinant); const std::size_t n = input.rows (); for (std::size_t index = 0; index < n; ++index) mpc_mul (determinant.mpc_data (), determinant.mpc_data (), factorization.factors.at (index, index).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); bool odd = false; for (std::size_t index = 0; index < n; ++index) if (factorization.pivots[index] != static_cast (index + 1)) odd = ! odd; if (odd) mpc_neg (determinant.mpc_data (), determinant.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } return MpfrComplexScalarStorage (std::move (determinant)); } MpfrComplexMatrixStorage mplapack_mpc_matrix_inverse (const MpfrComplexMatrixStorage& input) { if (input.rows () != input.columns ()) throw std::invalid_argument ("inv requires a square matrix"); const mpfr_prec_t precision_bits = input.precision_bits (); validate_precision (precision_bits); const std::size_t n = input.rows (); if (n == 0) return MpfrComplexMatrixStorage (0, 0, precision_bits); auto first = factor_complex (input); if (first.info > 0) throw MpcDetInvError (MpcDetInvError::Kind::singular, first.info, "MPLAPACK Cgetrf reported a singular matrix"); MpfrComplexMatrixStorage query_work (1, 1, precision_bits); MpfrComplexMatrixStorage::MplapackInteger query_info = 0; { MpfrMpcPrecisionScope scope (precision_bits); require_complex_inverse_contract (precision_bits, first.factors, query_work); Cgetri (MpfrComplexMatrixStorage::checked_mplapack_dimension (n), first.factors.data (), first.factors.leading_dimension (), first.pivots.data (), query_work.data (), -1, query_info); require_complex_inverse_contract (precision_bits, first.factors, query_work); } if (query_info != 0) throw MpcDetInvError (query_info < 0 ? MpcDetInvError::Kind::invalid_argument : MpcDetInvError::Kind::internal, query_info, "MPLAPACK Cgetri workspace query failed"); const std::size_t lwork = checked_complex_workspace_length ( query_work.at (0, 0), precision_bits); auto factorization = factor_complex (input); MpfrComplexMatrixStorage work (lwork, 1, precision_bits); MpfrComplexMatrixStorage::MplapackInteger info = 0; { MpfrMpcPrecisionScope scope (precision_bits); require_complex_inverse_contract (precision_bits, factorization.factors, work); Cgetri (MpfrComplexMatrixStorage::checked_mplapack_dimension (n), factorization.factors.data (), factorization.factors.leading_dimension (), factorization.pivots.data (), work.data (), static_cast (lwork), info); require_complex_inverse_contract (precision_bits, factorization.factors, work); } if (info > 0) throw MpcDetInvError (MpcDetInvError::Kind::singular, info, "MPLAPACK Cgetri reported a singular matrix"); if (info < 0) throw MpcDetInvError (MpcDetInvError::Kind::invalid_argument, info, "MPLAPACK Cgetri rejected an argument"); return std::move (factorization.factors); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_generalized_eig.h0000644000230300031750000000326515274353472021022 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_GENERALIZED_EIG_H #define OCTAVE_MPLAPACK_MP_GENERALIZED_EIG_H #include #include #include #include "mp_complex_matrix_storage.h" #include "mp_matrix_storage.h" namespace octave_mplapack { enum class GeneralizedEigAlgorithm { auto_select, chol, qz }; class MpGeneralizedEigError : public std::runtime_error { public: MpGeneralizedEigError (int info, const char *message) : std::runtime_error (message), m_info (info) { } int info () const noexcept { return m_info; } private: int m_info; }; struct MpGeneralizedRealDefiniteEigResult { MpfrMatrixStorage eigenvalues; MpfrMatrixStorage right_vectors; MpfrMatrixStorage left_vectors; MpfrMatrixStorage diagonal; }; struct MpGeneralizedComplexDefiniteEigResult { MpfrMatrixStorage eigenvalues; MpfrComplexMatrixStorage right_vectors; MpfrComplexMatrixStorage left_vectors; MpfrMatrixStorage diagonal; }; struct MpGeneralizedQzEigResult { MpfrComplexMatrixStorage eigenvalues; MpfrComplexMatrixStorage right_vectors; MpfrComplexMatrixStorage left_vectors; MpfrComplexMatrixStorage diagonal; }; using MpGeneralizedEigResult = std::variant< MpGeneralizedRealDefiniteEigResult, MpGeneralizedComplexDefiniteEigResult, MpGeneralizedQzEigResult>; MpGeneralizedEigResult mplapack_mpfr_matrix_generalized_eig ( const MpfrMatrixStorage& a, const MpfrMatrixStorage& b, GeneralizedEigAlgorithm algorithm); MpGeneralizedEigResult mplapack_mpc_matrix_generalized_eig ( const MpfrComplexMatrixStorage& a, const MpfrComplexMatrixStorage& b, GeneralizedEigAlgorithm algorithm); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_matrix_storage.cc0000644000230300031750000001646415274353472022627 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_matrix_storage.h" #include #include #include #include namespace octave_mplapack { namespace { void validate_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ("complex matrix precision is outside MPFR limits"); } } // namespace static_assert (std::is_same_v); static_assert (sizeof (MpfrComplexMatrixStorage::NativeScalar) == sizeof (mpc_t)); static_assert (alignof (MpfrComplexMatrixStorage::NativeScalar) == alignof (mpc_t)); MpfrComplexMatrixStorage::MpfrComplexMatrixStorage ( std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits) : m_rows (rows), m_columns (columns), m_precision_bits (precision_bits), m_values (make_elements (checked_element_count (rows, columns), precision_bits)) { checked_mplapack_dimension (rows); checked_mplapack_dimension (columns); } MpfrComplexMatrixStorage::MpfrComplexMatrixStorage ( std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const std::vector>& values) : MpfrComplexMatrixStorage (rows, columns, precision_bits) { if (values.size () != m_values.size ()) throw std::invalid_argument ("complex matrix element count mismatch"); for (std::size_t i = 0; i < values.size (); ++i) mpc_set_d_d (m_values[i].mpc_data (), values[i].real (), values[i].imag (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } MpfrComplexMatrixStorage::MpfrComplexMatrixStorage ( std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const std::vector& values) : MpfrComplexMatrixStorage (rows, columns, precision_bits) { if (values.size () != m_values.size ()) throw std::invalid_argument ("complex matrix element count mismatch"); for (std::size_t i = 0; i < values.size (); ++i) if (m_values[i].set_str (values[i], 10) != 0) throw std::invalid_argument ("invalid complex matrix element text"); } MpfrComplexMatrixStorage& MpfrComplexMatrixStorage::operator= (MpfrComplexMatrixStorage other) noexcept { swap (other); return *this; } void MpfrComplexMatrixStorage::swap (MpfrComplexMatrixStorage& other) noexcept { using std::swap; swap (m_rows, other.m_rows); swap (m_columns, other.m_columns); swap (m_precision_bits, other.m_precision_bits); m_values.swap (other.m_values); } std::size_t MpfrComplexMatrixStorage::rows () const noexcept { return m_rows; } std::size_t MpfrComplexMatrixStorage::columns () const noexcept { return m_columns; } std::size_t MpfrComplexMatrixStorage::numel () const noexcept { return m_values.size (); } mpfr_prec_t MpfrComplexMatrixStorage::precision_bits () const noexcept { return m_precision_bits; } MpfrComplexMatrixStorage::MplapackInteger MpfrComplexMatrixStorage::leading_dimension () const { return checked_mplapack_dimension (std::max (1, m_rows)); } MpfrComplexMatrixStorage::NativeScalar* MpfrComplexMatrixStorage::data () noexcept { return m_values.data (); } const MpfrComplexMatrixStorage::NativeScalar* MpfrComplexMatrixStorage::data () const noexcept { return m_values.data (); } MpfrComplexMatrixStorage::NativeScalar& MpfrComplexMatrixStorage::at (std::size_t row, std::size_t column) { return m_values.at (offset (row, column)); } const MpfrComplexMatrixStorage::NativeScalar& MpfrComplexMatrixStorage::at (std::size_t row, std::size_t column) const { return m_values.at (offset (row, column)); } bool MpfrComplexMatrixStorage::all_elements_have_uniform_precision () const noexcept { return std::all_of (m_values.begin (), m_values.end (), [this] (const NativeScalar& value) { return value.real_precision () == m_precision_bits && value.imag_precision () == m_precision_bits; }); } bool MpfrComplexMatrixStorage::element_exactly_equal_text ( std::size_t row, std::size_t column, const std::string& text) const { NativeScalar expected = NativeScalar::with_precision (m_precision_bits); if (expected.set_str (text, 10) != 0) throw std::invalid_argument ("invalid complex matrix comparison text"); const NativeScalar& actual = at (row, column); return mpfr_equal_p (mpc_realref (actual.mpc_data ()), mpc_realref (expected.mpc_data ())) != 0 && mpfr_equal_p (mpc_imagref (actual.mpc_data ()), mpc_imagref (expected.mpc_data ())) != 0; } bool MpfrComplexMatrixStorage::element_exactly_equal_double ( std::size_t row, std::size_t column, const std::complex& value) const noexcept { try { NativeScalar expected = NativeScalar::with_precision (m_precision_bits, value.real (), value.imag ()); const NativeScalar& actual = at (row, column); return mpfr_equal_p (mpc_realref (actual.mpc_data ()), mpc_realref (expected.mpc_data ())) != 0 && mpfr_equal_p (mpc_imagref (actual.mpc_data ()), mpc_imagref (expected.mpc_data ())) != 0; } catch (...) { return false; } } bool MpfrComplexMatrixStorage::element_exactly_equal ( std::size_t row, std::size_t column, const MpfrComplexMatrixStorage& other, std::size_t other_row, std::size_t other_column) const { const NativeScalar& lhs = at (row, column); const NativeScalar& rhs = other.at (other_row, other_column); return mpfr_equal_p (mpc_realref (lhs.mpc_data ()), mpc_realref (rhs.mpc_data ())) != 0 && mpfr_equal_p (mpc_imagref (lhs.mpc_data ()), mpc_imagref (rhs.mpc_data ())) != 0; } std::size_t MpfrComplexMatrixStorage::checked_element_count (std::size_t rows, std::size_t columns) { checked_mplapack_dimension (rows); checked_mplapack_dimension (columns); if (rows != 0 && columns > std::numeric_limits::max () / rows) throw std::overflow_error ("complex matrix element count overflow"); return rows * columns; } MpfrComplexMatrixStorage::MplapackInteger MpfrComplexMatrixStorage::checked_mplapack_dimension (std::size_t value) { using Limit = std::numeric_limits; if (value > static_cast (Limit::max ())) throw std::overflow_error ("complex matrix dimension exceeds MPLAPACK INTEGER"); return static_cast (value); } std::vector MpfrComplexMatrixStorage::make_elements (std::size_t count, mpfr_prec_t precision_bits) { validate_precision (precision_bits); std::vector values; values.reserve (count); for (std::size_t i = 0; i < count; ++i) values.emplace_back (NativeScalar::with_precision (precision_bits)); return values; } std::size_t MpfrComplexMatrixStorage::offset (std::size_t row, std::size_t column) const { if (row >= m_rows || column >= m_columns) throw std::out_of_range ("complex matrix element index out of range"); return row + column * m_rows; } void swap (MpfrComplexMatrixStorage& lhs, MpfrComplexMatrixStorage& rhs) noexcept { lhs.swap (rhs); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_complex_structure.cc0000644000230300031750000000566115274353472021634 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_structure.h" #include #include #include "mp_complex_precision.h" namespace octave_mplapack { namespace { MpfrScalarStorage component (const MpfrComplexScalarStorage& source, bool imaginary) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrScalarStorage::NativeScalar result = MpfrScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); mpfr_set (result.mpfr_data (), imaginary ? mpc_imagref (source.native_value ().mpc_data ()) : mpc_realref (source.native_value ().mpc_data ()), MPFR_RNDN); return MpfrScalarStorage (std::move (result)); } MpfrComplexScalarStorage conjugate (const MpfrComplexScalarStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexScalarStorage::NativeScalar result = MpfrComplexScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); mpc_conj (result.mpc_data (), source.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return MpfrComplexScalarStorage (std::move (result)); } MpfrComplexScalarStorage copy (const MpfrComplexScalarStorage& source) { MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexScalarStorage::NativeScalar result = MpfrComplexScalarStorage::NativeScalar::with_precision ( source.precision_bits ()); mpc_set (result.mpc_data (), source.native_value ().mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return MpfrComplexScalarStorage (std::move (result)); } } // namespace MpfrScalarStorage mpfr_complex_scalar_real (const MpfrComplexScalarStorage& source) { return component (source, false); } MpfrScalarStorage mpfr_complex_scalar_imag (const MpfrComplexScalarStorage& source) { return component (source, true); } MpfrComplexScalarStorage mpfr_complex_scalar_conj (const MpfrComplexScalarStorage& source) { return conjugate (source); } MpfrComplexScalarStorage mpfr_complex_scalar_transpose (const MpfrComplexScalarStorage& source) { return copy (source); } MpfrComplexScalarStorage mpfr_complex_scalar_ctranspose (const MpfrComplexScalarStorage& source) { return conjugate (source); } MpfrComplexMatrixStorage mpfr_complex_matrix_reshape (const MpfrComplexMatrixStorage& source, std::size_t rows, std::size_t columns) { if (MpfrComplexMatrixStorage::checked_element_count (rows, columns) != source.numel ()) throw std::invalid_argument ("complex reshape element count does not match"); MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result (rows, columns, source.precision_bits ()); for (std::size_t index = 0; index < source.numel (); ++index) mpc_set (result.data ()[index].mpc_data (), source.data ()[index].mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return result; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_precision.cc0000644000230300031750000001262415274353472020035 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_precision.h" #include #include #include #include #include namespace octave_mplapack { namespace { std::atomic current_default_precision_bits { initial_default_precision_bits }; class MpfrIntervalValue { public: explicit MpfrIntervalValue (mpfr_prec_t precision_bits) { mpfr_init2 (m_value, precision_bits); } ~MpfrIntervalValue () { mpfr_clear (m_value); } MpfrIntervalValue (const MpfrIntervalValue&) = delete; MpfrIntervalValue& operator= (const MpfrIntervalValue&) = delete; mpfr_ptr get () noexcept { return m_value; } mpfr_srcptr get () const noexcept { return m_value; } private: mpfr_t m_value; }; void require_valid_precision (mpfr_prec_t precision_bits) { if (precision_bits < MPFR_PREC_MIN || precision_bits > MPFR_PREC_MAX) throw std::invalid_argument ("precision is outside the MPFR range"); } template precision_count_t certified_integer_conversion (ComputeBounds compute_bounds, ExtractInteger extract_integer) { // The input is at most 64 bits. Directed MPFR bounds certify the result; // increasing working precision is only needed when an integer boundary is // still enclosed. Failure is reported rather than returning an unproven // rounded value. for (mpfr_prec_t working_precision = 128; working_precision <= 16384; working_precision *= 2) { MpfrIntervalValue lower (working_precision); MpfrIntervalValue upper (working_precision); compute_bounds (lower.get (), upper.get (), working_precision); const precision_count_t lower_integer = extract_integer (lower.get ()); const precision_count_t upper_integer = extract_integer (upper.get ()); if (lower_integer == upper_integer) return lower_integer; } throw std::runtime_error ("unable to certify precision conversion"); } } // namespace mpfr_prec_t default_precision_bits () noexcept { return current_default_precision_bits.load (std::memory_order_relaxed); } void set_default_precision_bits (mpfr_prec_t precision_bits) { require_valid_precision (precision_bits); mpfrxx::set_default_precision_bits (precision_bits); if (mpfrxx::default_precision_bits () != precision_bits) throw std::runtime_error ( "failed to synchronize the current-thread MPFR default precision"); current_default_precision_bits.store (precision_bits, std::memory_order_relaxed); } void synchronize_current_thread_precision () { const mpfr_prec_t precision_bits = default_precision_bits (); require_valid_precision (precision_bits); mpfrxx::set_default_precision_bits (precision_bits); if (mpfrxx::default_precision_bits () != precision_bits) throw std::runtime_error ( "failed to synchronize the current-thread MPFR default precision"); } mpfr_prec_t bits_for_decimal_digits (precision_count_t decimal_digits) { if (decimal_digits == 0) throw std::invalid_argument ("decimal digits must be positive"); for (mpfr_prec_t working_precision = 128; working_precision <= 16384; working_precision *= 2) { MpfrIntervalValue lower (working_precision); MpfrIntervalValue upper (working_precision); MpfrIntervalValue ten (working_precision); MpfrIntervalValue digits (working_precision); mpfr_set_ui (ten.get (), 10, MPFR_RNDN); mpfr_set_uj (digits.get (), decimal_digits, MPFR_RNDN); mpfr_log2 (lower.get (), ten.get (), MPFR_RNDD); mpfr_log2 (upper.get (), ten.get (), MPFR_RNDU); mpfr_mul (lower.get (), lower.get (), digits.get (), MPFR_RNDD); mpfr_mul (upper.get (), upper.get (), digits.get (), MPFR_RNDU); if (mpfr_cmp_si (lower.get (), MPFR_PREC_MAX) > 0) throw std::overflow_error ("decimal precision exceeds MPFR_PREC_MAX"); // If only the upper bound exceeds MPFR_PREC_MAX, refine the interval // before deciding whether the exact value is in range. if (mpfr_cmp_si (upper.get (), MPFR_PREC_MAX) > 0) continue; const precision_count_t lower_bits = static_cast ( mpfr_get_uj (lower.get (), MPFR_RNDU)); const precision_count_t upper_bits = static_cast ( mpfr_get_uj (upper.get (), MPFR_RNDU)); if (lower_bits == upper_bits) return static_cast (lower_bits); } throw std::runtime_error ("unable to certify decimal precision conversion"); } precision_count_t decimal_digits_for_bits (mpfr_prec_t precision_bits) { require_valid_precision (precision_bits); return certified_integer_conversion ( [precision_bits] (mpfr_ptr lower, mpfr_ptr upper, mpfr_prec_t working_precision) { MpfrIntervalValue two (working_precision); MpfrIntervalValue bits (working_precision); mpfr_set_ui (two.get (), 2, MPFR_RNDN); mpfr_set_si (bits.get (), precision_bits, MPFR_RNDN); mpfr_log10 (lower, two.get (), MPFR_RNDD); mpfr_log10 (upper, two.get (), MPFR_RNDU); mpfr_mul (lower, lower, bits.get (), MPFR_RNDD); mpfr_mul (upper, upper, bits.get (), MPFR_RNDU); }, [] (mpfr_srcptr value) { return static_cast ( mpfr_get_uj (value, MPFR_RNDD)); }); } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_value.h0000644000230300031750000000364615274353472017024 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_VALUE_H #define OCTAVE_MPLAPACK_MP_VALUE_H #include #include #include #include "mp_scalar_storage.h" class octave_value; class octave_mplapack_mpfr_scalar_internal : public octave_base_dld_value { public: octave_mplapack_mpfr_scalar_internal (); octave_mplapack_mpfr_scalar_internal (const std::string& text, mpfr_prec_t precision_bits); octave_mplapack_mpfr_scalar_internal (double value, mpfr_prec_t precision_bits); explicit octave_mplapack_mpfr_scalar_internal ( octave_mplapack::MpfrScalarStorage storage); octave_mplapack_mpfr_scalar_internal ( const octave_mplapack_mpfr_scalar_internal&) = default; ~octave_mplapack_mpfr_scalar_internal () override = default; octave_base_value * clone () const override; octave_base_value * empty_clone () const override; dim_vector dims () const override; bool is_defined () const override; bool is_storable () const override; bool is_real_scalar () const override; bool isreal () const override; bool is_scalar_type () const override; bool save_ascii (std::ostream& os) override; bool load_ascii (std::istream& is) override; bool save_binary (std::ostream& os, bool save_as_floats) override; bool load_binary (std::istream& is, bool swap, octave::mach_info::float_format fmt) override; void print (std::ostream& os, bool pr_as_read_syntax = false) override; void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const override; const octave_mplapack::MpfrScalarStorage& storage () const noexcept; static const octave_mplapack_mpfr_scalar_internal& checked_value (const octave_value& value); DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA private: octave_mplapack::MpfrScalarStorage m_storage; }; #endif mplapack-interop-0.5.1/src/mp_precision.h0000644000230300031750000000117115274353472017672 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_PRECISION_H #define OCTAVE_MPLAPACK_MP_PRECISION_H #include #include namespace octave_mplapack { using precision_count_t = std::uint64_t; constexpr mpfr_prec_t initial_default_precision_bits = 512; mpfr_prec_t default_precision_bits () noexcept; void set_default_precision_bits (mpfr_prec_t precision_bits); void synchronize_current_thread_precision (); mpfr_prec_t bits_for_decimal_digits (precision_count_t decimal_digits); precision_count_t decimal_digits_for_bits (mpfr_prec_t precision_bits); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_value.cc0000644000230300031750000000643615274353472020711 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_value.h" #include "mp_native_serialization.h" #include #include #include #include #include DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA ( octave_mplapack_mpc_scalar_internal, "mplapack_mpc_scalar_internal", "mplapack_mpc_scalar_internal"); octave_mplapack_mpc_scalar_internal::octave_mplapack_mpc_scalar_internal () : m_storage (0.0, 0.0, MPFR_PREC_MIN) { } octave_mplapack_mpc_scalar_internal::octave_mplapack_mpc_scalar_internal ( const std::string& text, mpfr_prec_t precision_bits) : m_storage (text, precision_bits) { } octave_mplapack_mpc_scalar_internal::octave_mplapack_mpc_scalar_internal ( double real, double imag, mpfr_prec_t precision_bits) : m_storage (real, imag, precision_bits) { } octave_mplapack_mpc_scalar_internal::octave_mplapack_mpc_scalar_internal ( octave_mplapack::MpfrComplexScalarStorage storage) : m_storage (std::move (storage)) { } octave_base_value *octave_mplapack_mpc_scalar_internal::clone () const { return new octave_mplapack_mpc_scalar_internal (*this); } octave_base_value *octave_mplapack_mpc_scalar_internal::empty_clone () const { return clone (); } dim_vector octave_mplapack_mpc_scalar_internal::dims () const { return dim_vector (1, 1); } bool octave_mplapack_mpc_scalar_internal::is_defined () const { return true; } bool octave_mplapack_mpc_scalar_internal::is_storable () const { return true; } bool octave_mplapack_mpc_scalar_internal::is_complex_scalar () const { return true; } bool octave_mplapack_mpc_scalar_internal::isreal () const { return false; } bool octave_mplapack_mpc_scalar_internal::is_scalar_type () const { return true; } bool octave_mplapack_mpc_scalar_internal::save_ascii (std::ostream& os) { return octave_mplapack::save_native_mpc_scalar (os, m_storage); } bool octave_mplapack_mpc_scalar_internal::load_ascii (std::istream& is) { return octave_mplapack::load_native_mpc_scalar (is, m_storage); } bool octave_mplapack_mpc_scalar_internal::save_binary (std::ostream& os, bool) { return octave_mplapack::save_native_mpc_scalar (os, m_storage); } bool octave_mplapack_mpc_scalar_internal::load_binary ( std::istream& is, bool, octave::mach_info::float_format) { return octave_mplapack::load_native_mpc_scalar (is, m_storage); } void octave_mplapack_mpc_scalar_internal::print (std::ostream& os, bool) { print_raw (os); } void octave_mplapack_mpc_scalar_internal::print_raw (std::ostream& os, bool) const { os << "[internal MPLAPACK MPC scalar; " << m_storage.precision_bits () << " bits]"; } const octave_mplapack::MpfrComplexScalarStorage& octave_mplapack_mpc_scalar_internal::storage () const noexcept { return m_storage; } const octave_mplapack_mpc_scalar_internal& octave_mplapack_mpc_scalar_internal::checked_value (const octave_value& value) { if (value.type_id () != static_type_id ()) error_with_id ("mplapack:InvalidNativeValue", "expected an internal MPLAPACK MPC scalar"); const auto *native_value = dynamic_cast ( value.internal_rep ()); if (! native_value) error_with_id ("mplapack:InvalidNativeValue", "invalid internal MPLAPACK MPC scalar representation"); return *native_value; } mplapack-interop-0.5.1/src/mp_complex_arithmetic.h0000644000230300031750000000336315274353472021564 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_ARITHMETIC_H #define OCTAVE_MPLAPACK_MP_COMPLEX_ARITHMETIC_H #include #include "mp_complex_matrix_storage.h" #include "mp_complex_scalar_storage.h" #include "mp_matrix_storage.h" #include "mp_scalar_storage.h" namespace octave_mplapack { enum class MpcElementwiseBinaryOperation { add, subtract, multiply, divide, power }; struct MpcElementwiseOperand { const MpfrScalarStorage *real_scalar = nullptr; const MpfrMatrixStorage *real_matrix = nullptr; const MpfrComplexScalarStorage *complex_scalar = nullptr; const MpfrComplexMatrixStorage *complex_matrix = nullptr; static MpcElementwiseOperand from_real_scalar ( const MpfrScalarStorage& value) noexcept; static MpcElementwiseOperand from_real_matrix ( const MpfrMatrixStorage& value) noexcept; static MpcElementwiseOperand from_complex_scalar ( const MpfrComplexScalarStorage& value) noexcept; static MpcElementwiseOperand from_complex_matrix ( const MpfrComplexMatrixStorage& value) noexcept; bool is_scalar () const noexcept; bool is_complex () const noexcept; mpfr_prec_t precision_bits () const; std::size_t rows () const; std::size_t columns () const; void copy_to (MpfrComplexMatrixStorage::NativeScalar& destination, std::size_t row, std::size_t column) const; }; MpfrComplexMatrixStorage mpc_matrix_elementwise_binary ( const MpcElementwiseOperand& lhs, const MpcElementwiseOperand& rhs, MpcElementwiseBinaryOperation operation); MpfrComplexMatrixStorage mpc_matrix_negate ( const MpfrComplexMatrixStorage& source); MpfrComplexScalarStorage mpc_scalar_negate ( const MpfrComplexScalarStorage& source); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_matrix_storage.h0000644000230300031750000000573115274353472022464 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_MATRIX_STORAGE_H #define OCTAVE_MPLAPACK_MP_COMPLEX_MATRIX_STORAGE_H #include #include #include #include #include #include "mp_complex_scalar_storage.h" namespace octave_mplapack { class MpfrComplexMatrixStorage { public: using NativeScalar = MpfrComplexScalarStorage::NativeScalar; using MplapackInteger = mplapackint; MpfrComplexMatrixStorage (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits); MpfrComplexMatrixStorage (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const std::vector>& values); MpfrComplexMatrixStorage (std::size_t rows, std::size_t columns, mpfr_prec_t precision_bits, const std::vector& values); MpfrComplexMatrixStorage (const MpfrComplexMatrixStorage&) = default; MpfrComplexMatrixStorage (MpfrComplexMatrixStorage&&) noexcept = default; ~MpfrComplexMatrixStorage () = default; MpfrComplexMatrixStorage& operator= (MpfrComplexMatrixStorage other) noexcept; void swap (MpfrComplexMatrixStorage& other) noexcept; std::size_t rows () const noexcept; std::size_t columns () const noexcept; std::size_t numel () const noexcept; mpfr_prec_t precision_bits () const noexcept; MplapackInteger leading_dimension () const; NativeScalar* data () noexcept; const NativeScalar* data () const noexcept; NativeScalar& at (std::size_t row, std::size_t column); const NativeScalar& at (std::size_t row, std::size_t column) const; bool all_elements_have_uniform_precision () const noexcept; bool element_exactly_equal_text (std::size_t row, std::size_t column, const std::string& text) const; bool element_exactly_equal_double (std::size_t row, std::size_t column, const std::complex& value) const noexcept; bool element_exactly_equal (std::size_t row, std::size_t column, const MpfrComplexMatrixStorage& other, std::size_t other_row, std::size_t other_column) const; static std::size_t checked_element_count (std::size_t rows, std::size_t columns); static MplapackInteger checked_mplapack_dimension (std::size_t value); private: static std::vector make_elements (std::size_t count, mpfr_prec_t precision_bits); std::size_t offset (std::size_t row, std::size_t column) const; std::size_t m_rows; std::size_t m_columns; mpfr_prec_t m_precision_bits; std::vector m_values; }; void swap (MpfrComplexMatrixStorage& lhs, MpfrComplexMatrixStorage& rhs) noexcept; } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_complex_matrix_concat.h0000644000230300031750000000176115274353472022266 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #ifndef OCTAVE_MPLAPACK_MP_COMPLEX_MATRIX_CONCAT_H #define OCTAVE_MPLAPACK_MP_COMPLEX_MATRIX_CONCAT_H #include #include #include #include "mp_complex_matrix_storage.h" namespace octave_mplapack { // A complex concatenation operand copies existing real or complex values into // a uniformly precisioned MPC destination. The callback is structural and // never consults the ambient precision. struct MpcConcatOperand { using CopyElement = std::function; std::size_t rows = 0; std::size_t columns = 0; mpfr_prec_t precision_bits = 0; bool has_mp_precision = false; CopyElement copy_element; }; MpfrComplexMatrixStorage mpc_matrix_concatenate ( const std::vector& operands, int dimension, std::size_t result_rows, std::size_t result_columns, mpfr_prec_t result_precision); } // namespace octave_mplapack #endif mplapack-interop-0.5.1/src/mp_script_reductions.cc0000644000230300031750000006115615274353472021611 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_script_reductions.h" #include #include #include #include #include "mp_complex_precision.h" namespace { using namespace octave_mplapack; std::size_t reduced_length (const MpfrMatrixStorage& source, std::size_t dimension) { return dimension == 1 ? source.rows () : source.columns (); } std::size_t result_rows (const MpfrMatrixStorage& source, const MpScriptReductionOptions& options) { return options.all ? 1 : (options.dimension == 1 ? 1 : source.rows ()); } std::size_t result_columns (const MpfrMatrixStorage& source, const MpScriptReductionOptions& options) { return options.all ? 1 : (options.dimension == 1 ? source.columns () : 1); } void validate_options (const MpScriptReductionOptions& options) { if (options.dimension != 1 && options.dimension != 2) throw std::invalid_argument ("reduction dimension must be 1 or 2"); } void validate_nonempty_dimension (const MpfrMatrixStorage& source, const MpScriptReductionOptions& options) { validate_options (options); if (options.all) return; (void) reduced_length (source, options.dimension); } bool real_nan (mpfr_srcptr value) noexcept { return mpfr_nan_p (value) != 0; } bool complex_nan (mpc_srcptr value) noexcept { return mpfr_nan_p (mpc_realref (value)) || mpfr_nan_p (mpc_imagref (value)); } void set_real_identity (mpfr_ptr value, bool product) { mpfr_set_ui (value, product ? 1 : 0, MPFR_RNDN); } void set_complex_identity (mpc_ptr value, bool product) { mpc_set_ui (value, product ? 1 : 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); } void real_accumulate (mpfr_ptr accumulator, mpfr_srcptr value, MpScriptReductionOperation operation) { if (operation == MpScriptReductionOperation::sum || operation == MpScriptReductionOperation::cumsum) mpfr_add (accumulator, accumulator, value, MPFR_RNDN); else if (operation == MpScriptReductionOperation::prod || operation == MpScriptReductionOperation::cumprod) mpfr_mul (accumulator, accumulator, value, MPFR_RNDN); else mpfr_fma (accumulator, value, value, accumulator, MPFR_RNDN); } void complex_accumulate (mpc_ptr accumulator, mpc_srcptr value, MpScriptReductionOperation operation) { const mpc_rnd_t rounding = MPC_RND (MPFR_RNDN, MPFR_RNDN); if (operation == MpScriptReductionOperation::sum || operation == MpScriptReductionOperation::cumsum) mpc_add (accumulator, accumulator, value, rounding); else mpc_mul (accumulator, accumulator, value, rounding); } void complex_sumsq_accumulate (mpfr_ptr accumulator, mpc_srcptr value) { mpfr_t magnitude; mpfr_init2 (magnitude, mpfr_get_prec (accumulator)); mpc_abs (magnitude, value, MPFR_RNDN); mpfr_fma (accumulator, magnitude, magnitude, accumulator, MPFR_RNDN); mpfr_clear (magnitude); } MpfrMatrixStorage mpfr_reduce_general (const MpfrMatrixStorage& source, MpScriptReductionOperation operation, const MpScriptReductionOptions& options) { validate_nonempty_dimension (source, options); if (operation == MpScriptReductionOperation::cumsum || operation == MpScriptReductionOperation::cumprod) { MpfrMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); const std::size_t length = reduced_length (source, options.dimension); const bool product = operation == MpScriptReductionOperation::cumprod; for (std::size_t fixed = 0; fixed < (options.dimension == 1 ? source.columns () : source.rows ()); ++fixed) { typename MpfrMatrixStorage::NativeScalar accumulator = MpfrMatrixStorage::NativeScalar::with_precision ( source.precision_bits ()); set_real_identity (accumulator.mpfr_data (), product); for (std::size_t step = 0; step < length; ++step) { const std::size_t position = options.reverse ? length - 1 - step : step; const std::size_t row = options.dimension == 1 ? position : fixed; const std::size_t column = options.dimension == 1 ? fixed : position; const auto& value = source.at (row, column); if (! (options.omit_nan && real_nan (value.mpfr_data ()))) real_accumulate (accumulator.mpfr_data (), value.mpfr_data (), operation); mpfr_set (result.at (row, column).mpfr_data (), accumulator.mpfr_data (), MPFR_RNDN); } } return result; } MpfrMatrixStorage result (result_rows (source, options), result_columns (source, options), source.precision_bits ()); const bool product = operation == MpScriptReductionOperation::prod; if (options.all) { auto& output = result.at (0, 0); set_real_identity (output.mpfr_data (), product); for (std::size_t index = 0; index < source.numel (); ++index) { const auto& value = source.data ()[index]; if (! (options.omit_nan && real_nan (value.mpfr_data ()))) real_accumulate (output.mpfr_data (), value.mpfr_data (), operation); } return result; } const std::size_t length = reduced_length (source, options.dimension); for (std::size_t fixed = 0; fixed < (options.dimension == 1 ? source.columns () : source.rows ()); ++fixed) { const std::size_t row = options.dimension == 1 ? 0 : fixed; const std::size_t column = options.dimension == 1 ? fixed : 0; auto& output = result.at (row, column); set_real_identity (output.mpfr_data (), product); for (std::size_t step = 0; step < length; ++step) { const std::size_t position = options.reverse ? length - 1 - step : step; const std::size_t source_row = options.dimension == 1 ? position : fixed; const std::size_t source_column = options.dimension == 1 ? fixed : position; const auto& value = source.at (source_row, source_column); if (! (options.omit_nan && real_nan (value.mpfr_data ()))) real_accumulate (output.mpfr_data (), value.mpfr_data (), operation); } } return result; } MpfrComplexMatrixStorage mpc_reduce_general (const MpfrComplexMatrixStorage& source, MpScriptReductionOperation operation, const MpScriptReductionOptions& options) { validate_options (options); MpfrMpcPrecisionScope scope (source.precision_bits ()); if (operation == MpScriptReductionOperation::cumsum || operation == MpScriptReductionOperation::cumprod) { MpfrComplexMatrixStorage result (source.rows (), source.columns (), source.precision_bits ()); const std::size_t length = options.dimension == 1 ? source.rows () : source.columns (); const bool product = operation == MpScriptReductionOperation::cumprod; for (std::size_t fixed = 0; fixed < (options.dimension == 1 ? source.columns () : source.rows ()); ++fixed) { auto accumulator = MpfrComplexMatrixStorage::NativeScalar::with_precision ( source.precision_bits ()); set_complex_identity (accumulator.mpc_data (), product); for (std::size_t step = 0; step < length; ++step) { const std::size_t position = options.reverse ? length - 1 - step : step; const std::size_t row = options.dimension == 1 ? position : fixed; const std::size_t column = options.dimension == 1 ? fixed : position; const auto& value = source.at (row, column); if (! (options.omit_nan && complex_nan (value.mpc_data ()))) complex_accumulate (accumulator.mpc_data (), value.mpc_data (), operation); mpc_set (result.at (row, column).mpc_data (), accumulator.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } } return result; } MpfrComplexMatrixStorage result ( options.all ? 1 : (options.dimension == 1 ? 1 : source.rows ()), options.all ? 1 : (options.dimension == 1 ? source.columns () : 1), source.precision_bits ()); const bool product = operation == MpScriptReductionOperation::prod; if (options.all) { auto& output = result.at (0, 0); set_complex_identity (output.mpc_data (), product); for (std::size_t index = 0; index < source.numel (); ++index) { const auto& value = source.data ()[index]; if (! (options.omit_nan && complex_nan (value.mpc_data ()))) complex_accumulate (output.mpc_data (), value.mpc_data (), operation); } return result; } const std::size_t length = options.dimension == 1 ? source.rows () : source.columns (); for (std::size_t fixed = 0; fixed < (options.dimension == 1 ? source.columns () : source.rows ()); ++fixed) { const std::size_t row = options.dimension == 1 ? 0 : fixed; const std::size_t column = options.dimension == 1 ? fixed : 0; auto& output = result.at (row, column); set_complex_identity (output.mpc_data (), product); for (std::size_t step = 0; step < length; ++step) { const std::size_t position = options.reverse ? length - 1 - step : step; const std::size_t source_row = options.dimension == 1 ? position : fixed; const std::size_t source_column = options.dimension == 1 ? fixed : position; const auto& value = source.at (source_row, source_column); if (! (options.omit_nan && complex_nan (value.mpc_data ()))) complex_accumulate (output.mpc_data (), value.mpc_data (), operation); } } return result; } int compare_real (mpfr_srcptr lhs, mpfr_srcptr rhs, MpScriptExtremumOperation operation) { const int compared = mpfr_cmp (lhs, rhs); if (operation == MpScriptExtremumOperation::minimum) return compared < 0 ? -1 : compared > 0; return compared > 0 ? -1 : compared < 0; } int compare_complex (mpc_srcptr lhs, mpc_srcptr rhs, MpScriptExtremumOperation operation, MpScriptComparisonMethod method) { mpfr_t left_key; mpfr_t right_key; mpfr_init2 (left_key, mpfr_get_prec (mpc_realref (lhs))); mpfr_init2 (right_key, mpfr_get_prec (mpc_realref (rhs))); if (method == MpScriptComparisonMethod::real) { mpfr_set (left_key, mpc_realref (lhs), MPFR_RNDN); mpfr_set (right_key, mpc_realref (rhs), MPFR_RNDN); } else { mpc_abs (left_key, lhs, MPFR_RNDN); mpc_abs (right_key, rhs, MPFR_RNDN); } int result = compare_real (left_key, right_key, operation); if (result == 0 && (method == MpScriptComparisonMethod::automatic || method == MpScriptComparisonMethod::absolute)) { mpfr_atan2 (left_key, mpc_imagref (lhs), mpc_realref (lhs), MPFR_RNDN); mpfr_atan2 (right_key, mpc_imagref (rhs), mpc_realref (rhs), MPFR_RNDN); result = compare_real (left_key, right_key, operation); } if (result == 0 && method == MpScriptComparisonMethod::real) result = compare_real (mpc_imagref (lhs), mpc_imagref (rhs), operation); mpfr_clear (left_key); mpfr_clear (right_key); return result; } } // namespace namespace octave_mplapack { MpfrMatrixStorage mpfr_script_reduce (const MpfrMatrixStorage& source, MpScriptReductionOperation operation, const MpScriptReductionOptions& options) { return mpfr_reduce_general (source, operation, options); } MpfrComplexMatrixStorage mpc_script_reduce (const MpfrComplexMatrixStorage& source, MpScriptReductionOperation operation, const MpScriptReductionOptions& options) { return mpc_reduce_general (source, operation, options); } MpfrMatrixStorage mpc_script_sumsq (const MpfrComplexMatrixStorage& source, const MpScriptReductionOptions& options) { MpfrMpcPrecisionScope scope (source.precision_bits ()); validate_options (options); MpfrMatrixStorage result ( options.all ? 1 : (options.dimension == 1 ? 1 : source.rows ()), options.all ? 1 : (options.dimension == 1 ? source.columns () : 1), source.precision_bits ()); if (options.all) { auto& output = result.at (0, 0); set_real_identity (output.mpfr_data (), false); for (std::size_t index = 0; index < source.numel (); ++index) if (! (options.omit_nan && complex_nan (source.data ()[index].mpc_data ()))) complex_sumsq_accumulate (output.mpfr_data (), source.data ()[index].mpc_data ()); return result; } const std::size_t length = options.dimension == 1 ? source.rows () : source.columns (); for (std::size_t fixed = 0; fixed < (options.dimension == 1 ? source.columns () : source.rows ()); ++fixed) { const std::size_t row = options.dimension == 1 ? 0 : fixed; const std::size_t column = options.dimension == 1 ? fixed : 0; auto& output = result.at (row, column); set_real_identity (output.mpfr_data (), false); for (std::size_t step = 0; step < length; ++step) { const std::size_t position = options.reverse ? length - 1 - step : step; const std::size_t source_row = options.dimension == 1 ? position : fixed; const std::size_t source_column = options.dimension == 1 ? fixed : position; const auto& value = source.at (source_row, source_column); if (! (options.omit_nan && complex_nan (value.mpc_data ()))) complex_sumsq_accumulate (output.mpfr_data (), value.mpc_data ()); } } return result; } MpfrMatrixStorage mpfr_script_reduce (const MpfrMatrixStorage& source, MpScriptReductionOperation operation, const MpScriptReductionOptions& options); MpScriptExtremumResultReal mpfr_script_extremum (const MpfrMatrixStorage& source, MpScriptExtremumOperation operation, const MpScriptExtremumOptions& options) { validate_options (options); MpfrMatrixStorage result ( options.all ? 1 : (options.dimension == 1 ? 1 : source.rows ()), options.all ? 1 : (options.dimension == 1 ? source.columns () : 1), source.precision_bits ()); std::vector indices (result.numel (), 0); const auto choose = [&] (mpfr_ptr output, std::size_t& selected, const std::vector& candidates) { bool initialized = false; for (const std::size_t index : candidates) { const auto& value = source.data ()[index]; if (options.omit_nan && real_nan (value.mpfr_data ())) continue; const bool value_is_nan = real_nan (value.mpfr_data ()); if (value_is_nan && ! options.omit_nan) { mpfr_set (output, value.mpfr_data (), MPFR_RNDN); selected = index; initialized = true; break; } if (! initialized || real_nan (output) || (! value_is_nan && compare_real (value.mpfr_data (), output, operation) < 0)) { mpfr_set (output, value.mpfr_data (), MPFR_RNDN); selected = index; initialized = true; } if (real_nan (value.mpfr_data ())) break; } if (! initialized) mpfr_set_nan (output); }; if (options.all) { std::vector candidates (source.numel ()); for (std::size_t index = 0; index < source.numel (); ++index) candidates[index] = index; std::size_t selected = 0; choose (result.at (0, 0).mpfr_data (), selected, candidates); indices[0] = (real_nan (result.at (0, 0).mpfr_data ()) && options.omit_nan) ? 0 : selected + 1; return {std::move (result), std::move (indices)}; } const std::size_t length = options.dimension == 1 ? source.rows () : source.columns (); for (std::size_t fixed = 0; fixed < (options.dimension == 1 ? source.columns () : source.rows ()); ++fixed) { std::vector candidates; candidates.reserve (length); for (std::size_t position = 0; position < length; ++position) candidates.push_back (options.dimension == 1 ? position + fixed * source.rows () : fixed + position * source.rows ()); const std::size_t row = options.dimension == 1 ? 0 : fixed; const std::size_t column = options.dimension == 1 ? fixed : 0; std::size_t selected = 0; choose (result.at (row, column).mpfr_data (), selected, candidates); indices[row + column * result.rows ()] = (real_nan (result.at (row, column).mpfr_data ()) && options.omit_nan) ? 0 : (options.dimension == 1 ? selected % source.rows () : selected / source.rows ()) + 1; } return {std::move (result), std::move (indices)}; } MpScriptExtremumResultComplex mpc_script_extremum (const MpfrComplexMatrixStorage& source, MpScriptExtremumOperation operation, const MpScriptExtremumOptions& options) { validate_options (options); MpfrMpcPrecisionScope scope (source.precision_bits ()); MpfrComplexMatrixStorage result ( options.all ? 1 : (options.dimension == 1 ? 1 : source.rows ()), options.all ? 1 : (options.dimension == 1 ? source.columns () : 1), source.precision_bits ()); std::vector indices (result.numel (), 0); const auto choose = [&] (mpc_ptr output, std::size_t& selected, const std::vector& candidates) { bool initialized = false; for (const std::size_t index : candidates) { const auto& value = source.data ()[index]; if (options.omit_nan && complex_nan (value.mpc_data ())) continue; const bool value_is_nan = complex_nan (value.mpc_data ()); const bool output_is_nan = complex_nan (output); if (value_is_nan && ! options.omit_nan) { mpc_set (output, value.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); selected = index; initialized = true; break; } if (! initialized || output_is_nan || (! value_is_nan && compare_complex (value.mpc_data (), output, operation, options.comparison) < 0)) { mpc_set (output, value.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); selected = index; initialized = true; } if (value_is_nan) break; } if (! initialized) mpc_set_nan (output); }; if (options.all) { std::vector candidates (source.numel ()); for (std::size_t index = 0; index < source.numel (); ++index) candidates[index] = index; std::size_t selected = 0; choose (result.at (0, 0).mpc_data (), selected, candidates); indices[0] = (complex_nan (result.at (0, 0).mpc_data ()) && options.omit_nan) ? 0 : selected + 1; return {std::move (result), std::move (indices)}; } const std::size_t length = options.dimension == 1 ? source.rows () : source.columns (); for (std::size_t fixed = 0; fixed < (options.dimension == 1 ? source.columns () : source.rows ()); ++fixed) { std::vector candidates; candidates.reserve (length); for (std::size_t position = 0; position < length; ++position) candidates.push_back (options.dimension == 1 ? position + fixed * source.rows () : fixed + position * source.rows ()); const std::size_t row = options.dimension == 1 ? 0 : fixed; const std::size_t column = options.dimension == 1 ? fixed : 0; std::size_t selected = 0; choose (result.at (row, column).mpc_data (), selected, candidates); indices[row + column * result.rows ()] = (complex_nan (result.at (row, column).mpc_data ()) && options.omit_nan) ? 0 : (options.dimension == 1 ? selected % source.rows () : selected / source.rows ()) + 1; } return {std::move (result), std::move (indices)}; } MpScriptExtremumResultReal mpfr_script_extremum_pair (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs, MpScriptExtremumOperation operation, const MpScriptExtremumOptions& options) { if (lhs.rows () != rhs.rows () && lhs.rows () != 1 && rhs.rows () != 1) throw std::invalid_argument ("nonconformant row dimensions for min/max"); if (lhs.columns () != rhs.columns () && lhs.columns () != 1 && rhs.columns () != 1) throw std::invalid_argument ("nonconformant column dimensions for min/max"); const std::size_t rows = std::max (lhs.rows (), rhs.rows ()); const std::size_t columns = std::max (lhs.columns (), rhs.columns ()); MpfrMatrixStorage result (rows, columns, std::max (lhs.precision_bits (), rhs.precision_bits ())); std::vector indices (result.numel (), 1); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) { const auto& left = lhs.at (lhs.rows () == 1 ? 0 : row, lhs.columns () == 1 ? 0 : column); const auto& right = rhs.at (rhs.rows () == 1 ? 0 : row, rhs.columns () == 1 ? 0 : column); const bool left_nan = real_nan (left.mpfr_data ()); const bool right_nan = real_nan (right.mpfr_data ()); bool choose_right = false; if (options.omit_nan && (left_nan || right_nan)) choose_right = left_nan && ! right_nan; else if (left_nan || right_nan) choose_right = right_nan && ! left_nan; else choose_right = compare_real (right.mpfr_data (), left.mpfr_data (), operation) < 0; mpfr_set (result.at (row, column).mpfr_data (), (choose_right ? right : left).mpfr_data (), MPFR_RNDN); indices[row + column * rows] = choose_right ? 2 : 1; } return {std::move (result), std::move (indices)}; } MpScriptExtremumResultComplex mpc_script_extremum_pair (const MpfrComplexMatrixStorage& lhs, const MpfrComplexMatrixStorage& rhs, MpScriptExtremumOperation operation, const MpScriptExtremumOptions& options) { if (lhs.rows () != rhs.rows () && lhs.rows () != 1 && rhs.rows () != 1) throw std::invalid_argument ("nonconformant row dimensions for min/max"); if (lhs.columns () != rhs.columns () && lhs.columns () != 1 && rhs.columns () != 1) throw std::invalid_argument ("nonconformant column dimensions for min/max"); const std::size_t rows = std::max (lhs.rows (), rhs.rows ()); const std::size_t columns = std::max (lhs.columns (), rhs.columns ()); const mpfr_prec_t precision = std::max (lhs.precision_bits (), rhs.precision_bits ()); MpfrMpcPrecisionScope scope (precision); MpfrComplexMatrixStorage result (rows, columns, precision); std::vector indices (result.numel (), 1); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) { const auto& left = lhs.at (lhs.rows () == 1 ? 0 : row, lhs.columns () == 1 ? 0 : column); const auto& right = rhs.at (rhs.rows () == 1 ? 0 : row, rhs.columns () == 1 ? 0 : column); const bool left_nan = complex_nan (left.mpc_data ()); const bool right_nan = complex_nan (right.mpc_data ()); bool choose_right = false; if (options.omit_nan && (left_nan || right_nan)) choose_right = left_nan && ! right_nan; else if (left_nan || right_nan) choose_right = right_nan && ! left_nan; else choose_right = compare_complex (right.mpc_data (), left.mpc_data (), operation, options.comparison) < 0; mpc_set (result.at (row, column).mpc_data (), (choose_right ? right : left).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); indices[row + column * rows] = choose_right ? 2 : 1; } return {std::move (result), std::move (indices)}; } } // namespace octave_mplapack mplapack-interop-0.5.1/src/mp_native_serialization.cc0000644000230300031750000002340415274353472022263 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_native_serialization.h" #include #include #include #include #include #include #include #include #include namespace octave_mplapack { namespace { constexpr const char *native_magic = "MPLAPACK_MP_NATIVE_V1"; constexpr std::uint64_t max_text_length = 64ULL * 1024ULL * 1024ULL; constexpr std::uint64_t max_element_count = 100000000ULL; bool write_line (std::ostream& stream, const std::string& value) noexcept { stream << value << '\n'; return static_cast (stream); } bool write_uint_line (std::ostream& stream, std::uint64_t value) noexcept { return write_line (stream, std::to_string (value)); } bool write_value (std::ostream& stream, const std::string& value) noexcept { if (value.size () > max_text_length) return false; stream << value.size () << ':' << value << '\n'; return static_cast (stream); } bool read_line (std::istream& stream, std::string& value, std::size_t max_length = 128) noexcept { value.clear (); if (! std::getline (stream, value) || value.size () > max_length) return false; return true; } bool parse_uint (const std::string& text, std::uint64_t& value) noexcept { if (text.empty ()) return false; const char *first = text.data (); const char *last = first + text.size (); const auto parsed = std::from_chars (first, last, value); return parsed.ec == std::errc () && parsed.ptr == last; } bool read_uint_line (std::istream& stream, std::uint64_t& value) noexcept { std::string line; return read_line (stream, line) && parse_uint (line, value); } bool read_value (std::istream& stream, std::string& value) noexcept { std::string length_text; value.clear (); if (! std::getline (stream, length_text, ':') || length_text.empty () || length_text.size () > 20) return false; std::uint64_t length = 0; if (! parse_uint (length_text, length) || length > max_text_length) return false; value.resize (static_cast (length)); if (length != 0) stream.read (value.data (), static_cast (length)); if (! stream || stream.get () != '\n') return false; return true; } bool write_header (std::ostream& stream, const char *kind, mpfr_prec_t precision, std::size_t rows, std::size_t columns, std::size_t count) noexcept { if (rows > std::numeric_limits::max () || columns > std::numeric_limits::max () || count > std::numeric_limits::max () || static_cast (precision) > std::numeric_limits::max ()) return false; return write_line (stream, native_magic) && write_line (stream, kind) && write_uint_line (stream, static_cast (precision)) && write_uint_line (stream, static_cast (rows)) && write_uint_line (stream, static_cast (columns)) && write_uint_line (stream, static_cast (count)); } bool read_header (std::istream& stream, const char *expected_kind, mpfr_prec_t& precision, std::size_t& rows, std::size_t& columns, std::size_t& count) noexcept { std::string magic; std::string kind; std::uint64_t precision_value = 0; std::uint64_t rows_value = 0; std::uint64_t columns_value = 0; std::uint64_t count_value = 0; if (! read_line (stream, magic) || magic != native_magic || ! read_line (stream, kind) || kind != expected_kind || ! read_uint_line (stream, precision_value) || ! read_uint_line (stream, rows_value) || ! read_uint_line (stream, columns_value) || ! read_uint_line (stream, count_value)) return false; const mpfr_prec_t converted_precision = static_cast (precision_value); if (static_cast (converted_precision) != precision_value || converted_precision < MPFR_PREC_MIN || converted_precision > MPFR_PREC_MAX || rows_value > std::numeric_limits::max () || columns_value > std::numeric_limits::max () || count_value > std::numeric_limits::max () || count_value > max_element_count) return false; const std::size_t converted_rows = static_cast (rows_value); const std::size_t converted_columns = static_cast (columns_value); const std::size_t converted_count = static_cast (count_value); try { if (MpfrMatrixStorage::checked_element_count (converted_rows, converted_columns) != converted_count) return false; } catch (...) { return false; } precision = converted_precision; rows = converted_rows; columns = converted_columns; count = converted_count; return true; } template bool write_elements (std::ostream& stream, const Storage& storage) noexcept { for (std::size_t column = 0; column < storage.columns (); ++column) for (std::size_t row = 0; row < storage.rows (); ++row) { std::string text; if constexpr (std::is_same_v) text = MpfrScalarStorage (storage.at (row, column)) .to_canonical_string (); else text = MpfrComplexScalarStorage (storage.at (row, column)) .to_canonical_string (); if (! write_value (stream, text)) return false; } return true; } template bool read_elements (std::istream& stream, std::size_t count, std::vector& values) noexcept { values.clear (); try { values.reserve (count); for (std::size_t index = 0; index < count; ++index) { std::string text; if (! read_value (stream, text)) return false; values.push_back (std::move (text)); } } catch (...) { return false; } return true; } } // namespace bool save_native_mpfr_scalar (std::ostream& stream, const MpfrScalarStorage& storage) noexcept { return write_header (stream, "real-scalar", storage.precision_bits (), 1, 1, 1) && write_value (stream, storage.to_canonical_string ()); } bool load_native_mpfr_scalar (std::istream& stream, MpfrScalarStorage& storage) noexcept { mpfr_prec_t precision = 0; std::size_t rows = 0; std::size_t columns = 0; std::size_t count = 0; std::string text; if (! read_header (stream, "real-scalar", precision, rows, columns, count) || rows != 1 || columns != 1 || count != 1 || ! read_value (stream, text)) return false; try { MpfrScalarStorage replacement (text, precision); storage = std::move (replacement); return true; } catch (...) { return false; } } bool save_native_mpc_scalar (std::ostream& stream, const MpfrComplexScalarStorage& storage) noexcept { return write_header (stream, "complex-scalar", storage.precision_bits (), 1, 1, 1) && write_value (stream, storage.to_canonical_string ()); } bool load_native_mpc_scalar (std::istream& stream, MpfrComplexScalarStorage& storage) noexcept { mpfr_prec_t precision = 0; std::size_t rows = 0; std::size_t columns = 0; std::size_t count = 0; std::string text; if (! read_header (stream, "complex-scalar", precision, rows, columns, count) || rows != 1 || columns != 1 || count != 1 || ! read_value (stream, text)) return false; try { MpfrComplexScalarStorage replacement (text, precision); storage = std::move (replacement); return true; } catch (...) { return false; } } bool save_native_mpfr_matrix (std::ostream& stream, const MpfrMatrixStorage& storage) noexcept { return write_header (stream, "real-matrix", storage.precision_bits (), storage.rows (), storage.columns (), storage.numel ()) && write_elements (stream, storage); } bool load_native_mpfr_matrix (std::istream& stream, MpfrMatrixStorage& storage) noexcept { mpfr_prec_t precision = 0; std::size_t rows = 0; std::size_t columns = 0; std::size_t count = 0; if (! read_header (stream, "real-matrix", precision, rows, columns, count)) return false; std::vector values; if (! read_elements (stream, count, values)) return false; try { MpfrMatrixStorage replacement (rows, columns, precision, values); storage = std::move (replacement); return true; } catch (...) { return false; } } bool save_native_mpc_matrix (std::ostream& stream, const MpfrComplexMatrixStorage& storage) noexcept { return write_header (stream, "complex-matrix", storage.precision_bits (), storage.rows (), storage.columns (), storage.numel ()) && write_elements (stream, storage); } bool load_native_mpc_matrix (std::istream& stream, MpfrComplexMatrixStorage& storage) noexcept { mpfr_prec_t precision = 0; std::size_t rows = 0; std::size_t columns = 0; std::size_t count = 0; if (! read_header (stream, "complex-matrix", precision, rows, columns, count)) return false; std::vector values; if (! read_elements (stream, count, values)) return false; try { MpfrComplexMatrixStorage replacement (rows, columns, precision, values); storage = std::move (replacement); return true; } catch (...) { return false; } } } // namespace octave_mplapack mplapack-interop-0.5.1/COPYING0000644000230300031750000000246315274353472015303 0ustar rafaelrafaelBSD 2-Clause License Copyright (c) 2026, MPLAPACK contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. mplapack-interop-0.5.1/README.md0000644000230300031750000004070515274353472015530 0ustar rafaelrafael# octave-mplapack **Released: `mplapack-interop 0.5.1` (2026-09-23).** The source is available on [GitHub](https://github.com/nakatamaho/octave-mplapack/releases/tag/v0.5.1). The published `v0.5.0` tag and archive remain immutable. This maintenance release closes the Ubuntu 26.04 installer compatibility issue and provides GNU Octave access to real and complex arbitrary-precision linear algebra through the native `mp` type. ## Quick start Ubuntu 26.04 only (the helper is not release-tested on other systems): First install the system dependencies: ```sh sudo apt-get update && sudo apt-get install -y build-essential cmake pkg-config autoconf automake libtool libgmp-dev libmpfr-dev libmpc-dev octave octave-dev xz-utils curl ``` Then, in a separate command, download and run the user-level installer: ```sh curl -fsSL https://raw.githubusercontent.com/nakatamaho/octave-mplapack/main/tools/install-local-octave-mplapack.sh | sh ``` Run these two commands in order; do not paste them onto one shell line. The second command does not use `sudo`, and writes under your home directory. The installer selects gmpfrxx_mkII 1.5.0 and the published 0.5.1 package by default. It also repairs installed MPLAPACK `.pc` metadata on Ubuntu systems where `libmpc-dev` does not provide `mpc.pc`. The installer prints the wrapper path. With the default paths, start it from the shell as follows: ```sh $HOME/.local/share/mplapack-interop/stack/bin/octave-mplapack ``` The wrapper is the normal Octave startup command; it loads `mplapack-interop` automatically and suppresses only the noisy `Octave:shadowed-function` notice for compatibility wrappers. At the Octave prompt, run the example directly: For example, compute a 2x2 multiple-precision SVD: ```octave A = mp ([3, 1; 0, 2]); [U, S, V] = svd (A); disp (S) assert (norm (double (A - U * S * V'), "fro") < 1e-12) ``` The compatibility wrappers are not removed. If you use ordinary `octave` instead of the wrapper and want to control the notice yourself, run `warning ('off', 'Octave:shadowed-function')` before `pkg load mplapack-interop`. ## News ### 0.5.1 — 2026-09-23 - The installer now uses gmpfrxx_mkII 1.5.0 and the published 0.5.1 source archive by default. The immutable 0.5.0 release remains selectable. - Installed MPLAPACK `.pc` metadata is normalized downstream so `pkg-config --cflags --libs mplapack_mpfr` works without a system `mpc.pc`. - Complex `log2` uses gmpfrxx `mpfrxx::log2` over MPC rather than a direct `mpc_log2` symbol dependency. - The new runnable `examples/18_complex_log2.m` covers the native complex path. The published 0.5.0 tag and archive remain immutable. Debian/PPA packaging and uploads remain separate follow-up work. ### 0.5.0 — 2026-09-15 - First public real-plus-complex release of `mplapack-interop`. - Supports dense linear algebra, SVD/eigenvalue problems, Schur/QZ, matrix functions, polynomial utilities, interpolation, solvers, quadrature, optimization, serialization, and documented compatibility helpers. - Complex paths include `Cgemm`, `Cgesv`, `Cgelsy`, `Cpotrf`, QR, pivoted QR, and the mandatory `Cgetrf` LU path. - Uses MPLAPACK 3.0.1 and gmpfrxx_mkII 1.4.1 with MPFR/MPC precision semantics and no builtin binary64 complex fallback. - Release QA passed the real/complex regression walls, precision canaries, package lifecycle, documentation checks, and native sanitizer suite. See [`NEWS.md`](NEWS.md) for the detailed release history. The exact frozen dependency handoff is in [`docs/dependency-release-stack-r1.md`](docs/dependency-release-stack-r1.md). ## Goal `mplapack-interop` provides GNU Octave access to MPLAPACK multiple-precision linear algebra through an Octave-native multiprecision numeric type named `mp`. MPLAPACK is the numerical backend rather than the user-facing programming model. ## Documentation The task-oriented [user manual](doc/mplapack-interop.texi) covers installation, precision, real/complex behavior, dense linear algebra, advanced numerics, serialization, graphics, random generation, interpolation, solvers, quadrature, optimization, and troubleshooting. The [public API inventory] (docs/public-api-inventory.md) is the complete machine-auditable coverage matrix. The [advanced compatibility matrix] (docs/advanced-numerics-compatibility.md) records supported and deferred forms, while the [backend map](docs/backend-map.md) connects public calls to native algorithms. Runnable examples are under [examples/](examples/01_scalar_precision.m). Developer documentation is generated from [docs/doxygen/Doxyfile](docs/doxygen/Doxyfile). A generated [Markdown version of the manual](docs/mplapack-interop.md) is also provided; edit the Texinfo source and run `tools/build-manual-markdown.sh` to refresh it. The difficult SVD example/verification suite is documented in [`docs/svd-tiers.md`](docs/svd-tiers.md) and [`docs/svd-verification.md`](docs/svd-verification.md), with runnable defaults in `examples/14_svd_tier_s.m` through `examples/16_svd_verified.m`. The one-case worked examples are indexed by [`docs/examples/tiered/README.md`](docs/examples/tiered/README.md), with a matching explanation for every NEIGT/SVT Tier S/A case. The GitHub Markdown piecewise-rendering policy and migration record are in [`docs/math-rendering-migration.md`](docs/math-rendering-migration.md). For a checkout, `tools/dev-octave.sh` verifies the `pkg-config` dependency, builds the native module, and starts a configured development session. It does not replace clean package/install QA. The current surface includes dense real and complex `mp`, precision-controlled construction, arithmetic, mixed real/complex `*`, `\`, and `/`, indexing and in-bounds assignment, `chol`, full/economy and pivoted `qr`, `lu`, `norm`, `det`, `inv`, `svd`, `rank`, `cond`, `rcond`, structured and general standard and generalized `eig`, dense concatenation, element-wise power, integer matrix powers, native elementary functions, reductions, and extrema. S03 also provides native comparisons, logical conversion and operators, `any`/`all`, `find`, and logical indexing. S04 adds native dense matrix utilities (`diag`, `triu`/`tril`, `repmat`, flips, `rot90`, `cat(1/2)`) and explicit `"like"` constructors for `mp` templates. S05 adds native sequences, rounding, spacing, and utility arithmetic; S06 adds descriptive statistics; S07 adds common line-graphics wrappers; and S08 closes the ordinary dense script corpus with native `sort`/`diff` and structural compatibility. Sparse, surface-graphics, and N-D APIs remain explicitly unsupported; see the [advanced numerical compatibility](docs/advanced-numerics-compatibility.md), [complex API](docs/complex-api.md), and [compatibility limits](docs/complex-compatibility.md). ### Hilbert inverse example The package includes a 1024-bit Hilbert inverse example in [`examples/05_hilbert_inverse.m`](examples/05_hilbert_inverse.m). It constructs each `1/(i+j-1)` from decimal `mp` values and computes all inverse columns as `H \ I`; this avoids the binary64 matrix produced by builtin `hilb(n)`. N01 also provides the explicit `inv(H)` API. The external MPLAPACK C++ consumer boundary is validated separately by the MPLAPACK release QA. Its source is intentionally not copied into this Octave package's examples. The required MPLAPACK MPFR dependency is discovered through `pkg-config` and must provide the uniform-precision scope interface. The package never vendors or searches a developer-specific MPLAPACK path. ### Difficult nonsymmetric eigensystem examples The repository also includes a high-precision QA/example suite for nonnormal eigenproblems. It covers Hadamard-similar, Frank, companion, and two Forsythe representations with both `balance` and `nobalance`; see [`docs/nonsymmetric-eig-suite.md`](docs/nonsymmetric-eig-suite.md) and run `tools/run-nonsymmetric-eig-suite.sh smoke` from a configured checkout. ### Verified NEIGT tiers The manifest-driven Tier-S/Tier-A and verified V-S/V-A examples are available as [`examples/14_neig_tier_s.m`](examples/14_neig_tier_s.m), [`examples/15_neig_tier_a.m`](examples/15_neig_tier_a.m), [`examples/16_neig_verified_vs.m`](examples/16_neig_verified_vs.m), and [`examples/17_neig_verified_va.m`](examples/17_neig_verified_va.m). They are repository-local QA/example entry points built from the existing public `mp`/`mpbits`/`eig`/`svd`/`qr`/solve interfaces; they do not add package-level numeric methods. The ordinary smoke/demo profiles measure 120/168 eig rows, and each profile has 26 separately counted verification jobs. The V layer is a conservative outward-safe proof baseline. It records exact MP inputs, candidate provenance, proof preconditions, and certificate status; it does not turn residuals or precision agreement into a proof. Use `mp_neig_write_outputs` for a new-directory result bundle and `mp_neig_replay` to independently replay its hash-bound V-S1 artifact. The `plot=false` path is headless and all display conversion is kept at the final presentation boundary. See the [NEIGT compatibility notes](docs/advanced-numerics-compatibility.md) and the generated [user manual](docs/mplapack-interop.md). ## Initial backend The backend is MPLAPACK's MPFR/MPC implementation for real and complex values. MPLAPACK remains a separately installed dependency discovered through `pkg-config`; it is not vendored here. ## Working diagnostic With the current source package installed: ```octave pkg load mplapack-interop info = mplapack_version() a = mp("0.1"); b = mp(0.1); mpbits() % 512 mpdigits(100); mpbits() % 333 c = mp("0.1"); s = char(c) d = double(c) disp(c) sum_value = a + b difference = a - b product = a .* b quotient = a ./ b A = mp ({"1", "2"; "3", "4"}); B = mp ([1, 2; 3, 4]); size (A) % 2 2 C = A * A x = A \ b R = mp ({"1", "0"; "0", "1"; "1", "1"}); r = mp ({"0"; "1"; "4"}); least_squares = R \ r element = A(2, 1) column = A(:, 2) double_A = double(A) disp(A) R = chol (mp ({"4", "2"; "2", "10"})); [Q, R] = qr (mp ([1, 2; 3, 4; 5, 7])); % native MPLAPACK MPFR Rgemm/Rgesv/Rgelss/Rpotrf/Rgeqrf/Rorgqr/Rgeqp3 results ``` This loads the private native module, reports the Octave, MPLAPACK, and MPFR versions, and executes the MPLAPACK MPFR `Rlamch_mpfr` probe. The constructor creates immutable public `1 x 1` scalar values. A fresh process starts at 512 bits. `mpbits` controls the canonical bit precision and `mpdigits(n)` selects `ceil(n * log2(10))` bits without hidden guard bits. In the example, `a` and `b` remain 512-bit values while `c` uses 333 bits. `char(c)` returns canonical decimal text that reconstructs the same MPFR value when parsed at `c`'s precision. `double(c)` is an explicit, potentially lossy binary64 conversion; `disp(c)` prints the canonical multiprecision text. Scalar arithmetic uses MPFR round-to-nearest. For two `mp` operands the result precision is the greater stored operand precision; with one real scalar `double`, the `mp` operand precision is used. The current default does not affect an arithmetic result. For example, `a + 0.1` converts the already-rounded binary64 operand directly at `a`'s precision and generally differs from `a + mp("0.1")`. M07 matrix constructors preserve the same source distinction element by element. A real double matrix transfers each existing binary64 value directly, while a text-cell matrix parses each decimal directly. Each matrix has one immutable precision, contiguous column-major MPFR storage, and normal two-dimensional shape metadata. M08 implements dense real `A * B` through MPLAPACK MPFR `Rgemm`, and M09 implements square `A \ B` through `Rgesv`; M15 extends full-rank rectangular `A \ B` through `Rgels`, with result precision equal to the maximum operand precision and a temporary current-thread precision scope. M16 upgrades rectangular `A \ B` to the rank-revealing MPLAPACK MPFR `Rgelss` path for minimum-norm least-squares solutions, while square systems remain on `Rgesv`. M10 adds read-only indexing, `double(A)`, and canonical matrix display. M11 adds native MPFR matrix `+`, `-`, `.*`, and `./`, unary signs, and two-dimensional singleton expansion. M12 adds read-only transpose, conjugate transpose for real values, and column-major reshape; these structural operations preserve source precision and do not consult the ambient precision default. M17 adds dense real `chol` through MPLAPACK MPFR `Rpotrf`, including selected-triangle semantics and optional status output, while preserving immutable source values and stored precision. M18 adds non-pivoted dense real `qr` through MPLAPACK MPFR `Rgeqrf` and `Rorgqr`; one-output `qr(A)` returns `R` and two-output forms return `Q,R`. M19 adds column-pivoted three-output `qr` through `Rgeqp3`, reusing `Rorgqr` for `Q`. M21 adds dense real `lu` through `Rgetrf`; packed one-output factors, permutation-aware two/three-output factors, and vector row pivots preserve the stored operand precision. N00 adds `norm`; N01 adds `det` and `inv` through stored-precision `Rgetrf`/`Rgetri` and `Cgetrf`/`Cgetri` paths. ## Current feature status | Feature | Scalar | Dense matrix | Backend | Status | |---|---:|---:|---|---| | `+ - .* ./` | yes | yes | MPFR | supported | | `*` | yes | yes | `Rgemm` | supported | | `\` | yes | yes | `Rgesv`/`Rgelss` | supported | | `/` | yes | yes | transpose solve; `Rgesv`/`Rgelss` | supported | | `chol` | yes | yes | `Rpotrf` | supported | | `qr` / pivoted `qr` | yes | yes | `Rgeqrf`/`Rgeqp3`/`Rorgqr` | supported | | `lu` | yes | yes | `Rgetrf` | supported | | structured `eig` | yes | yes | `Rsyevd`/`Cheevd` | supported | | complex | yes | yes | `Cgemm`/`Cgesv`/`Cgelsy`/`Cpotrf`/`Cgeqrf`/`Cgeqp3`/`Cgetrf` | supported | | T00–T14 advanced numerics | yes | yes | MPFR/MPC native bridges | supported/deferred by API | | sparse | no | no | future | deferred | ## Release provenance The published `mplapack-interop 0.5.0` source remains identified by tag `v0.5.0`, freeze commit `7187a0f6c5a40a4d5774f4f913b166ccb6a5dffa`, and archive SHA256 `3c4e992516deb1266918c1c5bf6542cc9e1b7f301aeeb1f354dd64f2558f9e04`. The published 0.5.1 maintenance release uses the official MPLAPACK 3.0.1 archive with gmpfrxx_mkII 1.5.0; its source archive identity and validation evidence are recorded in [`docs/dependency-release-stack-r2.md`](docs/dependency-release-stack-r2.md). Debian/PPA packaging and upload work remain separate. ## Public API baseline The following workflow is available in the current release line: ```octave pkg load mplapack-interop mpdigits(100); A = mp({"1", "2"; "3", "4"}); b = mp({"1"; "2"}); C = A * A; x = A \ b; ``` The completed baseline uses normal Octave matrix operations such as indexing, `\`, and read-only conversion/display. Native backend entry points stay private. ## Precision warning These constructors intentionally have different input semantics: ```octave mp("0.1") mp(0.1) ``` The string form parses decimal text directly at the target MPFR precision. The numeric form receives an already-rounded IEEE binary64 value and preserves that exact value when converting to MPFR. Thus the two `0.1` values above are intentionally different. See [`docs/precision-semantics.md`](docs/precision-semantics.md). ## Historical 0.1.0 non-goals - Wrapping every MPLAPACK routine - Supporting every MPLAPACK backend - Complex multiprecision arithmetic (implemented in the 0.2.x line) - Replacing Octave BLAS/LAPACK - Transparent conversion of all Octave code to multiprecision - Complete MATLAB compatibility ## Development roadmap ```text M00 Bootstrap M01 Native build probe M02 Native mp storage M03 Public scalar constructor M04 Precision M05 Conversion/display M06 Element-wise arithmetic M07 Matrix storage M08 Matrix multiplication M09 Linear solve M10 Dense matrix inspection M11 Dense element-wise arithmetic M12 Dense transpose and reshape M13 Dense horizontal and vertical concatenation M14 Dense indexed assignment with value semantics M15 Full-rank rectangular dense solve M16 Rank-deficient rectangular minimum-norm solve M17 Dense real Cholesky factorization M18 Dense real non-pivoted QR factorization M19 Dense real pivoted QR factorization M20 Complex architecture audit and design freeze (no public complex support) M21 Dense real LU factorization M22 Real v0.1 API and release closure M23 v0.1.0 feature freeze and release candidate D01R1 Rename package identity to mplapack-interop and freeze binary architecture PPA1-PPA4 Debian/Ubuntu/PPA packaging and final release ``` M00 through M23, C00 through C12, S00 through S08, and T00 through T14 are complete (M20 is design-only and the real-only M23 candidate remains historical). No PPA upload exists. Consult [`docs/milestones/README.md`](docs/milestones/README.md) for gate definitions and status. mplapack-interop-0.5.1/DESCRIPTION0000644000230300031750000000046115274353472015752 0ustar rafaelrafaelName: mplapack-interop Version: 0.5.1 Date: 2026-09-23 Title: Multiple-Precision Linear Algebra with MPLAPACK Author: MPLAPACK contributors Maintainer: MPLAPACK contributors Description: GNU Octave interface to MPLAPACK multiple-precision linear algebra. Depends: octave (>= 11.1.0) License: BSD-2-Clause mplapack-interop-0.5.1/NEWS.md0000644000230300031750000003220315274353472015341 0ustar rafaelrafael# News ## mplapack-interop 0.5.1 (2026-09-23) This maintenance release fixes the Ubuntu 26.04 install path and keeps all `mp` values on the native MPFR/MPC backend. It is published as the GitHub release and annotated tag `v0.5.1`. - The installer defaults to the published 0.5.1 package and official gmpfrxx_mkII 1.5.0 archive; gmpfrxx 1.4.1 remains selectable. - Installed MPLAPACK `.pc` metadata is normalized downstream for systems whose `libmpc-dev` package does not provide `mpc.pc`; `pkg-config --cflags --libs` now exposes the MPLAPACK include and explicit GMP/MPFR/MPC libraries. - Complex `log2` calls use the gmpfrxx `mpfrxx::log2` compatibility wrapper instead of directly requiring the `mpc_log2` symbol. - The dependency probe checks the MPC log2 precision contract, and the clean installer smoke covers real and complex operations. The published `v0.5.0` tag and archive remain immutable. Debian/PPA packaging and uploads remain separate follow-up work. ## mplapack-interop 0.5.0 (2026-09-15) The 0.5.0 release closes the advanced arbitrary-precision surface for Schur/QZ, dense utilities, matrix functions, polynomial helpers, exact sets, serialization, three-dimensional graphics boundaries, random generation, 1-D/2-D interpolation, nonlinear equations, scalar quadrature, and bounded/simplex optimization. All numerical paths retain the one-operation/one-precision MPFR/MPC contract and reject unsupported calls instead of falling through to builtin binary64 implementations. The final T-series wall passed M00–M23, C00–C12 including mandatory C11L, N00–N08, S00–S08, and T00–T14, with 1024/2048-bit canaries, package lifecycle, and native ASan/UBSan/LSan coverage. The released surface and deferred re-entry records are in `docs/advanced-numerics-compatibility.md` and `docs/todo/`. DOC00 closes the user/developer documentation surface with a task-oriented manual, complete public API inventory, native backend map, runnable examples, Octave help text, and reproducible manual/Doxygen build checks. The D04 dependency is the official MPLAPACK 3.0.1 release. D04 freezes this package against the exact published MPLAPACK and gmpfrxx_mkII source identities recorded in the release-stack handoff. ## 0.4.0 S00 begins the ordinary Octave script-compatibility series with native arbitrary-precision `abs`, `arg`, `angle`, and `sign`, special-value predicates, exact `isequal`/`isequaln`, and the `isnumeric` class predicate. S01 adds native MPFR/MPC element-wise power, integer square-matrix powers, and the audited elementary-function family with exact real-domain promotion. S02 adds native MPFR/MPC `sum`, `prod`, `sumsq`, `cumsum`, and `cumprod`, plus `min`/`max` with dimensions, NaN controls, cumulative direction, indices, and supported complex comparison methods. The 0.3.1 source release remains immutable. S05 adds native MPFR/MPC sequence generation, rounding, spacing, and utility arithmetic. S06 adds native descriptive statistics. S07 adds the common line-graphics boundary wrappers with conversion limited to the final graphics call. S08 closes the ordinary dense script corpus with native `sort`/`diff`, structural audits, precision canaries, and explicit firewall coverage for deferred surface graphics. No numerical path uses an implicit binary64 fallback. S03 adds native MPFR/MPC comparisons, logical conversion and element-wise logical operators, `any`/`all`, `find`, general numeric linear indexing, and logical indexing/assignment. Ordered comparisons remain explicitly rejected for complex values; no comparison or logical path uses builtin binary64 complex arithmetic. S04 adds native dense `diag`, `triu`/`tril`, `repmat`, row/column flips, `rot90`, `cat(1/2)`, and `zeros`/`ones`/`eye`/`NaN`/`Inf` `"like"` constructors. The dense two-dimensional contract and explicit rejection of packed triangular output remain in force. ## 0.3.1 N08 adds dense real and complex matrix right division with `/`, including scalar forms, mixed `mp`/double operands, rectangular least-squares solves, rank-deficient minimum-norm results, and the complex conjugate-transpose identity. Existing `mldivide` square-singular error behavior is unchanged; right division uses a private rank-revealing retry for Octave-compatible singular results. All paths preserve one-operation/one-precision MPFR/MPC semantics and operation-owned destructive-call buffers. ## 0.3.0 This release completes the numerical API after the frozen 0.2.1 package identity. N00 adds native arbitrary-precision `norm` support; all operation paths preserve stored MPFR/MPC precision and avoid binary64 fallbacks. N05 adds dense general standard `eig` through MPLAPACK `Rgeevx`/`Cgeevx`, including balance/nobalance controls, right and left eigenvectors, permanent Grcar coverage, and high-precision real conjugate-pair conversion. N06 adds dense generalized `eig(A,B)` through the definite `Rsygvd`/`Chegvd` and QZ `Rggev`/`Cggev` drivers. It supports Octave-compatible `chol`/`qz` algorithm selection, matrix/vector eigenvalue layouts, left eigenvectors, singular-B infinite eigenvalues, mixed real/complex promotion, and 1024/2048-bit precision canaries without binary64 fallback. N07 closes the documented dense real/complex API surface, adds the permanent high-precision Grcar example, and records the compatibility firewall. The 0.3.0 source archive and tag are created only after the complete freeze regression and reproducibility gates pass. ## 0.2.1 The GNU Octave package public identity is now `mplapack-interop`, version `0.2.1`. The rename avoids presenting the Octave package as the MPLAPACK upstream project; the repository remains `octave-mplapack` and the public numeric API remains `mp`, `mpbits`, and `mpdigits`. Existing `mplapack` 0.2.0 source/tag/archive provenance is retained as a historical release and is not an alias for the new package. The release documentation adds an Octave high-precision Hilbert inverse example. The inverse is computed as `H \\ I`, because `inv(mp)` is intentionally outside the public API and the example must not pass through binary64 `hilb(n)` construction. The separate MPLAPACK public-header consumer is covered by MPLAPACK release QA and is not copied into this package's examples. ## 0.2.0 The first public real-plus-complex release adds dense complex `mp` scalars and matrices with explicit MPFR/MPC precision semantics. It provides mixed real/complex construction, arithmetic, structure and indexing operations, MPLAPACK `Cgemm`, `Cgesv`, `Cgelsy`, `Cpotrf`, `Cgeqrf`/`Cungqr`, `Cgeqp3`, and `Cgetrf`, including the mandatory complex LU path. Destructive backend calls use operation-owned copies, real-only operations remain on real MPLAPACK paths, and no builtin binary64 complex fallback is used. The release dependency stack is `gmpfrxx_mkII 1.4.1`, MPLAPACK `3.0.1`, and this package `0.2.0`. Exact source commits, tags, archives, checksums, licenses, and isolated-build evidence are recorded in `docs/dependency-release-stack.md` and `reports/D00-report.md`. ## 0.1.0 The frozen first release candidate is a dense real arbitrary-precision Octave package. It provides MPFR scalar and matrix construction with explicit bit/digit precision control, precision-preserving arithmetic and structural operations, dense `Rgemm` multiplication, square and rank-revealing `Rgesv`/`Rgelss` left division, and `Rpotrf`, `Rgeqrf`/`Rorgqr`, `Rgeqp3`, and `Rgetrf` factorizations. Indexing and assignment preserve native value semantics. The source archive, dependency probe, installed-package lifecycle, and full sanitizer/precision QA are release-ready for PPA handoff. The v0.1.0 scope is intentionally limited: complex, sparse, N-D, reductions, general transcendentals, determinant, inverse, rank, condition, norm, eigenvalue, SVD, and update APIs are not included. `qr(A,B)` and sparse factorization forms are also deferred. Ubuntu PPA packaging and the final release tag occur after this upstream freeze. ## Development history before 0.1.0 - Bootstrapped the repository, package metadata, project contracts, and milestone plan. - Planned MPFR real arithmetic as the first MPLAPACK backend. - Added the private `__mplapack_core__.oct` module and public `mplapack_version()` diagnostic. - Added an MPLAPACK MPFR `Rlamch_mpfr` runtime probe, dependency/linkage QA, deterministic source-package generation, and isolated package-install QA. - Added internal RAII-backed MPLAPACK MPFR scalar storage with explicit per-object precision and immutable Octave custom-value ownership. - Added deep-copy, module-lifetime, sanitizer, clear/shutdown, and installed- package lifecycle QA for the internal native value. - Added the public scalar `mp` class with direct decimal-text and exact binary64 constructors. - Added signed-zero and special-value preservation, matrix-construction firewalls, and installed public-wrapper lifecycle QA. - Added public bit-precision control through `mpbits` with a 512-bit fresh- session default. - Added decimal-digit convenience control through `mpdigits`, using certified upward conversion with no hidden guard bits. - Added canonical, source-precision round-trip decimal conversion for scalar `mp` values. - Added explicit round-to-nearest IEEE binary64 conversion and canonical scalar multiprecision display. - Added scalar `mp` addition and subtraction, scalar element-wise multiplication and division, and unary signs. - Added mixed `mp`/binary64 scalar arithmetic with operand-derived precision and explicit MPFR round-to-nearest semantics. - Added one-native-object dense MPFR matrix storage with uniform precision and contiguous column-major layout. - Added construction from real double matrices and decimal-text cell matrices, including shape-preserving empty matrices and public shape metadata. - Added dense real matrix `mtimes` through the MPLAPACK MPFR reference `Rgemm` path, with operand-derived uniform operation precision and native scalar/matrix scaling. - Synchronized `mpbits`/`mpdigits` with the current-thread MPFR default for the MPLAPACK uniform-precision calling contract. - Added dense real `mp` linear solve through MPLAPACK MPFR `Rgesv`, including multiple right-hand sides and operation-owned factorization buffers. - Added read-only dense matrix indexing with `end`, precision-preserving matrix-to-double conversion, and canonical matrix display. - Added dense matrix element-wise `+`, `-`, `.*`, and `./`, unary signs, and two-dimensional singleton expansion using direct MPFR arithmetic. - Added precision-preserving dense matrix transpose, conjugate transpose for real values, and two-dimensional column-major `reshape`, including one inferred dimension. - Added native dense real `mp` horizontal and vertical concatenation with arbitrary operand counts, mixed precision, mixed real-double inputs, and Octave-compatible supported empty-shape behavior. Concatenation returns one immutable native `mp` value and never an array of scalar wrappers. - Added in-bounds dense real `mp` indexed assignment with value semantics, precision-preserving deep copies, scalar/row/column/submatrix and colon assignment, and direct binary64 RHS insertion. Matrix growth, deletion, logical assignment, and general vector linear assignment remain deferred. - Added full-rank rectangular dense real `mp` left division through MPLAPACK MPFR `Rgels`, including QR/LQ paths, multiple right-hand sides, padded operation-owned RHS storage, and checked workspace queries. Rank-revealing rectangular solving remains deferred. - Added rank-revealing rectangular dense real `mp` left division through the validated MPLAPACK MPFR `Rgelss` driver. Rectangular systems now return minimum-norm least-squares solutions for rank-deficient and full-rank cases, with precision-derived `RCOND`, checked workspace queries, and uniformly operation-precision work buffers. Square systems retain the `Rgesv` path. - Matrix logical indexing, matrix `char`, general `cat`, comparisons, powers, and reductions remain unimplemented. - Added dense real `mp` Cholesky factorization through MPLAPACK MPFR `Rpotrf`, with upper/lower selected-triangle semantics, optional status output, precision-preserving operation-owned copies, and immutable public values. - Added non-pivoted dense real `mp` QR factorization through MPLAPACK MPFR `Rgeqrf`/`Rorgqr`, including one-output `R`, full/economy two-output forms, deprecated numeric-zero economy compatibility, and precision-preserving immutable operation-owned buffers. - Added dense real column-pivoted `mp` QR through MPLAPACK MPFR `Rgeqp3` and `Rorgqr`, with Octave-compatible matrix/vector permutation outputs, full/economy forms, precision-safe JPVT handling, and immutable operation-owned buffers. Non-pivoted one/two-output QR remains unchanged. - Added the M20 complex architecture audit and design freeze. The installed `mpfrxx::mpc_class` backend, uniform-precision contract, future payload variants, complex routine inventory, and real-only PPA boundary are documented; public complex `mp` values remain unimplemented. - Added dense real `mp` LU factorization through MPLAPACK MPFR `Rgetrf`, with packed one-output factors, permutation-aware two/three-output forms, 1-based vector pivots, rectangular and singular support, and immutable operation-owned precision-safe buffers. mplapack-interop-0.5.1/test/0000755000230300031750000000000015274353472015222 5ustar rafaelrafaelmplapack-interop-0.5.1/test/test_neigt18.m0000644000230300031750000001053315274353472017720 0ustar rafaelrafael% NEIGT18: compatible simple eigenfactor boxes and individual-claim traps. test_root = fileparts (fileparts (mfilename ("fullpath"))); private_root = fullfile (test_root, "examples", "neig_tiers", "private"); addpath (private_root); saved_bits = mpbits (); unwind_protect mpbits (256); bundle = net_manifest (); jobs = bundle.jobs.profiles.smoke.jobs; real_job = net_v_a1_job (jobs{17}, bundle.jobs.profiles.smoke, "smoke"); complex_job = net_v_a1_job (jobs{18}, bundle.jobs.profiles.smoke, "smoke"); defective_job = net_v_a1_job (jobs{19}, bundle.jobs.profiles.smoke, "smoke"); assert (real_job.pass && real_job.milestone_pass); assert (complex_job.pass && complex_job.milestone_pass); assert (defective_job.milestone_pass && ! defective_job.pass); assert (strcmp (real_job.status, "CERTIFIED_EIGENFACTORS")); assert (strcmp (complex_job.status, "CERTIFIED_EIGENFACTORS")); assert (strcmp (defective_job.status, "INCONCLUSIVE_DEFECTIVE_INDIVIDUAL")); assert (real_job.certificate.roots_disjoint); assert (complex_job.certificate.roots_disjoint); assert (real_job.certificate.inverse_witness.nonsingular); assert (complex_job.certificate.inverse_witness.nonsingular); assert (real_job.certificate.compatibility.encloses_zero); assert (complex_job.certificate.compatibility.encloses_zero); assert (real_job.certificate.width_ratio <= real_job.certificate.useful_target); assert (complex_job.certificate.width_ratio <= complex_job.certificate.useful_target); % An arbitrary coherent phase gauge remains a valid simultaneous factor. q = 768; mpbits (q); pair = net_exact_similarity (4, q); J = mp (zeros (4, 4)); simple_diagonal = [1, 2, 4, 8]; for diagonal_index = 1:4 J(diagonal_index,diagonal_index) = mp (simple_diagonal(diagonal_index)); endfor real_A = pair.Y * J * pair.X; phase = mp (eye (4)); phase(1,1) = net_mp_complex (mp (0), mp (1)); phased_E = net_iv_cmatrix_mul (real_job.certificate.E_box, ... net_iv_cmatrix_point (phase, q), q); phased = net_v_a1_validate_assembly (real_A, phased_E, ... real_job.certificate.Lambda_box, q); assert (phased.encloses_zero); % A duplicated factor column and a Lambda-only permutation are rejected; % neither can manufacture a false compatible factorization. E_bad = real_job.certificate.E_box; E_bad.rl(:,2) = E_bad.rl(:,1); E_bad.rh(:,2) = E_bad.rh(:,1); E_bad.il(:,2) = E_bad.il(:,1); E_bad.ih(:,2) = E_bad.ih(:,1); rejected_duplicate = net_v_a1_validate_assembly (real_A, ... E_bad, real_job.certificate.Lambda_box, q); assert (! rejected_duplicate.encloses_zero); Lambda_bad = real_job.certificate.Lambda_box; Lambda_bad.rl(1,1) = real_job.certificate.Lambda_box.rl(2,2); Lambda_bad.rh(1,1) = real_job.certificate.Lambda_box.rh(2,2); Lambda_bad.il(1,1) = real_job.certificate.Lambda_box.il(2,2); Lambda_bad.ih(1,1) = real_job.certificate.Lambda_box.ih(2,2); Lambda_bad.rl(2,2) = real_job.certificate.Lambda_box.rl(1,1); Lambda_bad.rh(2,2) = real_job.certificate.Lambda_box.rh(1,1); Lambda_bad.il(2,2) = real_job.certificate.Lambda_box.il(1,1); Lambda_bad.ih(2,2) = real_job.certificate.Lambda_box.ih(1,1); rejected_permutation = net_v_a1_validate_assembly (real_A, ... real_job.certificate.E_box, Lambda_bad, q); assert (! rejected_permutation.encloses_zero); % Repeated-root individual vectors are not promoted to an all-simple % eigenfactorization; the non-isolated graph attempt must fail closed. repeated = net_similarity_model ("semisimple", 4, 0, 256); [Vr, Dr] = eig (repeated.A_frozen, "nobalance"); Vr = net_widen (Vr, q, 256); Dr = net_widen (Dr, q, 256); repeated_factor = net_v_a1_factors (net_widen (repeated.A_frozen, q, 256), ... Vr, Dr, q, -40); assert (! repeated_factor.pass); assert (any (strcmp (repeated_factor.status, ... {"INCONCLUSIVE_GRAPH", "INCONCLUSIVE_NONISOLATED_ROOTS", ... "INCONCLUSIVE_FACTOR_INVERSE"}))); fprintf ("PASS: NEIGT18 compatible eigenfactor boxes, gauges, and repeated-root traps\n"); unwind_protect_cleanup mpbits (saved_bits); if (any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect mplapack-interop-0.5.1/test/complex_lu.tst0000644000230300031750000001134615274353472020132 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_complex_matrix (value, rows_expected, columns_expected, precision_expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows_expected)); %! assert (info.columns, uint64 (columns_expected)); %! assert (info.is_complex); %! assert (info.all_elements_same_precision); %! assert (info.precision_bits, uint64 (precision_expected)); %!endfunction %!test %! mpbits (512); %! A = mp ([1 + 1i, 2 + 2i; 3 - 1i, 4 + 0i]); %! packed = lu (A); %! assert_complex_matrix (packed, 2, 2, 512); %! assert (double (packed), [3 - 1i, 4; 0.2 + 0.4i, 1.2 + 0.4i], 1e-12); %! [L, U] = lu (A); %! assert_complex_matrix (L, 2, 2, 512); %! assert_complex_matrix (U, 2, 2, 512); %! assert (double (L * U), double (A), 1e-10); %! assert (double (L), [0.2 + 0.4i, 1; 1, 0], 1e-12); %! assert (double (U), [3 - 1i, 4; 0, 1.2 + 0.4i], 1e-12); %! [Lp, Up, P] = lu (A); %! assert (strcmp (class (P), "double")); %! assert (P, [0, 1; 1, 0]); %! assert (double (P * A), double (Lp * Up), 1e-10); %! [Lv, Uv, p] = lu (A, "vector"); %! assert (strcmp (class (p), "double")); %! assert (size (p), [2, 1]); %! assert (p, [2; 1]); %! assert (double (A(p, :)), double (Lv * Uv), 1e-10); %!test %! mpbits (512); %! tall = mp ([1 + 0i, 2 + 2i; 5 + 1i, 4 + 0i; 3 - 1i, 6 + 1i]); %! [L, U, P] = lu (tall); %! assert_complex_matrix (L, 3, 2, 512); %! assert_complex_matrix (U, 2, 2, 512); %! assert (size (P), [3, 3]); %! assert (double (P * tall), double (L * U), 1e-10); %! [L2, U2] = lu (tall); %! assert (double (tall), double (L2 * U2), 1e-10); %! wide = mp ([1 + 0i, 2 - 1i, 5 + 2i; 3 + 1i, 4 + 0i, 6 - 1i]); %! [Lw, Uw, Pw] = lu (wide); %! assert_complex_matrix (Lw, 2, 2, 512); %! assert_complex_matrix (Uw, 2, 3, 512); %! assert (size (Pw), [2, 2]); %! assert (double (Pw * wide), double (Lw * Uw), 1e-10); %! [Lw2, Uw2] = lu (wide); %! assert (double (wide), double (Lw2 * Uw2), 1e-10); %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! delta = mp ("1", "0"); %! for k = 1:exponent %! delta = delta ./ mp ("2", "0"); %! endfor %! A = mp (complex ([4, 2; 1, 3], [0, 1; 0, 0])); %! A(2, 1) = mp ("1", "0") + delta; %! expected = (mp ("1", "0") + delta) ./ mp ("4", "0"); %! mpbits (128); %! [L, U, P] = lu (A); %! assert (P, eye (2)); %! assert_complex_matrix (L, 2, 2, precision); %! assert (strcmp (char (L(2, 1)), char (expected))); %! assert (double (P * A), double (L * U), 1e-12); %! assert (mpbits (), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! low = mp (complex ([1, 0; 1, 1], [0, 1; 0, 0])); %! delta = mp ("1", "0"); %! for k = 1:700 %! delta = delta ./ mp ("2", "0"); %! endfor %! low(2, 1) = mp ("1", "0") + delta; %! [~, ~, plow] = lu (low, "vector"); %! assert (plow(1), 1); %! mpbits (1024); %! high = mp (complex ([1, 0; 1, 1], [0, 1; 0, 0])); %! delta = mp ("1", "0"); %! for k = 1:700 %! delta = delta ./ mp ("2", "0"); %! endfor %! high(2, 1) = mp ("1", "0") + delta; %! mpbits (128); %! [~, ~, phigh] = lu (high, "vector"); %! assert (phigh(1), 2); %! mpbits (4096); %! [~, ~, phigh_ambient] = lu (high, "vector"); %! assert (phigh_ambient, phigh); %! assert (mpbits (), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (256); %! S = mp ([1 + 1i, 2 + 2i; 2 + 2i, 4 + 4i]); %! [L, U, P] = lu (S); %! assert_complex_matrix (L, 2, 2, 256); %! assert_complex_matrix (U, 2, 2, 256); %! assert (P, [0, 1; 1, 0]); %! assert (double (P * S), double (L * U), 1e-10); %! [Lv, Uv, p] = lu (S, "vector"); %! assert (p, [2; 1]); %! assert (double (S(p, :)), double (Lv * Uv), 1e-10); %!test %! mpbits (256); %! for shape_cell = {[0, 0], [0, 3], [3, 0]} %! shape = shape_cell{1}; %! A = mp (complex (zeros (shape(1), shape(2)), ... %! zeros (shape(1), shape(2)))); %! packed = lu (A); %! [L, U, P] = lu (A); %! [Lv, Uv, p] = lu (A, "vector"); %! assert (size (packed), [0, 0]); %! assert (size (L), [0, 0]); %! assert (size (U), [0, 0]); %! assert (size (P), [0, 0]); %! assert (size (p), [0, 0]); %! assert (size (Lv), [0, 0]); %! assert (size (Uv), [0, 0]); %! endfor %!test %! A = mp ([1 + 1i, 2; 3, 4 - 1i]); %! fail ("lu (A, \"matrix\")", "vector"); %! fail ("lu (A, \"econ\")", "vector"); %! fail ("lu (A, 0)", "vector"); %! fail ("[a,b,c,d] = lu (A)", "at most three outputs"); mplapack-interop-0.5.1/test/test_neigt06.m0000644000230300031750000000242115274353472017712 0ustar rafaelrafael% Focused NEIGT06 Toeplitz/symmetric controls. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect small = net_toeplitz_model (2, 4, "original", 256); assert (small.relation_exact); small_reference = net_toeplitz_reference (2, 4, 384); assert (all (abs (small_reference.overlaps - mp (3) / mp (2)) ... < mp ("1e-100"))); for representation = {"original", "explicitly_symmetric"} fixture = net_toeplitz_model (16, 4, representation{1}, 512); assert (fixture.relation_exact); audit = net_toeplitz_audit (fixture, 640); assert (strcmp (audit.status, "MEASURED")); target = net_pow2 (-200, 512); assert (audit.symmetric_eig_match.threshold < target); assert (audit.nobalance_metrics.right_residual < target); assert (audit.nobalance_metrics.left_residual < target); assert (audit.condition_separation.matrix_and_eigenvalue_conditions_separate); assert (audit.condition_separation.scaling_D > mp (1)); endfor fprintf ("PASS: NEIGT06 Toeplitz relation, MP references, and symmetric control\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/m21_rgetrf_probe.cc0000644000230300031750000001660015274353472020673 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include #include #include namespace { using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } std::vector matrix (std::size_t rows, std::size_t columns, mpfr_prec_t precision, std::initializer_list values) { const std::vector text (values.begin (), values.end ()); check (text.size () == rows * columns, "probe matrix element count mismatch"); std::vector result; result.reserve (text.size ()); for (const auto& value : text) { Real element = Real::with_precision (precision); check (mpfr_set_str (element.mpfr_data (), value.c_str (), 10, MPFR_RNDN) == 0, "probe matrix text is invalid"); result.push_back (std::move (element)); } // The input list is row-major for readability; convert to column-major. std::vector column_major; column_major.reserve (result.size ()); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < rows; ++row) { Real element = Real::with_precision (precision); mpfr_set (element.mpfr_data (), result[row * columns + column].mpfr_data (), MPFR_RNDN); column_major.push_back (std::move (element)); } return column_major; } void check_text (const Real& value, const char *text, const char *message) { Real expected = Real::with_precision (value.precision ()); check (mpfr_set_str (expected.mpfr_data (), text, 10, MPFR_RNDN) == 0, "probe expected text is invalid"); check (mpfr_equal_p (value.mpfr_data (), expected.mpfr_data ()) != 0, message); } void check_fraction (const Real& value, unsigned long numerator, unsigned long denominator, const char *message) { Real expected = Real::with_precision (value.precision ()); mpfr_set_ui (expected.mpfr_data (), numerator, MPFR_RNDN); mpfr_div_ui (expected.mpfr_data (), expected.mpfr_data (), denominator, MPFR_RNDN); Real difference = Real::with_precision (value.precision ()); mpfr_sub (difference.mpfr_data (), value.mpfr_data (), expected.mpfr_data (), MPFR_RNDN); mpfr_abs (difference.mpfr_data (), difference.mpfr_data (), MPFR_RNDN); Real tolerance = Real::with_precision (value.precision ()); mpfr_set_ui_2exp (tolerance.mpfr_data (), 1, -static_cast (value.precision () * 3 / 4), MPFR_RNDN); check (mpfr_cmp (difference.mpfr_data (), tolerance.mpfr_data ()) < 0, message); } void factor (std::vector& values, std::size_t rows, std::size_t columns, std::vector& pivots, mplapackint& info, mpfr_prec_t precision) { const mpfr_prec_t ambient = mpfrxx::default_precision_bits (); pivots.assign (std::min (rows, columns), 0); info = 0; { MplapackMpfrPrecisionScope scope (precision); Rgetrf (static_cast (rows), static_cast (columns), values.data (), static_cast (std::max (1, rows)), pivots.data (), info); } check (mpfrxx::default_precision_bits () == ambient, "Rgetrf probe did not restore ambient precision"); } void test_mapping () { auto values = matrix (2, 2, 256, {"1", "2", "3", "4"}); std::vector pivots; mplapackint info = 0; factor (values, 2, 2, pivots, info, 256); check (info == 0 && pivots == std::vector ({2, 2}), "Rgetrf simple IPIV mismatch"); check_text (values[0], "3", "Rgetrf simple packed pivot mismatch"); check_fraction (values[1], 1, 3, "Rgetrf simple multiplier mismatch"); check_text (values[2], "4", "Rgetrf simple packed U mismatch"); check_fraction (values[3], 2, 3, "Rgetrf simple diagonal mismatch"); auto multi = matrix (3, 2, 256, {"1", "2", "3", "4", "5", "6"}); factor (multi, 3, 2, pivots, info, 256); check (info == 0 && pivots == std::vector ({3, 3}), "Rgetrf multi-pivot IPIV mismatch"); } void test_precision () { for (const auto case_data : {std::pair (1024, -700), std::pair (2048, -1500)}) { const mpfr_prec_t precision = case_data.first; auto values = matrix (2, 2, precision, {"4", "0", "2", "3"}); Real delta = Real::with_precision (precision); mpfr_set_ui_2exp (delta.mpfr_data (), 1, case_data.second, MPFR_RNDN); mpfr_set_ui (values[1].mpfr_data (), 1, MPFR_RNDN); mpfr_add (values[1].mpfr_data (), values[1].mpfr_data (), delta.mpfr_data (), MPFR_RNDN); std::vector pivots; mplapackint info = 0; factor (values, 2, 2, pivots, info, precision); check (info == 0 && pivots == std::vector ({1, 2}), "Rgetrf precision pivot mismatch"); Real expected = Real::with_precision (precision); mpfr_set_ui (expected.mpfr_data (), 1, MPFR_RNDN); mpfr_div_ui (expected.mpfr_data (), expected.mpfr_data (), 4, MPFR_RNDN); Real tail = Real::with_precision (precision); mpfr_set_ui_2exp (tail.mpfr_data (), 1, case_data.second - 2, MPFR_RNDN); mpfr_add (expected.mpfr_data (), expected.mpfr_data (), tail.mpfr_data (), MPFR_RNDN); check (mpfr_equal_p (values[1].mpfr_data (), expected.mpfr_data ()) != 0, "Rgetrf precision multiplier tail mismatch"); } } void test_pivot_precision_and_status () { for (const auto precision : {mpfr_prec_t (512), mpfr_prec_t (1024)}) { auto values = matrix (2, 2, precision, {"1", "0", "1", "1"}); Real delta = Real::with_precision (precision); mpfr_set_ui_2exp (delta.mpfr_data (), 1, -700, MPFR_RNDN); mpfr_add (values[1].mpfr_data (), values[1].mpfr_data (), delta.mpfr_data (), MPFR_RNDN); std::vector pivots; mplapackint info = 0; factor (values, 2, 2, pivots, info, precision); check (pivots[0] == (precision == 512 ? 1 : 2), "Rgetrf precision-dependent pivot mismatch"); } auto singular = matrix (2, 2, 256, {"1", "2", "2", "4"}); std::vector pivots; mplapackint info = 0; factor (singular, 2, 2, pivots, info, 256); check (info == 2, "Rgetrf singular INFO mismatch"); mpfrxx::set_default_precision_bits (4096); auto high_ambient = matrix (2, 2, 256, {"1", "0", "0", "2"}); factor (high_ambient, 2, 2, pivots, info, 256); check (info == 0 && high_ambient[0].precision () == 256 && mpfrxx::default_precision_bits () == 4096, "Rgetrf high ambient precision mismatch"); mpfrxx::set_default_precision_bits (128); } } // namespace int main () { try { mpfrxx::set_default_precision_bits (128); test_mapping (); test_precision (); test_pivot_precision_and_status (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: installed MPLAPACK MPFR Rgetrf precision/IPIV probe\n"; return 0; } mplapack-interop-0.5.1/test/mp_complex_pivoted_qr_test.cc0000644000230300031750000002316315274353472023174 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include "mp_complex_qr.h" namespace { using Matrix = octave_mplapack::MpfrComplexMatrixStorage; using Integer = Matrix::MplapackInteger; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } std::complex as_double (const Matrix& matrix, std::size_t row, std::size_t column) { return octave_mplapack::MpfrComplexScalarStorage ( matrix.at (row, column)).to_double (); } void check_orthogonality (const Matrix& q, const char *message) { const double tolerance = 1.0e-10; for (std::size_t first = 0; first < q.columns (); ++first) for (std::size_t second = 0; second < q.columns (); ++second) { std::complex sum {0.0, 0.0}; for (std::size_t row = 0; row < q.rows (); ++row) sum += std::conj (as_double (q, row, first)) * as_double (q, row, second); const std::complex expected = first == second ? std::complex {1.0, 0.0} : std::complex {0.0, 0.0}; check (std::abs (sum - expected) < tolerance, message); } } void check_reconstruction (const Matrix& input, const octave_mplapack::MpcPivotedQrResult& result, const char *message) { const double tolerance = 1.0e-10; check (result.permutation.size () == input.columns (), message); for (std::size_t column = 0; column < input.columns (); ++column) { const Integer pivot = result.permutation[column]; check (pivot >= 1 && pivot <= static_cast (input.columns ()), message); const std::size_t source = static_cast (pivot - 1); for (std::size_t row = 0; row < input.rows (); ++row) { std::complex sum {0.0, 0.0}; for (std::size_t inner = 0; inner < result.q.columns (); ++inner) sum += as_double (result.q, row, inner) * as_double (result.r, inner, column); check (std::abs (sum - as_double (input, row, source)) < tolerance, message); } } } void check_permutation (const std::vector& permutation, const char *message) { std::vector seen (permutation.size (), false); for (const Integer value : permutation) { check (value >= 1 && value <= static_cast (permutation.size ()), message); const std::size_t index = static_cast (value - 1); check (! seen[index], message); seen[index] = true; } } void check_r_structure (const Matrix& r, const char *message) { for (std::size_t column = 0; column < r.columns (); ++column) for (std::size_t row = column + 1; row < r.rows (); ++row) check (mpfr_zero_p (mpc_realref (r.at (row, column).mpc_data ())) != 0 && mpfr_zero_p (mpc_imagref (r.at (row, column).mpc_data ())) != 0, message); } void test_full_economy_and_permutation () { const Matrix input (3, 3, 512, std::vector> { {1.0, 1.0}, {2.0, 0.0}, {0.0, 1.0}, {2.0, -1.0}, {1.0, 2.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, -2.0}, {3.0, 1.0}}); const Matrix before (input); const auto full = octave_mplapack::mplapack_mpc_matrix_pivoted_qr (input, false, true); check (full.q.rows () == 3 && full.q.columns () == 3 && full.r.rows () == 3 && full.r.columns () == 3, "full pivoted complex QR shape mismatch"); check_permutation (full.permutation, "full pivoted complex QR permutation mismatch"); check_orthogonality (full.q, "full pivoted complex QR is not unitary"); check_reconstruction (input, full, "full pivoted complex QR reconstruction mismatch"); check_r_structure (full.r, "full pivoted complex QR R lower entry is not zero"); check (input.element_exactly_equal (0, 0, before, 0, 0), "pivoted complex QR modified its input"); const Matrix tall (4, 3, 512, std::vector> { {1.0, 1.0}, {2.0, 0.0}, {0.0, 1.0}, {1.0, -1.0}, {2.0, -1.0}, {1.0, 2.0}, {1.0, 0.0}, {0.0, 2.0}, {0.0, 1.0}, {1.0, -2.0}, {3.0, 1.0}, {2.0, 0.0}}); const auto economy = octave_mplapack::mplapack_mpc_matrix_pivoted_qr (tall, true, true); check (economy.q.rows () == 4 && economy.q.columns () == 3 && economy.r.rows () == 3 && economy.r.columns () == 3, "economy pivoted complex QR shape mismatch"); check_permutation (economy.permutation, "economy pivoted complex QR permutation mismatch"); check_orthogonality (economy.q, "economy pivoted complex QR is not unitary"); check_reconstruction (tall, economy, "economy pivoted complex QR reconstruction mismatch"); const Matrix wide (2, 4, 512, std::vector> { {1.0, 1.0}, {2.0, 0.0}, {0.0, 1.0}, {1.0, -1.0}, {2.0, -1.0}, {1.0, 2.0}, {1.0, 0.0}, {0.0, 2.0}}); const auto wide_result = octave_mplapack::mplapack_mpc_matrix_pivoted_qr (wide, false, true); check (wide_result.q.rows () == 2 && wide_result.q.columns () == 2 && wide_result.r.rows () == 2 && wide_result.r.columns () == 4, "wide pivoted complex QR shape mismatch"); check_permutation (wide_result.permutation, "wide pivoted complex QR permutation mismatch"); check_orthogonality (wide_result.q, "wide pivoted complex QR is not unitary"); check_reconstruction (wide, wide_result, "wide pivoted complex QR reconstruction mismatch"); } void test_precision_pivot_and_ambient_scope () { mpfrxx::set_default_precision_bits (128); for (const mpfr_prec_t precision : {mpfr_prec_t (1024), mpfr_prec_t (2048)}) { Matrix input (1, 2, precision); mpfr_set_ui (mpc_realref (input.at (0, 0).mpc_data ()), 1, MPFR_RNDN); mpfr_set_zero (mpc_imagref (input.at (0, 0).mpc_data ()), 0); mpfr_set_ui (mpc_realref (input.at (0, 1).mpc_data ()), 1, MPFR_RNDN); mpfr_set_zero (mpc_imagref (input.at (0, 1).mpc_data ()), 0); Real delta = Real::with_precision (precision); mpfr_set_ui_2exp (delta.mpfr_data (), 1, -1500, MPFR_RNDN); mpfr_add (mpc_realref (input.at (0, 1).mpc_data ()), mpc_realref (input.at (0, 1).mpc_data ()), delta.mpfr_data (), MPFR_RNDN); const auto result = octave_mplapack::mplapack_mpc_matrix_pivoted_qr (input, false, true); check_permutation (result.permutation, "precision pivot returned an invalid permutation"); const Integer expected_first = precision == 1024 ? 1 : 2; check (result.permutation.front () == expected_first, "precision-sensitive complex pivot order mismatch"); check (result.q.precision_bits () == precision && result.r.precision_bits () == precision && result.q.all_elements_have_uniform_precision () && result.r.all_elements_have_uniform_precision (), "pivoted complex QR precision metadata mismatch"); check (mpfrxx::default_precision_bits () == 128, "pivoted complex QR changed ambient precision"); if (precision == 2048) { Real expected = Real::with_precision (precision); mpfr_set_ui (expected.mpfr_data (), 1, MPFR_RNDN); mpfr_add (expected.mpfr_data (), expected.mpfr_data (), delta.mpfr_data (), MPFR_RNDN); Real absolute_factor = Real::with_precision (precision); mpfr_abs (absolute_factor.mpfr_data (), mpc_realref (result.r.at (0, 0).mpc_data ()), MPFR_RNDN); check (mpfr_cmp (absolute_factor.mpfr_data (), expected.mpfr_data ()) == 0, "2048-bit pivoted complex QR tail was not preserved"); } } } void test_empty_shapes () { const Matrix empty_rows (0, 3, 512); const auto rows_result = octave_mplapack::mplapack_mpc_matrix_pivoted_qr ( empty_rows, false, true); check (rows_result.q.rows () == 0 && rows_result.q.columns () == 0 && rows_result.r.rows () == 0 && rows_result.r.columns () == 3, "empty-row pivoted complex QR shape mismatch"); check (rows_result.permutation == std::vector {1, 2, 3}, "empty-row pivoted complex QR permutation mismatch"); const Matrix empty_columns (3, 0, 512); const auto columns_result = octave_mplapack::mplapack_mpc_matrix_pivoted_qr ( empty_columns, true, true); check (columns_result.q.rows () == 3 && columns_result.q.columns () == 0 && columns_result.r.rows () == 0 && columns_result.r.columns () == 0 && columns_result.permutation.empty (), "empty-column pivoted complex QR shape mismatch"); } } // namespace int main () { try { test_full_economy_and_permutation (); test_precision_pivot_and_ambient_scope (); test_empty_shapes (); std::cout << "PASS: complex Cgeqp3/Cungqr pivoted QR full, economy, wide, permutation, reconstruction, orthogonality, precision, ambient scope, shapes, and immutability\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/t13_quadrature.tst0000644000230300031750000000351715274353472020630 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (256); %! options = struct ("AbsTol", mp ("1e-45"), "RelTol", mp ("1e-45")); %! [value, err] = integral (@(x) x * x, mp ("0"), mp ("1"), options); %! assert (abs (value - mp ("1") / mp ("3")) < mp ("1e-40")); %! assert (err < mp ("1e-40")); %! [split, unused] = quadgk (@(x) exp (-x), mp ("0"), mp ("1"), ... %! "Waypoints", mp ("0.25")); %! assert (abs (split - (mp ("1") - exp (mp ("-1")))) < mp ("1e-35")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (256); %! options = struct ("AbsTol", mp ("1e-35"), "RelTol", mp ("1e-35")); %! finite = integral (@(x) 1 / sqrt (x), mp ("0"), mp ("1"), options); %! assert (abs (finite - mp ("2")) < mp ("1e-28")); %! infinite = integral (@(x) exp (-x), mp ("0"), mp ("Inf"), options); %! assert (abs (infinite - mp ("1")) < mp ("1e-28")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (512); %! options = struct ("AbsTol", mp ("1e-100"), "RelTol", mp ("1e-100")); %! real_part = integral (@(x) cos (x), mp ("0"), acos (mp ("-1")), options); %! complex_part = integral (@(x) exp (i * x), mp ("0"), ... %! acos (mp ("-1")), options); %! assert (abs (real_part) < mp ("1e-90")); %! assert (abs (complex_part - mp ("0", "2")) < mp ("1e-90")); %! ## 512-bit arithmetic resolves this result well beyond binary64. %! tiny = mp ("1") / (mp ("10") ^ 80); %! high = integral (@(x) tiny * x, mp ("0"), mp ("2"), options); %! assert (abs (high - mp ("2") * tiny) < mp ("1e-90")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect mplapack-interop-0.5.1/test/test_neigt02.m0000644000230300031750000000272415274353472017714 0ustar rafaelrafael% Focused NEIGT02 exact construction and widening test. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect mpbits (512); pair = net_exact_similarity (8, 512); assert (pair.exact && pair.xy_error == mp (0) && pair.yx_error == mp (0)); H = net_hadamard (8, 512); assert (norm (H * ctranspose (H) - 8 * mp (eye (8)), "fro") == mp (0)); fixture = net_similarity_model ("jordan", 8, 24, 512); assert (fixture.model_products_exact); assert (norm (fixture.similarity.X * fixture.A_model ... - fixture.J * fixture.similarity.X, "fro") == mp (0)); before = fixture.A_frozen; mpbits (1024); widened = net_widen (fixture.A_frozen, 1024, 512); assert (norm (widened - fixture.A_frozen, "fro") == mp (0)); assert (norm (fixture.A_frozen - before, "fro") == mp (0)); for setting = {[1024, 700], [2048, 1500]} mpbits (setting{1}(1)); tiny = net_pow2 (-setting{1}(2), setting{1}(1)); widened_tiny = net_widen (tiny, setting{1}(1), setting{1}(1)); assert (widened_tiny != mp (0)); endfor caught = false; try net_widen (fixture.A_frozen, 256, 512); catch caught = true; end_try_catch assert (caught); fprintf ("PASS: NEIGT02 exact similarities, Hadamard, guards, widening, and tails\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/test_neigt17.m0000644000230300031750000000513615274353472017722 0ustar rafaelrafael% NEIGT17: verified pseudospectrum points, cells, and fail-closed boundaries. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect mpbits (256); bundle = net_manifest (); jobs = bundle.jobs.profiles.smoke.jobs; for index = 13:16 job = jobs{index}; result = net_v_s3_job (job, bundle.jobs.profiles.smoke, "smoke"); assert (result.pass && result.milestone_pass); assert (strcmp (result.status, "PASS")); expected_method = "neigt_svd_pseudospectrum_point_v1"; if (strcmp (job.kind, "pseudospectrum_cell")) expected_method = "neigt_svd_pseudospectrum_cell_v1"; endif assert (strcmp (result.certificate.method, expected_method)); assert (strcmp (result.claim_status, job.expected)); assert (! isempty (result.raw_B_hash)); assert (! isempty (result.raw_U_hash)); assert (! isempty (result.raw_s_hash)); assert (! isempty (result.raw_V_hash)); assert (result.certificate.gU < mp (1)); assert (result.certificate.gV < mp (1)); assert (result.certificate.delta >= mp (0)); assert (result.certificate.lower >= mp (0)); assert (result.certificate.upper >= result.certificate.lower); if (strcmp (job.kind, "pseudospectrum_cell")) assert (result.certificate.cell.positive_area); assert (result.certificate.cell.area > mp (0)); assert (result.certificate.cell.distance > mp (0)); assert (strcmp (result.certificate.cell.status, job.expected)); endif endfor % The classifier receives a genuinely straddling outward interval and must % not manufacture an inside/outside decision at the boundary. epsilon = net_pow2 (-12, 256); assert (strcmp (net_v_s3_classify (epsilon / mp (2), epsilon * mp (2), ... epsilon), "INCONCLUSIVE")); assert (strcmp (net_v_s3_classify (epsilon, epsilon, epsilon), ... "CERTIFIED_INSIDE")); caught = false; try net_v_s3_classify (mp (2), mp (1), epsilon); catch caught = true; end_try_catch assert (caught); caught = false; try net_v_s3_classify (mp (0), mp (1), mp (0)); catch caught = true; end_try_catch assert (caught); fprintf ("PASS: NEIGT17 verified SVD pseudospectrum points, positive-area cells, and boundary traps\n"); unwind_protect_cleanup mpbits (saved_bits); if (any (strcmp (strsplit (path (), pathsep), ... fullfile (test_root, "examples", "neig_tiers", "private")))) rmpath (fullfile (test_root, "examples", "neig_tiers", "private")); endif end_unwind_protect mplapack-interop-0.5.1/test/mp_lapack_probe.cc0000644000230300031750000000561115274353472020652 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include namespace { using Real = mpfrxx::mpfr_class; void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } Real at_precision (mpfr_prec_t precision) { return Real::with_precision (precision); } void set_one (Real& value) { mpfr_set_ui (value.mpfr_data (), 1, MPFR_RNDN); } void set_two (Real& value) { mpfr_set_ui (value.mpfr_data (), 2, MPFR_RNDN); } void add_power_of_two (Real& value, long exponent) { Real increment = at_precision (value.precision ()); mpfr_set_ui_2exp (increment.mpfr_data (), 1, exponent, MPFR_RNDN); mpfr_add (value.mpfr_data (), value.mpfr_data (), increment.mpfr_data (), MPFR_RNDN); } class DefaultPrecisionGuard { public: explicit DefaultPrecisionGuard (mpfr_prec_t precision) : m_saved (mpfrxx::default_precision_bits ()) { mpfrxx::set_default_precision_bits (precision); } ~DefaultPrecisionGuard () noexcept { mpfrxx::set_default_precision_bits (m_saved); } private: mpfr_prec_t m_saved; }; void run_probe (mpfr_prec_t operation_precision) { constexpr long epsilon_exponent = -700; Real a[4] = {at_precision (operation_precision), at_precision (operation_precision), at_precision (operation_precision), at_precision (operation_precision)}; Real b[2] = {at_precision (operation_precision), at_precision (operation_precision)}; set_one (a[0]); set_one (a[1]); set_one (a[2]); set_one (a[3]); add_power_of_two (a[3], epsilon_exponent); set_two (b[0]); set_two (b[1]); add_power_of_two (b[1], epsilon_exponent); mplapackint pivots[2] = {0, 0}; mplapackint info = -1; { MplapackMpfrPrecisionScope scope (operation_precision); Rgesv (2, 1, a, 2, pivots, b, 2, info); require (mpfrxx::default_precision_bits () == operation_precision, "Rgesv changed the scoped precision"); } require (info == 0, "Rgesv precision probe did not converge"); Real expected = at_precision (operation_precision); set_one (expected); require (mpfr_equal_p (b[0].mpfr_data (), expected.mpfr_data ()) != 0, "Rgesv precision probe first solution mismatch"); require (mpfr_equal_p (b[1].mpfr_data (), expected.mpfr_data ()) != 0, "Rgesv precision probe second solution mismatch"); } } // namespace int main () { try { DefaultPrecisionGuard guard (128); run_probe (1024); require (mpfrxx::default_precision_bits () == 128, "Rgesv precision probe did not restore the outside default"); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: installed MPLAPACK MPFR Rgesv precision probe\n"; return 0; } mplapack-interop-0.5.1/test/complex_gemm.tst0000644000230300031750000000676215274353472020445 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_matrix_info (value, expected_rows, expected_columns, ... %! expected_precision) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (expected_rows)); %! assert (info.columns, uint64 (expected_columns)); %! assert (info.precision_bits, uint64 (expected_precision)); %! assert (info.is_complex && info.all_elements_same_precision); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1 + 2i, 5 + 6i; 3 + 4i, 7 + 8i]); %! B = mp ([1 + 0i, 2 - 1i; 0 + 1i, 1 + 2i]); %! A_before = double (A); %! B_before = double (B); %! C = A * B; %! assert_matrix_info (C, 2, 2, 512); %! assert (double (C), [-5 + 7i, -3 + 19i; -5 + 11i, 1 + 27i]); %! assert (! isreal (C)); %! assert (double (A), A_before); %! assert (double (B), B_before); %! clear A B; %! assert (double (C), [-5 + 7i, -3 + 19i; -5 + 11i, 1 + 27i]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! R = mp ([1, 3; 2, 4]); %! mpbits (512); %! Z = mp ([1 + 2i, 3 + 4i; 5 + 6i, 7 + 8i]); %! scale = mp ("2", "-1"); %! mpbits (1024); %! RZ = R * Z; %! ZR = Z * R; %! assert_matrix_info (RZ, 2, 2, 512); %! assert_matrix_info (ZR, 2, 2, 512); %! assert (double (RZ), [16 + 20i, 24 + 28i; ... %! 22 + 28i, 34 + 40i]); %! assert (double (ZR), [7 + 10i, 15 + 22i; ... %! 19 + 22i, 43 + 50i]); %! assert (mpbits (), uint64 (1024)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (1024)); %! I = complex (eye (2), zeros (2)); %! builtin_result = Z * I; %! assert_matrix_info (builtin_result, 2, 2, 512); %! assert (double (builtin_result), double (Z)); %! scaled = Z * scale; %! assert_matrix_info (scaled, 2, 2, 512); %! assert (double (scaled), [4 + 3i, 10 + 5i; ... %! 16 + 7i, 22 + 9i]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! tail = mp ("1", "1"); %! for k = 1:exponent %! tail = tail ./ mp ("2"); %! endfor %! A = mp (complex (zeros (1, 2), zeros (1, 2))); %! A(1, 1) = tail; %! B = mp (complex ([1; 0], zeros (2, 1))); %! mpbits (128); %! result = A * B; %! assert (! isreal (result)); %! assert (strcmp (char (result), char (tail))); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp (complex (ones (2, 2), zeros (2, 2))); %! B = mp (complex (ones (3, 1), zeros (3, 1))); %! caught = false; %! try %! A * B; %! catch exception %! caught = true; %! assert (strcmp (exception.identifier, "mplapack:mp:DimensionMismatch")); %! end_try_catch %! assert (caught); %! E = mp (complex (zeros (1, 0), zeros (1, 0))); %! F = mp (complex (zeros (0, 2), zeros (0, 2))); %! empty = E * F; %! assert_matrix_info (empty, 1, 2, 256); %! assert (! isempty (empty)); %! assert (double (empty), zeros (1, 2)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/n07_closure.tst0000644000230300031750000000300215274353472020111 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_rejected (thunk, label) %! rejected = false; %! try %! thunk (); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, label); %!endfunction %!function result = reference_square (value) %! d = double (value); %! result = [d(1, 1) * d(1, 1) + d(1, 2) * d(2, 1), ... %! d(1, 1) * d(1, 2) + d(1, 2) * d(2, 2); ... %! d(2, 1) * d(1, 1) + d(2, 2) * d(2, 1), ... %! d(2, 1) * d(1, 2) + d(2, 2) * d(2, 2)]; %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! assert_rejected (@() sparse (A), "sparse conversion must remain unsupported"); %! assert_rejected (@() reshape (A, [1, 1, 4]), ... %! "N-dimensional reshape must remain unsupported"); %! C = mp ([1 + 1i, 2; 3, 4 - 1i]); %! assert_rejected (@() (C < C), "ordered complex comparison must remain unsupported"); %! assert (isequal (C == C, true (2)), "complex equality compatibility"); %! assert (double (norm (C ^ 2 - mp (reference_square (C)), "fro")) < 1e-12); %! assert (double (C / C), eye (2), 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (512); %! G = mp (gallery ("grcar", 32)); %! [V, D] = eig (G, "nobalance"); %! assert (double (norm (G * V - V * D, "fro")) < 1e-12, ... %! "permanent N07 Grcar residual"); %! assert (__mplapack_core__ ("matrix_test_info", D).precision_bits ... %! == uint64 (512)); mplapack-interop-0.5.1/test/test_svd_verification.m0000644000230300031750000000114015274353472021771 0ustar rafaelrafael## SVT18 integration wall for self-contained Tier V verifiers. test_root = fileparts (mfilename ("fullpath")); repo_root = fileparts (test_root); suite_dir = fullfile (repo_root, "examples", "svd_tiers"); private_dir = fullfile (suite_dir, "private"); addpath (suite_dir); addpath (private_dir); assert (svt_v0_selftest ().ok); assert (svt_v1_values_selftest ().ok); assert (svt_v1_projector_selftest ().ok); assert (svt_v2_factor_selftest ().ok); assert (svt_v3_inverse_selftest ().ok); fprintf ("PASS: test_svd_verification (SVT18 V0/V1/V2/V3 integration)\n"); rmpath (private_dir); rmpath (suite_dir); mplapack-interop-0.5.1/test/mp_complex_cholesky_test.cc0000644000230300031750000001507315274353472022642 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include "mp_complex_cholesky.h" namespace { using Matrix = octave_mplapack::MpfrComplexMatrixStorage; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void set_power_of_two_real (mpc_ptr value, long exponent) { mpfr_set_ui_2exp (mpc_realref (value), 1, exponent, MPFR_RNDN); mpfr_set_zero (mpc_imagref (value), 0); } void check_close (const Matrix& matrix, std::size_t row, std::size_t column, std::complex expected, const char *message) { const std::complex actual = octave_mplapack::MpfrComplexScalarStorage ( matrix.at (row, column)).to_double (); check (std::abs (actual - expected) < 1.0e-12, message); } void test_triangle_selection () { const Matrix upper_input (2, 2, 1024, std::vector> { {4.0, 9.0}, {777.0, 888.0}, {2.0, 1.0}, {10.0, -7.0}}); const Matrix upper_before = upper_input; const auto upper = octave_mplapack::mplapack_mpc_matrix_cholesky (upper_input, false); check (upper.info == 0 && upper.factor.rows () == 2 && upper.factor.columns () == 2 && upper.factor.precision_bits () == 1024, "upper complex Cholesky metadata mismatch"); check_close (upper.factor, 0, 0, {2.0, 0.0}, "upper complex Cholesky first diagonal mismatch"); check_close (upper.factor, 0, 1, {1.0, 0.5}, "upper complex Cholesky off-diagonal mismatch"); check_close (upper.factor, 1, 1, {std::sqrt (8.75), 0.0}, "upper complex Cholesky second diagonal mismatch"); check (mpfr_zero_p (mpc_imagref (upper.factor.at (1, 0).mpc_data ())) != 0, "upper complex Cholesky lower triangle was not cleared"); check (upper_input.element_exactly_equal (0, 0, upper_before, 0, 0) && upper_input.element_exactly_equal (1, 0, upper_before, 1, 0), "upper complex Cholesky modified input"); const Matrix lower_input (2, 2, 1024, std::vector> { {4.0, 9.0}, {2.0, -1.0}, {777.0, 888.0}, {10.0, -7.0}}); const auto lower = octave_mplapack::mplapack_mpc_matrix_cholesky (lower_input, true); check (lower.info == 0 && lower.factor.rows () == 2 && lower.factor.columns () == 2, "lower complex Cholesky metadata mismatch"); check_close (lower.factor, 0, 0, {2.0, 0.0}, "lower complex Cholesky first diagonal mismatch"); check_close (lower.factor, 1, 0, {1.0, -0.5}, "lower complex Cholesky off-diagonal mismatch"); check_close (lower.factor, 1, 1, {std::sqrt (8.75), 0.0}, "lower complex Cholesky second diagonal mismatch"); check (mpfr_zero_p (mpc_imagref (lower.factor.at (0, 1).mpc_data ())) != 0, "lower complex Cholesky upper triangle was not cleared"); } void test_precision_and_ambient () { mpfrxx::set_default_precision_bits (128); for (const auto setting : {std::array {{1024, -700}}, std::array {{2048, -1500}}}) { const mpfr_prec_t precision = static_cast (setting[0]); Matrix input (2, 2, precision); set_power_of_two_real (input.at (0, 0).mpc_data (), 0); set_power_of_two_real (input.at (0, 1).mpc_data (), 0); set_power_of_two_real (input.at (1, 0).mpc_data (), 0); Real delta = Real::with_precision (precision); mpfr_set_ui_2exp (delta.mpfr_data (), 1, setting[1], MPFR_RNDN); mpfr_add (mpc_realref (input.at (1, 1).mpc_data ()), mpc_realref (input.at (0, 0).mpc_data ()), delta.mpfr_data (), MPFR_RNDN); mpfr_set_zero (mpc_imagref (input.at (1, 1).mpc_data ()), 0); const auto result = octave_mplapack::mplapack_mpc_matrix_cholesky (input, false); check (result.info == 0 && result.factor.precision_bits () == precision && result.factor.all_elements_have_uniform_precision (), "complex Cholesky precision metadata mismatch"); Real expected = Real::with_precision (precision); mpfr_set_ui_2exp (expected.mpfr_data (), 1, setting[1] / 2, MPFR_RNDN); check (mpfr_equal_p (mpc_realref (result.factor.at (1, 1).mpc_data ()), expected.mpfr_data ()) != 0, "complex Cholesky precision tail mismatch"); check (mpfr_zero_p (mpc_imagref (result.factor.at (1, 1).mpc_data ())) != 0, "complex Cholesky diagonal acquired an imaginary part"); check (mpfrxx::default_precision_bits () == 128, "complex Cholesky changed ambient precision"); } const Matrix empty (0, 0, 2048); const auto empty_result = octave_mplapack::mplapack_mpc_matrix_cholesky (empty, false); check (empty_result.info == 0 && empty_result.factor.rows () == 0 && empty_result.factor.columns () == 0 && empty_result.factor.precision_bits () == 2048, "empty complex Cholesky shape mismatch"); } void test_nonpositive_and_shapes () { const Matrix semidefinite (2, 2, 512, std::vector> { {1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}}); const auto result = octave_mplapack::mplapack_mpc_matrix_cholesky (semidefinite, false); check (result.info == 2 && result.factor.rows () == 1 && result.factor.columns () == 1, "complex Cholesky non-PD status mismatch"); check_close (result.factor, 0, 0, {1.0, 0.0}, "complex Cholesky partial factor mismatch"); const Matrix nonsquare (2, 1, 256); bool rejected = false; try { octave_mplapack::mplapack_mpc_matrix_cholesky (nonsquare, false); } catch (const std::invalid_argument&) { rejected = true; } check (rejected, "complex Cholesky accepted a non-square matrix"); } } // namespace int main () { try { test_triangle_selection (); test_precision_and_ambient (); test_nonpositive_and_shapes (); std::cout << "PASS: complex Cpotrf selected-triangle Hermitian Cholesky, diagonal behavior, non-PD status, precision, ambient scope, shapes, and immutability\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/test_neigt19.m0000644000230300031750000000611115274353472017716 0ustar rafaelrafael% NEIGT19: genuine triangular and defective block-Schur certificates. test_root = fileparts (fileparts (mfilename ("fullpath"))); private_root = fullfile (test_root, "examples", "neig_tiers", "private"); addpath (private_root); saved_bits = mpbits (); unwind_protect mpbits (256); bundle = net_manifest (); jobs = bundle.jobs.profiles.smoke.jobs; real_result = net_v_a1_schur_job (jobs{17}, bundle.jobs.profiles.smoke, "smoke"); complex_result = net_v_a1_schur_job (jobs{18}, bundle.jobs.profiles.smoke, "smoke"); block_result = net_v_a1_schur_job (jobs{19}, bundle.jobs.profiles.smoke, "smoke"); assert (real_result.pass && complex_result.pass && block_result.pass); assert (strcmp (real_result.status, "CERTIFIED_SCHUR_TRIANGULAR")); assert (strcmp (complex_result.status, "CERTIFIED_SCHUR_TRIANGULAR")); assert (strcmp (block_result.status, "CERTIFIED_BLOCK_SCHUR")); for current = {real_result, complex_result} certificate = current{1}.certificate; assert (certificate.all_normalizations_positive); assert (certificate.lower_triangle_algebraically_forced); assert (certificate.lower_left_zero_proof); assert (all (certificate.normalization_lower > mp (0))); for i = 1:4 for j = 1:(i - 1) assert (certificate.T_box.rl(i,j) == mp (0)); assert (certificate.T_box.rh(i,j) == mp (0)); assert (certificate.T_box.il(i,j) == mp (0)); assert (certificate.T_box.ih(i,j) == mp (0)); endfor endfor endfor block_certificate = block_result.certificate; assert (block_certificate.block_dimension == 2); assert (! block_certificate.lower_triangle_algebraically_forced); assert (block_certificate.lower_left_zero_proof); for i = 3:4 for j = 1:2 assert (block_certificate.T_box.rl(i,j) == mp (0)); assert (block_certificate.T_box.rh(i,j) == mp (0)); assert (block_certificate.T_box.il(i,j) == mp (0)); assert (block_certificate.T_box.ih(i,j) == mp (0)); endfor endfor % The strictly lower entry inside the defective leading block is retained % from the direct Q'*A*Q enclosure rather than clipped to zero. block_lower = net_iv_complex (block_certificate.T_direct.rl(2,1), ... block_certificate.T_direct.rh(2,1), ... block_certificate.T_direct.il(2,1), ... block_certificate.T_direct.ih(2,1)); assert (block_lower.rl < mp (0) || block_lower.rh > mp (0) ... || block_lower.il < mp (0) || block_lower.ih > mp (0)); % A zero column cannot be normalized and must fail closed. zero_column = net_iv_cmatrix_point (mp ([0, 0; 0, 1]), 256); bad_qr = net_v_a1_interval_qr (zero_column, 256); assert (! bad_qr.pass); assert (strcmp (bad_qr.status, "INCONCLUSIVE_QR_NORMALIZATION")); assert (! bad_qr.all_normalizations_positive); fprintf ("PASS: NEIGT19 interval QR, true triangular Schur, block Schur, and normalization traps\n"); unwind_protect_cleanup mpbits (saved_bits); if (any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect mplapack-interop-0.5.1/test/test_neigt07.m0000644000230300031750000000254215274353472017717 0ustar rafaelrafael% Focused NEIGT07 Forsythe split/scaled/zero tests. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect for n = [7, 8] reference = net_forsythe_reference (n, 4, 640); assert (reference.unit_roots(1) == mp ("(1,0)")); assert (abs (reference.unit_roots .* conj (reference.unit_roots) ... - mp (1)) < net_pow2 (-450, 640)); for representation = {"original", "explicitly_scaled"} fixture = net_forsythe_model (n, 4, representation{1}, 512); assert (fixture.relation_exact); audit = net_forsythe_audit (fixture, 640); assert (audit.circle_match.threshold < net_pow2 (-180, 512)); assert (audit.metrics.right_residual < net_pow2 (-180, 512)); assert (audit.metrics.left_residual < net_pow2 (-180, 512)); endfor endfor zero = net_forsythe_model (8, 4, "zero_limit", 512); zero_audit = net_forsythe_audit (zero, 640); assert (zero_audit.first_n_minus_one_nonzero && zero_audit.nth_power_zero); assert (strcmp (zero_audit.unique_eigenvector_target, "NOT_APPLICABLE")); fprintf ("PASS: NEIGT07 Forsythe circle, scaling identity, and zero-limit Jordan audit\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/svd.tst0000644000230300031750000001316315274353472016556 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_close_mp (value, tolerance, label) %! got = double (norm (value, "fro")); %! assert (got < tolerance, label); %!endfunction %!function assert_svd_shapes (m, n, economy, U, S, V) %! k = min (m, n); %! if (economy) %! assert (size (U), [m, k]); %! assert (size (S), [k, k]); %! assert (size (V), [n, k]); %! else %! assert (size (U), [m, m]); %! assert (size (S), [m, n]); %! assert (size (V), [n, n]); %! endif %!endfunction %!function check_real_svd (m, n) %! A = mp (reshape (1:(m * n), m, n)); %! [U, S, V] = svd (A); %! assert_svd_shapes (m, n, false, U, S, V); %! assert (isa (U, "mp") && isa (S, "mp") && isa (V, "mp")); %! assert (__mplapack_core__ ("value_is_real", U)); %! assert (__mplapack_core__ ("value_is_real", S)); %! assert (__mplapack_core__ ("value_is_real", V)); %! if (m > 0 && n > 0) %! assert_close_mp (A - U * S * transpose (V), 1e-10, ... %! "real full SVD reconstruction"); %! endif %! k = min (m, n); %! if (k > 0) %! assert_close_mp (transpose (U) * U - mp (eye (m)), 1e-10, ... %! "real full U orthogonality"); %! assert_close_mp (transpose (V) * V - mp (eye (n)), 1e-10, ... %! "real full V orthogonality"); %! endif %! singular_values = svd (A); %! assert (size (singular_values), [k, 1]); %! assert (__mplapack_core__ ("value_is_real", singular_values)); %! if (k == 1) %! assert_close_mp (singular_values - S, 1e-10, ... %! "real scalar singular values output"); %! else %! for index = 1:k %! assert_close_mp (singular_values (index) - S (index, index), 1e-10, ... %! "real singular values output"); %! endfor %! endif %! [Ue, Se, Ve] = svd (A, "econ"); %! assert_svd_shapes (m, n, true, Ue, Se, Ve); %! if (m > 0 && n > 0) %! assert_close_mp (A - Ue * Se * transpose (Ve), 1e-10, ... %! "real economy SVD reconstruction"); %! endif %! if (k > 0) %! assert_close_mp (transpose (Ue) * Ue - mp (eye (k)), 1e-10, ... %! "real economy U orthogonality"); %! assert_close_mp (transpose (Ve) * Ve - mp (eye (k)), 1e-10, ... %! "real economy V orthogonality"); %! endif %! [U0, S0, V0] = svd (A, 0); %! assert_svd_shapes (m, n, true, U0, S0, V0); %!endfunction %!function check_complex_svd (m, n) %! A = mp (complex (reshape (1:(m * n), m, n), ... %! reshape (m:(m * n + m - 1), m, n))); %! [U, S, V] = svd (A); %! assert_svd_shapes (m, n, false, U, S, V); %! assert (isa (U, "mp") && isa (S, "mp") && isa (V, "mp")); %! assert (! __mplapack_core__ ("value_is_real", U)); %! assert (__mplapack_core__ ("value_is_real", S)); %! assert (! __mplapack_core__ ("value_is_real", V)); %! if (m > 0 && n > 0) %! assert_close_mp (A - U * S * ctranspose (V), 1e-10, ... %! "complex full SVD reconstruction"); %! endif %! k = min (m, n); %! if (k > 0) %! identity = mp (complex (eye (k), zeros (k))); %! assert_close_mp (ctranspose (U) * U - mp (complex (eye (m), zeros (m))), ... %! 1e-10, "complex full U unitarity"); %! assert_close_mp (ctranspose (V) * V - mp (complex (eye (n), zeros (n))), ... %! 1e-10, "complex full V unitarity"); %! assert (isa (identity, "mp")); %! endif %! singular_values = svd (A); %! assert (size (singular_values), [k, 1]); %! assert (__mplapack_core__ ("value_is_real", singular_values)); %! [Ue, Se, Ve] = svd (A, "econ"); %! assert_svd_shapes (m, n, true, Ue, Se, Ve); %! assert (__mplapack_core__ ("value_is_real", Se)); %! if (m > 0 && n > 0) %! assert_close_mp (A - Ue * Se * ctranspose (Ve), 1e-10, ... %! "complex economy SVD reconstruction"); %! endif %! [U0, S0, V0] = svd (A, 0); %! assert_svd_shapes (m, n, true, U0, S0, V0); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! for shape = [1, 1; 3, 2; 2, 3; 0, 3; 3, 0; 0, 0].' %! check_real_svd (shape (1), shape (2)); %! endfor %! for shape = [1, 1; 3, 2; 2, 3; 0, 3; 3, 0; 0, 0].' %! check_complex_svd (shape (1), shape (2)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! A1024 = mp ({"1e-700", "0"; "0", "1"}); %! s1024 = svd (A1024); %! assert (__mplapack_core__ ("value_shape_info", s1024).precision_bits == 1024); %! assert (! __mplapack_core__ ("scalar_test_info", s1024 (2)).is_zero); %! mpbits (2048); %! A2048 = mp ({"1e-1500", "0"; "0", "1"}); %! [U, S, V] = svd (A2048); %! assert (__mplapack_core__ ("matrix_test_info", S).precision_bits == 2048); %! assert_close_mp (S (1, 1) - mp ("1"), 1e-10, ... %! "2048-bit dominant singular value"); %! assert (! __mplapack_core__ ("scalar_test_info", S (2, 2)).is_zero); %! before = A2048; %! svd (A2048); %! assert_close_mp (A2048 - before, 1e-10, "SVD input immutability"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! A = mp ({"1", "2"; "3", "4"}); %! mpbits (128); %! assert (mpbits () == 128); %! svd (A); %! assert (mpbits () == 128); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ([1, 2; 3, 4]); %! rejected = false; %! try %! svd (A, "bad-option"); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, "invalid SVD option was accepted"); %! rejected = false; %! try %! [U, S] = svd (A); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, "two-output SVD was accepted"); mplapack-interop-0.5.1/test/t11_interp2.tst0000644000230300031750000000507215274353472020032 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (512); %! x = mp ({"0", "1", "3"}); %! y = mp ({"0", "2", "5"}); %! z = mp ({"0", "1", "3"; "2", "3", "5"; "5", "6", "8"}); %! xi = mp ([0.5, 2]); %! yi = mp ([0.5, 2]); %! linear = interp2 (x, y, z, xi, yi, "linear"); %! assert (linear(1) == mp ("1")); %! assert (linear(2) == mp ("4")); %! nearest = interp2 (x, y, z, xi, yi, "nearest"); %! assert (nearest(1) == mp ("0")); %! matrix_x = mp ({"0", "1", "3"; "0", "1", "3"; "0", "1", "3"}); %! matrix_y = mp ({"0", "0", "0"; "2", "2", "2"; "5", "5", "5"}); %! matrix_grid = interp2 (matrix_x, matrix_y, z, xi, yi); %! assert (matrix_grid(1) == linear(1) && matrix_grid(2) == linear(2)); %! descending = interp2 (fliplr (x), fliplr (y), flipud (fliplr (z)), ... %! xi, yi); %! assert (descending(1) == linear(1) && descending(2) == linear(2)); %! extrapolated = interp2 (x, y, z, mp ("-1"), mp ("-1"), ... %! "linear", "extrap"); %! assert (extrapolated == mp ("-2")); %! assert (isnan (interp2 (x, y, z, mp ("-1"), mp ("-1")))); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (512); %! axis = mp ([0, 1, 2, 3]); %! values = mp ([0, 1, 4, 9]); %! z = mp ([0, 1, 4, 9; 1, 2, 5, 10; 4, 5, 8, 13; 9, 10, 13, 18]); %! xi = mp ("0.5"); %! yi = mp ("1.5"); %! spline_value = interp2 (axis, axis, z, xi, yi, "spline"); %! pchip_value = interp2 (axis, axis, z, xi, yi, "pchip"); %! assert (spline_value == mp ("2.5")); %! assert (pchip_value > mp ("1") && pchip_value < mp ("5")); %! complex_z = mp ({"(0,0)", "(1,0)"; "(0,1)", "(1,1)"}); %! complex_value = interp2 (mp ([0, 1]), mp ([0, 1]), complex_z, ... %! mp ("0.25"), mp ("0.5")); %! assert (real (complex_value) == mp ("0.25")); %! assert (imag (complex_value) == mp ("0.5")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (1024); %! step = mp ("1"); %! for k = 1:700, step = step * mp ("0.5"); endfor %! query = mp ("1") + step; %! z = mp ([0, 2; 1, 3]); %! value = interp2 (mp ([0, 2]), mp ([0, 1]), z, query, mp ("0")); %! assert (double (query) == 1); %! assert (value > mp ("1")); %! default_grid = interp2 (mp ([0, 1; 1, 2]), mp ("1.5"), mp ("1.5")); %! assert (default_grid == mp ("1")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect mplapack-interop-0.5.1/test/complex_release_firewall.tst0000644000230300031750000000414215274353472023013 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_rejected (thunk, label) %! rejected = false; %! try %! thunk (); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, label); %!endfunction %!function result = reference_square (value) %! d = double (value); %! result = [d(1, 1) * d(1, 1) + d(1, 2) * d(2, 1), ... %! d(1, 1) * d(1, 2) + d(1, 2) * d(2, 2); ... %! d(2, 1) * d(1, 1) + d(2, 2) * d(2, 1), ... %! d(2, 1) * d(1, 2) + d(2, 2) * d(2, 2)]; %!endfunction %!test %! mpbits (256); %! A = mp ([1 + 1i, 2; 3, 4 - 1i]); %! [Vg, Dg, Wg] = eig (A); %! assert (double (norm (A * Vg - Vg * Dg, "fro")) < 1e-12, ... %! "N05 general eig complex right residual"); %! assert (double (norm (ctranspose (Wg) * A - Dg * ctranspose (Wg), ... %! "fro")) < 1e-12, ... %! "N05 general eig complex left residual"); %! assert (double (norm (sin (A) - sin (double (A)), "fro")) < 1e-12); %! assert (double (norm (exp (A) - exp (double (A)), "fro")) < 1e-12); %! assert (double (norm (sqrt (A) - sqrt (double (A)), "fro")) < 1e-12); %! assert (double (norm (A ^ 2 - mp (reference_square (A)), "fro")) < 1e-12); %! assert (double (norm (A .^ 2 - double (A) .^ 2, "fro")) < 1e-12); %! assert_rejected (@() (A < A), "complex ordered-comparison fallback"); %! assert_rejected (@() (A > A), "complex ordered-comparison fallback"); %! assert (isequal (A == A, true (2)), "complex equality compatibility"); %! assert (isequal (logical (A), true (2)), "complex logical compatibility"); %! assert (isequal (A & A, true (2)), "complex logical-and compatibility"); %! assert_rejected (@() sparse (A), "complex sparse fallback"); %! assert (double (A / A), eye (2), 1e-12); %! d = det (A); %! X = inv (A); %! assert (isfinite (double (d))); %! assert (double (norm (A * X - mp (complex (eye (2), zeros (2))))) < 1e-12); %! [U, S, V] = svd (A); %! assert (__mplapack_core__ ("value_is_real", S)); %! assert (double (norm (A - U * S * ctranspose (V), "fro")) < 1e-12); %! assert (rank (A), 2); %! assert (double (cond (A)) > 1); %! assert (double (rcond (A)) > 0); mplapack-interop-0.5.1/test/eig_general.tst0000644000230300031750000001512415274353472020222 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_right_residual (A, V, D, tolerance, label) %! residual = double (norm (A * V - V * D, "fro")); %! assert (residual < tolerance, label); %!endfunction %!function assert_left_residual (A, D, W, tolerance, label) %! residual = double (norm (ctranspose (W) * A - D * ctranspose (W), "fro")); %! assert (residual < tolerance, label); %!endfunction %!function assert_general_shapes (V, D, W, precision, label) %! v_info = __mplapack_core__ ("matrix_test_info", V); %! d_info = __mplapack_core__ ("matrix_test_info", D); %! w_info = __mplapack_core__ ("matrix_test_info", W); %! assert (v_info.rows == uint64 (2) && v_info.columns == uint64 (2), label); %! assert (d_info.rows == uint64 (2) && d_info.columns == uint64 (2), label); %! assert (w_info.rows == uint64 (2) && w_info.columns == uint64 (2), label); %! assert (v_info.precision_bits == uint64 (precision), label); %! assert (d_info.precision_bits == uint64 (precision), label); %! assert (w_info.precision_bits == uint64 (precision), label); %! assert (v_info.is_complex && d_info.is_complex && w_info.is_complex, label); %! assert (v_info.all_elements_same_precision ... %! && d_info.all_elements_same_precision ... %! && w_info.all_elements_same_precision, label); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([0, 1; -1, 0]); %! A_before = double (A); %! [V, D, W] = eig (A); %! assert_general_shapes (V, D, W, 512, "real general eig shape/precision"); %! assert_right_residual (A, V, D, 1e-12, "real general right residual"); %! assert_left_residual (A, D, W, 1e-12, "real general left residual"); %! values = sort (diag (double (D))); %! assert (values, [-1i; 1i], 1e-12); %! [Vv, d] = eig (A, "vector"); %! assert (__mplapack_core__ ("matrix_test_info", Vv).is_complex); %! assert (__mplapack_core__ ("matrix_test_info", d).is_complex); %! assert (sort (double (d)), values, 1e-12); %! assert (double (A), A_before); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1 + 0i, 2 + 1i; 0 + 0i, 3 + 0i]); %! A_before = double (A); %! [V, D, W] = eig (A, "nobalance"); %! assert_general_shapes (V, D, W, 512, "complex general eig shape/precision"); %! assert_right_residual (A, V, D, 1e-12, "complex general right residual"); %! assert_left_residual (A, D, W, 1e-12, "complex general left residual"); %! assert (sort (diag (double (D))), [1; 3], 1e-12); %! assert (double (A), A_before); %! [Vb, Db] = eig (A, "balance"); %! assert_right_residual (A, Vb, Db, 1e-12, "complex balance residual"); %! [Vv, d] = eig (A, "vector"); %! assert (__mplapack_core__ ("matrix_test_info", Vv).is_complex); %! assert (__mplapack_core__ ("matrix_test_info", d).is_complex); %! assert (sort (double (d)), [1; 3], 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! G = mp (gallery ("grcar", 8)); %! [Vd, Dd] = eig (G); %! [Vb, Db, Wb] = eig (G, "balance"); %! [Vn, Dn] = eig (G, "nobalance"); %! assert_right_residual (G, Vd, Dd, 1e-12, "Grcar default right residual"); %! assert_right_residual (G, Vb, Db, 1e-12, "Grcar balanced right residual"); %! assert_left_residual (G, Db, Wb, 1e-12, "Grcar balanced left residual"); %! assert_right_residual (G, Vn, Dn, 1e-12, "Grcar unbalanced right residual"); %! assert (double (Dd), double (Db), 1e-12); %! assert (__mplapack_core__ ("matrix_test_info", Vb).is_complex); %! assert (__mplapack_core__ ("matrix_test_info", Wb).is_complex); %! for precision = [128, 256, 512] %! mpbits (precision); %! Gp = mp (gallery ("grcar", 8)); %! [Vp, Dp] = eig (Gp, "balance"); %! assert_right_residual (Gp, Vp, Dp, 1e-12, ... %! "Grcar precision progression residual"); %! assert (__mplapack_core__ ("matrix_test_info", Dp).precision_bits ... %! == uint64 (precision)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! delta = mp ("1"); %! for k = 1:80 %! delta = delta * mp ("0.5"); %! endfor %! nearly = mp ([1, 1; 0, 1]); %! nearly (2, 2) = mp ("1") + delta; %! [Vj, Dj] = eig (nearly); %! assert_right_residual (nearly, Vj, Dj, 1e-12, ... %! "nearly repeated general eig residual"); %! scaled = mp ([1, 1; 0, 1]); %! scaled (1, 1) = mp ("1e100"); %! scaled (2, 2) = mp ("1e-100"); %! [Vs, Ds] = eig (scaled); %! assert_right_residual (scaled, Vs, Ds, 1e-12, ... %! "badly scaled general eig residual"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! tiny = mp ("1"); %! for k = 1:exponent %! tiny = tiny * mp ("0.5"); %! endfor %! A = mp ([1, 2; 0, 3]); %! A (1, 1) = tiny; %! mpbits (128); %! [V, D] = eig (A, "nobalance"); %! assert_right_residual (A, V, D, 1e-12, "general eig high precision residual"); %! d_info = __mplapack_core__ ("matrix_test_info", D); %! assert (d_info.precision_bits == uint64 (precision)); %! assert (! __mplapack_core__ ("matrix_test_element_equal_text", ... %! D, 1, 1, "(0,0)")); %! assert (__mplapack_core__ ("precision_get_bits") == uint64 (128)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (192); %! A = mp ([1, 2; 0, 3]); %! mpbits (768); %! [V, D] = eig (A); %! assert_right_residual (A, V, D, 1e-12, "ambient precision general eig residual"); %! assert (__mplapack_core__ ("matrix_test_info", V).precision_bits ... %! == uint64 (192)); %! assert (__mplapack_core__ ("precision_get_bits") == uint64 (768)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") ... %! == uint64 (768)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ([1, 2; 0, 3]); %! diagonal = eig (A, "matrix"); %! vector = eig (A, "vector"); %! assert (diag (double (diagonal)), double (vector), 1e-12); %! [V, d, W] = eig (A, "vector"); %! assert (double (d), double (vector), 1e-12); %! assert_left_residual (A, diag (double (d)), W, 1e-12, ... %! "standard vector three-output left residual"); mplapack-interop-0.5.1/test/mp_scalar_arithmetic_test.cc0000644000230300031750000002207715274353472022752 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include "mp_scalar_storage.h" using octave_mplapack::MpfrScalarStorage; namespace { class DirectMpfrValue { public: explicit DirectMpfrValue (mpfr_prec_t precision) { mpfr_init2 (m_value, precision); } ~DirectMpfrValue () { mpfr_clear (m_value); } DirectMpfrValue (const DirectMpfrValue&) = delete; DirectMpfrValue& operator= (const DirectMpfrValue&) = delete; mpfr_ptr get () noexcept { return m_value; } mpfr_srcptr get () const noexcept { return m_value; } private: mpfr_t m_value; }; enum class Operation { add, subtract, multiply, divide }; bool same_native_value (mpfr_srcptr lhs, mpfr_srcptr rhs) { if (mpfr_nan_p (lhs) || mpfr_nan_p (rhs)) return mpfr_nan_p (lhs) && mpfr_nan_p (rhs); if (mpfr_zero_p (lhs) || mpfr_zero_p (rhs)) return (mpfr_zero_p (lhs) && mpfr_zero_p (rhs) && mpfr_signbit (lhs) == mpfr_signbit (rhs)); return mpfr_equal_p (lhs, rhs) != 0; } MpfrScalarStorage project_operation (Operation operation, const MpfrScalarStorage& lhs, const MpfrScalarStorage& rhs) { switch (operation) { case Operation::add: return lhs.add (rhs); case Operation::subtract: return lhs.subtract (rhs); case Operation::multiply: return lhs.multiply (rhs); case Operation::divide: return lhs.divide (rhs); } assert (false); return lhs; } void direct_operation (Operation operation, mpfr_ptr result, mpfr_srcptr lhs, mpfr_srcptr rhs) { switch (operation) { case Operation::add: mpfr_add (result, lhs, rhs, MPFR_RNDN); return; case Operation::subtract: mpfr_sub (result, lhs, rhs, MPFR_RNDN); return; case Operation::multiply: mpfr_mul (result, lhs, rhs, MPFR_RNDN); return; case Operation::divide: mpfr_div (result, lhs, rhs, MPFR_RNDN); return; } assert (false); } void compare_text_operation (Operation operation, const char *lhs_text, mpfr_prec_t lhs_precision, const char *rhs_text, mpfr_prec_t rhs_precision) { MpfrScalarStorage lhs (lhs_text, lhs_precision); MpfrScalarStorage rhs (rhs_text, rhs_precision); MpfrScalarStorage result = project_operation (operation, lhs, rhs); const mpfr_prec_t result_precision = lhs_precision > rhs_precision ? lhs_precision : rhs_precision; assert (result.precision_bits () == result_precision); DirectMpfrValue direct_lhs (lhs_precision); DirectMpfrValue direct_rhs (rhs_precision); DirectMpfrValue direct_result (result_precision); assert (mpfr_set_str (direct_lhs.get (), lhs_text, 10, MPFR_RNDN) == 0); assert (mpfr_set_str (direct_rhs.get (), rhs_text, 10, MPFR_RNDN) == 0); direct_operation (operation, direct_result.get (), direct_lhs.get (), direct_rhs.get ()); assert (same_native_value ( result.native_value ().mpfr_data (), direct_result.get ())); assert (lhs.precision_bits () == lhs_precision); assert (rhs.precision_bits () == rhs_precision); } void compare_double_operation (Operation operation, const char *mp_text, double binary64, mpfr_prec_t precision, bool double_on_left) { MpfrScalarStorage mp_operand (mp_text, precision); MpfrScalarStorage double_operand (binary64, precision); MpfrScalarStorage result = double_on_left ? project_operation (operation, double_operand, mp_operand) : project_operation (operation, mp_operand, double_operand); assert (result.precision_bits () == precision); DirectMpfrValue direct_mp (precision); DirectMpfrValue direct_double (precision); DirectMpfrValue direct_result (precision); assert (mpfr_set_str (direct_mp.get (), mp_text, 10, MPFR_RNDN) == 0); mpfr_set_d (direct_double.get (), binary64, MPFR_RNDN); if (double_on_left) direct_operation (operation, direct_result.get (), direct_double.get (), direct_mp.get ()); else direct_operation (operation, direct_result.get (), direct_mp.get (), direct_double.get ()); assert (same_native_value ( result.native_value ().mpfr_data (), direct_result.get ())); } void test_exact_and_mixed_precision () { compare_text_operation (Operation::add, "0.125", 128, "0.25", 256); compare_text_operation (Operation::subtract, "0.5", 256, "0.125", 128); compare_text_operation (Operation::multiply, "0.125", 128, "0.5", 512); compare_text_operation (Operation::divide, "0.5", 512, "0.125", 256); const mpfr_prec_t precisions[] = {2, 8, 32, 128, 256, 333, 512, 1024}; for (const mpfr_prec_t lhs_precision : precisions) for (const mpfr_prec_t rhs_precision : precisions) { compare_text_operation (Operation::add, "0.1", lhs_precision, "0.2", rhs_precision); compare_text_operation (Operation::subtract, "0.1", lhs_precision, "0.2", rhs_precision); compare_text_operation (Operation::multiply, "0.1", lhs_precision, "0.2", rhs_precision); compare_text_operation (Operation::divide, "0.1", lhs_precision, "0.2", rhs_precision); } } void test_rounding_and_global_independence () { compare_text_operation (Operation::add, "1", 2, "0.25", 2); MpfrScalarStorage lhs ("1", 2); MpfrScalarStorage rhs ("0.25", 2); const MpfrScalarStorage tied = lhs.add (rhs); assert (tied.exactly_equal_string ("1")); const mpfr_rnd_t saved_rounding = mpfr_get_default_rounding_mode (); mpfr_set_default_rounding_mode (MPFR_RNDD); const MpfrScalarStorage downward = lhs.divide (MpfrScalarStorage ("3", 2)); mpfr_set_default_rounding_mode (MPFR_RNDU); const MpfrScalarStorage upward = lhs.divide (MpfrScalarStorage ("3", 2)); mpfr_set_default_rounding_mode (saved_rounding); assert (downward.exactly_equal (upward)); } void test_double_temporaries () { const mpfr_prec_t precisions[] = {2, 8, 32, 128, 256, 333, 512, 1024}; for (const mpfr_prec_t precision : precisions) for (const Operation operation : {Operation::add, Operation::subtract, Operation::multiply, Operation::divide}) { compare_double_operation (operation, "1.25", 0.1, precision, false); compare_double_operation (operation, "1.25", 0.1, precision, true); } MpfrScalarStorage base ("1", 128); assert (! base.add (MpfrScalarStorage ("0.1", 128)).exactly_equal ( base.add (MpfrScalarStorage (0.1, 128)))); assert (base.add (MpfrScalarStorage ("0.125", 128)).exactly_equal ( base.add (MpfrScalarStorage (0.125, 128)))); } void test_special_values_and_negation () { const char *values[] = {"0", "-0", "1", "-1", "Inf", "-Inf", "NaN"}; for (const Operation operation : {Operation::add, Operation::subtract, Operation::multiply, Operation::divide}) for (const char *lhs : values) for (const char *rhs : values) compare_text_operation (operation, lhs, 128, rhs, 256); MpfrScalarStorage positive_zero ("0", 128); MpfrScalarStorage negative_zero ("-0", 128); MpfrScalarStorage positive_infinity ("Inf", 128); MpfrScalarStorage negative_infinity ("-Inf", 128); MpfrScalarStorage not_a_number ("NaN", 128); assert (positive_zero.negate ().is_zero ()); assert (positive_zero.negate ().signbit ()); assert (negative_zero.negate ().is_zero ()); assert (! negative_zero.negate ().signbit ()); assert (positive_infinity.negate ().is_infinite ()); assert (positive_infinity.negate ().signbit ()); assert (negative_infinity.negate ().is_infinite ()); assert (! negative_infinity.negate ().signbit ()); assert (not_a_number.negate ().is_nan ()); assert (not_a_number.negate ().precision_bits () == 128); } void test_stress () { constexpr std::size_t iterations = 10000; const mpfr_prec_t precisions[] = {2, 8, 32, 128, 256, 333, 512, 1024}; MpfrScalarStorage accumulator ("1", 128); for (std::size_t i = 0; i < iterations; ++i) { const mpfr_prec_t precision = precisions[i % 8]; MpfrScalarStorage value ((i % 29) == 0 ? "0" : "0.125", precision); switch (i % 4) { case 0: accumulator = accumulator.add (value); break; case 1: accumulator = accumulator.subtract (value); break; case 2: accumulator = accumulator.multiply (value); break; default: accumulator = accumulator.divide (value); break; } MpfrScalarStorage binary64 (0.1, accumulator.precision_bits ()); accumulator = accumulator.add (binary64).negate ().negate (); assert (accumulator.precision_bits () >= precision); } } } // namespace int main () { test_exact_and_mixed_precision (); test_rounding_and_global_independence (); test_double_temporaries (); test_special_values_and_negation (); test_stress (); return 0; } mplapack-interop-0.5.1/test/mp_script_sequence_test.cc0000644000230300031750000001100215274353472022452 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_script_sequence.h" #include #include #include #include #include namespace { using namespace octave_mplapack; void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } bool complex_equals (const MpfrComplexScalarStorage::NativeScalar& value, long real, long imag) { return mpfr_cmp_si (mpc_realref (value.mpc_data ()), real) == 0 && mpfr_cmp_si (mpc_imagref (value.mpc_data ()), imag) == 0; } void check_real_sort () { const MpfrMatrixStorage source ( 2, 3, 256, std::vector { "3", "2", "1", "NaN", "2", "4" }); const auto ascending = mpfr_script_sort (source, 1, false); require (ascending.values.element_exactly_equal_text (0, 0, "2"), "real sort ascending first column mismatch"); require (ascending.values.element_exactly_equal_text (1, 0, "3"), "real sort ascending second row mismatch"); require (ascending.values.element_exactly_equal_text (0, 1, "1"), "real sort ascending second column mismatch"); require (mpfr_nan_p (ascending.values.at (1, 1).mpfr_data ()) != 0, "real sort must place NaN last in ascending order"); require (ascending.indices == std::vector {2, 1, 1, 2, 1, 2}, "real sort indices mismatch"); const auto descending = mpfr_script_sort (source, 2, true); require (descending.values.element_exactly_equal_text (0, 0, "3"), "real row sort first row mismatch"); require (descending.values.element_exactly_equal_text (0, 1, "2"), "real row sort first row second value mismatch"); require (mpfr_nan_p (descending.values.at (1, 0).mpfr_data ()) != 0, "real descending sort value mismatch"); require (descending.indices == std::vector {1, 2, 3, 3, 2, 1}, "real descending sort indices mismatch"); } void check_complex_sort () { const MpfrComplexMatrixStorage source ( 1, 6, 256, std::vector> { {1, 1}, {-1, 1}, {-1, -1}, {1, -1}, {2, 0}, {0, 2} }); const auto result = mpc_script_sort (source, 2, false); require (result.indices == std::vector {3, 4, 1, 2, 5, 6}, "complex magnitude/phase sort indices mismatch"); require (complex_equals (result.values.data ()[0], -1, -1), "complex sort first value mismatch"); require (complex_equals (result.values.data ()[4], 2, 0), "complex sort magnitude tie-break mismatch"); } void check_diff () { const MpfrMatrixStorage source ( 2, 2, 256, std::vector {"1", "2", "3", "5"}); const auto row_difference = mpfr_script_diff (source, 1, 1); require (row_difference.rows () == 1 && row_difference.columns () == 2, "real row diff shape mismatch"); require (row_difference.element_exactly_equal_text (0, 0, "1") && row_difference.element_exactly_equal_text (0, 1, "2"), "real row diff values mismatch"); const auto column_difference = mpfr_script_diff (source, 1, 2); require (column_difference.rows () == 2 && column_difference.columns () == 1, "real column diff shape mismatch"); require (column_difference.element_exactly_equal_text (0, 0, "2") && column_difference.element_exactly_equal_text (1, 0, "3"), "real column diff values mismatch"); const auto second_difference = mpfr_script_diff ( MpfrMatrixStorage (1, 4, 256, std::vector {"1", "4", "9", "16"}), 2, 2); require (second_difference.element_exactly_equal_text (0, 0, "2") && second_difference.element_exactly_equal_text (0, 1, "2"), "real second diff values mismatch"); const MpfrComplexMatrixStorage complex_source ( 3, 1, 256, std::vector> { {1, 2}, {3, 4}, {8, 1} }); const auto complex_difference = mpc_script_diff (complex_source, 1, 1); require (complex_equals (complex_difference.data ()[0], 2, 2), "complex diff first value mismatch"); require (complex_equals (complex_difference.data ()[1], 5, -3), "complex diff second value mismatch"); } } // namespace int main () { try { check_real_sort (); check_complex_sort (); check_diff (); std::cout << "PASS: native MPFR/MPC sort and diff sequence tests\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/t00_schur_qz.tst0000644000230300031750000000364115274353472020303 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({'1','2','3';'4','5','6';'7','8','10'}); %! [P,H] = hess (A); %! assert (double (norm (P*H*P'-A, "fro")) < 1e-60); %! assert (double (norm (P'*P-eye (3,"like",P), "fro")) < 1e-60); %! [U,S] = schur (A); %! assert (double (norm (U'*A*U-S, "fro")) < 1e-60); %! [Uc,Sc] = schur (A, "complex"); %! assert (double (norm (Uc'*A*Uc-Sc, "fro")) < 1e-60); %! B = mp ({'1','0','0';'0','0','0';'0','0','2'}); %! [AA,BB,Q,Z] = qz (A,B); %! assert (double (norm (Q*A*Z-AA, "fro")) < 1e-60); %! assert (double (norm (Q*B*Z-BB, "fro")) < 1e-60); %! [AAr,BBr,Qr,Zr] = qz (A,B,"real"); %! assert (double (norm (Qr*A*Zr-AAr, "fro")) < 1e-60); %! assert (double (norm (Qr*B*Zr-BBr, "fro")) < 1e-60); %! C = [mp('1','2'),mp('2','-1');mp('3','0'),mp('4','3')]; %! [Uc,Sc] = schur (C); %! assert (double (norm (Uc'*C*Uc-Sc, "fro")) < 1e-60); %! [Pc,Hc] = hess (C); %! assert (double (norm (Pc*Hc*Pc'-C, "fro")) < 1e-60); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for bits = [1024, 2048] %! mpbits (bits); %! limit = 1500; %! if (bits == 1024), limit = 700; endif %! tiny = mp ('1'); %! for k = 1:limit %! tiny = tiny * mp ('0.5'); %! endfor %! A = mp ({'1','0';'0','2'}); %! A(1,1) = tiny; %! [P,H] = hess (A); %! assert (double (norm (P*H*P'-A, "fro")) < 1e-12); %! [U,S] = schur (A); %! assert (double (norm (U'*A*U-S, "fro")) < 1e-12); %! assert (__mplapack_core__ ("matrix_test_info", H).precision_bits == uint64 (bits)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({'1','2';'3','4'}); %! assert (double (norm (balance (A)-A, "fro")) < 1e-12); %! [P,H] = hess (A); %! assert (double (norm (P*H*P'-A, "fro")) < 1e-12); mplapack-interop-0.5.1/test/matrix_storage.tst0000644000230300031750000001556215274353472021017 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function y = m07_pass_through (x) %! y = x; %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (333); %! A = mp ({"11", "12", "13"; "21", "22", "23"}); %! assert (strcmp (class (A), "mp")); %! info = __mplapack_core__ ("matrix_test_info", A); %! assert (strcmp (info.internal_type, "mplapack_mpfr_matrix_internal")); %! assert (strcmp (info.storage_kind, "column_major_contiguous")); %! assert (info.rows, uint64 (2)); %! assert (info.columns, uint64 (3)); %! assert (info.numel, uint64 (6)); %! assert (info.precision_bits, uint64 (333)); %! assert (info.leading_dimension, int64 (2)); %! assert (info.all_elements_same_precision); %! native_order = {"11", "21", "12", "22", "13", "23"}; %! for index = 1:numel (native_order) %! row = mod (index - 1, 2) + 1; %! column = floor ((index - 1) / 2) + 1; %! assert (__mplapack_core__ ( %! "matrix_test_element_equal_text", A, row, column, %! native_order{index})); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for bits = [32, 128, 256, 333, 512, 1024] %! mpbits (bits); %! A = mp ([1, 2; 3, 4]); %! info = __mplapack_core__ ("matrix_test_info", A); %! assert (info.precision_bits, uint64 (bits)); %! assert (info.all_elements_same_precision); %! endfor %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! mpbits (1024); %! B = mp ([1, 2; 3, 4]); %! assert (__mplapack_core__ ( %! "matrix_test_info", A).precision_bits, uint64 (256)); %! assert (__mplapack_core__ ( %! "matrix_test_info", B).precision_bits, uint64 (1024)); %! mpdigits (100); %! C = mp ({"0.1", "0.2"; "0.3", "0.4"}); %! info = __mplapack_core__ ("matrix_test_info", C); %! assert (info.precision_bits, uint64 (333)); %! assert (info.all_elements_same_precision); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! text = mp ({"0.1", "0.125"}); %! binary64 = mp ([0.1, 0.125]); %! assert (__mplapack_core__ ( %! "matrix_test_element_equal_double", binary64, 1, 1, 0.1)); %! assert (__mplapack_core__ ( %! "matrix_test_element_equal_double", binary64, 1, 2, 0.125)); %! assert (! __mplapack_core__ ( %! "matrix_test_element_equal", text, 1, 1, binary64, 1, 1)); %! assert (__mplapack_core__ ( %! "matrix_test_element_equal", text, 1, 2, binary64, 1, 2)); %! assert (__mplapack_core__ ( %! "matrix_test_element_equal_text", text, 1, 1, "0.1")); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! numeric_scalar = mp (reshape (1, 1, 1)); %! text_cell_scalar = mp ({"1"}); %! numeric_info = __mplapack_core__ ("scalar_test_info", numeric_scalar); %! cell_info = __mplapack_core__ ("scalar_test_info", text_cell_scalar); %! assert (strcmp (numeric_info.internal_type, %! "mplapack_mpfr_scalar_internal")); %! assert (strcmp (cell_info.internal_type, %! "mplapack_mpfr_scalar_internal")); %! assert (size (numeric_scalar), [1, 1]); %! assert (size (text_cell_scalar), [1, 1]); %!test %! empty_00 = mp ([]); %! empty_03 = mp (zeros (0, 3)); %! empty_40 = mp (zeros (4, 0)); %! empty_cell = mp (cell (0, 3)); %! assert (size (empty_00), [0, 0]); %! assert (size (empty_03), [0, 3]); %! assert (size (empty_40), [4, 0]); %! assert (size (empty_cell), [0, 3]); %! assert (isempty (empty_00)); %! assert (isempty (empty_03)); %! assert (isempty (empty_40)); %! assert (isempty (empty_cell)); %! assert (size (empty_03, 1), 0); %! assert (size (empty_03, 2), 3); %! assert (rows (empty_03), 0); %! assert (columns (empty_03), 3); %! assert (numel (empty_03), 0); %! assert (ndims (empty_03), 2); %! assert (size (empty_40, 1), 4); %! assert (size (empty_40, 2), 0); %! assert (rows (empty_40), 4); %! assert (columns (empty_40), 0); %! assert (numel (empty_40), 0); %! assert (ndims (empty_40), 2); %! assert (__mplapack_core__ ( %! "matrix_test_info", empty_03).leading_dimension, int64 (1)); %! assert (__mplapack_core__ ( %! "matrix_test_info", empty_40).leading_dimension, int64 (4)); %!test %! A = mp ({"11", "12", "13"; "21", "22", "23"}); %! assert (size (A), [2, 3]); %! assert (size (A, 1), 2); %! assert (size (A, 2), 3); %! assert (size (A, 3), 1); %! [r, c] = size (A); %! assert (r, 2); %! assert (c, 3); %! assert (rows (A), 2); %! assert (columns (A), 3); %! assert (numel (A), 6); %! assert (ndims (A), 2); %! assert (! isempty (A)); %! assert (strtrim (evalc ("disp (A)")), ... %! "[1.1e+1 1.2e+1 1.3e+1\n 2.1e+1 2.2e+1 2.3e+1]"); %! assert (isempty (strfind (evalc ("disp (A)"), "payload_"))); %! assert (isempty (strfind (evalc ("disp (A)"), %! "mplapack_mpfr_matrix_internal"))); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! original = mp ({"1", "2"; "3", "4"}); %! assigned = original; %! copied = mp (original); %! collection = {original}; %! record.value = original; %! passed = m07_pass_through (original); %! internal_clone = __mplapack_core__ ("matrix_test_clone", original); %! clear original; %! for value = {assigned, copied, collection{1}, record.value, passed} %! info = __mplapack_core__ ("matrix_test_info", value{1}); %! assert (info.rows, uint64 (2)); %! assert (info.columns, uint64 (2)); %! assert (info.precision_bits, uint64 (256)); %! assert (__mplapack_core__ ( %! "matrix_test_element_equal_text", value{1}, 2, 2, "4")); %! endfor %! clone_info = __mplapack_core__ ("matrix_test_info", internal_clone); %! assert (clone_info.precision_bits, uint64 (256)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! z = mp ([1 + 2i, 3]); %! assert (! isreal (z)); %! assert (double (z), [1 + 2i, 3]); %!error mp (ones (2, 2, 2)) %!error mp (reshape (cellstr (["1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"]), 2, 2, 2)) %!error mp ({"1", 2}) %!test %! value = mp ("1"); %! try %! mp ({value, "2"}); %! error ("M07 cell-of-mp assembly unexpectedly succeeded"); %! catch exception %! assert (! isempty (strfind ( %! exception.message, "each matrix cell must contain one nonempty text row"))); %! end_try_catch %!test %! saved = mpbits (); %! unwind_protect %! mpbits (333); %! try %! mp ({"1", "bad"; "3", "4"}); %! error ("M07 malformed text matrix unexpectedly succeeded"); %! catch exception %! assert (! isempty (strfind ( %! exception.message, "invalid text in mp matrix constructor"))); %! end_try_catch %! assert (mpbits (), uint64 (333)); %! valid = mp ({"1", "2"; "3", "4"}); %! assert (__mplapack_core__ ( %! "matrix_test_info", valid).precision_bits, uint64 (333)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/t09_random.tst0000644000230300031750000000726715274353472017746 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved_bits = mpbits (); %! saved_rng = mprng ("state"); %! unwind_protect %! mpbits (128); %! mprng ("seed", uint64 (7)); %! value = mprand (); %! encoded = __mplapack_core__ ("serialize", value); %! assert (strcmp (encoded.elements{1}, ... %! "6.0142955925964410792087642635995321571e-1")); %! mprng ("seed", uint64 (7)); %! repeat = mprand (); %! assert (isequal (__mplapack_core__ ("serialize", value), ... %! __mplapack_core__ ("serialize", repeat))); %! unwind_protect_cleanup %! mpbits (saved_bits); %! mprng ("state", saved_rng); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! saved_rng = mprng ("state"); %! path = "/tmp/mplapack-t09-rng-state.mat"; %! unwind_protect %! mpbits (512); %! mprng ("seed", uint64 (123456789)); %! mprand (4, 1); %! checkpoint = mprng ("state"); %! expected = mprandn (3, 1); %! mprng ("state", checkpoint); %! restored = mprandn (3, 1); %! assert (isequal (__mplapack_core__ ("serialize", expected), ... %! __mplapack_core__ ("serialize", restored))); %! saved_state = checkpoint; %! save ("-binary", path, "saved_state"); %! clear saved_state; %! load (path, "saved_state"); %! assert (isequal (saved_state, checkpoint)); %! mprng ("state", saved_state); %! restored_again = mprand (2, 2); %! mprng ("state", checkpoint); %! expected_again = mprand (2, 2); %! assert (isequal (__mplapack_core__ ("serialize", restored_again), ... %! __mplapack_core__ ("serialize", expected_again))); %! unwind_protect_cleanup %! mpbits (saved_bits); %! mprng ("state", saved_rng); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! saved_rng = mprng ("state"); %! unwind_protect %! for bits = [128, 512, 1024, 2048] %! mpbits (bits); %! mprng ("seed", uint64 (bits + 17)); %! value = mprand (2, 1); %! encoded = __mplapack_core__ ("serialize", value); %! assert (encoded.precision_bits == uint64 (bits)); %! assert (all (value >= mp ("0")) && all (value < mp ("1"))); %! if (bits >= 1024) %! assert (value(1) != mp (double (value(1))), ... %! "random p-bit value was reduced to binary64"); %! endif %! endfor %! mpbits (128); %! mprng ("seed", uint64 (9)); %! low = mprand (); %! mpbits (512); %! high = mprand (); %! assert (__mplapack_core__ ("serialize", low).precision_bits == uint64 (128)); %! assert (__mplapack_core__ ("serialize", high).precision_bits == uint64 (512)); %! unwind_protect_cleanup %! mpbits (saved_bits); %! mprng ("state", saved_rng); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! saved_rng = mprng ("state"); %! unwind_protect %! mpbits (256); %! mprng ("seed", uint64 (20260908)); %! uniform = mprand (256, 1); %! normal = mprandn (256, 1); %! assert (all (uniform >= mp ("0")) && all (uniform < mp ("1"))); %! uniform_mean = double (mean (uniform)); %! uniform_second = double (mean (uniform .* uniform)); %! normal_mean = double (mean (normal)); %! normal_second = double (mean (normal .* normal)); %! assert (uniform_mean > 0.35 && uniform_mean < 0.65); %! assert (uniform_second > 0.15 && uniform_second < 0.50); %! assert (normal_mean > -0.35 && normal_mean < 0.35); %! assert (normal_second > 0.50 && normal_second < 1.50); %! integers = mprandi (0, 2, [6000, 1]); %! integer_values = double (integers); %! counts = [0, 0, 0]; %! for index = 1:numel (integer_values) %! counts (integer_values(index) + 1) += 1; %! endfor %! assert (all (counts > 1700 & counts < 2300)); %! unwind_protect_cleanup %! mpbits (saved_bits); %! mprng ("state", saved_rng); %! end_unwind_protect mplapack-interop-0.5.1/test/mp_scalar_storage_test.cc0000644000230300031750000003200715274353472022257 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include #include #include #include #include #include #include "mp_scalar_storage.h" #include "mp_precision.h" using octave_mplapack::MpfrScalarStorage; using octave_mplapack::bits_for_decimal_digits; using octave_mplapack::decimal_digits_for_bits; static_assert ( std::is_same_v); static_assert ( std::is_same_v); static_assert (std::is_nothrow_move_constructible_v); static_assert (std::is_nothrow_move_assignable_v); namespace { std::uint64_t double_bits (double value) { std::uint64_t bits = 0; static_assert (sizeof (bits) == sizeof (value)); std::memcpy (&bits, &value, sizeof (bits)); return bits; } void test_precision_configuration_and_conversion () { assert (octave_mplapack::initial_default_precision_bits == 512); assert (octave_mplapack::default_precision_bits () == 512); assert (decimal_digits_for_bits (512) == 154); struct Conversion { octave_mplapack::precision_count_t digits; mpfr_prec_t bits; }; const Conversion conversions[] = { {1, 4}, {10, 34}, {38, 127}, {100, 333}, {1000, 3322} }; for (const auto& conversion : conversions) { assert (bits_for_decimal_digits (conversion.digits) == conversion.bits); assert (decimal_digits_for_bits (conversion.bits) == conversion.digits); } assert (decimal_digits_for_bits (128) == 38); assert (decimal_digits_for_bits (332) == 99); assert (decimal_digits_for_bits (333) == 100); octave_mplapack::set_default_precision_bits (128); assert (octave_mplapack::default_precision_bits () == 128); bool invalid_rejected = false; try { octave_mplapack::set_default_precision_bits (0); } catch (const std::invalid_argument&) { invalid_rejected = true; } assert (invalid_rejected); assert (octave_mplapack::default_precision_bits () == 128); bool overflow_rejected = false; try { bits_for_decimal_digits ( std::numeric_limits::max ()); } catch (const std::overflow_error&) { overflow_rejected = true; } assert (overflow_rejected); assert (octave_mplapack::default_precision_bits () == 128); octave_mplapack::set_default_precision_bits (512); assert (mpfr_get_default_prec () == 512); } void test_basic_ownership () { MpfrScalarStorage a ("0.125", 128); const mpfr_prec_t initialized_mpfr_default = mpfr_get_default_prec (); assert (a.precision_bits () == 128); assert (a.exactly_equal_string ("0.125")); MpfrScalarStorage copied (a); assert (copied.precision_bits () == 128); assert (copied.exactly_equal (a)); MpfrScalarStorage assigned ("-2.25", 512); assigned = a; assert (assigned.precision_bits () == 128); assert (assigned.exactly_equal (a)); assigned = assigned; assert (assigned.precision_bits () == 128); assert (assigned.exactly_equal_string ("0.125")); MpfrScalarStorage moved (std::move (copied)); assert (moved.precision_bits () == 128); assert (moved.exactly_equal_string ("0.125")); MpfrScalarStorage move_assigned ("1.5", 256); move_assigned = std::move (moved); assert (move_assigned.precision_bits () == 128); assert (move_assigned.exactly_equal_string ("0.125")); assert (mpfr_get_default_prec () == initialized_mpfr_default); } void test_precision_and_parsing () { MpfrScalarStorage a ("0.125", 128); MpfrScalarStorage b ("1.5", 256); MpfrScalarStorage c ("-2.25", 512); MpfrScalarStorage decimal ("0.1", 512); assert (a.precision_bits () == 128); assert (b.precision_bits () == 256); assert (c.precision_bits () == 512); assert (decimal.precision_bits () == 512); assert (decimal.exactly_equal_string ("0.1")); bool invalid_text_rejected = false; try { MpfrScalarStorage invalid ("not-a-number", 128); } catch (const std::invalid_argument&) { invalid_text_rejected = true; } assert (invalid_text_rejected); bool invalid_precision_rejected = false; try { MpfrScalarStorage invalid ("1", 0); } catch (const std::invalid_argument&) { invalid_precision_rejected = true; } assert (invalid_precision_rejected); invalid_precision_rejected = false; try { MpfrScalarStorage invalid ("1", -1); } catch (const std::invalid_argument&) { invalid_precision_rejected = true; } assert (invalid_precision_rejected); invalid_precision_rejected = false; try { MpfrScalarStorage invalid ("1", MPFR_PREC_MAX + 1); } catch (const std::invalid_argument&) { invalid_precision_rejected = true; } assert (invalid_precision_rejected); } void test_double_construction_and_special_values () { const mpfr_prec_t precision = octave_mplapack::default_precision_bits (); assert (precision == octave_mplapack::initial_default_precision_bits); assert (precision == 512); MpfrScalarStorage decimal_text ("0.1", precision); MpfrScalarStorage binary64 (0.1, precision); assert (! decimal_text.exactly_equal (binary64)); assert (decimal_text.exactly_equal_string ("0.1")); assert (! decimal_text.exactly_equal_double (0.1)); assert (binary64.exactly_equal_double (0.1)); MpfrScalarStorage dyadic_text ("0.125", precision); MpfrScalarStorage dyadic_binary64 (0.125, precision); assert (dyadic_text.exactly_equal (dyadic_binary64)); assert (dyadic_binary64.exactly_equal_double (0.125)); MpfrScalarStorage smallest_normal ( std::numeric_limits::min (), precision); MpfrScalarStorage largest_finite ( std::numeric_limits::max (), precision); MpfrScalarStorage smallest_subnormal ( std::numeric_limits::denorm_min (), precision); assert (smallest_normal.exactly_equal_double ( std::numeric_limits::min ())); assert (largest_finite.exactly_equal_double ( std::numeric_limits::max ())); assert (smallest_subnormal.exactly_equal_double ( std::numeric_limits::denorm_min ())); MpfrScalarStorage positive_zero (0.0, precision); MpfrScalarStorage negative_zero (-0.0, precision); assert (positive_zero.is_zero () && ! positive_zero.signbit ()); assert (negative_zero.is_zero () && negative_zero.signbit ()); MpfrScalarStorage positive_infinity ( std::numeric_limits::infinity (), precision); MpfrScalarStorage negative_infinity ( -std::numeric_limits::infinity (), precision); MpfrScalarStorage not_a_number ( std::numeric_limits::quiet_NaN (), precision); assert (positive_infinity.is_infinite () && ! positive_infinity.signbit ()); assert (negative_infinity.is_infinite () && negative_infinity.signbit ()); assert (not_a_number.is_nan ()); MpfrScalarStorage copied (negative_zero); assert (copied.is_zero () && copied.signbit ()); MpfrScalarStorage moved (std::move (positive_infinity)); assert (moved.is_infinite () && ! moved.signbit ()); } void test_constructor_rounding_is_explicit () { const mpfr_rnd_t saved_rounding = mpfr_get_default_rounding_mode (); mpfr_set_default_rounding_mode (MPFR_RNDD); MpfrScalarStorage downward_text ("0.1", 128); MpfrScalarStorage downward_double (0.1, 128); mpfr_set_default_rounding_mode (MPFR_RNDU); MpfrScalarStorage upward_text ("0.1", 128); MpfrScalarStorage upward_double (0.1, 128); mpfr_set_default_rounding_mode (saved_rounding); assert (downward_text.exactly_equal (upward_text)); assert (downward_double.exactly_equal (upward_double)); } void test_canonical_conversion_and_double_conversion () { MpfrScalarStorage one ("1", 512); MpfrScalarStorage negative_one ("-1", 512); MpfrScalarStorage dyadic ("0.125", 512); assert (one.to_canonical_string () == "1e+0"); assert (negative_one.to_canonical_string () == "-1e+0"); assert (dyadic.to_canonical_string () == "1.25e-1"); const mpfr_prec_t precisions[] = {128, 256, 333, 512, 1024}; const char *texts[] = { "1", "-1", "0.125", "0.1", "1.234567890123456789", "1e100", "1e-100" }; for (const mpfr_prec_t precision : precisions) for (const char *text : texts) { MpfrScalarStorage original (text, precision); const std::string canonical = original.to_canonical_string (); MpfrScalarStorage reconstructed (canonical, precision); assert (original.exactly_equal (reconstructed)); } MpfrScalarStorage positive_zero (0.0, 512); MpfrScalarStorage negative_zero (-0.0, 512); MpfrScalarStorage positive_infinity ( std::numeric_limits::infinity (), 512); MpfrScalarStorage negative_infinity ( -std::numeric_limits::infinity (), 512); MpfrScalarStorage not_a_number ( std::numeric_limits::quiet_NaN (), 512); assert (positive_zero.to_canonical_string () == "0"); assert (negative_zero.to_canonical_string () == "-0"); assert (positive_infinity.to_canonical_string () == "Inf"); assert (negative_infinity.to_canonical_string () == "-Inf"); assert (not_a_number.to_canonical_string () == "NaN"); assert (double_bits (positive_zero.to_double ()) == double_bits (0.0)); assert (double_bits (negative_zero.to_double ()) == double_bits (-0.0)); assert (std::isinf (positive_infinity.to_double ()) && positive_infinity.to_double () > 0.0); assert (std::isinf (negative_infinity.to_double ()) && negative_infinity.to_double () < 0.0); assert (std::isnan (not_a_number.to_double ())); const double binary64_values[] = { 0.0, -0.0, 1.0, -1.0, 0.5, 0.1, std::numeric_limits::min (), std::numeric_limits::max (), std::numeric_limits::denorm_min (), std::nextafter (1.0, 2.0) }; for (const double value : binary64_values) { MpfrScalarStorage stored (value, 512); assert (double_bits (stored.to_double ()) == double_bits (value)); } MpfrScalarStorage halfway ( "1.00000000000000011102230246251565404236316680908203125", 256); assert (double_bits (halfway.to_double ()) == double_bits (1.0)); MpfrScalarStorage overflow ("1e10000", 256); MpfrScalarStorage underflow ("1e-10000", 256); MpfrScalarStorage negative_underflow ("-1e-10000", 256); assert (std::isinf (overflow.to_double ())); assert (double_bits (underflow.to_double ()) == double_bits (0.0)); assert (double_bits (negative_underflow.to_double ()) == double_bits (-0.0)); const mpfr_rnd_t saved_rounding = mpfr_get_default_rounding_mode (); mpfr_set_default_rounding_mode (MPFR_RNDD); const std::string downward_text = halfway.to_canonical_string (); const std::uint64_t downward_double = double_bits (halfway.to_double ()); mpfr_set_default_rounding_mode (MPFR_RNDU); assert (halfway.to_canonical_string () == downward_text); assert (double_bits (halfway.to_double ()) == downward_double); mpfr_set_default_rounding_mode (saved_rounding); MpfrScalarStorage large ("0.1", 8192); const std::string large_text = large.to_canonical_string (); MpfrScalarStorage large_round_trip (large_text, 8192); assert (large.exactly_equal (large_round_trip)); assert (large.to_double () == 0.1); } void test_contiguous_container_and_stress () { constexpr std::size_t iterations = 10000; const mpfr_prec_t precisions[] = {128, 256, 512}; const char *texts[] = {"0.125", "1.5", "-2.25", "0.1"}; std::vector values; for (std::size_t i = 0; i < iterations; ++i) { const mpfr_prec_t precision = precisions[i % 3]; const char *text = texts[i % 4]; values.emplace_back (text, precision); MpfrScalarStorage copy (values.back ()); assert (copy.precision_bits () == precision); assert (copy.exactly_equal (values.back ())); const std::string canonical = copy.to_canonical_string (); MpfrScalarStorage reconstructed (canonical, precision); assert (copy.exactly_equal (reconstructed)); static_cast (copy.to_double ()); if ((i % 17) == 0) { MpfrScalarStorage moved (std::move (copy)); assert (moved.precision_bits () == precision); assert (moved.exactly_equal_string (text)); } } assert (values.size () == iterations); for (std::size_t i = 0; i < values.size (); i += 97) { assert (values[i].precision_bits () == precisions[i % 3]); assert (values[i].exactly_equal_string (texts[i % 4])); } std::vector copied = values; assert (copied.size () == values.size ()); values.clear (); assert (copied.front ().exactly_equal_string ("0.125")); } } // namespace int main () { test_precision_configuration_and_conversion (); test_basic_ownership (); test_precision_and_parsing (); test_double_construction_and_special_values (); test_constructor_rounding_is_explicit (); test_canonical_conversion_and_double_conversion (); test_contiguous_container_and_stress (); return 0; } mplapack-interop-0.5.1/test/chol.tst0000644000230300031750000001455015274353472016710 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_matrix_close (value, expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! got = __mplapack_core__ ("matrix_test_element_double", ... %! value, row, column); %! assert (got, expected(row, column), 1e-12); %! endfor %! endfor %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! upper_input = mp ({"4", "2"; "999", "10"}); %! [R, p] = chol (upper_input); %! assert (isa (R, "mp")); %! assert (class (p), "double"); %! assert (p, 0); %! assert_matrix_close (R, [2, 1; 0, 3]); %! lower_input = mp ({"4", "999"; "2", "10"}); %! [L, p_lower] = chol (lower_input, "lower"); %! assert (p_lower, 0); %! assert_matrix_close (L, [2, 0; 1, 3]); %! assert_matrix_close (chol (upper_input, "upper"), [2, 1; 0, 3]); %! L2 = chol (mp ({"4", "2"; "2", "10"}), "lower"); %! assert_matrix_close (L2, [2, 0; 1, 3]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ({"1", "2"; "2", "1"}); %! [R, p] = chol (A); %! assert (p, 2); %! assert (size (R), [1, 1]); %! assert (__mplapack_core__ ("scalar_test_equal_double", R, 1)); %! fail ("chol (A)", "not positive definite"); %! [R2, p2] = chol (mp ({"4", "0", "0"; "0", "-1", "0"; ... %! "0", "0", "9"})); %! assert (p2, 2); %! assert (size (R2), [1, 1]); %! assert (__mplapack_core__ ("scalar_test_equal_double", R2, 2)); %! fail ("chol (mp ([1, 2; 2, 1]))", "not positive definite"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! [x, p] = chol (mp ("4")); %! assert (isa (x, "mp")); %! assert (__mplapack_core__ ("value_shape_info", x).is_matrix, false); %! assert (p, 0); %! assert (__mplapack_core__ ("scalar_test_equal_double", x, 2)); %! [z, zp] = chol (mp ("0")); %! assert (zp, 1); %! assert (size (z), [0, 0]); %! fail ("chol (mp (\"0\"))", "not positive definite"); %! [n, np] = chol (mp ("-1")); %! assert (np, 1); %! assert (size (n), [0, 0]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"4", "2"; "999", "10"}); %! before = double (A); %! [R, p] = chol (A); %! assert (p, 0); %! assert (double (A), before); %! assert (__mplapack_core__ ("matrix_test_info", R).precision_bits, ... %! uint64 (256)); %! clear A; %! assert (__mplapack_core__ ("matrix_test_element_double", R, 1, 1), 2); %! C = mp ({"4", "2"; "999", "10"}); %! mpbits (4096); %! [R_high, p_high] = chol (C); %! assert (p_high, 0); %! assert (__mplapack_core__ ("matrix_test_info", R_high).precision_bits, ... %! uint64 (256)); %! ## The source was constructed before the higher ambient default. %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! delta_text = strcat (".", repmat ("0", 1, 210), "1"); %! mpbits (1024); %! one_plus_delta = strcat ("1", delta_text); %! A = mp ({"1", "1"; "1", one_plus_delta}); %! mpbits (128); %! [R, p] = chol (A); %! assert (p, 0); %! assert (__mplapack_core__ ("matrix_test_info", R).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_element_double", R, 1, 1), 1); %! assert (__mplapack_core__ ("matrix_test_element_double", R, 1, 2), 1); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! R, 2, 1, 0)); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! delta_2048 = strcat (".", repmat ("0", 1, 451), "1"); %! mpbits (2048); %! one_plus_delta_2048 = strcat ("1", delta_2048); %! A2 = mp ({"1", "1"; "1", one_plus_delta_2048}); %! mpbits (128); %! [R2, p2] = chol (A2, "lower"); %! assert (p2, 0); %! assert (__mplapack_core__ ("matrix_test_info", R2).precision_bits, ... %! uint64 (2048)); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! delta_text = strcat (".", repmat ("0", 1, 210), "1"); %! mpbits (512); %! one_plus_delta = strcat ("1", delta_text); %! A512 = mp ({"1", "1"; "1", one_plus_delta}); %! [R512, p512] = chol (A512); %! assert (p512 > 0); %! mpbits (1024); %! A1024 = mp ({"1", "1"; "1", one_plus_delta}); %! mpbits (128); %! [R1024, p1024] = chol (A1024); %! assert (p1024, 0); %! assert (__mplapack_core__ ("matrix_test_info", R1024).precision_bits, ... %! uint64 (1024)); %! assert (size (R512), [1, 1]); %! assert (__mplapack_core__ ("scalar_test_equal_double", R512, 1)); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! A = mp ([4, 2; NaN, 10]); %! [R, p] = chol (A); %! assert (p, 0); %! assert_matrix_close (R, [2, 1; 0, 3]); %! B = mp ([4, NaN; 2, 10]); %! [L, p2] = chol (B, "lower"); %! assert (p2, 0); %! assert_matrix_close (L, [2, 0; 1, 3]); %! upper_inf = mp ([4, 2; Inf, 10]); %! [R_inf, p_inf] = chol (upper_inf); %! assert (p_inf, 0); %! assert_matrix_close (R_inf, [2, 1; 0, 3]); %! lower_inf = mp ([4, -Inf; 2, 10]); %! [L_inf, p_inf_lower] = chol (lower_inf, "lower"); %! assert (p_inf_lower, 0); %! assert_matrix_close (L_inf, [2, 0; 1, 3]); %! S = mp ({"4", "2"; "2", "10"}); %! R = chol (S); %! C = R.' * R; %! assert_matrix_close (C, [4, 2; 2, 10]); %! L = chol (S, "lower"); %! C2 = L * L.'; %! assert_matrix_close (C2, [4, 2; 2, 10]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({"1", "2", "3"; "4", "5", "6"}); %! fail ("chol (A)", "requires a square"); %! fail ("chol (A, \"foo\")", "upper.*lower"); %! fail ("[R,p,Q] = chol (mp (\"4\"))", "at most a factor"); mplapack-interop-0.5.1/test/mp_matrix_arithmetic_test.cc0000644000230300031750000001054515274353472023006 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_arithmetic.h" #include #include #include #include namespace { using octave_mplapack::MpfrElementwiseBinaryOperation; using octave_mplapack::MpfrElementwiseOperand; using octave_mplapack::MpfrMatrixStorage; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void check_text (const MpfrMatrixStorage& value, const std::vector& expected) { check (value.numel () == expected.size (), "unexpected element count"); for (std::size_t column = 0; column < value.columns (); ++column) for (std::size_t row = 0; row < value.rows (); ++row) { const std::size_t index = row + column * value.rows (); check (value.element_exactly_equal_text (row, column, expected[index]), "unexpected element value"); } } MpfrMatrixStorage binary (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs, MpfrElementwiseBinaryOperation operation) { return octave_mplapack::mpfr_matrix_elementwise_binary ( MpfrElementwiseOperand::from_matrix (lhs), MpfrElementwiseOperand::from_matrix (rhs), operation); } } // namespace int main () { try { const MpfrMatrixStorage values ( 2, 3, 256, std::vector {"1", "4", "2", "5", "3", "6"}); const MpfrMatrixStorage other ( 2, 3, 512, std::vector {"10", "40", "20", "50", "30", "60"}); const auto sum = binary (values, other, MpfrElementwiseBinaryOperation::add); check (sum.precision_bits () == 512, "addition precision mismatch"); check_text (sum, {"11", "44", "22", "55", "33", "66"}); const auto difference = binary ( other, values, MpfrElementwiseBinaryOperation::subtract); check_text (difference, {"9", "36", "18", "45", "27", "54"}); const auto product = binary ( values, other, MpfrElementwiseBinaryOperation::multiply); check_text (product, {"10", "160", "40", "250", "90", "360"}); const auto quotient = binary ( other, values, MpfrElementwiseBinaryOperation::divide); check_text (quotient, {"10", "10", "10", "10", "10", "10"}); const MpfrMatrixStorage row ( 1, 3, 256, std::vector {"10", "20", "30"}); const MpfrMatrixStorage column ( 2, 1, 256, std::vector {"100", "200"}); const auto broadcast = binary ( column, row, MpfrElementwiseBinaryOperation::add); check (broadcast.rows () == 2 && broadcast.columns () == 3, "broadcast shape mismatch"); check_text (broadcast, {"110", "210", "120", "220", "130", "230"}); const octave_mplapack::MpfrScalarStorage scalar_value ("2", 256); const MpfrElementwiseOperand scalar = MpfrElementwiseOperand::from_scalar (scalar_value); const auto scaled = octave_mplapack::mpfr_matrix_elementwise_binary ( MpfrElementwiseOperand::from_matrix (values), scalar, MpfrElementwiseBinaryOperation::multiply); check_text (scaled, {"2", "8", "4", "10", "6", "12"}); const auto negated = octave_mplapack::mpfr_matrix_negate (values); check_text (negated, {"-1", "-4", "-2", "-5", "-3", "-6"}); const MpfrMatrixStorage empty (2, 0, 333); const MpfrMatrixStorage empty_row (1, 0, 333); const auto empty_result = binary ( empty, empty_row, MpfrElementwiseBinaryOperation::add); check (empty_result.rows () == 2 && empty_result.columns () == 0, "empty broadcast shape mismatch"); check (empty_result.precision_bits () == 333, "empty broadcast precision mismatch"); bool mismatch = false; try { const MpfrMatrixStorage bad (4, 3, 256); (void) binary (values, bad, MpfrElementwiseBinaryOperation::add); } catch (const std::invalid_argument&) { mismatch = true; } check (mismatch, "incompatible shape unexpectedly succeeded"); std::cout << "PASS: native element-wise arithmetic, broadcasting, " "precision, empty shapes, and error handling\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/precision.tst0000644000230300031750000001463415274353472017761 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function info = m04_precision_info (value) %! info = __mplapack_core__ ("scalar_test_info", value); %!endfunction %!function m04_expect_precision_error (operation, expected_identifier) %! before = mpbits (); %! try %! operation (); %! error ("M04 invalid precision unexpectedly succeeded"); %! catch exception %! assert (strcmp (exception.identifier, expected_identifier)); %! end_try_catch %! assert (mpbits (), before); %!endfunction %!test %! assert (mpbits (), uint64 (512)); %! assert (mpdigits (), uint64 (154)); %! assert (isa (mpbits (), "uint64")); %! assert (isa (mpdigits (), "uint64")); %! assert (__mplapack_core__ ("module_test_locked")); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! mpdigits (100); %! value = mp ("0.1"); %! assert (m04_precision_info (value).precision_bits, int64 (333)); %! assert (__mplapack_core__ ( %! "precision_test_mpfr_global_bits"), uint64 (333)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! assert (mpbits (128), uint64 (128)); %! assert (mpbits (), uint64 (128)); %! assert (mpdigits (), uint64 (38)); %! assert (mpbits (256), uint64 (256)); %! assert (mpbits (), uint64 (256)); %! assert (mpbits (512), uint64 (512)); %! assert (mpdigits (), uint64 (154)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! requests = uint64 ([1, 10, 38, 100, 1000]); %! expected_bits = uint64 ([4, 34, 127, 333, 3322]); %! for i = 1:numel (requests) %! assert (mpdigits (requests(i)), requests(i)); %! assert (mpbits (), expected_bits(i)); %! assert (mpdigits (), requests(i)); %! endfor %! mpbits (332); %! assert (mpdigits (), uint64 (99)); %! mpbits (333); %! assert (mpdigits (), uint64 (100)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! value_128 = mp ("0.1"); %! mpbits (256); %! value_256 = mp ("0.1"); %! mpbits (512); %! value_512 = mp ("0.1"); %! assigned = value_128; %! copied = mp (value_128); %! assert (m04_precision_info (value_128).precision_bits, int64 (128)); %! assert (m04_precision_info (value_256).precision_bits, int64 (256)); %! assert (m04_precision_info (value_512).precision_bits, int64 (512)); %! assert (m04_precision_info (assigned).precision_bits, int64 (128)); %! assert (m04_precision_info (copied).precision_bits, int64 (128)); %! assert (__mplapack_core__ ( %! "scalar_test_equal_string", value_128, "0.1")); %! assert (__mplapack_core__ ( %! "scalar_test_equal", value_128, assigned)); %! assert (__mplapack_core__ ( %! "scalar_test_equal", value_128, copied)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! assert (mpdigits (100), uint64 (100)); %! assert (mpbits (), uint64 (333)); %! value = mp ("1"); %! assert (m04_precision_info (value).precision_bits, int64 (333)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for bits = [128, 256, 512] %! mpbits (bits); %! decimal = mp ("0.1"); %! binary64 = mp (0.1); %! assert (! __mplapack_core__ ( %! "scalar_test_equal", decimal, binary64)); %! dyadic_text = mp ("0.125"); %! dyadic_double = mp (0.125); %! assert (__mplapack_core__ ( %! "scalar_test_equal", dyadic_text, dyadic_double)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! assert (mpbits (uint8 (64)), uint64 (64)); %! assert (mpbits (uint32 (256)), uint64 (256)); %! assert (mpbits (int64 (512)), uint64 (512)); %! assert (mpbits (single (1024)), uint64 (1024)); %! assert (mpdigits (uint64 (100)), uint64 (100)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! maximum_bits = uint64 (intmax ("int64")) - uint64 (256); %! assert (mpbits (uint64 (1)), uint64 (1)); %! assert (mpbits (maximum_bits), maximum_bits); %! maximum_digits = mpdigits (); %! assert (mpdigits (maximum_digits), maximum_digits); %! assert (mpbits () <= maximum_bits); %! m04_expect_precision_error ( %! @() mpdigits (maximum_digits + uint64 (1)), %! "mplapack:mpdigits:PrecisionOverflow"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! invalid_id = "mplapack:mpbits:InvalidPrecision"; %! m04_expect_precision_error (@() mpbits (0), invalid_id); %! m04_expect_precision_error (@() mpbits (-1), invalid_id); %! m04_expect_precision_error (@() mpbits (128.5), invalid_id); %! m04_expect_precision_error (@() mpbits (NaN), invalid_id); %! m04_expect_precision_error (@() mpbits (Inf), invalid_id); %! m04_expect_precision_error (@() mpbits (1 + 2i), invalid_id); %! m04_expect_precision_error (@() mpbits ([128, 256]), invalid_id); %! m04_expect_precision_error (@() mpbits (ones (2)), invalid_id); %! m04_expect_precision_error (@() mpbits ("128"), invalid_id); %! m04_expect_precision_error (@() mpbits ({128}), invalid_id); %! m04_expect_precision_error (@() mpbits (struct ()), invalid_id); %! m04_expect_precision_error (@() mpbits (2^53 + 2), invalid_id); %! m04_expect_precision_error ( %! @() mpbits (intmax ("int64")), %! "mplapack:mpbits:PrecisionOverflow"); %! assert (mpbits (), uint64 (256)); %! %! digits_id = "mplapack:mpdigits:InvalidPrecision"; %! m04_expect_precision_error (@() mpdigits (0), digits_id); %! m04_expect_precision_error (@() mpdigits (-1), digits_id); %! m04_expect_precision_error (@() mpdigits (10.5), digits_id); %! m04_expect_precision_error (@() mpdigits (NaN), digits_id); %! m04_expect_precision_error (@() mpdigits (Inf), digits_id); %! m04_expect_precision_error (@() mpdigits (1 + 2i), digits_id); %! m04_expect_precision_error (@() mpdigits ([10, 20]), digits_id); %! m04_expect_precision_error ( %! @() mpdigits (intmax ("int64")), %! "mplapack:mpdigits:PrecisionOverflow"); %! assert (mpbits (), uint64 (256)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!error mpbits (1, 2) %!error mpdigits (1, 2) mplapack-interop-0.5.1/test/test_neigt24.m0000644000230300031750000000335015274353472017714 0ustar rafaelrafael% NEIGT24: numbered examples and documentation/example-runner integration. test_root = fileparts (fileparts (mfilename ("fullpath"))); example_root = fullfile (test_root, "examples"); tier_root = fullfile (example_root, "neig_tiers"); addpath (tier_root); neigt24_saved_ambient_bits = mpbits (); unwind_protect mpbits (768); numbered = {"14_neig_tier_s.m", "15_neig_tier_a.m", ... "16_neig_verified_vs.m", "17_neig_verified_va.m"}; for numbered_index = 1:numel (numbered) path_name = fullfile (example_root, numbered{numbered_index}); assert (exist (path_name, "file") == 2); clear result; run (path_name); assert (exist ("result", "var") == 1 && isstruct (result)); assert (mpbits () == uint64 (768)); assert (result.scope_ok && result.ok); assert (! isfield (result, "used_binary64_fallback") ... || ! result.used_binary64_fallback); if (numbered_index <= 2) assert (any (strcmp (result.status, {"NUMERICS_COMPLETE", ... "NUMERICS_ONLY_COMPLETE"}))); assert (result.coverage.measured_eig_rows > 0); else assert (result.coverage.verification_job_count > 0); assert (strcmp (result.status, "COMPLETE")); endif endfor % The numbered examples are documented entry points, while these are the % exact replay APIs. Keep the help text available in a source checkout. for name = {"mp_neig_tiers", "mp_neig_verify_examples", ... "mp_neig_write_outputs", "mp_neig_replay"} help_text = evalc (sprintf ("help %s", name{1})); assert (! isempty (strfind (help_text, "NEIGT"))); endfor fprintf ("PASS: NEIGT24 numbered Tier-S/Tier-A/V-S/V-A examples and help integration\n"); unwind_protect_cleanup mpbits (neigt24_saved_ambient_bits); end_unwind_protect mplapack-interop-0.5.1/test/t04_exact_sets.tst0000644000230300031750000000540415274353472020612 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! a = mp ({'3','1','3','2'}); %! [u,ia,inv] = unique (a); %! assert (double (norm (u-mp ([1,2,3]), "fro")) < 1e-50); %! assert (ia == [2;4;1]); %! assert (inv == [3;1;3;2]); %! [us,is,js] = unique (a, "stable"); %! assert (double (norm (us-mp ([3,1,2]), "fro")) < 1e-50); %! assert (is == [1;2;4]); %! assert (js == [1;2;1;3]); %! b = mp ({'2','4','1'}); %! [u,ua,ub] = union (a,b); %! assert (double (norm (u-mp ([1,2,3,4]), "fro")) < 1e-50); %! assert (ua == [2;4;1] && ub == 2); %! [u,ua,ub] = union (a,b, "stable"); %! assert (double (norm (u-mp ([3,1,2,4]), "fro")) < 1e-50); %! assert (ua == [1;2;4] && ub == 2); %! [i,ia,ib] = intersect (a,b); %! assert (double (norm (i-mp ([1,2]), "fro")) < 1e-50); %! assert (ia == [2;4] && ib == [3;1]); %! [d,di] = setdiff (a,b, "stable"); %! assert (double (norm (d-mp ('3'), "fro")) < 1e-50); %! assert (di == 1); %! [x,xi,xj] = setxor (a,b); %! assert (double (norm (x-mp ([3,4]), "fro")) < 1e-50); %! assert (xi == 1 && xj == 2); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! C = [mp('1','2'),mp('2','-1');mp('1','2'),mp('3','0')]; %! [u,ia,inv] = unique (C, "rows"); %! assert (size (u) == [2,2]); %! assert (ia == [1;2]); %! assert (inv == [1;2]); %! B = [mp('3','0'),mp('0','1');mp('1','2'),mp('2','-1')]; %! [u,ua,ub] = union (C,B,"rows","stable"); %! assert (size (u) == [3,2]); %! assert (ua == [1;2] && ub == 1); %! [i,ia,ib] = intersect (C,B,"rows"); %! assert (size (i) == [1,2]); %! assert (ia == 1 && ib == 2); %! [tf,loc] = ismember (C,B,"rows"); %! assert (tf == [true;false]); %! assert (loc == [2;0]); %! [d,di] = setdiff (C,B,"rows","stable"); %! assert (size (d) == [1,2] && di == 2); %! [x,xi,xj] = setxor (C,B,"rows","stable"); %! assert (size (x) == [2,2] && xi == 2 && xj == 1); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! z = [mp('0'),mp('-0'),mp('Inf'),mp('-Inf'),mp('NaN'),mp('NaN')]; %! uz = unique (z, "stable"); %! assert (numel (uz) == 5); %! assert (isequaln (uz(1),mp('0'))); %! assert (isinf (uz(2)) && isinf (uz(3))); %! assert (isnan (uz(4)) && isnan (uz(5))); %! [tf,loc] = ismember (mp('NaN'),uz); %! assert (! tf && loc == 0); %! C = [mp('1','2'),mp('1','2')]; %! [tf,loc] = ismember (C, C); %! assert (tf == [true,true] && loc == [1,1]); %! empty = zeros (0,1,"like",C); %! assert (isempty (unique (empty))); %! assert (isempty (union (empty,empty))); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/mp_complex_lu_test.cc0000644000230300031750000002627515274353472021447 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include "mp_complex_lu.h" namespace { using Matrix = octave_mplapack::MpfrComplexMatrixStorage; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } std::complex as_double (const Matrix& matrix, std::size_t row, std::size_t column) { return octave_mplapack::MpfrComplexScalarStorage ( matrix.at (row, column)).to_double (); } void set_real (mpc_ptr value, unsigned long integer) { mpfr_set_ui (mpc_realref (value), integer, MPFR_RNDN); mpfr_set_zero (mpc_imagref (value), 0); } void check_close (const Matrix& matrix, std::size_t row, std::size_t column, std::complex expected, const char *message) { check (std::abs (as_double (matrix, row, column) - expected) < 1.0e-12, message); } void check_zero (const Matrix& matrix, std::size_t row, std::size_t column, const char *message) { const auto& value = matrix.at (row, column); check (mpfr_zero_p (mpc_realref (value.mpc_data ())) != 0 && mpfr_zero_p (mpc_imagref (value.mpc_data ())) != 0, message); } void check_raw_reconstruction ( const Matrix& input, const Matrix& lower, const Matrix& upper, const std::vector& permutation, const char *message) { const double tolerance = 1.0e-10; check (permutation.size () == input.rows (), "complex LU permutation shape mismatch"); for (std::size_t column = 0; column < input.columns (); ++column) for (std::size_t row = 0; row < input.rows (); ++row) { std::complex product {0.0, 0.0}; for (std::size_t inner = 0; inner < lower.columns (); ++inner) product += as_double (lower, row, inner) * as_double (upper, inner, column); const auto source = static_cast ( permutation[row] - static_cast (1)); check (source < input.rows () && std::abs (product - as_double (input, source, column)) < tolerance, message); } } void check_factor_shapes (const Matrix& input, const octave_mplapack::MpcLuResult& result, const char *message) { const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t k = std::min (m, n); check (result.packed.rows () == m && result.packed.columns () == n && result.lower.rows () == m && result.lower.columns () == k && result.upper.rows () == k && result.upper.columns () == n, message); } void test_square_and_rectangular_shapes () { const Matrix square (2, 2, 512, std::vector> { {1.0, 1.0}, {3.0, -1.0}, {2.0, 2.0}, {4.0, 0.0}}); const auto before = square; const auto result = octave_mplapack::mplapack_mpc_matrix_lu (square); check (result.info == 0, "square complex LU unexpectedly failed"); check_factor_shapes (square, result, "square complex LU shape mismatch"); check (result.permutation.size () == 2 && result.permutation[0] == 2 && result.permutation[1] == 1, "square complex LU permutation mismatch"); check_close (result.packed, 0, 0, {3.0, -1.0}, "square complex LU pivot mismatch"); check_close (result.lower, 0, 0, {1.0, 0.0}, "complex LU lower unit diagonal mismatch"); check_close (result.lower, 1, 0, {0.2, 0.4}, "complex LU multiplier mismatch"); check_close (result.upper, 0, 1, {4.0, 0.0}, "complex LU upper entry mismatch"); check_close (result.upper, 1, 1, {1.2, 0.4}, "complex LU trailing pivot mismatch"); check_zero (result.lower, 0, 1, "complex LU lower upper entry not zero"); check_zero (result.upper, 1, 0, "complex LU upper lower entry not zero"); check_raw_reconstruction (square, result.lower, result.upper, result.permutation, "square complex LU reconstruction mismatch"); check (square.element_exactly_equal (0, 0, before, 0, 0) && square.element_exactly_equal (1, 1, before, 1, 1), "complex Cgetrf modified public input"); const Matrix tall (3, 2, 512, std::vector> { {1.0, 0.0}, {5.0, 1.0}, {3.0, -1.0}, {2.0, 2.0}, {4.0, 0.0}, {6.0, 1.0}}); const auto tall_result = octave_mplapack::mplapack_mpc_matrix_lu (tall); check_factor_shapes (tall, tall_result, "tall complex LU shape mismatch"); check_raw_reconstruction (tall, tall_result.lower, tall_result.upper, tall_result.permutation, "tall complex LU reconstruction mismatch"); const Matrix wide (2, 3, 512, std::vector> { {1.0, 0.0}, {3.0, 1.0}, {2.0, -1.0}, {4.0, 0.0}, {5.0, 2.0}, {6.0, -1.0}}); const auto wide_result = octave_mplapack::mplapack_mpc_matrix_lu (wide); check_factor_shapes (wide, wide_result, "wide complex LU shape mismatch"); check_raw_reconstruction (wide, wide_result.lower, wide_result.upper, wide_result.permutation, "wide complex LU reconstruction mismatch"); } void test_precision_and_scope () { mpfrxx::set_default_precision_bits (128); for (const auto setting : {std::array {{1024, -700}}, std::array {{2048, -1500}}}) { const mpfr_prec_t precision = static_cast (setting[0]); Matrix input (2, 2, precision); set_real (input.at (0, 0).mpc_data (), 4); set_real (input.at (0, 1).mpc_data (), 2); set_real (input.at (1, 0).mpc_data (), 1); Real delta = Real::with_precision (precision); mpfr_set_ui_2exp (delta.mpfr_data (), 1, setting[1], MPFR_RNDN); mpfr_add (mpc_realref (input.at (1, 0).mpc_data ()), mpc_realref (input.at (1, 0).mpc_data ()), delta.mpfr_data (), MPFR_RNDN); set_real (input.at (1, 1).mpc_data (), 3); const auto before = input; const auto result = octave_mplapack::mplapack_mpc_matrix_lu (input); check (result.info == 0 && result.packed.precision_bits () == precision && result.lower.precision_bits () == precision && result.upper.precision_bits () == precision && result.packed.all_elements_have_uniform_precision (), "complex LU precision metadata mismatch"); Real expected = Real::with_precision (precision); mpfr_set_ui (expected.mpfr_data (), 1, MPFR_RNDN); mpfr_div_ui (expected.mpfr_data (), expected.mpfr_data (), 4, MPFR_RNDN); Real tail = Real::with_precision (precision); mpfr_set_ui_2exp (tail.mpfr_data (), 1, setting[1] - 2, MPFR_RNDN); mpfr_add (expected.mpfr_data (), expected.mpfr_data (), tail.mpfr_data (), MPFR_RNDN); check (mpfr_equal_p (mpc_realref (result.lower.at (1, 0).mpc_data ()), expected.mpfr_data ()) != 0, "complex LU multiplier tail was not preserved"); check (input.element_exactly_equal (0, 0, before, 0, 0) && input.element_exactly_equal (1, 0, before, 1, 0), "complex Cgetrf modified input storage"); check (mpfrxx::default_precision_bits () == 128, "complex Cgetrf leaked ambient precision"); } mpfrxx::set_default_precision_bits (4096); const Matrix low_precision (2, 2, 256, std::vector> { {1.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {2.0, 0.0}}); const auto result = octave_mplapack::mplapack_mpc_matrix_lu (low_precision); check (result.packed.precision_bits () == 256 && mpfrxx::default_precision_bits () == 4096, "complex LU changed operation precision from ambient precision"); } void test_precision_dependent_pivot () { Matrix low (2, 2, 512); Matrix high (2, 2, 1024); for (Matrix* input : {&low, &high}) { set_real (input->at (0, 0).mpc_data (), 1); set_real (input->at (1, 0).mpc_data (), 1); Real delta = Real::with_precision (input->precision_bits ()); mpfr_set_ui_2exp (delta.mpfr_data (), 1, -700, MPFR_RNDN); mpfr_add (mpc_realref (input->at (1, 0).mpc_data ()), mpc_realref (input->at (1, 0).mpc_data ()), delta.mpfr_data (), MPFR_RNDN); set_real (input->at (0, 1).mpc_data (), 0); set_real (input->at (1, 1).mpc_data (), 1); } const auto low_result = octave_mplapack::mplapack_mpc_matrix_lu (low); const auto high_result = octave_mplapack::mplapack_mpc_matrix_lu (high); check (low_result.permutation.at (0) == 1 && high_result.permutation.at (0) == 2, "precision-dependent complex LU pivot mismatch"); } void test_singular_empty_and_lifetime () { const Matrix singular (2, 2, 256, std::vector> { {1.0, 0.0}, {2.0, 0.0}, {2.0, 0.0}, {4.0, 0.0}}); const auto result = octave_mplapack::mplapack_mpc_matrix_lu (singular); check (result.info == 2 && result.permutation.at (0) == 2 && result.packed.rows () == 2 && result.upper.rows () == 2, "singular complex LU status or partial factors mismatch"); check_raw_reconstruction (singular, result.lower, result.upper, result.permutation, "singular complex LU partial reconstruction mismatch"); const Matrix empty (0, 3, 512); const auto empty_result = octave_mplapack::mplapack_mpc_matrix_lu (empty); check (empty_result.info == 0 && empty_result.packed.rows () == 0 && empty_result.packed.columns () == 0 && empty_result.lower.rows () == 0 && empty_result.upper.rows () == 0 && empty_result.permutation.empty (), "empty complex LU result mismatch"); Matrix scoped_input (2, 2, 512, std::vector> { {4.0, 0.0}, {1.0, 2.0}, {2.0, -1.0}, {3.0, 0.0}}); auto retained = octave_mplapack::mplapack_mpc_matrix_lu (scoped_input); scoped_input = Matrix (0, 0, 512); check (retained.packed.rows () == 2 && retained.packed.columns () == 2 && retained.packed.all_elements_have_uniform_precision (), "complex LU result did not retain operation-owned storage"); } } // namespace int main () { try { test_square_and_rectangular_shapes (); test_precision_and_scope (); test_precision_dependent_pivot (); test_singular_empty_and_lifetime (); std::cout << "PASS: complex Cgetrf LU packed/two-factor shapes, row permutations, rectangular and singular behavior, source-precision pivots, ambient scope, immutability, and lifetime\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/structure.tst0000644000230300031750000002141015274353472020014 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function info = structure_info (value) %! if (__mplapack_core__ ("value_is_matrix", value)) %! info = __mplapack_core__ ("matrix_test_info", value); %! else %! info = __mplapack_core__ ("scalar_test_info", value); %! endif %!endfunction %!function assert_matrix_text (value, expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! value, row, column, expected{row, column})); %! endfor %! endfor %!endfunction %!test %! x = mp ("1.25"); %! assert_scalar_text = @(value, text) ... %! __mplapack_core__ ("scalar_test_equal_string", value, text); %! assert (assert_scalar_text (transpose (x), "1.25")); %! assert (assert_scalar_text (ctranspose (x), "1.25")); %! assert (structure_info (transpose (x)).precision_bits, int64 (512)); %! assert (! __mplapack_core__ ("value_is_matrix", transpose (x))); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"11", "12", "13"; "21", "22", "23"}); %! T = A.'; %! H = A'; %! assert_matrix_text (T, {"11", "21"; "12", "22"; "13", "23"}); %! assert_matrix_text (H, {"11", "21"; "12", "22"; "13", "23"}); %! assert (size (T), [3, 2]); %! assert (structure_info (T).precision_bits, uint64 (256)); %! assert_matrix_text (T.', {"11", "12", "13"; "21", "22", "23"}); %! assert_matrix_text (H', {"11", "12", "13"; "21", "22", "23"}); %! row = mp ({"1", "2", "3"}); %! column = row.'; %! assert (size (column), [3, 1]); %! assert_matrix_text (column, {"1"; "2"; "3"}); %! assert_matrix_text (column.', {"1", "2", "3"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"11", "12", "13"; "21", "22", "23"}); %! R = reshape (A, 3, 2); %! V = reshape (A, [3, 2]); %! row = reshape (A, 1, 6); %! column = reshape (A, 6, 1); %! inferred_rows = reshape (A, [], 2); %! inferred_columns = reshape (A, 2, []); %! expected_linear = {"11"; "21"; "12"; "22"; "13"; "23"}; %! assert_matrix_text (R, {"11", "22"; "21", "13"; "12", "23"}); %! assert_matrix_text (V, {"11", "22"; "21", "13"; "12", "23"}); %! assert_matrix_text (row, {"11", "21", "12", "22", "13", "23"}); %! assert_matrix_text (column, expected_linear); %! assert_matrix_text (inferred_rows, {"11", "22"; "21", "13"; "12", "23"}); %! assert_matrix_text (inferred_columns, {"11", "12", "13"; "21", "22", "23"}); %! assert_matrix_text (reshape (row, 2, 3), {"11", "12", "13"; ... %! "21", "22", "23"}); %! assert (structure_info (R).precision_bits, uint64 (256)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! scalar = mp ("7"); %! assert_scalar = reshape (scalar, 1, 1); %! assert (! __mplapack_core__ ("value_is_matrix", assert_scalar)); %! assert (__mplapack_core__ ("scalar_test_equal_string", assert_scalar, "7")); %! try %! reshape (scalar, 1, 2); %! error ("scalar reshape unexpectedly succeeded"); %! catch exception %! assert (strcmp (exception.identifier, "mplapack:mp:InvalidDimension")); %! end_try_catch %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! empty = mp (zeros (0, 3)); %! assert (size (empty.'), [3, 0]); %! assert (size (empty'), [3, 0]); %! assert (size (reshape (empty, 0, 3)), [0, 3]); %! assert (size (reshape (empty, 3, 0)), [3, 0]); %! assert (size (reshape (empty, [], 3)), [0, 3]); %! assert (size (reshape (empty, 3, [])), [3, 0]); %! empty_square = mp (zeros (0, 0)); %! assert (size (reshape (empty_square, 0, 0)), [0, 0]); %!test %! A = mp ({"1", "2"; "3", "4"}); %! try %! reshape (A, 3, 3); %! error ("reshape element mismatch unexpectedly succeeded"); %! catch exception %! assert (strcmp (exception.identifier, "mplapack:mp:InvalidDimension")); %! end_try_catch %! for bad = {[1, 2, 3], [-1, 4], [1.5, 4], [Inf, 4], [NaN, 4]} %! try %! reshape (A, bad{1}); %! error ("invalid reshape dimensions unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, ... %! "invalid reshape dimensions unexpectedly succeeded")); %! assert (strcmp (exception.identifier, "mplapack:mp:InvalidDimension")); %! end_try_catch %! endfor %! try %! reshape (A, [], []); %! error ("two inferred dimensions unexpectedly succeeded"); %! catch exception %! assert (strcmp (exception.identifier, "mplapack:mp:InvalidDimension")); %! end_try_catch %! try %! reshape (A, 2, 2, 1); %! error ("N-D reshape unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, "N-D reshape unexpectedly succeeded")); %! end_try_catch %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! tail = strcat ("1.", repmat ("0", 1, 210), "1"); %! A = mp ({tail, "0"; "0", "1"}); %! mpbits (128); %! T = A.'; %! H = A'; %! R = reshape (A, 1, 4); %! assert (structure_info (T).precision_bits, uint64 (1024)); %! assert (structure_info (H).precision_bits, uint64 (1024)); %! assert (structure_info (R).precision_bits, uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_element_equal", T, 1, 1, ... %! A, 1, 1)); %! assert (__mplapack_core__ ("matrix_test_element_equal", H, 1, 1, ... %! A, 1, 1)); %! assert (__mplapack_core__ ("matrix_test_element_equal", R, 1, 1, ... %! A, 1, 1)); %! assert (mpbits (), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! mpbits (4096); %! assert (structure_info (A.').precision_bits, uint64 (1024)); %! assert (structure_info (reshape (A, 2, 2)).precision_bits, uint64 (1024)); %! assert (mpbits (), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2048); %! tail = strcat ("1.", repmat ("0", 1, 450), "1"); %! A = mp ({tail, "0"; "0", "1"}); %! mpbits (128); %! T = A.'; %! R = reshape (A, 1, 4); %! assert (structure_info (T).precision_bits, uint64 (2048)); %! assert (structure_info (R).precision_bits, uint64 (2048)); %! assert (__mplapack_core__ ("matrix_test_element_equal", T, 1, 1, ... %! A, 1, 1)); %! assert (__mplapack_core__ ("matrix_test_element_equal", R, 1, 1, ... %! A, 1, 1)); %! assert (mpbits (), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! values = [11, 12, 13; 21, 22, 23]; %! A = mp (values); %! assert (size (double (A.')), [3, 2]); %! assert (double (reshape (A, 1, 6)), [11, 21, 12, 22, 13, 23]); %! transposed = A.'; %! assert (char (transposed (1, 1)), "1.1e+1"); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! A + mp ("1"), 1, 1, "12")); %! P = A.' * mp ({"1"; "1"}); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", P, 1, 1, "32")); %! S = reshape (mp ({"2", "0"; "0", "2"}), 2, 2); %! solved = S \ mp ({"4"; "6"}); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", solved, 1, 1, "2")); %!test %! plus_zero = mp (0.0); %! minus_zero = mp (-0.0); %! special = mp ({"0", "-0"; "Inf", "NaN"}); %! special_transposed = special.'; %! special_reshaped = reshape (special, 4, 1); %! assert (__mplapack_core__ ("scalar_test_info", special_transposed (1, 1)).is_zero); %! assert (! __mplapack_core__ ("scalar_test_info", ... %! special_transposed (1, 1)).signbit); %! assert (__mplapack_core__ ("scalar_test_info", ... %! special_transposed (2, 1)).signbit); %! assert (__mplapack_core__ ("scalar_test_info", ... %! special_transposed (1, 2)).is_infinite); %! assert (__mplapack_core__ ("scalar_test_info", ... %! special_transposed (2, 2)).is_nan); %! assert (__mplapack_core__ ("scalar_test_info", ... %! special_reshaped (1)).is_zero); %! assert (! __mplapack_core__ ("scalar_test_info", ... %! special_reshaped (1)).signbit); %! assert (__mplapack_core__ ("scalar_test_info", ... %! special_reshaped (2)).is_infinite); %! assert (__mplapack_core__ ("scalar_test_info", ... %! special_reshaped (3)).signbit); %! assert (__mplapack_core__ ("scalar_test_info", ... %! special_reshaped (4)).is_nan); %! assert (__mplapack_core__ ("scalar_test_info", plus_zero).is_zero); %! assert (__mplapack_core__ ("scalar_test_info", minus_zero).signbit); mplapack-interop-0.5.1/test/native_lifetime.m0000644000230300031750000000236015274353472020545 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause assert (! isempty (which ("__mplapack_core__"))); value = __mplapack_core__ ("scalar_test_create", "0.125", 128); assigned = value; cloned = __mplapack_core__ ("scalar_test_clone", value); collection = {value, assigned, cloned}; assert (__mplapack_core__ ("module_test_locked")); clear value __mplapack_core__; assert (strcmp (typeinfo (assigned), "mplapack_mpfr_scalar_internal")); printed = evalc ("disp (assigned)"); assert (! isempty (strfind (printed, "internal MPLAPACK MPFR scalar"))); clear printed; assert (__mplapack_core__ ("module_test_locked")); assigned_info = __mplapack_core__ ("scalar_test_info", assigned); clone_info = __mplapack_core__ ("scalar_test_info", cloned); cell_info = __mplapack_core__ ("scalar_test_info", collection{1}); assert (assigned_info.precision_bits == 128); assert (clone_info.precision_bits == 128); assert (cell_info.precision_bits == 128); assert (__mplapack_core__ ( "scalar_test_equal_string", assigned, "0.125")); assert (__mplapack_core__ ("scalar_test_equal", assigned, cloned)); clear assigned cloned collection assigned_info clone_info cell_info; assert (__mplapack_core__ ("module_test_locked")); fprintf ("PASS: locked-module clear and live-value lifecycle\n"); mplapack-interop-0.5.1/test/m18_qr_probe.cc0000644000230300031750000001153715274353472020036 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include namespace { using Real = mpfrxx::mpfr_class; Real at_precision (mpfr_prec_t precision) { return Real::with_precision (precision); } void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void set_power (Real& value, mpfr_exp_t exponent) { mpfr_set_ui_2exp (value.mpfr_data (), 1, exponent, MPFR_RNDN); } void run_case (mpfr_prec_t precision, mpfr_exp_t exponent) { constexpr mplapackint m = 3; constexpr mplapackint n = 2; constexpr mplapackint k = 2; std::vector query_a (m * n, at_precision (precision)); std::vector query_tau (k, at_precision (precision)); std::vector query_work (1, at_precision (precision)); set_power (query_a[4], exponent); mpfr_add_ui (query_a[4].mpfr_data (), query_a[4].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (query_a[0].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (query_a[3].mpfr_data (), 1, MPFR_RNDN); mplapackint info = 0; const auto before = mpfrxx::default_precision_bits (); { MplapackMpfrPrecisionScope scope (precision); Rgeqrf (m, n, query_a.data (), m, query_tau.data (), query_work.data (), -1, info); check (mpfrxx::default_precision_bits () == precision, "Rgeqrf query changed scoped precision"); } check (before == mpfrxx::default_precision_bits (), "Rgeqrf query leaked ambient precision"); check (info == 0, "Rgeqrf query failed"); check (mpfr_integer_p (query_work[0].mpfr_data ()) != 0 && mpfr_sgn (query_work[0].mpfr_data ()) > 0, "Rgeqrf query returned invalid workspace"); const auto lwork = static_cast ( mpfr_get_si (query_work[0].mpfr_data (), MPFR_RNDZ)); std::vector a (m * n, at_precision (precision)); std::vector tau (k, at_precision (precision)); std::vector work (lwork, at_precision (precision)); set_power (a[4], exponent); mpfr_add_ui (a[4].mpfr_data (), a[4].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (a[0].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (a[3].mpfr_data (), 1, MPFR_RNDN); { MplapackMpfrPrecisionScope scope (precision); Rgeqrf (m, n, a.data (), m, tau.data (), work.data (), lwork, info); } check (info == 0, "Rgeqrf solve failed"); Real expected = at_precision (precision); set_power (expected, exponent); mpfr_add_ui (expected.mpfr_data (), expected.mpfr_data (), 1, MPFR_RNDN); check (mpfr_equal_p (a[4].mpfr_data (), expected.mpfr_data ()) != 0, "Rgeqrf precision tail was not preserved"); std::vector q (m * m, at_precision (precision)); for (mplapackint column = 0; column < m; ++column) for (mplapackint row = 0; row < m; ++row) { if (column < n) mpfr_set (q[row + column * m].mpfr_data (), a[row + column * m].mpfr_data (), MPFR_RNDN); else mpfr_set_zero (q[row + column * m].mpfr_data (), 0); } std::vector query_qwork (1, at_precision (precision)); std::vector q_tau (tau); { MplapackMpfrPrecisionScope scope (precision); Rorgqr (m, m, k, q.data (), m, q_tau.data (), query_qwork.data (), -1, info); } check (info == 0, "Rorgqr query failed"); const auto q_lwork = static_cast ( mpfr_get_si (query_qwork[0].mpfr_data (), MPFR_RNDZ)); std::vector q_actual (q); std::vector q_work (q_lwork, at_precision (precision)); { MplapackMpfrPrecisionScope scope (precision); Rorgqr (m, m, k, q_actual.data (), m, q_tau.data (), q_work.data (), q_lwork, info); } check (info == 0, "Rorgqr solve failed"); check (mpfrxx::default_precision_bits () == before, "Rorgqr leaked ambient precision"); } void run_high_ambient () { mpfrxx::set_default_precision_bits (4096); std::vector a (1, at_precision (256)); mpfr_set_ui (a[0].mpfr_data (), 4, MPFR_RNDN); std::vector tau (1, at_precision (256)); std::vector work (1, at_precision (256)); mplapackint info = 0; { MplapackMpfrPrecisionScope scope (256); Rgeqrf (1, 1, a.data (), 1, tau.data (), work.data (), -1, info); } check (info == 0 && mpfrxx::default_precision_bits () == 4096, "high ambient QR probe failed"); } } // namespace int main () { try { mpfrxx::set_default_precision_bits (128); run_case (1024, -700); run_case (2048, -1500); run_high_ambient (); check (mpfrxx::default_precision_bits () == 4096, "QR probe did not preserve final ambient precision"); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: installed MPLAPACK MPFR Rgeqrf/Rorgqr precision probe\n"; return 0; } mplapack-interop-0.5.1/test/complex_mixed_closure.tst0000644000230300031750000001642615274353472022360 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_complex_matrix (value, rows_expected, columns_expected, precision_expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows_expected)); %! assert (info.columns, uint64 (columns_expected)); %! assert (info.is_complex); %! assert (info.all_elements_same_precision); %! assert (info.precision_bits, uint64 (precision_expected)); %!endfunction %!function assert_real_matrix (value, rows_expected, columns_expected, precision_expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows_expected)); %! assert (info.columns, uint64 (columns_expected)); %! assert (! info.is_complex); %! assert (info.all_elements_same_precision); %! assert (info.precision_bits, uint64 (precision_expected)); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! real_value = mp ([1, 2; 3, 4]); %! mpbits (1024); %! complex_value = mp ([1 + 2i, 5 - 1i; 7 + 0i, 11 + 3i]); %! mpbits (128); %! sum_value = real_value + complex_value; %! difference = complex_value - real_value; %! product = real_value .* complex_value; %! quotient = complex_value ./ real_value; %! assert_complex_matrix (sum_value, 2, 2, 1024); %! assert_complex_matrix (difference, 2, 2, 1024); %! assert_complex_matrix (product, 2, 2, 1024); %! assert_complex_matrix (quotient, 2, 2, 1024); %! assert (double (sum_value), double (real_value) + double (complex_value), 1e-12); %! assert (double (difference), double (complex_value) - double (real_value), 1e-12); %! assert (double (product), double (real_value) .* double (complex_value), 1e-12); %! assert (double (quotient), double (complex_value) ./ double (real_value), 1e-12); %! real_only = real_value + mp ([5, 6; 7, 8]); %! assert_real_matrix (real_only, 2, 2, 256); %! no_demotion = mp ("1", "0") + mp ("2"); %! assert (__mplapack_core__ ("scalar_test_info", no_demotion).is_complex); %! assert (__mplapack_core__ ("scalar_test_info", -no_demotion).is_complex); %! assert (__mplapack_core__ ("scalar_test_info", +no_demotion).is_complex); %! builtin_mixed = real_value + [10 + 1i, 20 - 2i; 30 + 3i, 40 - 4i]; %! assert_complex_matrix (builtin_mixed, 2, 2, 256); %! assert (double (builtin_mixed), double (real_value) + ... %! [10 + 1i, 20 - 2i; 30 + 3i, 40 - 4i], 1e-12); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! real_matrix = mp ([1, 2; 3, 4]); %! complex_matrix = mp ([2 + 1i, 0 - 1i; 1 + 2i, 3 + 0i]); %! left_product = real_matrix * complex_matrix; %! right_product = complex_matrix * real_matrix; %! builtin_right = real_matrix * [2 + 1i, 0 - 1i; 1 + 2i, 3 + 0i]; %! assert_complex_matrix (left_product, 2, 2, 512); %! assert_complex_matrix (right_product, 2, 2, 512); %! assert_complex_matrix (builtin_right, 2, 2, 512); %! assert (double (left_product), double (real_matrix) * double (complex_matrix), 1e-12); %! assert (double (right_product), double (complex_matrix) * double (real_matrix), 1e-12); %! assert (double (builtin_right), double (real_matrix) * ... %! [2 + 1i, 0 - 1i; 1 + 2i, 3 + 0i], 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! coefficient = mp ([3, 1; 1, 2]); %! real_rhs = mp ([7; 4]); %! complex_rhs = mp ([7 + 1i; 4 - 2i]); %! mixed_rhs = coefficient \ complex_rhs; %! mixed_lhs = mp ([3 + 1i, 1 - 2i; 1 + 0i, 2 + 3i]) \ real_rhs; %! builtin_rhs = coefficient \ [7 + 1i; 4 - 2i]; %! assert_complex_matrix (mixed_rhs, 2, 1, 512); %! assert_complex_matrix (mixed_lhs, 2, 1, 512); %! assert_complex_matrix (builtin_rhs, 2, 1, 512); %! expected_rhs = [2 + 0.8i; 1 - 1.4i]; %! expected_lhs = [397 / 173 - (72 / 173) * i; ... %! 62 / 173 - (57 / 173) * i]; %! assert (double (mixed_rhs), expected_rhs, 1e-10); %! assert (double (mixed_lhs), expected_lhs, 1e-10); %! assert (double (builtin_rhs), expected_rhs, 1e-10); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! real_left = mp ([1, 2; 3, 4]); %! complex_right = mp ([5 + 1i, 6 - 2i; 7 + 3i, 8 + 4i]); %! horizontal = [real_left, complex_right]; %! horizontal_reversed = [complex_right, real_left]; %! vertical = [real_left; complex_right]; %! vertical_reversed = [complex_right; real_left]; %! assert_complex_matrix (horizontal, 2, 4, 256); %! assert_complex_matrix (horizontal_reversed, 2, 4, 256); %! assert_complex_matrix (vertical, 4, 2, 256); %! assert_complex_matrix (vertical_reversed, 4, 2, 256); %! assert (double (horizontal), [double(real_left), double(complex_right)], 1e-12); %! assert (double (horizontal_reversed), [double(complex_right), double(real_left)], 1e-12); %! assert (double (vertical), [double(real_left); double(complex_right)], 1e-12); %! assert (double (vertical_reversed), [double(complex_right); double(real_left)], 1e-12); %! mpbits (1024); %! high_complex = mp ([1 + 1i; 2 - 3i]); %! mpbits (128); %! widened = [real_left, high_complex]; %! assert_complex_matrix (widened, 2, 3, 1024); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! real_lhs = mp ([1, 2; 3, 4]); %! real_before = double (real_lhs); %! complex_rhs = mp ([9 + 1i, 8 - 2i; 7 + 3i, 6 + 4i]); %! complex_result = real_lhs; %! complex_result(1, 2) = complex_rhs(1, 2); %! assert_complex_matrix (complex_result, 2, 2, 256); %! assert (double (real_lhs), real_before); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! complex_result, 1, 2, 8 - 2i)); %! complex_result(2, 1) = 17; %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! complex_result, 2, 1, 17 + 0i)); %! high_rhs = mpbits (1024); %! high_rhs = mp ("1", "2"); %! mpbits (128); %! widened = real_lhs; %! widened(1, 1) = high_rhs; %! assert_complex_matrix (widened, 2, 2, 1024); %! linear = real_lhs; %! linear(:) = mp (complex (ones (2, 2), 2 * ones (2, 2))); %! assert_complex_matrix (linear, 2, 2, 256); %! assert (double (linear), complex (ones (2, 2), 2 * ones (2, 2))); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1 + 2i, 3 - 4i; 5 + 6i, 7 - 8i]); %! B = reshape (A, [1, 4]); %! assert_complex_matrix (B, 1, 4, 512); %! assert (double (B), reshape (double (A), [1, 4])); %! assert (double (A.'), double (A).'); %! assert (double (A'), double (A)'); %! assert (double (real (A)), real (double (A))); %! assert (double (imag (A)), imag (double (A))); %! assert (double (conj (A)), conj (double (A))); %! assert (strcmp (class (double (A(1, 2))), "double")); %! assert (__mplapack_core__ ("scalar_test_info", A(1, 2)).is_complex); %! assert (! isempty (char (A(1, 2)))); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/mp_general_eig_test.cc0000644000230300031750000000626715274353472021540 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_general_eig.h" #include #include #include #include #include #include using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; namespace { void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } double component_double (const MpfrComplexMatrixStorage::NativeScalar& value, bool imaginary) { return mpfr_get_d (imaginary ? mpc_imagref (value.mpc_data ()) : mpc_realref (value.mpc_data ()), MPFR_RNDN); } } // namespace int main () { try { MpfrMatrixStorage real (2, 2, 256, std::vector {0.0, 1.0, -1.0, 0.0}); const auto balanced = octave_mplapack::mplapack_mpfr_matrix_general_eig (real, true); const auto unbalanced = octave_mplapack::mplapack_mpfr_matrix_general_eig (real, false); require (balanced.eigenvalues.rows () == 2 && balanced.right_vectors.rows () == 2 && balanced.left_vectors.columns () == 2, "real general eig shape mismatch"); require (balanced.eigenvalues.precision_bits () == 256 && balanced.right_vectors.precision_bits () == 256, "real general eig precision mismatch"); for (std::size_t index = 0; index < 2; ++index) { require (std::abs (component_double ( balanced.eigenvalues.at (index, 0), false)) < 1e-12, "real conjugate-pair real part mismatch"); require (std::abs (std::abs (component_double ( balanced.eigenvalues.at (index, 0), true)) - 1.0) < 1e-12, "real conjugate-pair imaginary part mismatch"); } require (real.element_exactly_equal_double (0, 1, -1.0), "real general eig modified its input"); require (unbalanced.eigenvalues.rows () == 2, "Rgeevx nobalance path did not return eigenvalues"); MpfrComplexMatrixStorage complex (2, 2, 256, std::vector {"(1,0)", "(0,0)", "(2,1)", "(3,0)"}); const auto complex_result = octave_mplapack::mplapack_mpc_matrix_general_eig (complex, true); require (complex_result.eigenvalues.rows () == 2 && complex_result.right_vectors.columns () == 2 && complex_result.left_vectors.columns () == 2, "complex general eig shape mismatch"); require (complex_result.eigenvalues.precision_bits () == 256, "complex general eig precision mismatch"); require (complex.element_exactly_equal_text (0, 1, "(2,1)"), "complex general eig modified its input"); std::cout << "PASS: real Rgeevx and complex Cgeevx general eig, " "balance/nobalance, conjugate-pair conversion, precision, " "shapes, and immutability\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/t03_polynomial_core.tst0000644000230300031750000000473015274353472021643 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! p = mp ({'1','-3','2'}); %! x = mp ([0,1,2]); %! y = polyval (p, x); %! assert (double (norm (y-mp ([2,0,0]), "fro")) < 1e-50); %! A = mp ({'1','2';'0','3'}); %! pm = polyvalm (p, A); %! assert (double (norm (pm-(A*A-mp ('3')*A+mp ('2')*eye (2, "like", A)), "fro")) < 1e-50); %! c = conv (p, mp ([1,4])); %! [q,r] = deconv (c, p); %! assert (double (norm (q-mp ([1,4]), "fro")) < 1e-50); %! assert (double (norm (r, "fro")) < 1e-50); %! assert (double (norm (polyder (p)-mp ([2,-3]), "fro")) < 1e-50); %! dprod = polyder (p, mp ([1,4])); %! assert (double (norm (dprod-polyder (c), "fro")) < 1e-50); %! [dq,dd] = polyder (mp ([1,0]), mp ([1,-1])); %! assert (double (norm (dq-mp ([0,-1]), "fro")) < 1e-50); %! assert (double (norm (dd-mp ([1,-2,1]), "fro")) < 1e-50); %! pint = polyint (polyder (p), mp ('7')); %! assert (double (norm (pint-mp ([1,-3,7]), "fro")) < 1e-50); %! C = compan (p); %! assert (size (C) == [2,2]); %! assert (double (norm (poly (C)-p, "fro")) < 1e-45); %! rr = roots (p); %! assert (double (norm (poly (rr)-p, "fro")) < 1e-45); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! pc = mp ([1,0,1]); %! rc = roots (pc); %! assert (numel (rc) == 2 && ! isreal (rc)); %! assert (double (norm (poly (rc)-pc, "fro")) < 1e-45); %! rv = mp ([1,2,3,4,5]); %! pw = poly (rv); %! assert (double (norm (poly (roots (pw))-pw, "fro")) < 1e-35); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! tiny = mp ('1'); %! for k = 1:700, tiny = tiny * mp ('0.5'); endfor %! rv = [mp('1'),mp('1')+tiny]; %! p = poly (rv); %! rr = roots (p); %! assert (abs (rr(1)-rr(2)) > tiny*mp ('0.5')); %! assert (double (norm (poly (rr)-p, "fro")) < 1e-40); %! assert (__mplapack_core__ ("matrix_test_info", p).precision_bits == uint64 (1024)); %! mpbits (2048); %! tiny = mp ('1'); %! for k = 1:1500, tiny = tiny * mp ('0.5'); endfor %! p2048 = mp ({'1','-2','1'}); %! p2048(1,2) = -mp ('2') - tiny; %! rr2048 = roots (p2048); %! assert (abs (rr2048(1)-rr2048(2)) > tiny*mp ('0.5')); %! assert (__mplapack_core__ ("matrix_test_info", rr2048).precision_bits == uint64 (2048)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/test_nonsymmetric_eig_suite.m0000644000230300031750000000457515274353472023236 0ustar rafaelrafael## Focused nonsymmetric eigensystem test entry point. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "nonsymmetric_eig")); mp_eig_suite_selftest (); smoke = mp_eig_suite ("smoke", struct ("family", "hadamard")); assert (smoke.ok && numel (smoke.rows) == 6); demo = mp_eig_suite ("demo", struct ("family", "hadamard")); assert (demo.ok && numel (demo.rows) == 8); frank_smoke = mp_eig_suite ("smoke", struct ("family", "frank")); assert (frank_smoke.ok && numel (frank_smoke.rows) == 6); frank_demo = mp_eig_suite ("demo", struct ("family", "frank")); assert (frank_demo.ok && numel (frank_demo.rows) == 8); companion_smoke = mp_eig_suite ("smoke", struct ("family", "companion")); assert (companion_smoke.ok && numel (companion_smoke.rows) == 6); companion_demo = mp_eig_suite ("demo", struct ("family", "companion")); assert (companion_demo.ok && numel (companion_demo.rows) == 8); native_companion = companion_demo.rows(1); assert (strcmp (native_companion.backend, "native") && native_companion.input_error > mp ("0")); forsythe_smoke = mp_eig_suite ("smoke", struct ("family", "forsythe")); assert (forsythe_smoke.ok && numel (forsythe_smoke.rows) == 12); forsythe_demo = mp_eig_suite ("demo", struct ("family", "forsythe")); assert (forsythe_demo.ok && numel (forsythe_demo.rows) == 16); for k = 1:numel (forsythe_demo.rows) row = forsythe_demo.rows(k); if (! row.native) if (row.work_bits == 512 && strcmp (row.representation, "original")) assert (row.circle_error < mp ("2")^(-64)); elseif (row.work_bits == 512) assert (row.circle_error < mp ("2")^(-200)); endif endif endfor all_smoke = mp_eig_suite ("smoke"); assert (all_smoke.ok && numel (all_smoke.rows) == 30); all_demo = mp_eig_suite ("demo"); assert (all_demo.ok && numel (all_demo.rows) == 40); output_dir = tempname (); written = mp_eig_suite ("smoke", struct ("output_dir", output_dir)); assert (written.ok && exist (written.output.summary, "file") ... && exist (written.output.eigenvalues, "file") ... && exist (written.output.environment, "file") ... && exist (written.output.report, "file")); caught = false; try nes_write (written, output_dir); catch exception caught = strcmp (exception.identifier, "NEIG:WriteExists"); end_try_catch assert (caught); rmdir (output_dir, "s"); fprintf ("PASS: test_nonsymmetric_eig_suite (NEIG06)\n"); mplapack-interop-0.5.1/test/script-compat/0000755000230300031750000000000015274353472020007 5ustar rafaelrafaelmplapack-interop-0.5.1/test/script-compat/s06.tst0000644000230300031750000000746615274353472021170 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2", "3"; "4", "5", "6"}); %! assert (double (mean (A)), [2.5, 3.5, 4.5], 1e-15); %! assert (double (mean (A, 2)), [2; 5], 1e-15); %! assert (double (mean (A, "all")), 3.5, 1e-15); %! assert (double (mean (A, "double")), [2.5, 3.5, 4.5], 1e-15); %! assert (double (median (A)), [2.5, 3.5, 4.5], 1e-15); %! assert (double (median (A, 2)), [2; 5], 1e-15); %! assert (double (median (A, "all")), 3.5, 1e-15); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2", "3"; "4", "5", "6"}); %! assert (double (var (A)), [4.5, 4.5, 4.5], 1e-15); %! assert (double (var (A, 1)), [2.25, 2.25, 2.25], 1e-15); %! assert (double (std (A)), [2.1213203435596424, ... %! 2.1213203435596424, ... %! 2.1213203435596424], 1e-15); %! assert (double (std (A, 1)), [1.5, 1.5, 1.5], 1e-15); %! assert (double (var (A, [], "all")), 3.5, 1e-15); %! [V, M] = var (A, 0, 2); %! assert (double (V), [1; 1], 1e-15); %! assert (double (M), [2; 5], 1e-15); %! [S, N] = std (A, 1, "all"); %! assert (double (S), 1.707825127659933, 1e-15); %! assert (double (N), 3.5, 1e-15); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! X = mp ({"1", "NaN", "3"}); %! assert (isnan (mean (X))); %! assert (isequal (mean (X, "omitnan"), mp ("2"))); %! assert (isnan (median (X))); %! assert (isequal (median (X, "omitnan"), mp ("2"))); %! assert (isnan (var (X))); %! assert (isequal (var (X, [], "omitnan"), mp ("2"))); %! assert (isequal (range (X), mp ("2"))); %! [lo, hi] = bounds (X); %! assert (isequal (lo, mp ("1")) && isequal (hi, mp ("3"))); %! assert (isnan (range (X, "includenan"))); %! [lo, hi] = bounds (X, "includenan"); %! assert (isnan (lo) && isnan (hi)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! stable = mp ({"100000000000000000000000000000001", ... %! "100000000000000000000000000000002", ... %! "100000000000000000000000000000003", ... %! "100000000000000000000000000000004"}); %! assert (double (var (stable, 1)), 1.25, 1e-12); %! assert (double (std (stable, 1)), 1.118033988749895, 1e-12); %! Z = mp ([1 + 2i, 2 + 4i, 3 + 8i]); %! assert (double (mean (Z)), 2 + 14 / 3 * 1i, 1e-12); %! [V, M] = var (Z); %! assert (double (V), 31 / 3, 1e-12); %! assert (double (M), 2 + 14 / 3 * 1i, 1e-12); %! assert (double (median (Z)), 2 + 4i, 1e-12); %! assert (double (range (Z)), 2 + 6i, 1e-12); %! [lo, hi] = bounds (Z); %! assert (double (lo), 1 + 2i, 1e-12); %! assert (double (hi), 3 + 8i, 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for precision = [1024, 2048] %! mpbits (precision); %! exponent = (precision == 1024) * -700 ... %! + (precision == 2048) * -1500; %! x = mp ("2") ^ exponent; %! values = [x, x + x, x + 2 * x]; %! m = mean (values); %! assert (__mplapack_core__ ("value_shape_info", m).precision_bits == precision); %! assert (isequal (m, 2 * x)); %! v = var (values, 1); %! assert (__mplapack_core__ ("value_shape_info", v).precision_bits == precision); %! assert (isequal (v, 2 * (x ^ 2 / 3))); %! mpbits (128); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 128); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!error %! var (mp ([1, 2]), 2); mplapack-interop-0.5.1/test/script-compat/s03.tst0000644000230300031750000000725115274353472021155 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 0; -2, NaN]); %! assert (isequal (A < 1, [false, true; true, false])); %! assert (isequal (A <= 1, [true, true; true, false])); %! assert (isequal (A > -2, [true, true; false, false])); %! assert (isequal (A >= -2, [true, true; true, false])); %! assert (isequal (A == [1, 0; -2, NaN], [true, true; true, false])); %! assert (isequal (A ~= [1, 0; -2, NaN], [false, false; false, true])); %! assert (isequal (1 < A, [false, false; false, false])); %! assert (isequal (A == 1, [true, false; false, false])); %! assert (isequal (A == A, [true, true; true, false])); %! assert (isequal (logical (A), [true, false; true, true])); %! assert (isequal (~A, [false, true; false, false])); %! assert (isequal (A & [true, false; false, true], ... %! [true, false; false, true])); %! assert (isequal (A | false, [true, false; true, true])); %! assert (isequal (xor (A, [true, true; false, false]), ... %! [false, true; true, true])); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 0; -2, NaN]); %! assert (isequal (any (A), [true, true])); %! assert (isequal (any (A, 2), [true; true])); %! assert (isequal (all (A), [true, false])); %! assert (isequal (all (A, 2), [false; true])); %! assert (any (A, "all")); %! assert (! all (mp ([1, 0]))); %! assert (all (mp (ones (2, 2)), "all")); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 0; -2, NaN]); %! assert (isequal (find (A), [1; 2; 4])); %! assert (isequal (find (A, 2), [1; 2])); %! assert (isequal (find (A, 2, "last"), [2; 4])); %! [rows, columns] = find (A); %! assert (isequal (rows, [1; 2; 2])); %! assert (isequal (columns, [1; 1; 2])); %! [rows, columns, values] = find (A); %! assert (isequal (rows, [1; 2; 2])); %! assert (isequal (columns, [1; 1; 2])); %! assert (isequaln (double (values), [1; -2; NaN])); %! assert (isequaln (double (A (logical (A))), [1; -2; NaN])); %! assert (isequaln (double (A ([1, 4])), [1; NaN])); %! B = A; %! B (A > 0) = mp (7); %! assert (isequaln (double (B), [7, 0; -2, NaN])); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! Z = mp ([1 + 2i, 0; 0, NaN + 1i]); %! assert (isequal (Z == Z, [true, true; true, false])); %! assert (isequal (Z ~= Z, [false, false; false, true])); %! assert (isequal (logical (Z), [true, false; false, true])); %! assert (isequal (Z & [true, false; true, false], ... %! [true, false; false, false])); %! assert (isequal (find (Z), [1; 4])); %! rejected = false; %! try %! Z < Z; %! catch %! rejected = true; %! end_try_catch %! assert (rejected); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for precision = [1024, 2048] %! mpbits (precision); %! x = mp ("2") ^ ((precision == 1024) * -700 ... %! + (precision == 2048) * -1500); %! assert (logical (x)); %! assert (x == x); %! assert (! (x ~= x)); %! assert (any (x)); %! assert (! (mpbits () != precision)); %! mpbits (128); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 128); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!error %! mp ([1 + 1i]) < mp ([2 + 2i]); mplapack-interop-0.5.1/test/script-compat/s02.tst0000644000230300031750000001025515274353472021152 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! assert (double (sum (A)), [4, 6]); %! assert (double (sum (A, 2)), [3; 7]); %! assert (double (sum (A, "all")), 10); %! assert (double (prod (A)), [3, 8]); %! assert (double (prod (A, 2)), [2; 12]); %! assert (double (prod (A, "all")), 24); %! assert (double (sumsq (A)), [10, 20]); %! assert (double (sumsq (A, "all")), 30); %! assert (double (sum (A, "double")), [4, 6]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! assert (double (cumsum (A)), [1, 2; 4, 6]); %! assert (double (cumsum (A, 2)), [1, 3; 3, 7]); %! assert (double (cumsum (A, "reverse")), [4, 6; 3, 4]); %! assert (double (cumsum (A, 2, "reverse")), [3, 2; 7, 4]); %! assert (double (cumprod (A)), [1, 2; 3, 8]); %! assert (double (cumprod (A, "reverse")), [3, 8; 3, 4]); %! assert (double (cumprod (A, 2)), [1, 2; 3, 12]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! Z = mp ([1 + 2i, 3 - 1i; 2, 4 + 3i]); %! assert (double (sum (Z)), [3 + 2i, 7 + 2i], 1e-12); %! assert (double (sum (Z, "all")), 10 + 4i, 1e-12); %! assert (double (prod (Z)), [(1 + 2i) * 2, (3 - 1i) * (4 + 3i)], 1e-12); %! assert (double (sumsq (Z)), [9, 35], 1e-12); %! assert (double (sumsq (Z, "all")), 44, 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, NaN; 2, 3]); %! assert (double (sum (A)), [3, NaN]); %! assert (double (sum (A, "omitnan")), [3, 3]); %! assert (double (prod (A)), [2, NaN]); %! assert (double (prod (A, "omitnan")), [2, 3]); %! assert (double (sumsq (A, "omitnan")), [5, 9]); %! [mn, mi] = min (A); %! assert (double (mn), [1, 3]); %! assert (mi, [1, 2]); %! [mn, mi] = min (A, "includenan"); %! assert (isnan (mn), [false, true]); %! assert (mi, [1, 1]); %! [mx, mi] = max (A, "omitnan"); %! assert (double (mx), [2, 3]); %! assert (mi, [2, 2]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! [mn, mi] = min (A); %! assert (double (mn), [1, 2]); %! assert (mi, [1, 1]); %! [mx, mi] = max (A); %! assert (double (mx), [3, 4]); %! assert (mi, [2, 2]); %! assert (double (min (A, [], 2)), [1; 3]); %! assert (double (max (A, [], 2)), [2; 4]); %! assert (double (min (A, [], "all")), 1); %! assert (double (max (A, [], "all")), 4); %! assert (double (min (A, mp (2))), [1, 2; 2, 2]); %! assert (double (max (A, mp (2))), [2, 2; 3, 4]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!error %! [~, ~] = min (mp ([1, 2]), mp (2)); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! Z = mp ([1 + 1i, -1 - 1i; 1 - 1i, -1 + 1i]); %! [mn, mi] = min (Z); %! [mx, ma] = max (Z); %! assert (double (mn), [1 - 1i, -1 - 1i], 1e-12); %! assert (mi, [2, 1]); %! assert (double (mx), [1 + 1i, -1 + 1i], 1e-12); %! assert (ma, [1, 2]); %! W = mp ([1 + 2i, -1 + 3i]); %! assert (abs (double (min (W, "ComparisonMethod", "real")) ... %! - (-1 + 3i)) < 1e-12); %! V = mp ([1 + 1i, -1 - 1i]); %! assert (abs (double (min (V, "ComparisonMethod", "abs")) ... %! - (-1 - 1i)) < 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for precision = [1024, 2048] %! mpbits (precision); %! exponent = (precision == 1024) * -700 + (precision == 2048) * -1500; %! x = mp ("2") ^ exponent; %! y = sumsq (x); %! info = __mplapack_core__ ("scalar_test_info", y); %! assert (info.precision_bits == precision); %! assert (isfinite (y)); %! mpbits (128); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 128); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/script-compat/s08.tst0000644000230300031750000001651715274353472021167 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! mpbits (256); %! t = linspace (mp ("0"), mp ("1"), 5); %! one = t + mp ("1"); %! y = sqrt (one) .* exp (log (one)) .* (sin (t) .^ 2 + cos (t) .^ 2); %! assert (isa (y, "mp")); %! assert (size (y), [1, 5]); %! assert (double (sum (y)), sum (double (y)), 1e-12); %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! h = plot (ax, t, y, "o-"); %! assert (isgraphics (h, "line")); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "NaN", "3"; "4", "5", "Inf"}); %! mask = isfinite (A) & (A > mp ("2")); %! selected = A(mask); %! assert (numel (selected), 3); %! assert (double (min (selected)), 3); %! assert (double (max (selected)), 5); %! assert (double (mean (selected)), 4); %! assert (double (std (selected)), 1); %! assert (all (isfinite (selected))); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! template = mp ({"1", "2"; "3", "4"}); %! Z = zeros (2, 3, "like", template); %! O = ones (2, 3, "like", template); %! I = eye (2, "like", template); %! assert (size (Z), [2, 3]); %! assert (double (O), ones (2, 3)); %! assert (double (I), eye (2)); %! D = diag (mp ([1, 2, 3])); %! assert (double (D), diag ([1, 2, 3])); %! assert (double (triu (D + mp (1))), triu (double (D + mp (1)))); %! assert (double (tril (D + mp (1))), tril (double (D + mp (1)))); %! R = repmat (mp ([1, 2]), 2, 2); %! assert (double (R), repmat ([1, 2], 2, 2)); %! assert (double (flip (R, 1)), flip (double (R), 1)); %! assert (double (cat (1, R, R)), cat (1, double (R), double (R))); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"4", "1"; "2", "3"}); %! right_identity = A / A; %! assert (double (norm (right_identity - eye (2, "like", A))), ... %! 0, 1e-12); %! values = eig (A); %! singular = svd (A); %! assert (numel (values), 2); %! assert (numel (singular), 2); %! assert (rank (A), 2); %! assert (double (cond (A)) > 1); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! mpbits (256); %! A = mp (gallery ("grcar", 8)); %! e = eig (A); %! identity = eye (8, "like", A); %! residual = norm (A / A - identity); %! assert (double (residual) < 1e-12); %! balanced = eig (A, "balance"); %! unbalanced = eig (A, "nobalance"); %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! h1 = plot (ax, real (e), imag (e), "o"); %! hold (ax, "on"); %! h2 = plot (ax, real (balanced), imag (balanced), "x"); %! h3 = plot (ax, real (unbalanced), imag (unbalanced), "+"); %! axis (ax, "equal"); %! grid (ax, "on"); %! assert (isgraphics (h1, "line") && isgraphics (h2, "line") %! && isgraphics (h3, "line")); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! mpbits (256); %! negative_root = sqrt (mp ("-1")); %! negative_log = log (mp ("-1")); %! z = mp ([1 + 2i, 2 - 1i, -1 + 1i]); %! trig = sin (z) + cos (z); %! assert (! isreal (negative_root) && ! isreal (negative_log)); %! assert (! isreal (trig)); %! assert (double (abs (z)), abs (double (z)), 1e-12); %! assert (double (angle (z)), angle (double (z)), 1e-12); %! assert (isequal (z, z)); %! rejected = false; %! try %! z < z; %! catch %! rejected = true; %! end_try_catch %! assert (rejected); %! assert (double (mean (z)), mean (double (z)), 1e-12); %! [~, order] = sort (z); %! assert (isequal (order, [3, 2, 1])); %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! h = plot (ax, z, "o"); %! assert (get (h, "xdata"), [1, 2, -1]); %! assert (get (h, "ydata"), [2, -1, 1]); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"3", "1"; "2", "NaN"}); %! [ascending, ia] = sort (A); %! assert (isequaln (double (ascending), [2, 1; 3, NaN])); %! assert (isequal (ia, [2, 1; 1, 2])); %! [descending, id] = sort (A, 2, "descend"); %! assert (isequaln (double (descending), [3, 1; NaN, 2])); %! assert (isequal (id, [1, 2; 2, 1])); %! D = mp ([1, 4, 9, 16]); %! assert (double (diff (D)), [3, 5, 7]); %! assert (double (diff (D, 2)), [2, 2]); %! M = mp ([1, 3, 6; 2, 5, 9]); %! assert (double (diff (M, 1, 1)), [1, 2, 3]); %! assert (double (diff (M, 1, 2)), [2, 3; 3, 4]); %! assert (isequal (double (diff (M, 0)), double (M))); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for precision = [1024, 2048] %! mpbits (precision); %! exponent = (precision == 1024) * -700 ... %! + (precision == 2048) * -1500; %! x = mp ("2") ^ exponent; %! incremented = x + eps (x); %! sorted = sort ([x, incremented]); %! differences = diff ([x, incremented]); %! assert (__mplapack_core__ ("value_shape_info", sorted).precision_bits == precision); %! assert (__mplapack_core__ ("value_shape_info", differences).precision_bits == precision); %! assert (isequal (sorted (1), x)); %! assert (all (differences == eps (x))); %! mpbits (128); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 128); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! assert (length (A), 2); %! assert (isequal (size (A), [2, 2])); %! assert (rows (A), 2); %! assert (columns (A), 2); %! assert (numel (A), 4); %! assert (ndims (A), 2); %! assert (! isempty (A)); %! empty = zeros (0, 3, "like", A); %! assert (isempty (empty)); %! assert (size (empty), [0, 3]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!error %! sort (mp ([1 + 1i, 2 + 2i]), 3); %!test %! assert (isequal (diff ([1, 2, 3]), [1, 1])); %!test %! saved = mpbits (); %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! mpbits (256); %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! A = mp ([1, 2; 3, 4]); %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! h = mesh (ax, A); %! assert (isgraphics (h)); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/script-compat/s05.tst0000644000230300031750000000664715274353472021167 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! increasing = mp ("0.1"):mp ("0.2"):mp ("0.5"); %! assert (size (increasing), [1, 3]); %! assert (double (increasing), [0.1, 0.3, 0.5], 1e-15); %! decreasing = mp ("5"):-mp ("2"):mp ("1"); %! assert (double (decreasing), [5, 3, 1]); %! empty_up = mp ("5"):mp ("1"); %! empty_down = mp ("1"):-mp ("1"):mp ("5"); %! assert (isempty (empty_up) && isempty (empty_down)); %! rejected = false; %! try %! mp ("1"):mp ("0"):mp ("2"); %! catch %! rejected = true; %! end_try_catch %! assert (rejected); %! precise_step = mp ("0.1"):mp ("0.1"):mp ("0.3"); %! assert (isequal (precise_step (1), mp ("0.1"))); %! assert (isequal (precise_step (3), mp ("0.3"))); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = linspace (mp ("0.1"), mp ("0.5"), 5); %! assert (size (A), [1, 5]); %! assert (isequal (A (1), mp ("0.1"))); %! assert (isequal (A (5), mp ("0.5"))); %! B = linspace (mp ("1"), mp ("2"), 1); %! assert (isequal (B, mp ("2"))); %! assert (isempty (linspace (mp ("1"), mp ("2"), 0))); %! Z = linspace (mp (1 + 2i), mp (3 + 4i), 3); %! assert (double (Z), [1 + 2i, 2 + 3i, 3 + 4i], 1e-12); %! assert (! __mplapack_core__ ("value_is_real", Z)); %! L = logspace (mp ("0"), mp ("2"), 3); %! assert (double (L), [1, 10, 100], 1e-12); %! LP = logspace (mp ("1"), pi, 3); %! assert (double (LP (1)), 10, 1e-12); %! assert (double (LP (3)), pi, 1e-12); %! assert (columns (logspace (mp ("0"), mp ("1"))), 50); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([-1.7, -1.5, 1.5, 1.7]); %! assert (double (floor (A)), [-2, -2, 1, 1]); %! assert (double (ceil (A)), [-1, -1, 2, 2]); %! assert (double (fix (A)), [-1, -1, 1, 1]); %! assert (double (round (A)), [-2, -2, 2, 2]); %! assert (double (rem (mp ([-5, 5]), mp ([3, -3]))), [-2, 2]); %! assert (double (mod (mp ([-5, 5]), mp ([3, -3]))), [1, -1]); %! assert (double (hypot (mp ([3, 5]), mp ([4, 12]))), [5, 13]); %! assert (double (atan2 (mp ([1, -1]), mp ([0, 0]))), ... %! [pi / 2, -pi / 2], 1e-12); %! assert (signbit (mp ({"-0", "0"})), [true, false]); %! e = eps (mp ("1")); %! assert (isequal (e, mp ("2") ^ -255)); %! info = __mplapack_core__ ("value_shape_info", e); %! assert (info.precision_bits == 256); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for precision = [1024, 2048] %! mpbits (precision); %! exponent = (precision == 1024) * -700 ... %! + (precision == 2048) * -1500; %! x = mp ("2") ^ exponent; %! y = linspace (x, x + eps (x), 2); %! assert (isequal (y (1), x)); %! assert (isequal (y (2), x + eps (x))); %! assert (__mplapack_core__ ("value_shape_info", y).precision_bits == precision); %! mpbits (128); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 128); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!error %! mp (1 + 1i):mp (2 + 2i); %!error %! floor (mp (1 + 2i)); %!error %! logspace (mp (1 + 1i), mp (2 + 2i)); mplapack-interop-0.5.1/test/script-compat/s04.tst0000644000230300031750000001070415274353472021153 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2, 3; 4, 5, 6]); %! assert (double (diag (A)), [1; 5]); %! assert (double (diag (A, 1)), [2; 6]); %! assert (double (diag (A, -1)), 4); %! V = mp ([7; 8; 9]); %! assert (double (diag (V, -1)), [0, 0, 0, 0; 7, 0, 0, 0; ... %! 0, 8, 0, 0; 0, 0, 9, 0]); %! assert (double (triu (A)), [1, 2, 3; 0, 5, 6]); %! assert (double (triu (A, 1)), [0, 2, 3; 0, 0, 6]); %! assert (double (tril (A)), [1, 0, 0; 4, 5, 0]); %! assert (double (tril (A, -1)), [0, 0, 0; 4, 0, 0]); %! info = __mplapack_core__ ("value_shape_info", triu (A)); %! assert (info.precision_bits == 256); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! Z = mp ([1 + 2i, 2 - 1i; 3, 4 + 3i]); %! assert (double (diag (Z)), [1 + 2i; 4 + 3i], 1e-12); %! assert (double (diag (Z, 1)), 2 - 1i, 1e-12); %! assert (double (triu (Z)), [1 + 2i, 2 - 1i; 0, 4 + 3i], 1e-12); %! assert (double (tril (Z, -1)), [0, 0; 3, 0], 1e-12); %! R = repmat (Z, [2, 2]); %! assert (double (R), repmat (double (Z), [2, 2]), 1e-12); %! assert (! __mplapack_core__ ("value_is_real", R)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (320); %! A = mp ([1, 2; 3, 4]); %! R = zeros (2, 3, "like", A); %! O = ones ([2, 2], "like", A); %! E = eye (2, "like", A); %! N = NaN (1, 2, "like", A); %! I = Inf (1, 2, "like", A); %! assert (isa (R, "mp") && isa (O, "mp") && isa (E, "mp")); %! assert (double (R), zeros (2, 3)); %! assert (double (O), ones (2, 2)); %! assert (double (E), eye (2)); %! assert (all (isnan (N)) && all (isinf (I))); %! Z = mp ([1 + 2i, 3 - 4i]); %! C = zeros (2, 2, "like", Z); %! CE = eye ([2, 3], "like", Z); %! CN = NaN (1, 2, "like", Z); %! CI = Inf (1, 2, "like", Z); %! assert (! __mplapack_core__ ("value_is_real", C)); %! assert (! __mplapack_core__ ("value_is_real", CE)); %! assert (double (C), zeros (2, 2), 1e-12); %! assert (double (CE), [1, 0, 0; 0, 1, 0], 1e-12); %! assert (all (isnan (CN)) && all (isinf (CI))); %! assert (__mplapack_core__ ("value_shape_info", R).precision_bits == 320); %! assert (__mplapack_core__ ("value_shape_info", CE).precision_bits == 320); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2, 3; 4, 5, 6]); %! assert (double (repmat (A, 2, 3)), ... %! repmat ([1, 2, 3; 4, 5, 6], 2, 3)); %! assert (double (flipud (A)), [4, 5, 6; 1, 2, 3]); %! assert (double (fliplr (A)), [3, 2, 1; 6, 5, 4]); %! assert (double (flip (A, 1)), flipud (double (A))); %! assert (double (flip (A, 2)), fliplr (double (A))); %! assert (double (flip (A)), flipud (double (A))); %! assert (double (rot90 (A)), [3, 6; 2, 5; 1, 4]); %! assert (double (rot90 (A, 2)), [6, 5, 4; 3, 2, 1]); %! assert (double (rot90 (A, -1)), [4, 1; 5, 2; 6, 3]); %! Z = mp ([1 + 1i, 2 + 2i; 3 + 3i, 4 + 4i]); %! assert (double (rot90 (Z)), [2 + 2i, 4 + 4i; 1 + 1i, 3 + 3i], 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! B = mp ([5, 6; 7, 8]); %! assert (double (cat (1, A, A)), [1, 2; 3, 4; 1, 2; 3, 4]); %! assert (double (cat (2, A, A)), [1, 2, 1, 2; 3, 4, 3, 4]); %! assert (double (cat (2, A, B)), [1, 2, 5, 6; 3, 4, 7, 8]); %! assert (double (cat (1, B, B)), [5, 6; 7, 8; 5, 6; 7, 8]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for precision = [1024, 2048] %! mpbits (precision); %! x = mp ("2") ^ ((precision == 1024) * -700 ... %! + (precision == 2048) * -1500); %! A = repmat (x, 2, 2); %! assert (__mplapack_core__ ("value_shape_info", A).precision_bits == precision); %! assert (logical (all (diag (A) == x))); %! mpbits (128); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 128); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!error %! triu (mp ([1, 2]), "pack"); %!error %! cat (3, mp ([1]), mp ([2])); %!error %! flip (mp ([1, 2]), 3); mplapack-interop-0.5.1/test/script-compat/s01.tst0000644000230300031750000000616415274353472021155 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function result = reference_square (value) %! d = double (value); %! result = [d(1, 1) * d(1, 1) + d(1, 2) * d(2, 1), ... %! d(1, 1) * d(1, 2) + d(1, 2) * d(2, 2); ... %! d(2, 1) * d(1, 1) + d(2, 2) * d(2, 1), ... %! d(2, 1) * d(1, 2) + d(2, 2) * d(2, 2)]; %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! a = mp ("2"); %! assert (isequal (a .^ mp ([2, 3]), mp ([4, 8]))); %! assert (isequal (mp ([2; 3]) .^ 2, mp ([4; 9]))); %! assert (isequal (2 .^ mp ([2, 3]), mp ([4, 8]))); %! assert (abs (double (mp ("-1") .^ mp ("0.5")) - 1i) < 1e-12); %! z = mp ("1", "2"); %! assert (abs (double (z .^ mp ("2")) - (-3 + 4i)) < 1e-12); %! assert (abs (double (mp ("2") .^ z) - 2^complex (1, 2)) < 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! assert (double (A ^ 0), eye (2)); %! assert (double (A ^ 2), [7, 10; 15, 22]); %! assert (double (A ^ -1) * double (A), eye (2), 1e-12); %! Z = mp ([1 + 1i, 2; 3, 4 - 1i]); %! assert (double (Z ^ 0), eye (2)); %! assert (double (Z ^ 2), reference_square (Z), 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! real_values = cell (1, 3); %! real_values{1} = mp ("0.25"); %! real_values{2} = mp ("2"); %! real_values{3} = mp ("-1"); %! functions = {"sqrt", "exp", "expm1", "log", "log1p", "log10", ... %! "log2", "sin", "cos", "tan", "asin", "acos", "atan", ... %! "sinh", "cosh", "tanh", "asinh", "acosh", "atanh", "cbrt"}; %! for i = 1:numel (functions) %! for j = 1:numel (real_values) %! value = feval (functions{i}, real_values{j}); %! assert (isa (value, "mp")); %! endfor %! endfor %! z = mp ("(0.25,-0.5)"); %! for i = 1:numel (functions) %! assert (isa (feval (functions{i}, z), "mp")); %! endfor %! assert (abs (double (sqrt (mp ("-1"))) - 1i) < 1e-12); %! assert (abs (double (log (mp ("-1"))) - pi * 1i) < 1e-12); %! assert (abs (double (asin (mp ("2"))) ... %! - (pi / 2 - 1i * log (2 + sqrt (3)))) < 1e-12); %! assert (abs (double (acos (mp ("2"))) ... %! - 1i * log (2 + sqrt (3))) < 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for precision = [1024, 2048] %! mpbits (precision); %! if (precision == 1024) %! x = mp ("1e-211"); %! else %! x = mp ("1e-451"); %! endif %! e = expm1 (x); %! l = log1p (x); %! assert (__mplapack_core__ ("scalar_test_info", e).precision_bits ... %! == precision); %! assert (__mplapack_core__ ("scalar_test_info", l).precision_bits ... %! == precision); %! assert (isfinite (e) && isfinite (l)); %! mpbits (128); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 128); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/script-compat/s07.tst0000644000230300031750000000600415274353472021154 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! x = mp ([1; 2; 3]); %! y = mp ([2; 4; 8]); %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! h = plot (ax, y, "o-", "linewidth", 2); %! assert (isgraphics (h, "line")); %! assert (get (h, "xdata"), [1, 2, 3]); %! assert (get (h, "ydata"), [2, 4, 8]); %! assert (get (h, "linewidth"), 2); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! end_unwind_protect %!test %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! x = mp ([1; 2; 3]); %! y = mp ([2; 4; 8]); %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! hold (ax, "on"); %! h = plot (ax, x, y, "o-", x, 2 * y, "x--", "color", [0, 0, 1]); %! assert (numel (h) == 2); %! assert (get (h(1), "xdata"), [1, 2, 3]); %! assert (get (h(2), "ydata"), [4, 8, 16]); %! hm = plot (ax, [1; 2; 3], y, "+"); %! assert (isgraphics (hm, "line")); %! hsx = semilogx (ax, x, y, "s"); %! hsy = semilogy (ax, x, y, "d"); %! hll = loglog (ax, x, y, "^"); %! hsc = scatter (ax, x, y); %! hst = stem (ax, x, y); %! hsr = stairs (ax, x, y); %! assert (isgraphics (hsx, "line") && isgraphics (hsy, "line")); %! assert (isgraphics (hll, "line") && isgraphics (hsc)); %! assert (isgraphics (hst) && isgraphics (hsr)); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! end_unwind_protect %!test %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! z = mp ([1 + 2i; 2 + 1i; 3 + 3i]); %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! h = plot (ax, z, "o"); %! assert (get (h, "xdata"), [1, 2, 3]); %! assert (get (h, "ydata"), [2, 1, 3]); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! end_unwind_protect %!test %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! A = mp (gallery ("grcar", 32)); %! balanced = eig (A, "balance"); %! unbalanced = eig (A, "nobalance"); %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! h1 = plot (ax, real (balanced), imag (balanced), "o"); %! hold (ax, "on"); %! h2 = plot (ax, real (unbalanced), imag (unbalanced), "x"); %! axis (ax, "equal"); %! grid (ax, "on"); %! assert (isgraphics (h1, "line") && isgraphics (h2, "line")); %! assert (numel (get (h1, "xdata")) == 32); %! assert (numel (get (h2, "ydata")) == 32); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! end_unwind_protect mplapack-interop-0.5.1/test/script-compat/s00.tst0000644000230300031750000000535115274353472021151 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! x = mp ([-2, 0; 3, -4]); %! assert (double (abs (x)), [2, 0; 3, 4]); %! assert (double (sign (x)), [-1, 0; 1, -1]); %! assert (double (angle (x)), [pi, 0; 0, pi], 1e-12); %! assert (double (arg (x)), double (angle (x)), 1e-12); %! assert (isreal (x)); %! assert (isfinite (x)); %! assert (! isnan (x)); %! assert (! isinf (x)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! z = mp ([1 + 1i, -1 + 1i; -1 - 1i, 0 - 0i]); %! assert (double (abs (z)), sqrt (2) * [1, 1; 1, 0], 1e-12); %! assert (double (angle (z)), [pi/4, 3*pi/4; -3*pi/4, 0], 1e-12); %! expected_sign = double (z) ./ abs (double (z)); %! expected_sign (2, 2) = 0; %! assert (double (sign (z)), expected_sign, 1e-12); %! assert (! isreal (z)); %! assert (isfinite (z)); %! assert (! isnan (z)); %! assert (! isinf (z)); %! zzero = mp ("-0", "-0"); %! assert (strcmp (char (sign (zzero)), "(0,0)")); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! x = mp ([Inf, -Inf; NaN, 1]); %! z = mp (zeros (2)); %! z(1, 1) = mp ("Inf", "1"); %! z(1, 2) = mp ("NaN", "0"); %! z(2, 1) = mp ("1", "-Inf"); %! z(2, 2) = mp ("2", "3"); %! assert (isinf (x), logical ([1, 1; 0, 0])); %! assert (isnan (x), logical ([0, 0; 1, 0])); %! assert (isfinite (x), logical ([0, 0; 0, 1])); %! assert (isinf (z), logical ([1, 0; 1, 0])); %! assert (isnan (z), logical ([0, 1; 0, 0])); %! assert (isfinite (z), logical ([0, 0; 0, 1])); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! a = mp ("1"); %! b = mp ("1"); %! n1 = mp ("NaN"); %! n2 = mp ("NaN"); %! assert (isequal (a, b)); %! assert (! isequal (a, n1)); %! assert (! isequal (n1, n2)); %! assert (isequaln (n1, n2)); %! assert (! isequal (a, 1)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for precision = [1024, 2048] %! mpbits (precision); %! x = mp ("1.23456789012345678901234567890123456789"); %! y = abs (x); %! z = angle (x); %! info_y = __mplapack_core__ ("scalar_test_info", y); %! info_z = __mplapack_core__ ("scalar_test_info", z); %! assert (info_y.precision_bits == precision); %! assert (info_z.precision_bits == precision); %! mpbits (128); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 128); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/mp_matrix_assignment_test.cc0000644000230300031750000001024015274353472023015 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_assignment.h" #include #include #include #include #include namespace { using Storage = octave_mplapack::MpfrMatrixStorage; using Operand = octave_mplapack::MpfrAssignmentOperand; Operand scalar_rhs (const std::string& text, mpfr_prec_t precision) { auto value = Storage::NativeScalar::with_precision (precision); assert (mpfr_set_str (value.mpfr_data (), text.c_str (), 10, MPFR_RNDN) == 0); Operand operand; operand.rows = 1; operand.columns = 1; operand.precision_bits = precision; operand.has_mp_precision = true; operand.copy_element = [value] (Storage::NativeScalar& destination, std::size_t, std::size_t) { mpfr_set (destination.mpfr_data (), value.mpfr_data (), MPFR_RNDN); }; return operand; } Operand matrix_rhs (const Storage& source) { Operand operand; operand.rows = source.rows (); operand.columns = source.columns (); operand.precision_bits = source.precision_bits (); operand.has_mp_precision = true; operand.copy_element = [&source] (Storage::NativeScalar& destination, std::size_t row, std::size_t column) { mpfr_set (destination.mpfr_data (), source.at (row, column).mpfr_data (), MPFR_RNDN); }; return operand; } Storage make_source () { Storage source (2, 2, 128); assert (mpfr_set_ui (source.at (0, 0).mpfr_data (), 1, MPFR_RNDN) == 0); assert (mpfr_set_ui (source.at (1, 0).mpfr_data (), 2, MPFR_RNDN) == 0); assert (mpfr_set_ui (source.at (0, 1).mpfr_data (), 3, MPFR_RNDN) == 0); assert (mpfr_set_ui (source.at (1, 1).mpfr_data (), 4, MPFR_RNDN) == 0); return source; } } // namespace int main () { Storage source = make_source (); const std::vector all_rows {0, 1}; const std::vector first_column {0}; Storage changed = octave_mplapack::mpfr_matrix_assign_two_subscript ( source, all_rows, first_column, scalar_rhs ("9", 128), 128); assert (changed.element_exactly_equal_text (0, 0, "9")); assert (changed.element_exactly_equal_text (1, 0, "9")); assert (source.element_exactly_equal_text (0, 0, "1")); assert (source.element_exactly_equal_text (1, 0, "2")); Storage rhs (2, 1, 256); assert (mpfr_set_ui (rhs.at (0, 0).mpfr_data (), 7, MPFR_RNDN) == 0); assert (mpfr_set_ui (rhs.at (1, 0).mpfr_data (), 8, MPFR_RNDN) == 0); Storage widened = octave_mplapack::mpfr_matrix_assign_two_subscript ( source, all_rows, first_column, matrix_rhs (rhs), 256); assert (widened.precision_bits () == 256); assert (widened.at (0, 0).precision () == 256); assert (widened.element_exactly_equal_text (0, 0, "7")); assert (widened.element_exactly_equal_text (1, 0, "8")); assert (widened.element_exactly_equal_text (0, 1, "3")); Storage linear = octave_mplapack::mpfr_matrix_assign_linear ( source, std::vector {1, 3}, scalar_rhs ("5", 128), 128); assert (linear.element_exactly_equal_text (1, 0, "5")); assert (linear.element_exactly_equal_text (1, 1, "5")); assert (linear.element_exactly_equal_text (0, 0, "1")); Storage linear_rhs_storage (2, 2, 256); assert (mpfr_set_ui (linear_rhs_storage.at (0, 0).mpfr_data (), 11, MPFR_RNDN) == 0); assert (mpfr_set_ui (linear_rhs_storage.at (1, 0).mpfr_data (), 12, MPFR_RNDN) == 0); assert (mpfr_set_ui (linear_rhs_storage.at (0, 1).mpfr_data (), 13, MPFR_RNDN) == 0); assert (mpfr_set_ui (linear_rhs_storage.at (1, 1).mpfr_data (), 14, MPFR_RNDN) == 0); Storage colon = octave_mplapack::mpfr_matrix_assign_linear ( source, std::vector {0, 1, 2, 3}, matrix_rhs (linear_rhs_storage), 256); assert (colon.precision_bits () == 256); assert (colon.element_exactly_equal_text (0, 0, "11")); assert (colon.element_exactly_equal_text (1, 0, "12")); bool rejected = false; try { (void) octave_mplapack::mpfr_matrix_assign_two_subscript ( source, all_rows, first_column, matrix_rhs (linear_rhs_storage), 128); } catch (const std::invalid_argument&) { rejected = true; } assert (rejected); return 0; } mplapack-interop-0.5.1/test/mp_complex_lapack_test.cc0000644000230300031750000001636515274353472022261 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_lapack.h" namespace { void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void set_power_of_two (mpc_ptr value, unsigned long exponent) { mpfr_set_ui (mpc_realref (value), 1, MPFR_RNDN); mpfr_div_2si (mpc_realref (value), mpc_realref (value), exponent, MPFR_RNDN); mpfr_set (mpc_imagref (value), mpc_realref (value), MPFR_RNDN); mpfr_neg (mpc_imagref (value), mpc_imagref (value), MPFR_RNDN); } } // namespace int main () { try { static_assert (std::is_same_v< octave_mplapack::MpfrComplexMatrixStorage::MplapackInteger, mplapackint>); const std::vector> coefficient { {3.0, 1.0}, {2.0, 0.0}, {1.0, -1.0}, {4.0, 2.0}}; const std::vector> right_hand_side { {4.0, 4.0}, {14.0, 10.0}, {10.0, 4.0}, {-8.0, 12.0}}; const std::vector> expected { {1.0, 2.0}, {3.0, 0.0}, {2.0, -1.0}, {-1.0, 4.0}}; for (mpfr_prec_t precision : {128, 512}) { octave_mplapack::MpfrComplexMatrixStorage lhs ( 2, 2, precision, coefficient); octave_mplapack::MpfrComplexMatrixStorage rhs ( 2, 2, precision, right_hand_side); const auto solution = octave_mplapack::mplapack_mpc_matrix_solve ( lhs, rhs); check (solution.precision_bits () == precision, "Cgesv solution precision mismatch"); for (std::size_t column = 0; column < 2; ++column) for (std::size_t row = 0; row < 2; ++row) { const octave_mplapack::MpfrComplexScalarStorage actual ( solution.at (row, column)); check (std::abs (actual.to_double () - expected[row + 2 * column]) < 1.0e-12, "Cgesv multiple-RHS solution mismatch"); } check (lhs.element_exactly_equal_double (0, 0, coefficient[0]), "Cgesv mutated coefficient matrix"); check (rhs.element_exactly_equal_double (1, 1, right_hand_side[3]), "Cgesv mutated right-hand side"); octave_mplapack::MpfrMatrixStorage real_lhs ( 2, 2, precision, {3.0, 2.0, 1.0, 4.0}); octave_mplapack::MpfrMatrixStorage real_rhs ( 2, 2, precision, {9.0, 8.0, 7.0, 9.0}); const auto complex_lhs = octave_mplapack::mplapack_mpc_matrix_from_real ( real_lhs, precision); const auto complex_rhs = octave_mplapack::mplapack_mpc_matrix_from_real ( real_rhs, precision); const auto mixed = octave_mplapack::mplapack_mpc_matrix_solve ( complex_lhs, complex_rhs); const octave_mplapack::MpfrComplexScalarStorage mixed_first ( mixed.at (0, 0)); const octave_mplapack::MpfrComplexScalarStorage mixed_last ( mixed.at (1, 1)); check (std::abs (mixed_first.to_double () - std::complex {2.8, 0.0}) < 1.0e-12, "mixed real/complex Cgesv mismatch"); check (std::abs (mixed_last.to_double () - std::complex {1.3, 0.0}) < 1.0e-12, "mixed real/complex multiple-RHS mismatch"); } for (const std::array settings : { std::array {{1024, 700}}, std::array {{2048, 1500}}}) { const mpfr_prec_t precision = static_cast (settings[0]); const unsigned long exponent = settings[1]; octave_mplapack::MpfrComplexMatrixStorage lhs ( 2, 2, precision, std::vector> { {1.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}}); octave_mplapack::MpfrComplexMatrixStorage rhs ( 2, 1, precision); set_power_of_two (rhs.at (0, 0).mpc_data (), exponent); set_power_of_two (rhs.at (1, 0).mpc_data (), exponent); mpfrxx::set_default_precision_bits (128); const auto solution = octave_mplapack::mplapack_mpc_matrix_solve (lhs, rhs); check (solution.precision_bits () == precision, "Cgesv canary precision mismatch"); check (mpfr_equal_p (mpc_realref (solution.at (0, 0).mpc_data ()), mpc_realref (rhs.at (0, 0).mpc_data ())) != 0, "Cgesv real precision canary changed"); check (mpfr_equal_p (mpc_imagref (solution.at (1, 0).mpc_data ()), mpc_imagref (rhs.at (1, 0).mpc_data ())) != 0, "Cgesv imaginary precision canary changed"); check (mpfrxx::default_precision_bits () == 128, "Cgesv changed ambient precision"); } octave_mplapack::MpfrComplexMatrixStorage singular ( 2, 2, 256, std::vector> { {1.0, 0.0}, {2.0, 0.0}, {2.0, 0.0}, {4.0, 0.0}}); octave_mplapack::MpfrComplexMatrixStorage singular_rhs ( 2, 1, 256, std::vector> {{1.0, 0.0}, {2.0, 0.0}}); bool singular_seen = false; try { octave_mplapack::mplapack_mpc_matrix_solve (singular, singular_rhs); } catch (const octave_mplapack::MpcCgesvError& exception) { singular_seen = true; check (exception.kind () == octave_mplapack::MpcCgesvError::Kind::singular, "Cgesv singular classification mismatch"); check (exception.info () > 0, "Cgesv singular info mismatch"); } check (singular_seen, "Cgesv singular solve unexpectedly succeeded"); octave_mplapack::MpfrComplexMatrixStorage nonsquare ( 2, 1, 256, std::vector> {{1.0, 0.0}, {2.0, 0.0}}); bool nonsquare_seen = false; try { octave_mplapack::mplapack_mpc_matrix_solve (nonsquare, singular_rhs); } catch (const std::invalid_argument&) { nonsquare_seen = true; } check (nonsquare_seen, "Cgesv nonsquare solve unexpectedly succeeded"); octave_mplapack::MpfrComplexMatrixStorage empty_lhs (0, 0, 256); octave_mplapack::MpfrComplexMatrixStorage empty_rhs (0, 3, 256); const auto empty = octave_mplapack::mplapack_mpc_matrix_solve ( empty_lhs, empty_rhs); check (empty.rows () == 0 && empty.columns () == 3, "Cgesv empty shape mismatch"); std::cout << "PASS: complex Cgesv dispatch, pivot type, singular behavior, multiple RHS, precision canaries, ambient precision, and immutability\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/mp_complex_storage_test.cc0000644000230300031750000001207415274353472022463 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_complex_matrix_storage.h" #include "mp_complex_precision.h" #include "mp_complex_scalar_storage.h" #include #include #include #include #include #include #include #include #include namespace { using Scalar = octave_mplapack::MpfrComplexScalarStorage; using Matrix = octave_mplapack::MpfrComplexMatrixStorage; void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void test_storage () { for (mpfr_prec_t precision : {128, 256, 512, 1024, 2048}) { Scalar value ("(1.25,-0)", precision); require (value.precision_bits () == precision, "complex scalar precision mismatch"); require (value.imag_signbit (), "negative imaginary zero was lost"); Scalar copy (value); require (copy.exactly_equal (value), "complex copy changed value"); Scalar moved (std::move (copy)); require (moved.exactly_equal (value), "complex move changed value"); Matrix matrix (2, 2, precision, std::vector { "(1,2)", "(3,4)", "(5,6)", "(7,8)"}); require (matrix.rows () == 2 && matrix.columns () == 2, "complex matrix shape mismatch"); require (matrix.leading_dimension () == 2, "complex matrix leading dimension mismatch"); require (matrix.all_elements_have_uniform_precision (), "complex matrix precision is not uniform"); require (matrix.at (1, 0).real_to_double () == 3.0, "complex matrix column-major layout mismatch"); Matrix matrix_copy (matrix); require (matrix_copy.data () != matrix.data (), "complex matrix copy aliases source"); mpfr_set_si (mpc_realref (matrix_copy.at (0, 0).mpc_data ()), 99, MPFR_RNDN); require (matrix.at (0, 0).real_to_double () == 1.0, "complex matrix work copy mutated source"); } } void test_scope () { mpfrxx::set_default_precision_bits (333); mpfrxx::set_default_rounding_mode (MPFR_RNDD); mpfrxx::set_default_mpc_precision_bits (333, 257); mpfrxx::set_default_mpc_rounding_mode (MPFR_RNDD, MPFR_RNDU); { octave_mplapack::MpfrMpcPrecisionScope outer (1024); require (mpfrxx::default_precision_bits () == 1024, "outer MPFR scope did not apply"); require (mpfrxx::default_mpc_real_precision_bits () == 1024 && mpfrxx::default_mpc_imag_precision_bits () == 1024, "outer MPC scope did not apply"); require (mpfrxx::default_rounding_mode () == MPFR_RNDN && mpfrxx::default_mpc_real_rounding_mode () == MPFR_RNDN && mpfrxx::default_mpc_imag_rounding_mode () == MPFR_RNDN, "outer scope did not normalize rounding"); { octave_mplapack::MpfrMpcPrecisionScope inner (2048); require (mpfrxx::default_precision_bits () == 2048 && mpfrxx::default_mpc_precision_bits () == 2048, "nested scope did not apply"); } require (mpfrxx::default_precision_bits () == 1024 && mpfrxx::default_mpc_real_precision_bits () == 1024, "nested scope did not restore outer state"); } require (mpfrxx::default_precision_bits () == 333, "scope did not restore MPFR precision"); require (mpfrxx::default_mpc_real_precision_bits () == 333 && mpfrxx::default_mpc_imag_precision_bits () == 257, "scope did not restore MPC component precision"); require (mpfrxx::default_rounding_mode () == MPFR_RNDD && mpfrxx::default_mpc_real_rounding_mode () == MPFR_RNDD && mpfrxx::default_mpc_imag_rounding_mode () == MPFR_RNDU, "scope did not restore rounding"); bool exception_seen = false; try { octave_mplapack::MpfrMpcPrecisionScope scope (512); throw std::runtime_error ("scope test"); } catch (const std::runtime_error&) { exception_seen = true; } require (exception_seen && mpfrxx::default_precision_bits () == 333, "exception path did not restore scope"); } void test_tls () { mpfrxx::set_default_precision_bits (128); std::atomic worker_ok (false); std::thread worker ([&] { mpfrxx::set_default_precision_bits (2048); Scalar value (0.0, 1.0, 2048); worker_ok.store (value.precision_bits () == 2048 && mpfrxx::default_precision_bits () == 2048, std::memory_order_release); }); worker.join (); require (worker_ok.load (std::memory_order_acquire), "worker precision was not independent"); require (mpfrxx::default_precision_bits () == 128, "worker changed main-thread precision"); } } int main () { try { test_storage (); test_scope (); test_tls (); std::cout << "PASS: complex storage, scope, TLS, lifetime, and special-value gates\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/m17_rpotrf_probe.cc0000644000230300031750000000646515274353472020733 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include namespace { using Real = mpfrxx::mpfr_class; Real at_precision (mpfr_prec_t precision) { return Real::with_precision (precision); } void set_integer (Real& value, long integer) { mpfr_set_si (value.mpfr_data (), integer, MPFR_RNDN); } void set_power_of_two (Real& value, long exponent) { mpfr_set_ui_2exp (value.mpfr_data (), 1, exponent, MPFR_RNDN); } void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void check_spd (mpfr_prec_t precision, long exponent) { std::vector a (4, at_precision (precision)); set_integer (a[0], 1); set_integer (a[1], 1); set_integer (a[2], 1); Real delta = at_precision (precision); set_power_of_two (delta, exponent); mpfr_add (a[3].mpfr_data (), delta.mpfr_data (), a[0].mpfr_data (), MPFR_RNDN); const auto original_default = mpfrxx::default_precision_bits (); mplapackint info = -1; { MplapackMpfrPrecisionScope scope (precision); Rpotrf ("U", 2, a.data (), 2, info); check (mpfrxx::default_precision_bits () == precision, "Rpotrf changed the scoped precision"); } check (info == 0, "Rpotrf SPD probe failed"); check (mpfrxx::default_precision_bits () == original_default, "Rpotrf did not restore ambient precision"); Real expected_tail = at_precision (precision); set_power_of_two (expected_tail, exponent / 2); check (mpfr_equal_p (a[3].mpfr_data (), expected_tail.mpfr_data ()) != 0, "Rpotrf factor tail was not preserved"); } void check_high_ambient () { const mpfr_prec_t source_precision = 256; std::vector a (4, at_precision (source_precision)); set_integer (a[0], 4); set_integer (a[1], 2); set_integer (a[2], 2); set_integer (a[3], 10); mpfrxx::set_default_precision_bits (4096); mplapackint info = -1; { MplapackMpfrPrecisionScope scope (source_precision); Rpotrf ("U", 2, a.data (), 2, info); } check (info == 0, "Rpotrf high-ambient probe failed"); check (mpfrxx::default_precision_bits () == 4096, "Rpotrf high ambient precision was not restored"); check (a[0].precision () == source_precision && a[3].precision () == source_precision, "Rpotrf high-ambient storage precision changed"); } void check_non_pd () { std::vector a (4, at_precision (1024)); set_integer (a[0], 1); set_integer (a[1], 1); set_integer (a[2], 1); set_integer (a[3], 1); mplapackint info = -1; { MplapackMpfrPrecisionScope scope (1024); Rpotrf ("U", 2, a.data (), 2, info); } check (info > 0, "Rpotrf non-positive-definite probe did not fail"); } } // namespace int main () { try { mpfrxx::set_default_precision_bits (128); check_spd (1024, -700); check_spd (2048, -1500); check_high_ambient (); mpfrxx::set_default_precision_bits (128); check_non_pd (); check (mpfrxx::default_precision_bits () == 128, "Rpotrf probe leaked ambient precision"); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: installed MPLAPACK MPFR Rpotrf precision probe\n"; return 0; } mplapack-interop-0.5.1/test/matrix_lifetime.m0000644000230300031750000000201015274353472020553 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause matrix = mp ({"1", "2"; "3", "4"}); assigned = matrix; collection = {matrix}; record.value = matrix; clear matrix; assert (size (assigned), [2, 2]); assert (size (collection{1}), [2, 2]); assert (size (record.value), [2, 2]); assert (__mplapack_core__ ( "matrix_test_element_equal_text", assigned, 2, 2, "4")); assert (__mplapack_core__ ("module_test_locked")); clear __mplapack_core__; assert (size (assigned), [2, 2]); assert (__mplapack_core__ ( "matrix_test_element_equal_text", assigned, 1, 2, "2")); assert (__mplapack_core__ ("module_test_locked")); for index = 1:1000 repeated = mp ([1, 2; 3, 4]); info = __mplapack_core__ ("matrix_test_info", repeated); assert (strcmp (info.internal_type, "mplapack_mpfr_matrix_internal")); assert (info.all_elements_same_precision); endfor clear repeated info assigned collection record; assert (__mplapack_core__ ("module_test_locked")); fprintf ("PASS: M07 matrix clear, copy/container, and repeated type initialization QA\n"); mplapack-interop-0.5.1/test/constructor.tst0000644000230300031750000001163115274353472020345 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function y = m03_pass_through (x) %! y = x; %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! assert (__mplapack_core__ ("scalar_default_precision"), int64 (128)); %! text_value = mp ("0.1"); %! double_value = mp (0.1); %! text_info = __mplapack_core__ ("scalar_test_info", text_value); %! double_info = __mplapack_core__ ("scalar_test_info", double_value); %! assert (text_info.precision_bits, int64 (128)); %! assert (double_info.precision_bits, int64 (128)); %! assert (! __mplapack_core__ ( %! "scalar_test_equal", text_value, double_value)); %! assert (__mplapack_core__ ( %! "scalar_test_equal_string", text_value, "0.1")); %! assert (! __mplapack_core__ ( %! "scalar_test_equal_double", text_value, 0.1)); %! assert (__mplapack_core__ ( %! "scalar_test_equal_double", double_value, 0.1)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! text_value = mp ("0.125"); %! double_value = mp (0.125); %! single_quoted = mp ('0.125'); %! assert (__mplapack_core__ ( %! "scalar_test_equal", text_value, double_value)); %! assert (__mplapack_core__ ( %! "scalar_test_equal", text_value, single_quoted)); %! assert (__mplapack_core__ ( %! "scalar_test_equal_string", text_value, "0.125")); %! assert (__mplapack_core__ ( %! "scalar_test_equal_double", double_value, 0.125)); %!test %! texts = {"0", "1", "-1", "0.125", "0.1", ... %! "1.2345678901234567890123456789", "1e100", "1e-100"}; %! for i = 1:numel (texts) %! value = mp (texts{i}); %! assert (__mplapack_core__ ( %! "scalar_test_equal_string", value, texts{i})); %! endfor %!test %! smallest_subnormal = realmin * eps; %! for value = [realmin, realmax, 1 + eps, smallest_subnormal] %! converted = mp (value); %! assert (__mplapack_core__ ( %! "scalar_test_equal_double", converted, value)); %! endfor %!test %! positive = mp (0.0); %! negative = mp (-0.0); %! positive_info = __mplapack_core__ ("scalar_test_info", positive); %! negative_info = __mplapack_core__ ("scalar_test_info", negative); %! assert (positive_info.is_zero && ! positive_info.signbit); %! assert (negative_info.is_zero && negative_info.signbit); %!test %! positive_inf = __mplapack_core__ ("scalar_test_info", mp (Inf)); %! negative_inf = __mplapack_core__ ("scalar_test_info", mp (-Inf)); %! nan_info = __mplapack_core__ ("scalar_test_info", mp (NaN)); %! assert (positive_inf.is_infinite && ! positive_inf.signbit); %! assert (negative_inf.is_infinite && negative_inf.signbit); %! assert (nan_info.is_nan); %! text_inf = __mplapack_core__ ("scalar_test_info", mp ("Inf")); %! text_negative_inf = __mplapack_core__ ( %! "scalar_test_info", mp ("-Inf")); %! text_nan = __mplapack_core__ ("scalar_test_info", mp ("NaN")); %! assert (text_inf.is_infinite && ! text_inf.signbit); %! assert (text_negative_inf.is_infinite && text_negative_inf.signbit); %! assert (text_nan.is_nan); %!test %! value = mp ("1"); %! assert (strcmp (class (value), "mp")); %! assert (size (value), [1, 1]); %! assert (rows (value), 1); %! assert (columns (value), 1); %! assert (numel (value), 1); %! assert (isempty (properties (value))); %! assert (strcmp (strtrim (evalc ("disp (value)")), char (value))); %! try %! value.payload_; %! error ("M03 private payload unexpectedly accessible"); %! catch exception %! assert (! isempty (strfind (exception.message, "private access"))); %! end_try_catch %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! original = mp ("1.25"); %! assigned = original; %! copied = mp (original); %! collection = {original, assigned}; %! record.value = original; %! passed = m03_pass_through (original); %! clear original; %! for value = {assigned, copied, collection{1}, collection{2}, ... %! record.value, passed} %! info = __mplapack_core__ ("scalar_test_info", value{1}); %! assert (info.precision_bits, int64 (128)); %! assert (__mplapack_core__ ( %! "scalar_test_equal_string", value{1}, "1.25")); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! a = mp ("1"); %! b = mp ("2"); %! product = a * b; %! assert (__mplapack_core__ ("scalar_test_equal_string", product, "2")); %! quotient = mldivide (a, b); %! assert (__mplapack_core__ ("scalar_test_equal_string", quotient, "2")); %!error mp () %!error mp (1, 2) %!test %! z = mp (1 + 2i); %! assert (! isreal (z)); %! assert (double (z) == 1 + 2i); %!test %! z = mp (complex (1, 0)); %! assert (! isreal (z)); %!error mp (["1"; "2"]) %!error mp ("") %!error mp ("abc") %!error mp ("1.2.3") %!error mp ("1,5") %!error mp (single (1)) %!error mp (struct ()) mplapack-interop-0.5.1/test/mp_matrix_structure_test.cc0000644000230300031750000000752715274353472022723 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_structure.h" #include #include #include #include namespace { using octave_mplapack::MpfrMatrixStorage; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void check_text (const MpfrMatrixStorage& value, const std::vector& expected) { check (value.numel () == expected.size (), "unexpected element count"); for (std::size_t column = 0; column < value.columns (); ++column) for (std::size_t row = 0; row < value.rows (); ++row) { const std::size_t index = row + column * value.rows (); check (value.element_exactly_equal_text (row, column, expected[index]), "unexpected structural value"); } } } // namespace int main () { try { const MpfrMatrixStorage source ( 2, 3, 256, std::vector {"11", "21", "12", "22", "13", "23"}); const auto transposed = octave_mplapack::mpfr_matrix_transpose (source); check (transposed.rows () == 3 && transposed.columns () == 2, "transpose shape mismatch"); check (transposed.precision_bits () == 256, "transpose precision mismatch"); check_text (transposed, {"11", "12", "13", "21", "22", "23"}); const auto reshaped = octave_mplapack::mpfr_matrix_reshape (source, 3, 2); check (reshaped.rows () == 3 && reshaped.columns () == 2, "reshape shape mismatch"); check_text (reshaped, {"11", "21", "12", "22", "13", "23"}); const auto row = octave_mplapack::mpfr_matrix_reshape (source, 1, 6); check_text (row, {"11", "21", "12", "22", "13", "23"}); const auto column = octave_mplapack::mpfr_matrix_reshape (source, 6, 1); check_text (column, {"11", "21", "12", "22", "13", "23"}); const auto round_trip = octave_mplapack::mpfr_matrix_reshape (row, 2, 3); check (round_trip.element_exactly_equal (1, 2, source, 1, 2), "reshape round-trip mismatch"); const MpfrMatrixStorage precise ( 1, 2, 1024, std::vector { "1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", "1"}); const auto precise_transpose = octave_mplapack::mpfr_matrix_transpose (precise); check (precise_transpose.precision_bits () == 1024, "high precision transpose lost precision"); check (precise_transpose.element_exactly_equal (0, 0, precise, 0, 0), "high precision transpose changed value"); const MpfrMatrixStorage empty_row (0, 3, 333); const auto empty_column = octave_mplapack::mpfr_matrix_transpose (empty_row); check (empty_column.rows () == 3 && empty_column.columns () == 0, "empty transpose shape mismatch"); check (empty_column.precision_bits () == 333, "empty transpose precision mismatch"); const MpfrMatrixStorage empty (0, 0, 512); const auto empty_again = octave_mplapack::mpfr_matrix_reshape (empty, 0, 0); check (empty_again.rows () == 0 && empty_again.columns () == 0, "empty reshape shape mismatch"); bool mismatch = false; try { (void) octave_mplapack::mpfr_matrix_reshape (source, 4, 2); } catch (const std::invalid_argument&) { mismatch = true; } check (mismatch, "invalid reshape element count unexpectedly succeeded"); std::cout << "PASS: native transpose, reshape, exact copies, empty shapes, and errors\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/test_neigt03.m0000644000230300031750000000442515274353472017715 0ustar rafaelrafael% Focused NEIGT03 matching, metrics, and reference-role test. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect mpbits (256); match = net_match (mp ([3; 1; 2]), mp ([1; 2; 3]), "absolute"); assert (match.threshold == mp (0)); assert (match.mapping == [3, 1, 2]); duplicate = net_match (mp ([0; 0; 2]), mp ([0; 1; 2]), "absolute"); assert (duplicate.threshold == mp (1)); augment = net_match (mp ([2; 0]), mp ([1; 3]), "absolute"); assert (augment.threshold == mp (1)); mpbits (2048); tiny_value = net_pow2 (-1500, 2048); zero_value = mp (0); one_value = mp (1); computed_tiny = [tiny_value; one_value]; reference_tiny = [zero_value; one_value]; tiny = net_match (computed_tiny, reference_tiny, "absolute"); assert (tiny.threshold == tiny_value); fixture = net_similarity_model ("simple", 6, 80, 512); reference = net_reference (fixture, 1024); mpbits (1024); [V, D, W] = eig (net_widen (fixture.A_frozen, 1024, 512), "nobalance"); metrics = net_metrics (fixture.A_frozen + mp (zeros (6)), V, D, W, ... reference.values, struct ("simple_mask", true (6, 1))); assert (strcmp (metrics.status, "MEASURED")); assert (metrics.absolute_match.threshold >= mp (0)); bad_left = ctranspose (W); bad = net_metrics (fixture.A_frozen + mp (zeros (6)), V, D, bad_left, ... reference.values, struct ("simple_mask", true (6, 1))); assert (bad.left_residual > metrics.left_residual); jordan = net_similarity_model ("jordan", 6, 80, 512); jordan_reference = net_reference (jordan, 1024); [Vj, Dj, Wj] = eig (net_widen (jordan.A_frozen, 1024, 512), "nobalance"); defective = net_metrics (jordan.A_frozen + mp (zeros (6)), Vj, Dj, Wj, ... jordan_reference.values, struct ("simple_mask", ... [false; false; true; true; true; true])); assert (strcmp (defective.condition_status{1}, "not_applicable_simple_root")); fprintf ("PASS: NEIGT03 MP bottleneck matching, left convention, references, and metrics\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/t12_linear_system_callback.m0000644000230300031750000000035315274353472022561 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [residual, jacobian] = t12_linear_system_callback (value) target = mp ("1.375"); residual = [value(1) - target; value(2) - 2 * target]; jacobian = mp ([1, 0; 0, 1]); endfunction mplapack-interop-0.5.1/test/t05_gamma_erf.tst0000644000230300031750000000347615274353472020376 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! five = mp ('5'); %! assert (isequal (gamma (five), mp ('24'))); %! gl = gammaln (five); %! assert (double (abs (gl-log (gamma (five)))) < 1e-50); %! assert (double (abs (lgamma (five)-gl)) < 1e-50); %! assert (double (abs (erf (mp ('0')))) == 0); %! assert (double (abs (erf (mp ('1'))+erfc (mp ('1'))-mp ('1'))) < 1e-50); %! assert (erfc (mp ('100')) > 0); %! assert (isinf (gamma (mp ('0'))) && ! signbit (gamma (mp ('0')))); %! assert (isinf (gamma (mp ('-0'))) && signbit (gamma (mp ('-0')))); %! assert (isinf (gamma (mp ('-1')))); %! assert (isinf (gammaln (mp ('0')))); %! assert (isnan (gamma (mp ('NaN')))); %! V = gamma (mp ({'1','2';'3','4'})); %! assert (double (norm (V-mp ({'1','1';'2','6'}), "fro")) < 1e-50); %! try %! gamma (mp ('1','2')); %! error ("expected complex gamma rejection"); %! catch err %! assert (strcmp (err.identifier, "mplapack:mp:ComplexUnsupported")); %! end_try_catch %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for bits = [1024, 2048] %! mpbits (bits); %! limit = 1500; %! if (bits == 1024), limit = 700; endif %! tiny = mp ('1'); %! for k = 1:limit, tiny = tiny * mp ('0.5'); endfor %! e = erf (tiny); %! c = erfc (tiny); %! assert (e > 0 && c < mp ('1')); %! assert (double (abs (e+c-mp ('1'))) < 1e-200); %! assert (isequal (gamma (mp ('5')), mp ('24'))); %! assert (__mplapack_core__ ("scalar_test_info", e).precision_bits == uint64 (bits)); %! assert (__mplapack_core__ ("scalar_test_info", gammaln (mp ('5'))).precision_bits == uint64 (bits)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/rank.tst0000644000230300031750000001134615274353472016716 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_matrix_close (value, expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! got = __mplapack_core__ ("matrix_test_element_double", ... %! value, row, column); %! assert (got, expected(row, column), 1e-12); %! endfor %! endfor %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ({"1", "2"; "2", "4"; "3", "6"}); %! X = A \ mp ({"1"; "2"; "3"}); %! assert_matrix_close (X, [1/5; 2/5]); %! X = A \ mp ({"1"; "2"; "4"}); %! assert_matrix_close (X, [17/70; 17/35]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! delta_text = strcat ("0.", repmat ("0", 1, 451), "1"); %! mpbits (2048); %! A = mp ({"1", "0"; "0", delta_text; "0", "0"}); %! B = mp ({"0"; delta_text; "0"}); %! mpbits (128); %! X = A \ B; %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (2048)); %! assert (__mplapack_core__ ("matrix_test_element_double", X, 2, 1), ... %! 1, 1e-12); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2"; "2", "4"; "3", "6"}); %! B = mp ({"1"; "2"; "3"}); %! mpbits (4096); %! X = A \ B; %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (256)); %! assert_matrix_close (X, [1/5; 2/5]); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (4096)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ({"1", "2", "3"; "2", "4", "6"}); %! B = mp ({"1", "2"; "2", "4"}); %! X = A \ B; %! assert_matrix_close (X, [1/14, 2/14; 2/14, 4/14; 3/14, 6/14]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp (zeros (3, 2)); %! B = mp ({"1"; "2"; "3"}); %! X = A \ B; %! info = __mplapack_core__ ("matrix_test_info", X); %! assert (info.rows, uint64 (2)); %! assert (info.columns, uint64 (1)); %! assert_matrix_close (X, [0; 0]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! delta_text = strcat ("0.", repmat ("0", 1, 210), "1"); %! mpbits (512); %! A512 = mp ({"1", "0"; "0", delta_text; "0", "0"}); %! B512 = mp ({"0"; delta_text; "0"}); %! X512 = A512 \ B512; %! assert (__mplapack_core__ ("matrix_test_info", X512).precision_bits, ... %! uint64 (512)); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! X512, 2, 1, 0)); %! mpbits (1024); %! A1024 = mp ({"1", "0"; "0", delta_text; "0", "0"}); %! B1024 = mp ({"0"; delta_text; "0"}); %! mpbits (128); %! X1024 = A1024 \ B1024; %! assert (__mplapack_core__ ("matrix_test_info", X1024).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_element_double", ... %! X1024, 2, 1), 1, 1e-12); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2"; "2", "4"; "3", "6"}); %! B = [1; 2; 3]; %! X = A \ B; %! assert_matrix_close (X, [1/5; 2/5]); %! X2 = [1, 2; 2, 4; 3, 6] \ mp ({"1"; "2"; "3"}); %! assert_matrix_close (X2, [1/5; 2/5]); %! B_mp = mp ({"1"; "2"; "3"}); %! mpbits (4096); %! X3 = A \ B_mp; %! assert (__mplapack_core__ ("matrix_test_info", X3).precision_bits, ... %! uint64 (256)); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "0"; "0", "1"; "1", "1"}); %! B = mp ({"0"; "1"; "4"}); %! X = A \ B; %! assert_matrix_close (X, [1; 2]); %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (256)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/rank_condition.tst0000644000230300031750000000577515274353472020775 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1, 2; 3, 4]); %! assert (rank (A), 2); %! assert (rank (A, mp ("1")), 1); %! c2 = cond (A); %! c1 = cond (A, 1); %! ci = cond (A, Inf); %! cf = cond (A, "fro"); %! rc = rcond (A); %! assert (double (c2) > 14 && double (c2) < 15); %! assert (double (c1) > 20 && double (c1) < 22); %! assert (double (ci) > 20 && double (ci) < 22); %! assert (double (cf) > 14 && double (cf) < 16); %! assert (abs (double (c1 * rc) - 1) < 1e-12); %! [d, det_rc] = det (A); %! assert (double (d), -2, 1e-12); %! assert (abs (double (det_rc - rc)) < 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! Z = mp ([1 + 2i, 2 - 1i; 3, 4 + 3i]); %! assert (rank (Z), 2); %! assert (double (cond (Z)) > 1); %! assert (double (cond (Z, 1)) > 1); %! assert (double (cond (Z, Inf)) > 1); %! assert (double (cond (Z, "fro")) > 1); %! assert (double (rcond (Z)) > 0 && double (rcond (Z)) < 1); %! [d, det_rc] = det (Z); %! assert (! isreal (d)); %! assert (double (det_rc) > 0 && double (det_rc) < 1); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1, 0; 0, 0]); %! assert (rank (A), 1); %! assert (rank (A, 0), 1); %! assert (rank (A, Inf), 0); %! assert (isinf (double (cond (A)))); %! assert (double (rcond (A)) == 0); %! empty = mp (zeros (0, 0)); %! assert (rank (empty), 0); %! assert (double (cond (empty)) == 0); %! assert (isinf (double (rcond (empty)))); %! nonsquare = mp ([1, 2, 3; 4, 5, 6]); %! assert (rank (nonsquare), 2); %! assert (double (cond (nonsquare)) > 1); %! fail ("cond (nonsquare, 1)", "square"); %! fail ("rcond (nonsquare)", "square"); %! fail ("cond (nonsquare, \"fro\")", "square"); %! fail ("[d, c] = det (empty)", "one output"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A512 = mp ([1, 0; 0, 1]); %! tail = mp ("1"); %! for k = 1:700, tail = tail .* mp ("0.5"); endfor %! A512 (2, 2) = tail; %! assert (rank (A512), 1); %! mpbits (1024); %! A1024 = mp ([1, 0; 0, 1]); %! tail = mp ("1"); %! for k = 1:700, tail = tail .* mp ("0.5"); endfor %! A1024 (2, 2) = tail; %! assert (rank (A1024), 2); %! assert (__mplapack_core__ ("matrix_test_info", A1024).precision_bits == 1024); %! mpbits (2048); %! A2048 = mp ([1, 0; 0, 1]); %! tail = mp ("1"); %! for k = 1:1500, tail = tail .* mp ("0.5"); endfor %! A2048 (2, 2) = tail; %! assert (rank (A2048), 2); %! assert (double (cond (A2048)) > 0); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ([1, 2; 3, 4]); %! fail ("cond (A, 3)", "cond norm"); %! fail ("cond (A, \"bad\")", "cond string option"); %! fail ("rank (A, mp ([1, 2]))", "real scalar"); mplapack-interop-0.5.1/test/test_neigt12.m0000644000230300031750000000163115274353472017711 0ustar rafaelrafael% NEIGT12: complete ordinary profile coverage and honest all-tier status. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); result = mp_neig_tiers ("smoke", struct ("tier", "all")); assert (strcmp (result.schema, "neigt-v1")); assert (strcmp (result.status, "NUMERICS_ONLY_COMPLETE")); assert (! result.ok && result.scope_ok); assert (result.coverage.case_count == 20); assert (result.coverage.measured_eig_rows == 120); assert (result.coverage.ordinary_complete); assert (strcmp (result.verification_status, "NOT_IMPLEMENTED")); for index = 1:numel (result.rows) row = result.rows{index}; assert (row.complete); if (strcmp (row.work_role, "native64")) assert (row.gate_pass); else assert (isfield (row, "gate") && row.gate_pass); endif endfor fprintf ("PASS: NEIGT12 ordinary smoke coverage is 120 rows and V remains explicit\n"); mplapack-interop-0.5.1/test/complex_elementwise.tst0000644000230300031750000000516715274353472022037 0ustar rafaelrafael%!function info = complex_elementwise_info (value) %! if (__mplapack_core__ ("value_is_matrix", value)) %! info = __mplapack_core__ ("matrix_test_info", value); %! else %! info = __mplapack_core__ ("scalar_test_info", value); %! endif %!endfunction %!test %! mpbits (512); %! a = mp ("1", "2"); %! b = mp ("3", "4"); %! assert (strcmp (char (a + b), "(4e+0,6e+0)")); %! assert (strcmp (char (a - b), "(-2e+0,-2e+0)")); %! assert (strcmp (char (a .* b), "(-5e+0,1e+1)")); %! assert (strcmp (char (a ./ mp ("1", "0")), "(1e+0,2e+0)")); %! assert (strcmp (char (-a), "(-1e+0,-2e+0)")); %! assert (strcmp (char (+a), char (a))); %!test %! mpbits (256); %! r = mp ("1.5"); %! z = mp ("2", "3"); %! assert (! isreal (r + z) && ! isreal (z + r)); %! assert (double (r + z) == complex (3.5, 3)); %! assert (double (z - r) == complex (0.5, 3)); %! assert (double (r .* z) == complex (3, 4.5)); %! assert (double (z ./ r) == complex (4 / 3, 2)); %! builtin = complex (0.25, -0.5); %! assert (! isreal (z + builtin)); %! assert (double (z + builtin) == complex (2.25, 2.5)); %! assert (! isreal (builtin - z)); %! assert (double (builtin - z) == complex (-1.75, -3.5)); %!test %! mpbits (512); %! A = mp ([1 + 2i, 3 + 4i; 5 + 6i, 7 + 8i]); %! row = mp ([10 + 1i, 20 + 2i]); %! column = mp ([100 + 10i; 200 + 20i]); %! assert (double (A + row), [11 + 3i, 23 + 6i; 15 + 7i, 27 + 10i]); %! assert (double (A + column), [101 + 12i, 103 + 14i; 205 + 26i, 207 + 28i]); %! assert (double (column - row), [90 + 9i, 80 + 8i; 190 + 19i, 180 + 18i]); %! assert (size (A .* [2 + 1i, 3 + 2i]), [2, 2]); %! assert (! isreal (-(A))); %! assert (complex_elementwise_info (A + row).precision_bits == 512); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! low = mp ("1", "2"); %! mpbits (1024); %! high = mp ("3", "4"); %! mpbits (2048); %! result = low + high; %! assert (complex_elementwise_info (result).precision_bits == 1024); %! assert (strcmp (char (result), "(4e+0,6e+0)")); %! assert (mpbits (), uint64 (2048)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 2048); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! positive = mp ("1", "0"); %! zero = mp ("0", "0"); %! quotient = positive ./ zero; %! qinfo = __mplapack_core__ ("scalar_test_info", quotient); %! assert (qinfo.is_infinite || qinfo.is_nan); %! nan_value = mp ("NaN", "0"); %! assert (__mplapack_core__ ("scalar_test_info", nan_value + positive).is_nan); %!test %! A = mp (complex (zeros (0, 3), zeros (0, 3))); %! B = mp (complex (ones (1, 3), zeros (1, 3))); %! C = A + B; %! assert (size (C), [0, 3]); %! assert (! isreal (C)); mplapack-interop-0.5.1/test/conversion.tst0000644000230300031750000001373515274353472020154 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function bits = m05_double_bits (value) %! bits = typecast (value, "uint64"); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! precisions = [128, 256, 333, 512, 1024]; %! texts = {"1", "-1", "0.125", "0.1", ... %! "1.234567890123456789", "1e100", "1e-100"}; %! for precision = precisions %! mpbits (precision); %! for i = 1:numel (texts) %! original = mp (texts{i}); %! canonical = char (original); %! assert (ischar (canonical)); %! assert (rows (canonical), 1); %! assert (! isempty (regexp (canonical, ... %! "^-?[1-9](\\.[0-9]+)?e[+-](0|[1-9][0-9]*)$", "once"))); %! assert (isempty (strfind (canonical, "payload_"))); %! assert (isempty (strfind ( %! canonical, "mplapack_mpfr_scalar_internal"))); %! reconstructed = mp (canonical); %! assert (__mplapack_core__ ( %! "scalar_test_equal", original, reconstructed)); %! endfor %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! old_value = mp ("0.1"); %! before = char (old_value); %! before_double = m05_double_bits (double (old_value)); %! mpbits (1024); %! assert (char (old_value), before); %! assert (m05_double_bits (double (old_value)), before_double); %! new_value = mp ("0.1"); %! assert (! strcmp (char (new_value), before)); %! mpbits (128); %! reconstructed = mp (before); %! assert (__mplapack_core__ ( %! "scalar_test_equal", old_value, reconstructed)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! positive_zero_mp = mp (0.0); %! negative_zero_mp = mp (-0.0); %! positive_infinity_mp = mp (Inf); %! negative_infinity_mp = mp (-Inf); %! not_a_number_mp = mp (NaN); %! values = {positive_zero_mp, negative_zero_mp, positive_infinity_mp, ... %! negative_infinity_mp, not_a_number_mp}; %! expected = {"0", "-0", "Inf", "-Inf", "NaN"}; %! for i = 1:numel (values) %! assert (char (values{i}), expected{i}); %! assert (evalc ("disp (values{i})"), [expected{i}, "\n"]); %! reconstructed = mp (char (values{i})); %! info = __mplapack_core__ ("scalar_test_info", reconstructed); %! if (i == 1) %! assert (info.is_zero && ! info.signbit); %! elseif (i == 2) %! assert (info.is_zero && info.signbit); %! elseif (i == 3) %! assert (info.is_infinite && ! info.signbit); %! elseif (i == 4) %! assert (info.is_infinite && info.signbit); %! else %! assert (info.is_nan); %! endif %! endfor %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! inputs = [0.0, -0.0, 1.0, -1.0, 0.5, 0.1, realmin, realmax, ... %! realmin * eps, 1 + eps]; %! for input = inputs %! converted = double (mp (input)); %! assert (m05_double_bits (converted), m05_double_bits (input)); %! endfor %! assert (double (mp ("0.1")), 0.1); %! assert (double (mp ("0.5")), 0.5); %! assert (double (mp ("0.125")), 0.125); %! assert (double (mp ("1.234567890123456789")), ... %! 1.2345678901234567); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! positive_zero = double (mp (0.0)); %! negative_zero = double (mp (-0.0)); %! assert (m05_double_bits (positive_zero), m05_double_bits (0.0)); %! assert (m05_double_bits (negative_zero), m05_double_bits (-0.0)); %! assert (isinf (double (mp (Inf))) && double (mp (Inf)) > 0); %! assert (isinf (double (mp (-Inf))) && double (mp (-Inf)) < 0); %! assert (isnan (double (mp (NaN)))); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! halfway = mp (... %! "1.00000000000000011102230246251565404236316680908203125"); %! assert (m05_double_bits (double (halfway)), ... %! m05_double_bits (1.0)); %! assert (isinf (double (mp ("1e10000")))); %! assert (isinf (double (mp ("-1e10000")))); %! positive_underflow = double (mp ("1e-10000")); %! negative_underflow = double (mp ("-1e-10000")); %! assert (m05_double_bits (positive_underflow), ... %! m05_double_bits (0.0)); %! assert (m05_double_bits (negative_underflow), ... %! m05_double_bits (-0.0)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! value = mp ("0.1"); %! canonical = char (value); %! format short; %! short_output = evalc ("disp (value)"); %! format long; %! long_output = evalc ("disp (value)"); %! assert (short_output, [canonical, "\n"]); %! assert (long_output, short_output); %! mpbits (512); %! assert (evalc ("disp (value)"), short_output); %! bare_output = evalc ("value"); %! assert (! isempty (strfind (bare_output, canonical))); %! assert (isempty (strfind (bare_output, "payload_"))); %! assert (isempty (strfind ( %! bare_output, "mplapack_mpfr_scalar_internal"))); %! assert (mpbits (), uint64 (512)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (333); %! original = mp ("0.1"); %! assigned = original; %! copied = mp (original); %! assert (char (assigned), char (original)); %! assert (char (copied), char (original)); %! assert (m05_double_bits (double (assigned)), ... %! m05_double_bits (double (original))); %! assert (m05_double_bits (double (copied)), ... %! m05_double_bits (double (original))); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! a = mp ("1"); %! assert (isa (sin (a), "mp")); %! assert (isa (exp (a), "mp")); %! assert (isa (sqrt (a), "mp")); %! assert (strcmp (char (a), "1e+0")); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (8192); %! value = mp ("0.1"); %! canonical = char (value); %! reconstructed = mp (canonical); %! assert (__mplapack_core__ ( %! "scalar_test_equal", value, reconstructed)); %! assert (double (value), 0.1); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/mrdivide.tst0000644000230300031750000001616715274353472017574 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! assert (norm (double (mp ("5") / mp ("2")) - 2.5) < 1e-12); %! A = mp ([1, 2; 3, 4]); %! assert (norm (double (A / mp ("2")) - [1, 2; 3, 4] / 2, "fro") < 1e-12); %! Z = mp ([1 + 2i, 2 - 1i; 3, 4 + 3i]); %! assert (norm (double (Z / mp ("2")) - double (Z) ./ 2, "fro") < 1e-12); %! B = mp ([1 + 1i; 2 - 1i]); %! Bd = double (B); %! expected = 2 * ctranspose (Bd) ./ sum (abs (Bd) .^ 2); %! assert (norm (double (mp ("2") / B) - expected, "fro") < 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! B = mp ([2, 1; 1, 3]); %! A_before = double (A); %! B_before = double (B); %! X = A / B; %! assert (size (X), [2, 2]); %! assert (norm (double (X) - A_before / B_before, "fro") < 1e-12); %! assert (norm (double (mrdivide (A, B)) - A_before / B_before, "fro") < 1e-12); %! assert (double (A), A_before); %! assert (double (B), B_before); %! info = __mplapack_core__ ("matrix_test_info", X); %! assert (! info.is_complex && info.precision_bits == 256); %! %! Z = mp ([1 + 2i, 2 - 1i; 3, 4 + 3i]); %! W = mp ([2 - 1i, 1 + 1i; 1, 3 + 2i]); %! Z_before = double (Z); %! W_before = double (W); %! Y = Z / W; %! assert (size (Y), [2, 2]); %! det_w = W_before(1, 1) * W_before(2, 2) ... %! - W_before(1, 2) * W_before(2, 1); %! expected = [(Z_before(1, 1) * W_before(2, 2) ... %! - Z_before(1, 2) * W_before(2, 1)) / det_w, ... %! (Z_before(1, 2) * W_before(1, 1) ... %! - Z_before(1, 1) * W_before(1, 2)) / det_w; ... %! (Z_before(2, 1) * W_before(2, 2) ... %! - Z_before(2, 2) * W_before(2, 1)) / det_w, ... %! (Z_before(2, 2) * W_before(1, 1) ... %! - Z_before(2, 1) * W_before(1, 2)) / det_w]; %! assert (norm (double (Y) - expected, "fro") < 1e-12); %! assert (double (Z), Z_before); %! assert (double (W), W_before); %! info = __mplapack_core__ ("matrix_test_info", Y); %! assert (info.is_complex && info.precision_bits == 256); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! G = mp (gallery ("grcar", 32)); %! I = mp (eye (32)); %! X = I / G; %! assert (size (X), [32, 32]); %! assert (norm (double (X * G - I), "fro") < 1e-10, ... %! "N08 permanent Grcar right-division residual"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! T = mp ([1, 2; 3, 4]); %! B = mp ([1, 2, 3; 0, 1, 1]); %! A = T * B; %! assert (size (A / B), [2, 2]); %! assert (norm (double (A / B) - double (A) / double (B), "fro") < 1e-11); %! %! Tc = mp ([1 + 1i, 2 - 1i; 3 + 2i, 4]); %! Bc = mp ([1 + 1i, 2, 3 - 1i; 1i, 1 - 1i, 2]); %! Ac = Tc * Bc; %! assert (size (Ac / Bc), [2, 2]); %! expected = double (Tc); %! assert (norm (double (Ac / Bc) - expected, "fro") < 1e-11); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! B = mp ([1, 2; 2, 4]); %! expected = double (A) / double (B); %! actual = A / B; %! assert (norm (double (actual) - expected, "fro") < 1e-11); %! %! Br = mp ([1, 2, 3; 2, 4, 6]); %! Ar = mp ([1, 2, 3]); %! assert (size (Ar / Br), [1, 2]); %! assert (norm (double (Ar / Br) - double (Ar) / double (Br), "fro") < 1e-11); %! %! Z = mp ([1 + 1i, 2; 3, 4 - 1i]); %! W = mp ([1 + 1i, 2; 2 + 2i, 4]); %! r = [1 + 1i, 2]; %! Zd = double (Z); %! alpha1 = (Zd(1, 1) * conj (r(1)) ... %! + Zd(1, 2) * conj (r(2))) / 6; %! alpha2 = (Zd(2, 1) * conj (r(1)) ... %! + Zd(2, 2) * conj (r(2))) / 6; %! expected = [alpha1 / 5, 2 * alpha1 / 5; ... %! alpha2 / 5, 2 * alpha2 / 5]; %! assert (norm (double (Z / W) - expected, "fro") < 1e-11); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = [1, 2; 3, 4]; %! B = mp ([2, 1; 1, 3]); %! assert (norm (double (A / B) - A / double (B), "fro") < 1e-12); %! Z = mp ([1 + 2i, 2 - 1i; 3, 4 + 3i]); %! Bc = [2 - 1i, 1 + 1i; 1, 3 + 2i]; %! det_b = Bc(1, 1) * Bc(2, 2) - Bc(1, 2) * Bc(2, 1); %! Zd = double (Z); %! expected = [(Zd(1, 1) * Bc(2, 2) - Zd(1, 2) * Bc(2, 1)) / det_b, ... %! (Zd(1, 2) * Bc(1, 1) - Zd(1, 1) * Bc(1, 2)) / det_b; ... %! (Zd(2, 1) * Bc(2, 2) - Zd(2, 2) * Bc(2, 1)) / det_b, ... %! (Zd(2, 2) * Bc(1, 1) - Zd(2, 1) * Bc(1, 2)) / det_b]; %! assert (norm (double (Z / Bc) - expected, "fro") < 1e-12); %! det_z = Zd(1, 1) * Zd(2, 2) - Zd(1, 2) * Zd(2, 1); %! expected = [(Bc(1, 1) * Zd(2, 2) - Bc(1, 2) * Zd(2, 1)) / det_z, ... %! (Bc(1, 2) * Zd(1, 1) - Bc(1, 1) * Zd(1, 2)) / det_z; ... %! (Bc(2, 1) * Zd(2, 2) - Bc(2, 2) * Zd(2, 1)) / det_z, ... %! (Bc(2, 2) * Zd(1, 1) - Bc(2, 1) * Zd(1, 2)) / det_z]; %! assert (norm (double (Bc / Z) - expected, "fro") < 1e-12); %! assert (__mplapack_core__ ("matrix_test_info", A / B).precision_bits == 256); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for dimensions = {[0, 0, 0, 0], [0, 2, 3, 2], [2, 0, 3, 0], ... %! [0, 0, 2, 0], [2, 0, 0, 0]} %! d = dimensions{1}; %! A = mp (zeros (d(1), d(2))); %! B = mp (zeros (d(3), d(4))); %! expected = zeros (d(1), d(3)); %! actual = A / B; %! assert (size (actual), size (expected)); %! endfor %! %! A = mp (ones (2, 2)); %! B = mp (ones (3, 1)); %! caught = false; %! try %! A / B; %! catch exception %! caught = true; %! assert (strcmp (exception.identifier, "mplapack:mp:DimensionMismatch")); %! end_try_catch %! assert (caught); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! special_values = {[Inf, 1; 2, 3], [1, 2; 3, Inf], ... %! [NaN, 1; 2, 3]}; %! for value = special_values %! actual = mp (value{1}) / mp (eye (2)); %! assert (size (actual), [2, 2]); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! tail = mp ("1"); %! for k = 1:exponent %! tail = tail ./ mp ("2"); %! endfor %! B = mp (eye (2)); %! B(1, 1) = tail; %! I = mp (eye (2)); %! mpbits (128); %! X = I / B; %! info = __mplapack_core__ ("matrix_test_info", X); %! assert (info.precision_bits == precision); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits") == 128); %! assert (norm (double (X * B - I), "fro") < 1e-12); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/t10_interpolation.tst0000644000230300031750000000617315274353472021340 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (1024); %! x = mp ({"0", "1", "3", "7"}); %! y = mp ({"0", "1", "9", "49"}); %! q = mp ({"0.5", "2", "5"}); %! linear = interp1 (x, y, q, "linear"); %! assert (linear(1) == mp ("0.5")); %! assert (linear(2) == mp ("5")); %! assert (linear(3) == mp ("29")); %! nearest = interp1 (x, y, q, "nearest"); %! assert (nearest(1) == mp ("1")); %! assert (nearest(2) == mp ("9")); %! previous = interp1 (x, y, q, "previous"); %! next_value = interp1 (x, y, q, "next"); %! assert (previous(2) == mp ("1")); %! assert (next_value(2) == mp ("9")); %! descending = interp1 (flipud (x), flipud (y), q, "linear"); %! assert (descending(3) == linear(3)); %! assert (isnan (interp1 (x, y, mp ("-1")))); %! assert (interp1 (x, y, mp ("-1"), "linear", "extrap") == mp ("-1")); %! linear_pp = interp1 (x, y, "linear", "pp"); %! assert (ppval (linear_pp, q)(2) == mp ("5")); %! assert (__mplapack_core__ ("serialize", linear).precision_bits == uint64 (1024)); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (512); %! x = mp ([0, 1, 2, 3]); %! y = mp ([0, 1, 4, 9]); %! q = mp ([0.5, 1.5, 2.5]); %! p = pchip (x, y); %! s = spline (x, y); %! pv = ppval (p, q); %! sv = ppval (s, q); %! assert (pv(1) > mp ("0") && pv(1) < mp ("1")); %! assert (pv(2) > mp ("1") && pv(2) < mp ("4")); %! assert (sv(1) == mp ("0.25")); %! assert (sv(2) == mp ("2.25")); %! assert (sv(3) == mp ("6.25")); %! assert (ppval (p, mp ("2.5")) > mp ("4") ... %! && ppval (p, mp ("2.5")) < mp ("9")); %! d = ppder (s); %! assert (ppval (d, mp ("2")) == mp ("4")); %! integrated = ppint (d); %! assert (ppval (integrated, mp ("2")) == mp ("4")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (1024); %! step = mp ("1"); %! for k = 1:700, step = step * mp ("0.5"); endfor %! query = mp ("1") + step; %! grid = mp ({"0", "2"}); %! data = mp ({"0", "2"}); %! value = interp1 (grid, data, query, "linear"); %! assert (double (query) == 1); %! assert (value > mp ("1")); %! z = mp ({"(0,1)", "(1,3)", "(2,5)", "(3,7)"}); %! complex_value = ppval (pchip (grid, mp ({"(0,1)", "(2,5)"})), query); %! assert (real (complex_value) > mp ("1")); %! assert (imag (complex_value) > mp ("2")); %! complex_grid = mp ({"0", "1", "2", "3"}); %! assert (real (interp1 (complex_grid, z, query, "spline")) > mp ("1")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! x = mp ([0, 1, 2]); %! coefficients = mp ([2, 3; 4, 5]); %! pp = mkpp (x, coefficients); %! [breaks, coefs, pieces, order, dimension] = unmkpp (pp); %! assert (pieces == 2 && order == 2 && dimension == 1); %! assert (ppval (pp, mp ([0.5, 1.5]))(1) == mp ("4")); %! assert (ppval (ppder (pp), mp ("0.5")) == mp ("2")); %! integral = ppint (pp); %! assert (ppval (integral, mp ("1")) == mp ("4")); %! assert (breaks(2) == mp ("1") && coefs(2,2) == mp ("5")); mplapack-interop-0.5.1/test/gesv.tst0000644000230300031750000001426015274353472016725 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_matrix_text (value, expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! value, row, column, expected{row, column})); %! endfor %! endfor %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"3", "1"; "1", "2"}); %! B = mp ({"9"; "8"}); %! X = mldivide (A, B); %! assert_matrix_text (X, {"2"; "3"}); %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (256)); %! assert_matrix_text (A, {"3", "1"; "1", "2"}); %! assert_matrix_text (B, {"9"; "8"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"3", "1"; "1", "2"}); %! B = mp ({"9", "7"; "8", "9"}); %! X = A \ B; %! assert_matrix_text (X, {"2", "1"; "3", "4"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"0", "1"; "1", "1"}); %! B = mp ({"2"; "3"}); %! X = A \ B; %! assert_matrix_text (X, {"1"; "2"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! tail = strcat ("1.", repmat ("0", 1, 210), "1"); %! rhs_tail = strcat ("2.", repmat ("0", 1, 210), "1"); %! A = mp ({"1", "1"; "1", tail}); %! B = mp ({"2"; rhs_tail}); %! mpbits (128); %! X = A \ B; %! assert (__mplapack_core__ ("matrix_test_element_double", X, 1, 1), 1); %! assert (__mplapack_core__ ("matrix_test_element_double", X, 2, 1), 1); %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! mpbits (4096); %! Y = A \ B; %! assert (__mplapack_core__ ("matrix_test_element_double", Y, 1, 1), 1); %! assert (__mplapack_core__ ("matrix_test_element_double", Y, 2, 1), 1); %! assert (__mplapack_core__ ("matrix_test_info", Y).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2048); %! tail = strcat ("1.", repmat ("0", 1, 450), "1"); %! rhs_tail = strcat ("2.", repmat ("0", 1, 450), "1"); %! A = mp ({"1", "1"; "1", tail}); %! B = mp ({"2"; rhs_tail}); %! mpbits (128); %! X = A \ B; %! assert (__mplapack_core__ ("matrix_test_element_double", X, 1, 1), 1); %! assert (__mplapack_core__ ("matrix_test_element_double", X, 2, 1), 1); %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (2048)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"3", "1"; "1", "2"}); %! B = mp ({"9"; "8"}); %! mpbits (128); %! X = A \ B; %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (256)); %! assert_matrix_text (X, {"2"; "3"}); %! mpbits (1024); %! B_high = mp ({"9"; "8"}); %! mpbits (128); %! X_mixed = A \ B_high; %! assert (__mplapack_core__ ("matrix_test_info", X_mixed).precision_bits, ... %! uint64 (1024)); %! mpbits (1024); %! A_high = mp ({"3", "1"; "1", "2"}); %! mpbits (256); %! B_low = mp ({"9"; "8"}); %! mpbits (128); %! X_reverse = A_high \ B_low; %! assert (__mplapack_core__ ("matrix_test_info", X_reverse).precision_bits, ... %! uint64 (1024)); %! assert_matrix_text (X_reverse, {"2"; "3"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"3", "1"; "1", "2"}); %! X_expected = mp ({"2", "1"; "3", "4"}); %! B = A * X_expected; %! X = A \ B; %! assert_matrix_text (X, {"2", "1"; "3", "4"}); %! X_double = A \ [9, 7; 8, 9]; %! assert_matrix_text (X_double, {"2", "1"; "3", "4"}); %! X_reverse = [3, 1; 1, 2] \ B; %! assert_matrix_text (X_reverse, {"2", "1"; "3", "4"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp (zeros (0, 0)); %! B = mp (zeros (0, 3)); %! X = A \ B; %! info = __mplapack_core__ ("matrix_test_info", X); %! assert (info.rows, uint64 (0)); %! assert (info.columns, uint64 (3)); %! assert (info.precision_bits, uint64 (256)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({"1", "2"; "2", "4"}); %! B = mp ({"1"; "2"}); %! try %! A \ B; %! error ("singular solve unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, "singular solve unexpectedly succeeded")); %! assert (strcmp (exception.identifier, "mplapack:mp:SingularMatrix")); %! end_try_catch %!test %! A = mp ({"1", "2"; "3", "4"}); %! B = mp ({"1"; "2"; "3"}); %! try %! A \ B; %! error ("dimension mismatch unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, "dimension mismatch unexpectedly succeeded")); %! assert (strcmp (exception.identifier, "mplapack:mp:DimensionMismatch")); %! end_try_catch %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! s = mp ("2"); %! X = s \ mp ({"4", "6"; "8", "10"}); %! assert_matrix_text (X, {"2", "3"; "4", "5"}); %! X_double_rhs = s \ [4, 6; 8, 10]; %! assert_matrix_text (X_double_rhs, {"2", "3"; "4", "5"}); %! y = s \ mp ("8"); %! assert (__mplapack_core__ ("scalar_test_equal_string", y, "4")); %! z = 2 \ mp ({"4"; "8"}); %! assert_matrix_text (z, {"2"; "4"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/test_neigt01.m0000644000230300031750000000044315274353472017707 0ustar rafaelrafael% Focused NEIGT01 skeleton test. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); report = mp_neig_tiers_selftest (); assert (report.ok && report.implemented); fprintf ("PASS: test_neigt01 (manifest/profile skeleton)\n"); mplapack-interop-0.5.1/test/mp_lapack_rank_test.cc0000644000230300031750000001674215274353472021544 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_lapack.h" #include #include #include #include #include #include namespace { using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrRankRevealingSolveResult; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } MpfrMatrixStorage matrix (std::size_t rows, std::size_t columns, mpfr_prec_t precision, std::initializer_list values) { return MpfrMatrixStorage (rows, columns, precision, std::vector (values.begin (), values.end ())); } void check_close (const Real& value, const Real& expected, const char *message) { Real difference = Real::with_precision (value.precision ()); mpfr_sub (difference.mpfr_data (), value.mpfr_data (), expected.mpfr_data (), MPFR_RNDN); Real magnitude = Real::with_precision (value.precision ()); mpfr_abs (magnitude.mpfr_data (), difference.mpfr_data (), MPFR_RNDN); check (mpfr_get_d (magnitude.mpfr_data (), MPFR_RNDN) < 1e-40, message); } Real rational (long numerator, long denominator, mpfr_prec_t precision) { Real result = Real::with_precision (precision); Real denominator_value = Real::with_precision (precision); mpfr_set_si (result.mpfr_data (), numerator, MPFR_RNDN); mpfr_set_si (denominator_value.mpfr_data (), denominator, MPFR_RNDN); mpfr_div (result.mpfr_data (), result.mpfr_data (), denominator_value.mpfr_data (), MPFR_RNDN); return result; } void test_rank_one_fixtures () { const auto a_over = matrix (3, 2, 1024, {"1", "2", "3", "2", "4", "6"}); const auto b_consistent = matrix (3, 1, 1024, {"1", "2", "3"}); const auto a_before = a_over; const auto b_before = b_consistent; const MpfrRankRevealingSolveResult consistent = octave_mplapack::mplapack_mpfr_matrix_rank_revealing_solve ( a_over, b_consistent); check (consistent.rank == 1, "rank-one overdetermined rank mismatch"); check_close (consistent.solution.at (0, 0), rational (1, 5, 1024), "rank-one overdetermined first value mismatch"); check_close (consistent.solution.at (1, 0), rational (2, 5, 1024), "rank-one overdetermined second value mismatch"); check (a_over.element_exactly_equal (0, 0, a_before, 0, 0) && b_consistent.element_exactly_equal (0, 0, b_before, 0, 0), "rank-one inputs were modified"); const auto b_inconsistent = matrix (3, 1, 1024, {"1", "2", "4"}); const auto inconsistent = octave_mplapack::mplapack_mpfr_matrix_rank_revealing_solve ( a_over, b_inconsistent); check (inconsistent.rank == 1, "inconsistent rank mismatch"); check_close (inconsistent.solution.at (0, 0), rational (17, 70, 1024), "inconsistent first value mismatch"); check_close (inconsistent.solution.at (1, 0), rational (17, 35, 1024), "inconsistent second value mismatch"); const auto a_under = matrix (2, 3, 1024, {"1", "2", "2", "4", "3", "6"}); const auto b_under = matrix (2, 1, 1024, {"1", "2"}); const auto under = octave_mplapack::mplapack_mpfr_matrix_rank_revealing_solve ( a_under, b_under); check (under.rank == 1, "rank-one underdetermined rank mismatch"); check_close (under.solution.at (0, 0), rational (1, 14, 1024), "underdetermined first value mismatch"); check_close (under.solution.at (1, 0), rational (2, 14, 1024), "underdetermined second value mismatch"); check_close (under.solution.at (2, 0), rational (3, 14, 1024), "underdetermined third value mismatch"); } void test_rank_zero_and_multiple_rhs () { const auto zero_a = matrix (3, 2, 512, {"0", "0", "0", "0", "0", "0"}); const auto zero_b = matrix (3, 2, 512, {"1", "2", "3", "4", "5", "6"}); const auto zero = octave_mplapack::mplapack_mpfr_matrix_rank_revealing_solve ( zero_a, zero_b); check (zero.rank == 0 && zero.solution.rows () == 2 && zero.solution.columns () == 2, "rank-zero result metadata mismatch"); for (std::size_t index = 0; index < zero.solution.numel (); ++index) check (mpfr_zero_p (zero.solution.data ()[index].mpfr_data ()) != 0, "rank-zero result is not zero"); const auto a = matrix (3, 2, 512, {"1", "0", "1", "0", "1", "1"}); const auto b = matrix (3, 2, 512, {"0", "1", "4", "1", "0", "4"}); const auto result = octave_mplapack::mplapack_mpfr_matrix_rank_revealing_solve (a, b); check (result.rank == 2 && result.solution.rows () == 2 && result.solution.columns () == 2, "full-rank multiple-RHS metadata mismatch"); check_close (result.solution.at (0, 0), rational (1, 1, 512), "multiple-RHS first value mismatch"); check_close (result.solution.at (1, 0), rational (2, 1, 512), "multiple-RHS second value mismatch"); check_close (result.solution.at (0, 1), rational (2, 1, 512), "multiple-RHS third value mismatch"); check_close (result.solution.at (1, 1), rational (1, 1, 512), "multiple-RHS fourth value mismatch"); } void test_precision_rank_transition () { mpfrxx::set_default_precision_bits (128); for (const auto case_data : {std::pair (512, -700), std::pair (1024, -700), std::pair (2048, -1500)}) { const mpfr_prec_t precision = case_data.first; auto a = matrix (3, 2, precision, {"1", "0", "0", "0", "0", "0"}); MpfrMatrixStorage b (3, 1, precision); Real delta = Real::with_precision (precision); mpfr_set_ui_2exp (delta.mpfr_data (), 1, case_data.second, MPFR_RNDN); mpfr_set (a.at (1, 1).mpfr_data (), delta.mpfr_data (), MPFR_RNDN); mpfr_set (b.at (1, 0).mpfr_data (), delta.mpfr_data (), MPFR_RNDN); const auto result = octave_mplapack::mplapack_mpfr_matrix_rank_revealing_solve (a, b); const auto expected_rank = precision == 512 ? 1 : 2; check (result.rank == expected_rank, "precision-dependent rank mismatch"); check (result.solution.precision_bits () == precision, "precision-dependent result precision mismatch"); if (precision != 512) check (mpfr_get_d (result.solution.at (1, 0).mpfr_data (), MPFR_RNDN) > 0.999999999999, "high-precision rank canary solution mismatch"); } check (mpfrxx::default_precision_bits () == 128, "rank-revealing solve leaked ambient precision"); } void test_mixed_precision () { const auto a = matrix (3, 2, 256, {"1", "0", "1", "0", "1", "1"}); const auto b = matrix (3, 1, 1024, {"0", "1", "4"}); const auto result = octave_mplapack::mplapack_mpfr_matrix_rank_revealing_solve (a, b); check (result.rank == 2 && result.solution.precision_bits () == 1024, "mixed rank-revealing precision mismatch"); check (mpfrxx::default_precision_bits () == 128, "mixed rank-revealing solve changed ambient precision"); } } // namespace int main () { try { test_rank_one_fixtures (); test_rank_zero_and_multiple_rhs (); test_precision_rank_transition (); test_mixed_precision (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: MPLAPACK MPFR rank-revealing Rgelss tests\n"; return 0; } mplapack-interop-0.5.1/test/mp_complex_blas_test.cc0000644000230300031750000001002615274353472021733 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include "mp_complex_blas.h" namespace { void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void set_power_of_two (mpc_ptr value, unsigned long exponent) { mpfr_set_ui (mpc_realref (value), 1, MPFR_RNDN); mpfr_div_2si (mpc_realref (value), mpc_realref (value), exponent, MPFR_RNDN); mpfr_set (mpc_imagref (value), mpc_realref (value), MPFR_RNDN); mpfr_neg (mpc_imagref (value), mpc_imagref (value), MPFR_RNDN); } } // namespace int main () { try { for (mpfr_prec_t precision : {128, 512}) { octave_mplapack::MpfrComplexMatrixStorage lhs ( 2, 2, precision, std::vector> { {1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}, {7.0, 8.0}}); octave_mplapack::MpfrComplexMatrixStorage rhs ( 2, 2, precision, std::vector> { {1.0, 0.0}, {0.0, 1.0}, {2.0, -1.0}, {1.0, 2.0}}); const auto product = octave_mplapack::mplapack_mpc_matrix_multiply ( lhs, rhs); check (product.precision_bits () == precision, "Cgemm result precision mismatch"); check (product.element_exactly_equal_double (0, 0, {-5.0, 7.0}), "Cgemm first result mismatch"); check (product.element_exactly_equal_double (1, 1, {1.0, 27.0}), "Cgemm second result mismatch"); check (lhs.element_exactly_equal_double (0, 0, {1.0, 2.0}), "Cgemm mutated lhs"); check (rhs.element_exactly_equal_double (1, 1, {1.0, 2.0}), "Cgemm mutated rhs"); octave_mplapack::MpfrMatrixStorage real ( 2, 2, precision, {1.0, 2.0, 3.0, 4.0}); const auto complex_real = octave_mplapack::mplapack_mpc_matrix_from_real (real, precision); const auto mixed = octave_mplapack::mplapack_mpc_matrix_multiply ( complex_real, rhs); check (mixed.element_exactly_equal_double (0, 0, {1.0, 3.0}), "mixed real/complex Cgemm mismatch"); } for (const std::array settings : { std::array {{1024, 700}}, std::array {{2048, 1500}}}) { const mpfr_prec_t precision = static_cast (settings[0]); const unsigned long exponent = static_cast (settings[1]); octave_mplapack::MpfrComplexMatrixStorage lhs (1, 1, precision); set_power_of_two (lhs.at (0, 0).mpc_data (), exponent); octave_mplapack::MpfrComplexMatrixStorage unit ( 1, 1, precision, std::vector> {{1.0, 0.0}}); const auto product = octave_mplapack::mplapack_mpc_matrix_multiply ( lhs, unit); check (mpfr_equal_p (mpc_realref (product.at (0, 0).mpc_data ()), mpc_realref (lhs.at (0, 0).mpc_data ())) != 0, "Cgemm real precision canary changed"); check (mpfr_equal_p (mpc_imagref (product.at (0, 0).mpc_data ()), mpc_imagref (lhs.at (0, 0).mpc_data ())) != 0, "Cgemm imaginary precision canary changed"); } octave_mplapack::MpfrComplexMatrixStorage empty_lhs (1, 0, 256); octave_mplapack::MpfrComplexMatrixStorage empty_rhs (0, 2, 256); const auto empty = octave_mplapack::mplapack_mpc_matrix_multiply ( empty_lhs, empty_rhs); check (empty.rows () == 1 && empty.columns () == 2 && empty.numel () == 2, "empty Cgemm shape mismatch"); std::cout << "PASS: complex Cgemm dispatch, precision boundary, mixed real/complex inputs, canaries, shapes, and immutability\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/mp_svd_test.cc0000644000230300031750000001361015274353472020061 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_svd.h" #include #include #include #include #include #include #include #include #include #include "mp_complex_precision.h" #include "mp_norm.h" #include "mp_precision.h" namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void require_real_shape (const MpfrMatrixStorage& value, std::size_t rows, std::size_t columns, mpfr_prec_t precision) { require (value.rows () == rows && value.columns () == columns, (std::string ("unexpected real SVD shape: got ") + std::to_string (value.rows ()) + "x" + std::to_string (value.columns ()) + ", expected " + std::to_string (rows) + "x" + std::to_string (columns)).c_str ()); require (value.precision_bits () == precision && value.all_elements_have_uniform_precision (), "real SVD precision contract failed"); } void require_complex_shape (const MpfrComplexMatrixStorage& value, std::size_t rows, std::size_t columns, mpfr_prec_t precision) { require (value.rows () == rows && value.columns () == columns, (std::string ("unexpected complex SVD shape: got ") + std::to_string (value.rows ()) + "x" + std::to_string (value.columns ()) + ", expected " + std::to_string (rows) + "x" + std::to_string (columns)).c_str ()); require (value.precision_bits () == precision && value.all_elements_have_uniform_precision (), "complex SVD precision contract failed"); } void require_nonnegative_singular_values (const MpfrMatrixStorage& value) { for (std::size_t index = 0; index < value.numel (); ++index) require (mpfr_sgn (value.data ()[index].mpfr_data ()) >= 0, "SVD singular value is negative"); } void test_real () { const mpfr_prec_t precision = 512; const MpfrMatrixStorage input (3, 2, precision, std::vector { "1", "3", "5", "2", "4", "6" }); const auto original = input; const auto full = octave_mplapack::mplapack_mpfr_matrix_svd (input, false); require_real_shape (full.u, 3, 3, precision); require_real_shape (full.s, 3, 2, precision); require_real_shape (full.v, 2, 2, precision); require_nonnegative_singular_values (full.s); const auto economy = octave_mplapack::mplapack_mpfr_matrix_svd (input, true); require_real_shape (economy.u, 3, 2, precision); require_real_shape (economy.s, 2, 2, precision); require_real_shape (economy.v, 2, 2, precision); require_nonnegative_singular_values (economy.s); require (input.element_exactly_equal (0, 0, original, 0, 0), "real SVD changed its input"); require (input.element_exactly_equal (2, 1, original, 2, 1), "real SVD changed its input tail"); const auto values = octave_mplapack::mplapack_mpfr_singular_values (input); require_real_shape (values, 2, 1, precision); require_nonnegative_singular_values (values); } void test_complex () { const mpfr_prec_t precision = 512; const MpfrComplexMatrixStorage input (2, 3, precision, std::vector { "(1,1)", "(3,-2)", "(2,-1)", "(4,2)", "(5,0)", "(6,3)" }); const auto full = octave_mplapack::mplapack_mpc_matrix_svd (input, false); require_complex_shape (full.u, 2, 2, precision); require_real_shape (full.s, 2, 3, precision); require_complex_shape (full.v, 3, 3, precision); require_nonnegative_singular_values (full.s); const auto economy = octave_mplapack::mplapack_mpc_matrix_svd (input, true); require_complex_shape (economy.u, 2, 2, precision); require_real_shape (economy.s, 2, 2, precision); require_complex_shape (economy.v, 3, 2, precision); const auto values = octave_mplapack::mplapack_mpc_singular_values (input); require_real_shape (values, 2, 1, precision); require_nonnegative_singular_values (values); } void test_shapes_and_precision () { const MpfrMatrixStorage empty (0, 3, 1024); const auto full = octave_mplapack::mplapack_mpfr_matrix_svd (empty, false); require_real_shape (full.u, 0, 0, 1024); require_real_shape (full.s, 0, 3, 1024); require_real_shape (full.v, 3, 3, 1024); const auto economy = octave_mplapack::mplapack_mpfr_matrix_svd (empty, true); require_real_shape (economy.u, 0, 0, 1024); require_real_shape (economy.s, 0, 0, 1024); require_real_shape (economy.v, 3, 0, 1024); const MpfrMatrixStorage high_precision (2, 2, 2048, std::vector { "1e-1500", "0", "0", "1" }); const auto values = octave_mplapack::mplapack_mpfr_singular_values (high_precision); require_real_shape (values, 2, 1, 2048); require_nonnegative_singular_values (values); const mpfr_prec_t ambient = mpfrxx::default_precision_bits (); mpfrxx::set_default_precision_bits (128); (void) octave_mplapack::mplapack_mpfr_matrix_svd (high_precision, true); require (mpfrxx::default_precision_bits () == 128, "real SVD did not restore ambient precision"); mpfrxx::set_default_precision_bits (ambient); } } // namespace int main () { try { test_real (); test_complex (); test_shapes_and_precision (); std::cout << "PASS: MPLAPACK MPFR/MPC SVD tests\n"; return EXIT_SUCCESS; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return EXIT_FAILURE; } } mplapack-interop-0.5.1/test/mp_lapack_test.cc0000644000230300031750000002013715274353472020522 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_lapack.h" #include #include #include #include #include namespace { using octave_mplapack::MpfrMatrixStorage; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } bool same (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs) { if (lhs.rows () != rhs.rows () || lhs.columns () != rhs.columns () || lhs.precision_bits () != rhs.precision_bits ()) return false; for (std::size_t column = 0; column < lhs.columns (); ++column) for (std::size_t row = 0; row < lhs.rows (); ++row) if (! lhs.element_exactly_equal (row, column, rhs, row, column)) return false; return true; } void check_text (const MpfrMatrixStorage& value, const std::vector& expected) { check (value.numel () == expected.size (), "unexpected result element count"); for (std::size_t index = 0; index < expected.size (); ++index) { Real expected_value = Real::with_precision (value.precision_bits ()); check (mpfr_set_str (expected_value.mpfr_data (), expected[index].c_str (), 10, MPFR_RNDN) == 0, "invalid expected test text"); check (mpfr_equal_p (value.data ()[index].mpfr_data (), expected_value.mpfr_data ()) != 0, "unexpected solve value"); } } void set_power_two_plus_one (Real& value, mpfr_exp_t exponent) { mpfr_set_ui (value.mpfr_data (), 1, MPFR_RNDN); Real epsilon = Real::with_precision (value.precision ()); mpfr_set_ui (epsilon.mpfr_data (), 1, MPFR_RNDN); mpfr_mul_2si (epsilon.mpfr_data (), epsilon.mpfr_data (), exponent, MPFR_RNDN); mpfr_add (value.mpfr_data (), value.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); } void test_basic_and_multiple_rhs () { const MpfrMatrixStorage a (2, 2, 256, std::vector {"3", "1", "1", "2"}); const MpfrMatrixStorage b (2, 2, 256, std::vector {"9", "8", "7", "9"}); const auto original_a = a; const auto original_b = b; const auto x = octave_mplapack::mplapack_mpfr_matrix_solve (a, b); check (x.rows () == 2 && x.columns () == 2, "multiple RHS shape mismatch"); check (x.precision_bits () == 256, "multiple RHS precision mismatch"); check_text (x, {"2", "3", "1", "4"}); check (same (a, original_a) && same (b, original_b), "Rgesv modified public input storage"); } void test_pivoting () { const MpfrMatrixStorage a (2, 2, 256, std::vector {"0", "1", "1", "1"}); const MpfrMatrixStorage b (2, 1, 256, std::vector {"2", "3"}); const auto x = octave_mplapack::mplapack_mpfr_matrix_solve (a, b); check_text (x, {"1", "2"}); } MpfrMatrixStorage precision_sensitive_system (mpfr_prec_t precision, mpfr_exp_t exponent) { MpfrMatrixStorage matrix (2, 2, precision); mpfr_set_ui (matrix.at (0, 0).mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (matrix.at (1, 0).mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (matrix.at (0, 1).mpfr_data (), 1, MPFR_RNDN); set_power_two_plus_one (matrix.at (1, 1), exponent); return matrix; } void test_precision_and_scope () { const auto previous = mpfrxx::default_precision_bits (); mpfrxx::set_default_precision_bits (128); const auto a = precision_sensitive_system (1024, -700); MpfrMatrixStorage b (2, 1, 1024); mpfr_set_ui (b.at (0, 0).mpfr_data (), 2, MPFR_RNDN); Real epsilon = Real::with_precision (1024); mpfr_set_ui (epsilon.mpfr_data (), 1, MPFR_RNDN); mpfr_mul_2si (epsilon.mpfr_data (), epsilon.mpfr_data (), -700, MPFR_RNDN); mpfr_add (b.at (1, 0).mpfr_data (), b.at (0, 0).mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); const auto x = octave_mplapack::mplapack_mpfr_matrix_solve (a, b); check (x.precision_bits () == 1024, "precision-sensitive result precision"); check_text (x, {"1", "1"}); check (mpfrxx::default_precision_bits () == 128, "Rgesv precision scope leaked"); const auto a2048 = precision_sensitive_system (2048, -1500); MpfrMatrixStorage b2048 (2, 1, 2048); mpfr_set_ui (b2048.at (0, 0).mpfr_data (), 2, MPFR_RNDN); Real eps2048 = Real::with_precision (2048); mpfr_set_ui (eps2048.mpfr_data (), 1, MPFR_RNDN); mpfr_mul_2si (eps2048.mpfr_data (), eps2048.mpfr_data (), -1500, MPFR_RNDN); mpfr_add (b2048.at (1, 0).mpfr_data (), b2048.at (0, 0).mpfr_data (), eps2048.mpfr_data (), MPFR_RNDN); const auto x2048 = octave_mplapack::mplapack_mpfr_matrix_solve (a2048, b2048); check (x2048.precision_bits () == 2048, "2048-bit result precision"); check_text (x2048, {"1", "1"}); check (mpfrxx::default_precision_bits () == 128, "2048-bit Rgesv precision scope leaked"); mpfrxx::set_default_precision_bits (previous); } void test_mixed_precision_and_empty () { const MpfrMatrixStorage a (2, 2, 256, std::vector {"3", "1", "1", "2"}); const MpfrMatrixStorage b (2, 1, 1024, std::vector {"9", "8"}); const auto x = octave_mplapack::mplapack_mpfr_matrix_solve (a, b); check (x.precision_bits () == 1024, "mixed solve precision mismatch"); check_text (x, {"2", "3"}); const MpfrMatrixStorage a_high ( 2, 2, 1024, std::vector {"3", "1", "1", "2"}); const MpfrMatrixStorage b_low ( 2, 1, 256, std::vector {"9", "8"}); const auto reverse = octave_mplapack::mplapack_mpfr_matrix_solve (a_high, b_low); check (reverse.precision_bits () == 1024, "reverse mixed solve precision mismatch"); check_text (reverse, {"2", "3"}); const MpfrMatrixStorage empty_a (0, 0, 512); const MpfrMatrixStorage empty_b (0, 3, 256); const auto empty_x = octave_mplapack::mplapack_mpfr_matrix_solve (empty_a, empty_b); check (empty_x.rows () == 0 && empty_x.columns () == 3, "empty solve shape mismatch"); check (empty_x.precision_bits () == 512, "empty solve precision mismatch"); } void test_errors () { const MpfrMatrixStorage nonsquare (2, 1, 256); const MpfrMatrixStorage rhs (2, 1, 256); bool caught = false; try { octave_mplapack::mplapack_mpfr_matrix_solve (nonsquare, rhs); } catch (const std::invalid_argument&) { caught = true; } check (caught, "non-square solve did not fail"); const MpfrMatrixStorage singular (2, 2, 256, std::vector {"1", "2", "2", "4"}); caught = false; try { octave_mplapack::mplapack_mpfr_matrix_solve (singular, rhs); } catch (const octave_mplapack::MpfrRgesvError& error) { caught = error.kind () == octave_mplapack::MpfrRgesvError::Kind::singular; } check (caught, "singular solve did not report Rgesv failure"); } void test_precision_contract_mismatch () { const auto previous = mpfrxx::default_precision_bits (); mpfrxx::set_default_precision_bits (128); const MpfrMatrixStorage a (1, 1, 256); const MpfrMatrixStorage b (1, 1, 256); bool caught = false; try { octave_mplapack::require_mplapack_mpfr_solve_precision_contract ( 256, a, b); } catch (const std::runtime_error& exception) { caught = std::string (exception.what ()).find ("precision contract") != std::string::npos; } check (caught, "precision contract mismatch was not rejected"); check (mpfrxx::default_precision_bits () == 128, "precision contract checker modified TLS"); mpfrxx::set_default_precision_bits (previous); } } // namespace int main () { try { test_basic_and_multiple_rhs (); test_pivoting (); test_precision_and_scope (); test_mixed_precision_and_empty (); test_errors (); test_precision_contract_mismatch (); return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/mp_matrix_concat_test.cc0000644000230300031750000000642415274353472022125 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_concat.h" #include #include #include #include using octave_mplapack::MpfrConcatOperand; using octave_mplapack::MpfrMatrixStorage; namespace { MpfrConcatOperand from_matrix (const MpfrMatrixStorage& source) { MpfrConcatOperand operand; operand.rows = source.rows (); operand.columns = source.columns (); operand.precision_bits = source.precision_bits (); operand.has_mp_precision = true; operand.copy_element = [&source] (MpfrMatrixStorage::NativeScalar& destination, std::size_t row, std::size_t column) { mpfr_set (destination.mpfr_data (), source.at (row, column).mpfr_data (), MPFR_RNDN); }; return operand; } MpfrConcatOperand from_double_matrix (const std::vector& values, std::size_t rows, std::size_t columns) { MpfrConcatOperand operand; operand.rows = rows; operand.columns = columns; operand.copy_element = [&values, rows] (MpfrMatrixStorage::NativeScalar& destination, std::size_t row, std::size_t column) { mpfr_set_d (destination.mpfr_data (), values[row + column * rows], MPFR_RNDN); }; return operand; } void assert_text (const MpfrMatrixStorage& matrix, std::size_t row, std::size_t column, const char *text) { assert (matrix.element_exactly_equal_text (row, column, text)); } } // namespace int main () { const MpfrMatrixStorage left ( 2, 2, 256, std::vector {"11", "21", "12", "22"}); const MpfrMatrixStorage right ( 2, 3, 1024, std::vector {"31", "41", "32", "42", "33", "43"}); const MpfrMatrixStorage horizontal = octave_mplapack::mpfr_matrix_concatenate ( std::vector {from_matrix (left), from_matrix (right)}, 1, 2, 5, 1024); assert (horizontal.rows () == 2 && horizontal.columns () == 5); assert (horizontal.precision_bits () == 1024); assert_text (horizontal, 0, 0, "11"); assert_text (horizontal, 1, 1, "22"); assert_text (horizontal, 0, 2, "31"); assert_text (horizontal, 1, 4, "43"); const MpfrMatrixStorage vertical = octave_mplapack::mpfr_matrix_concatenate ( std::vector {from_matrix (left), from_matrix (left)}, 0, 4, 2, 256); assert (vertical.rows () == 4 && vertical.columns () == 2); assert_text (vertical, 2, 0, "11"); assert_text (vertical, 3, 1, "22"); const std::vector doubles {0.125, -0.0, 2.0, 3.0}; const MpfrMatrixStorage mixed = octave_mplapack::mpfr_matrix_concatenate ( std::vector { from_double_matrix (doubles, 2, 2), from_matrix (left) }, 1, 2, 4, 256); assert (mixed.element_exactly_equal_double (0, 0, 0.125)); assert (mixed.element_exactly_equal_double (1, 0, -0.0)); assert_text (mixed, 0, 2, "11"); const MpfrMatrixStorage empty (0, 2, 2048); const MpfrMatrixStorage empty_result = octave_mplapack::mpfr_matrix_concatenate ( std::vector {from_matrix (empty)}, 1, 0, 2, 2048); assert (empty_result.rows () == 0 && empty_result.columns () == 2); assert (empty_result.precision_bits () == 2048); std::cout << "PASS: native mp matrix concatenation tests\n"; return 0; } mplapack-interop-0.5.1/test/complex_qr.tst0000644000230300031750000000637515274353472020142 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_qr_shapes (q, r, q_rows, q_columns, r_rows, r_columns) %! q_info = __mplapack_core__ ("matrix_test_info", q); %! r_info = __mplapack_core__ ("matrix_test_info", r); %! assert (q_info.rows == uint64 (q_rows)); %! assert (q_info.columns == uint64 (q_columns)); %! assert (r_info.rows == uint64 (r_rows)); %! assert (r_info.columns == uint64 (r_columns)); %! assert (q_info.is_complex && r_info.is_complex); %! assert (q_info.all_elements_same_precision && ... %! r_info.all_elements_same_precision); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1 + 1i, 2 - 1i; 2 + 0i, 1 + 2i; 0 + 1i, 1 + 0i]); %! A_before = double (A); %! [Q, R] = qr (A); %! assert_qr_shapes (Q, R, 3, 3, 3, 2); %! assert (double (Q' * Q), eye (3), 1e-10); %! assert (double (Q * R), A_before, 1e-10); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! R, 2, 1, 0 + 0i)); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! R, 3, 1, 0 + 0i)); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! R, 3, 2, 0 + 0i)); %! assert (double (A), A_before); %! R_only = qr (A); %! assert_qr_shapes (mp (complex (eye (3), zeros (3))), R_only, ... %! 3, 3, 3, 2); %! assert (double (R_only), double (R), 1e-10); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1 + 1i, 2 - 1i; 2 + 0i, 1 + 2i; 0 + 1i, 1 + 0i]); %! [Q, R] = qr (A, "econ"); %! assert_qr_shapes (Q, R, 3, 2, 2, 2); %! assert (double (Q' * Q), eye (2), 1e-10); %! assert (double (Q * R), double (A), 1e-10); %! [Q0, R0] = qr (A, 0); %! assert_qr_shapes (Q0, R0, 3, 2, 2, 2); %! assert (double (Q0 * R0), double (A), 1e-10); %! B = mp ([1 + 0i, 2 + 1i, 3 - 1i; 4 + 2i, 5 + 0i, 6 - 2i]); %! [Qw, Rw] = qr (B); %! assert_qr_shapes (Qw, Rw, 2, 2, 2, 3); %! assert (double (Qw' * Qw), eye (2), 1e-10); %! assert (double (Qw * Rw), double (B), 1e-10); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! tail = mp ("1", "-1"); %! for k = 1:exponent %! tail = tail ./ mp ("2", "0"); %! endfor %! A = mp (complex (eye (2), zeros (2))); %! A(1, 2) = tail; %! mpbits (128); %! [Q, R] = qr (A, "econ"); %! assert_qr_shapes (Q, R, 2, 2, 2, 2); %! assert (__mplapack_core__ ("matrix_test_info", R).precision_bits, ... %! uint64 (precision)); %! assert (! __mplapack_core__ ("scalar_test_info", R(1, 2)).is_zero); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp (complex (ones (2, 1), zeros (2, 1))); %! [Q, R] = qr (A); %! assert (size (Q), [2, 2]); %! assert (size (R), [2, 1]); mplapack-interop-0.5.1/test/mp_lapack_pivoted_qr_test.cc0000644000230300031750000002370615274353472022763 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_lapack.h" #include #include #include #include namespace { using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrPivotedQrResult; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } MpfrMatrixStorage matrix (std::size_t rows, std::size_t columns, mpfr_prec_t precision, std::initializer_list values) { return MpfrMatrixStorage (rows, columns, precision, std::vector (values.begin (), values.end ())); } void check_close (const Real& value, const Real& expected, mpfr_prec_t precision, const char *message) { Real difference = Real::with_precision (precision); mpfr_sub (difference.mpfr_data (), value.mpfr_data (), expected.mpfr_data (), MPFR_RNDN); mpfr_abs (difference.mpfr_data (), difference.mpfr_data (), MPFR_RNDN); Real tolerance = Real::with_precision (precision); mpfr_set_ui_2exp (tolerance.mpfr_data (), 1, -static_cast (precision / 2), MPFR_RNDN); check (mpfr_cmp (difference.mpfr_data (), tolerance.mpfr_data ()) < 0, message); } void check_reconstruction (const MpfrPivotedQrResult& result, const MpfrMatrixStorage& input, const char *message) { const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t q_columns = result.q.columns (); const mpfr_prec_t precision = input.precision_bits (); for (std::size_t column = 0; column < n; ++column) for (std::size_t row = 0; row < m; ++row) { Real reconstructed = Real::with_precision (precision); mpfr_set_zero (reconstructed.mpfr_data (), 0); for (std::size_t inner = 0; inner < q_columns; ++inner) { Real product = Real::with_precision (precision); mpfr_mul (product.mpfr_data (), result.q.at (row, inner).mpfr_data (), result.r.at (inner, column).mpfr_data (), MPFR_RNDN); mpfr_add (reconstructed.mpfr_data (), reconstructed.mpfr_data (), product.mpfr_data (), MPFR_RNDN); } const std::size_t source = static_cast (result.permutation[column] - 1); check_close (reconstructed, input.at (row, source), precision, message); } } void check_orthogonality (const MpfrPivotedQrResult& result, const char *message) { const std::size_t rows = result.q.rows (); const std::size_t columns = result.q.columns (); const mpfr_prec_t precision = result.q.precision_bits (); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < columns; ++row) { Real value = Real::with_precision (precision); mpfr_set_zero (value.mpfr_data (), 0); for (std::size_t inner = 0; inner < rows; ++inner) { Real product = Real::with_precision (precision); mpfr_mul (product.mpfr_data (), result.q.at (inner, row).mpfr_data (), result.q.at (inner, column).mpfr_data (), MPFR_RNDN); mpfr_add (value.mpfr_data (), value.mpfr_data (), product.mpfr_data (), MPFR_RNDN); } Real expected = Real::with_precision (precision); mpfr_set_ui (expected.mpfr_data (), row == column ? 1 : 0, MPFR_RNDN); check_close (value, expected, precision, message); } } void check_permutation (const MpfrPivotedQrResult& result, std::initializer_list expected, const char *message) { check (result.permutation.size () == expected.size (), message); std::size_t index = 0; for (const auto value : expected) check (result.permutation[index++] == value, message); } void test_deterministic_pivot () { const auto input = matrix (3, 3, 256, {"1", "0", "0", "0", "4", "0", "0", "0", "2"}); const auto full = octave_mplapack::mplapack_mpfr_matrix_pivoted_qr (input, false, true); check_permutation (full, {2, 3, 1}, "deterministic pivot mismatch"); check (full.q.rows () == 3 && full.q.columns () == 3 && full.r.rows () == 3 && full.r.columns () == 3, "pivoted square shape mismatch"); check_reconstruction (full, input, "pivoted reconstruction mismatch"); check_orthogonality (full, "pivoted orthogonality mismatch"); const auto tall = matrix (4, 3, 256, {"1", "0", "0", "0", "0", "5", "0", "0", "0", "0", "2", "0"}); const auto economy = octave_mplapack::mplapack_mpfr_matrix_pivoted_qr (tall, true, true); check_permutation (economy, {2, 3, 1}, "tall pivot mismatch"); check (economy.q.rows () == 4 && economy.q.columns () == 3 && economy.r.rows () == 3 && economy.r.columns () == 3, "pivoted economy shape mismatch"); check_reconstruction (economy, tall, "pivoted economy reconstruction mismatch"); check_orthogonality (economy, "pivoted economy orthogonality mismatch"); const auto wide = matrix (2, 4, 256, {"1", "0", "0", "4", "0", "2", "0", "0"}); const auto wide_result = octave_mplapack::mplapack_mpfr_matrix_pivoted_qr (wide, false, true); check (wide_result.q.rows () == 2 && wide_result.q.columns () == 2 && wide_result.r.rows () == 2 && wide_result.r.columns () == 4, "wide pivoted shape mismatch"); check_reconstruction (wide_result, wide, "wide pivoted reconstruction mismatch"); check_orthogonality (wide_result, "wide pivoted orthogonality mismatch"); } void test_precision_and_immutability () { mpfrxx::set_default_precision_bits (128); auto input = matrix (1, 2, 1024, {"1", "1"}); Real tail = Real::with_precision (1024); mpfr_set_ui_2exp (tail.mpfr_data (), 1, -700, MPFR_RNDN); mpfr_add (input.at (0, 1).mpfr_data (), input.at (0, 1).mpfr_data (), tail.mpfr_data (), MPFR_RNDN); const auto before = input; const auto result = octave_mplapack::mplapack_mpfr_matrix_pivoted_qr (input, false, true); check_permutation (result, {2, 1}, "precision pivot order mismatch"); check (result.q.precision_bits () == 1024 && result.r.precision_bits () == 1024, "pivoted precision metadata mismatch"); check (input.element_exactly_equal (0, 1, before, 0, 1), "pivoted QR mutated input"); check_reconstruction (result, input, "precision pivot reconstruction mismatch"); check_orthogonality (result, "precision pivot orthogonality mismatch"); check (mpfrxx::default_precision_bits () == 128, "pivoted QR leaked ambient precision"); mpfrxx::set_default_precision_bits (4096); const auto high_ambient_input = matrix (2, 2, 256, {"1", "0", "0", "2"}); const auto high_ambient = octave_mplapack::mplapack_mpfr_matrix_pivoted_qr ( high_ambient_input, false, true); check (high_ambient.q.precision_bits () == 256 && high_ambient.r.precision_bits () == 256, "high ambient pivoted QR widened result"); check (mpfrxx::default_precision_bits () == 4096, "high ambient pivoted QR changed ambient precision"); mpfrxx::set_default_precision_bits (128); auto high_precision_input = matrix (1, 2, 2048, {"1", "1"}); Real high_precision_tail = Real::with_precision (2048); mpfr_set_ui_2exp (high_precision_tail.mpfr_data (), 1, -1500, MPFR_RNDN); mpfr_add (high_precision_input.at (0, 1).mpfr_data (), high_precision_input.at (0, 1).mpfr_data (), high_precision_tail.mpfr_data (), MPFR_RNDN); const auto high_precision = octave_mplapack::mplapack_mpfr_matrix_pivoted_qr ( high_precision_input, false, true); check_permutation (high_precision, {2, 1}, "2048-bit precision pivot order mismatch"); Real expected = Real::with_precision (2048); mpfr_set_ui (expected.mpfr_data (), 1, MPFR_RNDN); mpfr_add (expected.mpfr_data (), expected.mpfr_data (), high_precision_tail.mpfr_data (), MPFR_RNDN); Real absolute_factor = Real::with_precision (2048); mpfr_abs (absolute_factor.mpfr_data (), high_precision.r.at (0, 0).mpfr_data (), MPFR_RNDN); check (mpfr_cmp (absolute_factor.mpfr_data (), expected.mpfr_data ()) == 0, "2048-bit pivoted QR tail was not preserved"); check (high_precision.q.precision_bits () == 2048 && high_precision.r.precision_bits () == 2048, "2048-bit pivoted QR precision metadata mismatch"); check (mpfrxx::default_precision_bits () == 128, "2048-bit pivoted QR changed ambient precision"); } void test_empty () { const auto empty = matrix (0, 3, 512, {}); const auto result = octave_mplapack::mplapack_mpfr_matrix_pivoted_qr (empty, false, true); check (result.q.rows () == 0 && result.q.columns () == 0 && result.r.rows () == 0 && result.r.columns () == 3, "empty pivoted QR shape mismatch"); check_permutation (result, {1, 2, 3}, "empty pivoted permutation mismatch"); const auto no_columns = matrix (3, 0, 512, {}); const auto econ = octave_mplapack::mplapack_mpfr_matrix_pivoted_qr ( no_columns, true, true); check (econ.q.rows () == 3 && econ.q.columns () == 0 && econ.r.rows () == 0 && econ.r.columns () == 0, "empty economy pivoted QR shape mismatch"); check (econ.permutation.empty (), "empty pivoted vector mismatch"); } } // namespace int main () { try { test_deterministic_pivot (); test_precision_and_immutability (); test_empty (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: native pivoted QR tests\n"; return 0; } mplapack-interop-0.5.1/test/test_neigt08.m0000644000230300031750000000327315274353472017722 0ustar rafaelrafael% Focused NEIGT08 Hadamard/Frank reuse and independent-reference tests. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect had = net_hadamard_model (8, 16, 512); href = net_hadamard_reference (8, 16, 640); assert (all (diag (had.T) == href.eigenvalues)); [V, D, W] = eig (had.A, "nobalance"); hmetrics = net_metrics (had.A, V, D, W, href.eigenvalues); assert (hmetrics.absolute_match.threshold < net_pow2 (-200, 512)); assert (hmetrics.right_residual < net_pow2 (-180, 512)); assert (hmetrics.left_residual < net_pow2 (-180, 512)); assert (all (href.condition_numbers > mp (0))); f5 = net_frank_audit (5, 512, 640); assert (f5.reflected_exact && all (f5.characteristic_checks)); assert (f5.polynomial.coefficients == mp ([1, -15, 55, -55, 15, -1])); assert (f5.positive_reference && f5.reference.central_exact); assert (f5.match_F0.threshold < net_pow2 (-180, 512)); assert (f5.match_F1.threshold < net_pow2 (-180, 512)); assert (f5.reflected_transpose_match.threshold < net_pow2 (-180, 512)); assert (f5.reciprocal_error < net_pow2 (-180, 640)); f8 = net_frank_audit (8, 512, 640); assert (f8.reflected_exact && all (f8.characteristic_checks)); assert (f8.positive_reference); assert (f8.match_F0.threshold < net_pow2 (-180, 512)); assert (f8.match_F1.threshold < net_pow2 (-180, 512)); assert (f8.reciprocal_error < net_pow2 (-180, 640)); fprintf ("PASS: NEIGT08 Hadamard/Frank reuse, recurrence, and Hermite-Jacobi reference\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/test_neigt23.m0000644000230300031750000000641015274353472017713 0ustar rafaelrafael% NEIGT23: exact output, independent replay, tamper, and conflict gates. test_root = fileparts (fileparts (mfilename ("fullpath"))); example_root = fullfile (test_root, "examples", "neig_tiers"); private_root = fullfile (example_root, "private"); inst_root = fullfile (test_root, "inst"); src_root = fullfile (test_root, "src"); addpath (example_root); addpath (private_root); saved_bits = mpbits (); unwind_protect output_dir = tempname (); bundle = mp_neig_write_outputs ("smoke", output_dir, ... struct ("tier", "all", "plot", false)); assert (bundle.ok && strcmp (bundle.status, "COMPLETE")); assert (bundle.ordinary.coverage.measured_eig_rows == 120); assert (bundle.replay.ok && ! bundle.replay.called_eig ... && ! bundle.replay.reconstructed_ideal_model); assert (exist (bundle.output.rows, "file") == 2); assert (exist (bundle.output.proof, "file") == 2); assert (exist (bundle.output.report, "file") == 2); assert (exist (fullfile (output_dir, "spectrum.png"), "file") == 0); rows_text = fileread (bundle.output.rows); assert (! isempty (strfind (rows_text, "case_id\tmode\twork_role"))); assert (! isempty (strfind (fileread (bundle.output.report), ... "NEIGT23_VS1_EXACT_REPLAY")) ... || ! isempty (strfind (fileread (bundle.output.report), ... "mp_neig_replay"))); % A second writer invocation must not overwrite an existing directory. caught = false; try mp_neig_write_outputs ("smoke", output_dir, struct ("tier", "S", ... "plot", false)); catch exception caught = strcmp (exception.identifier, "mplapack:neigt:OutputExists"); end_try_catch assert (caught); % Content tampering is detected before numerical replay. proof_text = fileread (bundle.output.proof); tampered = strcat (tempname (), ".json"); handle = fopen (tampered, "w"); fwrite (handle, strrep (proof_text, "VS1-01", "VS1-02")); fclose (handle); caught = false; try mp_neig_replay (tampered); catch exception caught = strcmp (exception.identifier, "mplapack:neigt:Deserialize"); end_try_catch assert (caught); % The second process replays the same exact record without the capture path. replay_command = sprintf (["octave-cli --no-gui --quiet --no-init-file ", ... "--path \"%s\" --path \"%s\" --path \"%s\" --path \"%s\" --eval ", ... "\"r=mp_neig_replay('%s'); assert(r.ok); ", ... "assert(~r.called_eig && ~r.reconstructed_ideal_model);\""], ... inst_root, src_root, example_root, private_root, bundle.output.proof); [exit_status, replay_output] = system (replay_command); assert (exit_status == 0); assert (isempty (strfind (replay_output, "error:"))); rmdir (output_dir, "s"); unlink (tampered); fprintf ("PASS: NEIGT23 exact output, replay, tamper, conflict, and headless gates\n"); unwind_protect_cleanup mpbits (saved_bits); if (exist (output_dir, "dir")), rmdir (output_dir, "s"); endif if (exist (tampered, "file")), unlink (tampered); endif if (any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif if (any (strcmp (strsplit (path (), pathsep), example_root))) rmpath (example_root); endif end_unwind_protect mplapack-interop-0.5.1/test/qr.tst0000644000230300031750000001411215274353472016377 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_matrix_close (value, expected, tolerance) %! if (nargin < 3) %! tolerance = 1e-11; %! endif %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! got = __mplapack_core__ ("matrix_test_element_double", ... %! value, row, column); %! assert (got, expected(row, column), tolerance); %! endfor %! endfor %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4; 5, 7; 11, 13]); %! R_one = qr (A); %! [Q, R] = qr (A); %! assert (size (R_one), [4, 2]); %! assert_matrix_close (R_one, double (R)); %! assert (size (Q), [4, 4]); %! assert (size (R), [4, 2]); %! assert_matrix_close (Q * R, [1, 2; 3, 4; 5, 7; 11, 13], 1e-10); %! assert_matrix_close (Q.' * Q, eye (4), 1e-10); %! for column = 1:columns (R) %! for row = column+1:rows (R) %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! R, row, column, 0)); %! endfor %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (256); %! A = mp ([1, 2; 3, 4; 5, 7; 11, 13]); %! [Qe, Re] = qr (A, "econ"); %! [Q0, R0] = qr (A, 0); %! assert (size (Qe), [4, 2]); %! assert (size (Re), [2, 2]); %! assert (size (Q0), [4, 2]); %! assert (size (R0), [2, 2]); %! assert_matrix_close (Qe * Re, double (A), 1e-10); %! assert_matrix_close (Q0 * R0, double (A), 1e-10); %! assert_matrix_close (Qe.' * Qe, eye (2), 1e-10); %! assert_matrix_close (Re, double (R0)); %! mpbits (512); %!test %! mpbits (256); %! wide = mp ([1, 2, 3, 4; 5, 6, 7, 8]); %! [Q, R] = qr (wide); %! [Qe, Re] = qr (wide, "econ"); %! assert (size (Q), [2, 2]); %! assert (size (R), [2, 4]); %! assert (size (Qe), [2, 2]); %! assert (size (Re), [2, 4]); %! assert_matrix_close (Q * R, double (wide), 1e-10); %! assert_matrix_close (Q.' * Q, eye (2), 1e-10); %! assert_matrix_close (Qe * Re, double (wide), 1e-10); %! mpbits (512); %!test %! mpbits (256); %! row = mp ([1, 2, 3]); %! col = mp ([1; 2; 3]); %! [Qr, Rr] = qr (row); %! [Qc, Rc] = qr (col, "econ"); %! assert (size (Qr), [1, 1]); %! assert (size (Rr), [1, 3]); %! assert (size (Qc), [3, 1]); %! assert (size (Rc), [1, 1]); %! assert_matrix_close (Qr * Rr, [1, 2, 3]); %! assert_matrix_close (Qc * Rc, [1; 2; 3]); %! mpbits (512); %!test %! mpbits (256); %! for shape_cell = {[0, 0], [0, 3], [3, 0]} %! shape = shape_cell{1}; %! A = mp (zeros (shape(1), shape(2))); %! [Q, R] = qr (A); %! [Qe, Re] = qr (A, "econ"); %! [Q0, R0] = qr (A, 0); %! assert (size (Q), [shape(1), shape(1)]); %! assert (size (R), [shape(1), shape(2)]); %! if (shape(1) > shape(2)) %! assert (size (Qe), [shape(1), shape(2)]); %! assert (size (Re), [shape(2), shape(2)]); %! else %! assert (size (Qe), [shape(1), shape(1)]); %! assert (size (Re), [shape(1), shape(2)]); %! endif %! assert (size (Q0), size (Qe)); %! assert (size (R0), size (Re)); %! endfor %! mpbits (512); %!test %! mpbits (256); %! for x = [5, -5, 0] %! [Q, R] = qr (mp (x)); %! assert (size (Q), [1, 1]); %! assert (size (R), [1, 1]); %! assert (__mplapack_core__ ("scalar_test_equal_double", Q, 1)); %! assert (__mplapack_core__ ("scalar_test_equal_double", R, x)); %! assert (__mplapack_core__ ("scalar_test_equal_double", qr (mp (x)), x)); %! endfor %! mpbits (512); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! tail = strcat ("1.", repmat ("0", 1, 210), "1"); %! A = mp ({"1", "1"; "0", tail; "0", "0"}); %! mpbits (128); %! [Q, R] = qr (A); %! [Qe, Re] = qr (A, "econ"); %! assert (__mplapack_core__ ("matrix_test_info", Q).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_info", R).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_info", Qe).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_info", Re).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_element_equal", R, 2, 2, ... %! A, 2, 2)); %! assert (__mplapack_core__ ("matrix_test_element_equal", Re, 2, 2, ... %! A, 2, 2)); %! assert (mpbits (), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! mpbits (4096); %! [Qh, Rh] = qr (A); %! assert (__mplapack_core__ ("matrix_test_info", Qh).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_info", Rh).precision_bits, ... %! uint64 (1024)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2048); %! tail = strcat ("1.", repmat ("0", 1, 450), "1"); %! A = mp ({"1", "1"; "0", tail; "0", "0"}); %! mpbits (128); %! [Q, R] = qr (A); %! assert (__mplapack_core__ ("matrix_test_info", R).precision_bits, ... %! uint64 (2048)); %! assert (__mplapack_core__ ("matrix_test_element_equal", R, 2, 2, ... %! A, 2, 2)); %! assert (mpbits (), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! before = double (A); %! [Q, R] = qr (A); %! assert (double (A), before); %! B = A; %! [QB, RB] = qr (B); %! assert (double (A), before); %! clear A B; %! assert (__mplapack_core__ ("matrix_test_element_double", Q, 1, 1) != 0); %! assert (__mplapack_core__ ("matrix_test_element_double", RB, 1, 1) != 0); %! mpbits (512); %!test %! A = mp ([1, 2; 3, 4]); %! [Qv, Rv] = qr (A, "vector"); %! [Qm, Rm] = qr (A, "matrix"); %! [Qp, Rp, P] = qr (A); %! assert (double (Qv * Rv), double (A), 1e-10); %! assert (double (Qm * Rm), double (A), 1e-10); %! assert (double (Qp * Rp), double (A * P), 1e-10); %! fail ("qr (A, \"foo\")", "option"); %! fail ("qr (A, A)", "qr option"); %! mpbits (512); mplapack-interop-0.5.1/test/mp_lapack_qr_test.cc0000644000230300031750000001753615274353472021235 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_lapack.h" #include #include #include #include #include namespace { using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrQrResult; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } MpfrMatrixStorage matrix (std::size_t rows, std::size_t columns, mpfr_prec_t precision, std::initializer_list values) { return MpfrMatrixStorage (rows, columns, precision, std::vector (values.begin (), values.end ())); } void check_close (const Real& value, const Real& expected, mpfr_prec_t precision, const char *message) { Real difference = Real::with_precision (precision); mpfr_sub (difference.mpfr_data (), value.mpfr_data (), expected.mpfr_data (), MPFR_RNDN); Real tolerance = Real::with_precision (precision); mpfr_set_ui_2exp (tolerance.mpfr_data (), 1, -static_cast (precision / 2), MPFR_RNDN); mpfr_abs (difference.mpfr_data (), difference.mpfr_data (), MPFR_RNDN); check (mpfr_cmp (difference.mpfr_data (), tolerance.mpfr_data ()) < 0, message); } void check_reconstruction (const MpfrQrResult& result, const MpfrMatrixStorage& input, const char *message) { const std::size_t m = input.rows (); const std::size_t n = input.columns (); const std::size_t q_columns = result.q.columns (); const mpfr_prec_t precision = input.precision_bits (); for (std::size_t column = 0; column < n; ++column) for (std::size_t row = 0; row < m; ++row) { Real reconstructed = Real::with_precision (precision); mpfr_set_zero (reconstructed.mpfr_data (), 0); for (std::size_t inner = 0; inner < q_columns; ++inner) { Real product = Real::with_precision (precision); mpfr_mul (product.mpfr_data (), result.q.at (row, inner).mpfr_data (), result.r.at (inner, column).mpfr_data (), MPFR_RNDN); mpfr_add (reconstructed.mpfr_data (), reconstructed.mpfr_data (), product.mpfr_data (), MPFR_RNDN); } check_close (reconstructed, input.at (row, column), precision, message); } } void check_orthogonality (const MpfrQrResult& result, const char *message) { const std::size_t rows = result.q.rows (); const std::size_t columns = result.q.columns (); const mpfr_prec_t precision = result.q.precision_bits (); for (std::size_t column = 0; column < columns; ++column) for (std::size_t row = 0; row < columns; ++row) { Real value = Real::with_precision (precision); mpfr_set_zero (value.mpfr_data (), 0); for (std::size_t inner = 0; inner < rows; ++inner) { Real product = Real::with_precision (precision); mpfr_mul (product.mpfr_data (), result.q.at (inner, row).mpfr_data (), result.q.at (inner, column).mpfr_data (), MPFR_RNDN); mpfr_add (value.mpfr_data (), value.mpfr_data (), product.mpfr_data (), MPFR_RNDN); } Real expected = Real::with_precision (precision); mpfr_set_ui (expected.mpfr_data (), row == column ? 1 : 0, MPFR_RNDN); check_close (value, expected, precision, message); } } void check_upper_structure (const MpfrMatrixStorage& r, const char *message) { const std::size_t active = std::min (r.rows (), r.columns ()); for (std::size_t column = 0; column < r.columns (); ++column) for (std::size_t row = 0; row < r.rows (); ++row) if (row >= active || row > column) check (mpfr_zero_p (r.at (row, column).mpfr_data ()) != 0, message); } void test_shapes_and_reconstruction () { const auto tall = matrix (4, 2, 256, {"1", "3", "5", "11", "2", "4", "7", "13"}); const auto full = octave_mplapack::mplapack_mpfr_matrix_qr (tall, false, true); check (full.q.rows () == 4 && full.q.columns () == 4 && full.r.rows () == 4 && full.r.columns () == 2, "full tall QR shape mismatch"); check_reconstruction (full, tall, "full tall reconstruction mismatch"); check_orthogonality (full, "full tall orthogonality mismatch"); check_upper_structure (full.r, "full R structure mismatch"); const auto economy = octave_mplapack::mplapack_mpfr_matrix_qr (tall, true, true); check (economy.q.rows () == 4 && economy.q.columns () == 2 && economy.r.rows () == 2 && economy.r.columns () == 2, "economy tall QR shape mismatch"); check_reconstruction (economy, tall, "economy tall reconstruction mismatch"); check_orthogonality (economy, "economy tall orthogonality mismatch"); const auto wide = matrix (2, 4, 256, {"1", "3", "2", "4", "5", "7", "6", "8"}); const auto wide_result = octave_mplapack::mplapack_mpfr_matrix_qr (wide, false, true); check (wide_result.q.rows () == 2 && wide_result.q.columns () == 2 && wide_result.r.rows () == 2 && wide_result.r.columns () == 4, "wide QR shape mismatch"); check_reconstruction (wide_result, wide, "wide reconstruction mismatch"); check_orthogonality (wide_result, "wide orthogonality mismatch"); const auto one_output = octave_mplapack::mplapack_mpfr_matrix_qr (tall, false, false); check (one_output.q.rows () == 0 && one_output.q.columns () == 0, "one-output QR unexpectedly generated Q"); check (one_output.r.rows () == 4 && one_output.r.columns () == 2, "one-output R shape mismatch"); } void test_precision_and_empty () { mpfrxx::set_default_precision_bits (128); for (const auto fixture : {std::pair (1024, -700), std::pair (2048, -1500)}) { const auto precision = fixture.first; auto input = matrix (2, 2, precision, {"1", "0", "1", "1"}); Real tail = Real::with_precision (precision); mpfr_set_ui_2exp (tail.mpfr_data (), 1, fixture.second, MPFR_RNDN); mpfr_add (input.at (1, 1).mpfr_data (), input.at (1, 1).mpfr_data (), tail.mpfr_data (), MPFR_RNDN); const auto result = octave_mplapack::mplapack_mpfr_matrix_qr (input, false, true); check (result.q.precision_bits () == precision && result.r.precision_bits () == precision, "QR precision metadata mismatch"); check (mpfr_equal_p (result.r.at (1, 1).mpfr_data (), input.at (1, 1).mpfr_data ()) != 0, "QR precision tail was not preserved"); check_reconstruction (result, input, "precision QR reconstruction mismatch"); check (mpfrxx::default_precision_bits () == 128, "QR leaked ambient precision"); } const auto empty = matrix (0, 3, 1024, {}); const auto empty_full = octave_mplapack::mplapack_mpfr_matrix_qr (empty, false, true); check (empty_full.q.rows () == 0 && empty_full.q.columns () == 0 && empty_full.r.rows () == 0 && empty_full.r.columns () == 3 && empty_full.r.precision_bits () == 1024, "empty QR shape mismatch"); const auto zero_columns = matrix (3, 0, 1024, {}); const auto zero_econ = octave_mplapack::mplapack_mpfr_matrix_qr (zero_columns, true, true); check (zero_econ.q.rows () == 3 && zero_econ.q.columns () == 0 && zero_econ.r.rows () == 0 && zero_econ.r.columns () == 0, "zero-column economy QR shape mismatch"); } } // namespace int main () { try { test_shapes_and_reconstruction (); test_precision_and_empty (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: MPLAPACK MPFR Rgeqrf/Rorgqr QR tests\n"; return 0; } mplapack-interop-0.5.1/test/mp_complex_qr_test.cc0000644000230300031750000001477615274353472021454 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include "mp_complex_qr.h" namespace { using Matrix = octave_mplapack::MpfrComplexMatrixStorage; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } std::complex as_double (const Matrix& matrix, std::size_t row, std::size_t column) { return octave_mplapack::MpfrComplexScalarStorage ( matrix.at (row, column)).to_double (); } void check_zero (const Matrix& matrix, std::size_t row, std::size_t column, const char *message) { check (mpfr_zero_p (mpc_realref (matrix.at (row, column).mpc_data ())) != 0 && mpfr_zero_p (mpc_imagref (matrix.at (row, column).mpc_data ())) != 0, message); } void check_orthogonality (const Matrix& q, const char *message) { const double tolerance = 1.0e-10; for (std::size_t first = 0; first < q.columns (); ++first) for (std::size_t second = 0; second < q.columns (); ++second) { std::complex sum {0.0, 0.0}; for (std::size_t row = 0; row < q.rows (); ++row) sum += std::conj (as_double (q, row, first)) * as_double (q, row, second); const std::complex expected = first == second ? std::complex {1.0, 0.0} : std::complex {0.0, 0.0}; check (std::abs (sum - expected) < tolerance, message); } } void check_reconstruction (const Matrix& input, const Matrix& q, const Matrix& r, const char *message) { const double tolerance = 1.0e-10; for (std::size_t column = 0; column < input.columns (); ++column) for (std::size_t row = 0; row < input.rows (); ++row) { std::complex sum {0.0, 0.0}; for (std::size_t inner = 0; inner < q.columns (); ++inner) sum += as_double (q, row, inner) * as_double (r, inner, column); check (std::abs (sum - as_double (input, row, column)) < tolerance, message); } } void test_full_economy_and_one_output () { const Matrix input (3, 2, 512, std::vector> { {1.0, 1.0}, {2.0, 0.0}, {0.0, 1.0}, {2.0, -1.0}, {1.0, 2.0}, {1.0, 0.0}}); const auto before = input; const auto full = octave_mplapack::mplapack_mpc_matrix_qr (input, false, true); check (full.q.rows () == 3 && full.q.columns () == 3 && full.r.rows () == 3 && full.r.columns () == 2, "full complex QR shape mismatch"); check_orthogonality (full.q, "full complex QR is not unitary"); check_reconstruction (input, full.q, full.r, "full complex QR reconstruction mismatch"); check_zero (full.r, 1, 0, "full complex QR R lower entry is not zero"); check_zero (full.r, 2, 0, "full complex QR R lower entry is not zero"); check_zero (full.r, 2, 1, "full complex QR R lower entry is not zero"); check (input.element_exactly_equal (0, 0, before, 0, 0), "complex QR modified its input"); const auto economy = octave_mplapack::mplapack_mpc_matrix_qr (input, true, true); check (economy.q.rows () == 3 && economy.q.columns () == 2 && economy.r.rows () == 2 && economy.r.columns () == 2, "economy complex QR shape mismatch"); check_orthogonality (economy.q, "economy complex QR is not unitary"); check_reconstruction (input, economy.q, economy.r, "economy complex QR reconstruction mismatch"); check_zero (economy.r, 1, 0, "economy complex QR R lower entry is not zero"); const auto one_output = octave_mplapack::mplapack_mpc_matrix_qr (input, false, false); check (one_output.q.rows () == 0 && one_output.q.columns () == 0 && one_output.r.rows () == 3 && one_output.r.columns () == 2, "one-output complex QR constructed Q"); } void test_precision_and_empty () { mpfrxx::set_default_precision_bits (128); for (const auto setting : {std::array {{1024, 700}}, std::array {{2048, 1500}}}) { const mpfr_prec_t precision = setting[0]; Matrix input (2, 2, precision); mpfr_set_ui (mpc_realref (input.at (0, 0).mpc_data ()), 1, MPFR_RNDN); mpfr_set_zero (mpc_imagref (input.at (0, 0).mpc_data ()), 0); mpfr_set_zero (mpc_realref (input.at (1, 0).mpc_data ()), 0); mpfr_set_zero (mpc_imagref (input.at (1, 0).mpc_data ()), 0); mpfr_set_ui_2exp (mpc_realref (input.at (0, 1).mpc_data ()), 1, -static_cast (setting[1]), MPFR_RNDN); mpfr_set_ui_2exp (mpc_imagref (input.at (0, 1).mpc_data ()), 1, -static_cast (setting[1]), MPFR_RNDN); mpfr_set_ui (mpc_realref (input.at (1, 1).mpc_data ()), 1, MPFR_RNDN); mpfr_set_zero (mpc_imagref (input.at (1, 1).mpc_data ()), 0); const auto result = octave_mplapack::mplapack_mpc_matrix_qr (input, true, true); check (result.q.precision_bits () == precision && result.r.precision_bits () == precision && result.q.all_elements_have_uniform_precision () && result.r.all_elements_have_uniform_precision (), "complex QR precision metadata mismatch"); check (mpfr_equal_p (mpc_realref (result.r.at (0, 1).mpc_data ()), mpc_realref (input.at (0, 1).mpc_data ())) != 0 && mpfr_equal_p (mpc_imagref (result.r.at (0, 1).mpc_data ()), mpc_imagref (input.at (0, 1).mpc_data ())) != 0, "complex QR precision canary changed"); check (mpfrxx::default_precision_bits () == 128, "complex QR changed ambient precision"); } const Matrix empty (0, 3, 2048); const auto empty_result = octave_mplapack::mplapack_mpc_matrix_qr (empty, false, true); check (empty_result.q.rows () == 0 && empty_result.q.columns () == 0 && empty_result.r.rows () == 0 && empty_result.r.columns () == 3, "empty complex QR shape mismatch"); } } // namespace int main () { try { test_full_economy_and_one_output (); test_precision_and_empty (); std::cout << "PASS: complex Cgeqrf/Cungqr full, economy, one-output, workspace, orthogonality, reconstruction, precision, ambient scope, shapes, and immutability\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/test_neigt16.m0000644000230300031750000000650515274353472017722 0ustar rafaelrafaelfunction test_neigt16 () % NEIGT16: counted cluster separation, centered powers, and raw projectors. addpath (fullfile (fileparts (mfilename ("fullpath")), "../examples/neig_tiers/private")); addpath (fullfile (fileparts (mfilename ("fullpath")), "../examples/neig_tiers")); saved_bits = mpbits (); unwind_protect mpbits (256); profile_data = struct ("work_bits", [256], "evaluation_bits", 768); jobs = load_jobs (); positive = struct ([]); for index = 1:numel (jobs) positive(index) = net_v_s2_job (jobs(index), profile_data, "smoke"); assert (positive(index).pass); assert (strcmp (positive(index).status, "CERTIFIED_CLUSTER")); assert (positive(index).milestone_pass); assert (positive(index).cluster.strict_separation); assert (positive(index).cluster.counted_total_roots == jobs(index).fixture.n); assert (positive(index).cluster.centered_power_pass); assert (positive(index).cluster.projector_pass); assert (positive(index).cluster.projector.raw_projector_bound <= net_pow2 (-40, 768)); assert (positive(index).cluster.region_radius <= positive(index).cluster.cluster_radius_target); endfor % The defective exact 2-by-2 block has a nilpotent centered square. This % checks the power primitive independently of the graph job's candidate. q = 256; mpbits (q); M = net_iv_cmatrix_point (mp ([1, 1; 0, 1]), q); shifted = net_iv_cmatrix_sub (M, net_iv_cmatrix_point (mp (eye (2)), q), q); squared = net_iv_cmatrix_mul (shifted, shifted, q); assert (net_iv_cmatrix_inf_upper (squared, q) == mp (0)); % An intentionally invalid claimed region must not become a cluster proof. bad_job = jobs(1); bad_job.adversarial_claimed_radius = mp (8); bad = net_v_s2_cluster (positive(1).graph, positive(1).selected_candidate, ... positive(1).query_center, bad_job, "smoke", 768); assert (! bad.pass); assert (! bad.strict_separation); assert (strcmp (bad.claim_status, "CERTIFIED_INVARIANT_BASIS")); % A full-space identity/triviality route is outside the certificate domain. full_job = jobs(1); full_job.cluster_dimension = full_job.fixture.n; full = net_v_s2_cluster (positive(1).graph, positive(1).selected_candidate, ... positive(1).query_center, full_job, "smoke", 768); assert (! full.pass); assert (strcmp (full.status, "INCONCLUSIVE_FULL_SPACE_OR_DIMENSION")); fprintf ("PASS: NEIGT16 counted clusters, centered powers, projectors, and traps\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect endfunction function jobs = load_jobs () jobs = struct (); jobs(1) = make_job ("VS2-01", "semisimple", 6, 2, "1", "1/4"); jobs(2) = make_job ("VS2-02", "jordan", 6, 2, "1", "1/4"); jobs(3) = make_job ("VS2-03", "two_jordan", 8, 4, "1+2^-13", "1/4"); jobs(3).fixture.gap_exponent = 12; jobs(4) = make_job ("VS2-04", "mks_zero", 6, 4, "0", "1/8"); jobs(4).fixture.m = 3; jobs(4).fixture.delta = "1/8"; endfunction function job = make_job (id, regime, n, k, center, radius) job = struct ("id", id, "tier", "V-S", "kind", "cluster_graph", ... "fixture", struct ("n", n, "regime", regime, ... "query_center", center, "query_radius", radius, ... "gap_exponent", 0, "m", 0, "delta", "1/8"), ... "cluster_dimension", k, "expected", "CERTIFIED_CLUSTER"); endfunction mplapack-interop-0.5.1/test/mp_complex_structure_test.cc0000644000230300031750000001163415274353472023060 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include "mp_complex_structure.h" #include "mp_matrix_structure.h" namespace { void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } } // namespace int main () { try { for (mpfr_prec_t precision : {128, 512, 1024, 2048}) { octave_mplapack::MpfrComplexScalarStorage scalar ( "(1.25,-2.5)", precision); const auto real = octave_mplapack::mpfr_complex_scalar_real (scalar); const auto imag = octave_mplapack::mpfr_complex_scalar_imag (scalar); const auto conjugate = octave_mplapack::mpfr_complex_scalar_conj (scalar); const auto transpose = octave_mplapack::mpfr_complex_scalar_transpose (scalar); const auto ctranspose = octave_mplapack::mpfr_complex_scalar_ctranspose (scalar); check (real.precision_bits () == precision && imag.precision_bits () == precision, "scalar component precision changed"); check (real.exactly_equal_string ("1.25"), "real component mismatch"); check (imag.exactly_equal_string ("-2.5"), "imaginary component mismatch"); check (conjugate.to_canonical_string () == "(1.25e+0,2.5e+0)", "scalar conjugate mismatch"); check (transpose.exactly_equal (scalar), "scalar transpose changed value"); check (ctranspose.exactly_equal (conjugate), "scalar conjugate transpose mismatch"); octave_mplapack::MpfrComplexScalarStorage signed_zero ( 0.0, -0.0, precision); const auto signed_conjugate = octave_mplapack::mpfr_complex_scalar_conj (signed_zero); check (signed_zero.imag_signbit () && ! signed_conjugate.imag_signbit (), "scalar conjugation did not flip signed zero"); const std::vector> values { {1.0, 2.0}, {5.0, 6.0}, {3.0, -4.0}, {7.0, -8.0} }; octave_mplapack::MpfrComplexMatrixStorage matrix ( 2, 2, precision, values); const auto matrix_real = octave_mplapack::mpfr_complex_matrix_real (matrix); const auto matrix_imag = octave_mplapack::mpfr_complex_matrix_imag (matrix); const auto matrix_conj = octave_mplapack::mpfr_complex_matrix_conj (matrix); const auto matrix_transpose = octave_mplapack::mpfr_complex_matrix_transpose (matrix); const auto matrix_ctranspose = octave_mplapack::mpfr_complex_matrix_ctranspose (matrix); const auto matrix_reshape = octave_mplapack::mpfr_complex_matrix_reshape (matrix, 1, 4); check (matrix_real.rows () == 2 && matrix_real.columns () == 2 && matrix_imag.precision_bits () == precision, "matrix component shape or precision mismatch"); check (matrix_real.element_exactly_equal_double (1, 0, 5.0), "matrix real component mismatch"); check (matrix_imag.element_exactly_equal_double (0, 1, -4.0), "matrix imaginary component mismatch"); check (matrix_conj.element_exactly_equal_double (0, 1, {3.0, 4.0}), "matrix conjugate mismatch"); check (matrix_transpose.element_exactly_equal_double (0, 1, {5.0, 6.0}), "matrix transpose mismatch"); check (matrix_ctranspose.element_exactly_equal_double (0, 1, {5.0, -6.0}), "matrix conjugate transpose mismatch"); check (matrix_reshape.rows () == 1 && matrix_reshape.columns () == 4 && matrix_reshape.element_exactly_equal_double (0, 0, {1.0, 2.0}) && matrix_reshape.element_exactly_equal_double (0, 1, {5.0, 6.0}) && matrix_reshape.element_exactly_equal_double (0, 2, {3.0, -4.0}) && matrix_reshape.element_exactly_equal_double (0, 3, {7.0, -8.0}), "matrix complex reshape mismatch"); } std::cout << "PASS: complex real/imag/conjugate/transpose helpers, signed zero, precision, and sanitizer coverage\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/t07_serialization.tst0000644000230300031750000000753515274353472021337 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_state_equal (lhs, rhs, label) %! assert (strcmp (lhs.schema, rhs.schema), label); %! assert (lhs.version == rhs.version, label); %! assert (strcmp (lhs.kind, rhs.kind), label); %! assert (lhs.rows == rhs.rows && lhs.columns == rhs.columns, label); %! assert (lhs.precision_bits == rhs.precision_bits, label); %! assert (isequal (lhs.elements, rhs.elements), label); %!endfunction %!function assert_rejected (thunk, label) %! rejected = false; %! try %! thunk (); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, label); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! for bits = [128, 512, 1024, 2048] %! mpbits (bits); %! tiny = mp ('1'); %! limit = 8; %! if (bits == 1024), limit = 700; endif %! if (bits == 2048), limit = 1500; endif %! for k = 1:limit, tiny = tiny * mp ('0.5'); endfor %! %! V = mp ({'1.2345678901234567890123456789', '-0'; '0', 'NaN'}); %! V(2, 1) = tiny; %! expected = __mplapack_core__ ('serialize', V); %! path = sprintf ('/tmp/mplapack-t07-binary-%d.mat', bits); %! save ('-binary', path, 'V'); %! clear V; %! mpbits (256); %! load (path, 'V'); %! actual = __mplapack_core__ ('serialize', V); %! assert_state_equal (expected, actual, ... %! 'binary save/load changed the MP state'); %! assert (__mplapack_core__ ('value_shape_info', V).precision_bits ... %! == uint64 (bits)); %! assert (mpbits () == uint64 (256), ... %! 'binary load changed the ambient precision'); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! C = mp ({'(1.234567890123456789,3.4)', '(0,-0)'; ... %! '(-Inf,NaN)', '(2.3,-4.5)'}); %! E = mp (zeros (0, 3)); %! CE = mp (complex (zeros (2, 0), zeros (2, 0))); %! expected_c = __mplapack_core__ ('serialize', C); %! expected_e = __mplapack_core__ ('serialize', E); %! expected_ce = __mplapack_core__ ('serialize', CE); %! saved_object = saveobj (C); %! mpbits (256); %! hook_value = loadobj (saved_object); %! assert_state_equal (expected_c, __mplapack_core__ ('serialize', hook_value), ... %! 'direct saveobj/loadobj changed the MP state'); %! assert (mpbits () == uint64 (256), ... %! 'direct loadobj changed the ambient precision'); %! save ('-text', '/tmp/mplapack-t07-text-512.mat', 'C', 'E', 'CE'); %! clear C E CE; %! load ('/tmp/mplapack-t07-text-512.mat'); %! assert_state_equal (expected_c, __mplapack_core__ ('serialize', C), ... %! 'text complex round trip changed the MP state'); %! assert_state_equal (expected_e, __mplapack_core__ ('serialize', E), ... %! 'text empty real round trip changed the shape'); %! assert_state_equal (expected_ce, __mplapack_core__ ('serialize', CE), ... %! 'text empty complex round trip changed the shape'); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! state = __mplapack_core__ ('serialize', mp ('1')); %! bad = state; %! bad.version = uint64 (2); %! assert_rejected (@() __mplapack_core__ ('deserialize', bad), ... %! 'future serialization versions must be rejected'); %! bad = state; %! bad.precision_bits = uint64 (0); %! assert_rejected (@() __mplapack_core__ ('deserialize', bad), ... %! 'invalid serialization precision must be rejected'); %! bad = state; %! bad.elements = {'1', '2'}; %! assert_rejected (@() __mplapack_core__ ('deserialize', bad), ... %! 'serialization element-count corruption must be rejected'); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/mp_matrix_storage_test.cc0000644000230300031750000002134415274353472022320 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_storage.h" #include #include #include #include #include #include #include #include #include #include namespace { using Matrix = octave_mplapack::MpfrMatrixStorage; static_assert (std::is_same_v); static_assert (std::is_same_v); static_assert (std::is_same_v ().data ()), mpfr_class *>); static_assert ( std::is_same_v ().data ()), const mpfr_class *>); static_assert (std::is_same_v); static_assert (std::is_same_v); void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void verify_mplapack_arguments (Matrix& matrix) { mpfr_class *values = matrix.data (); mplapackint leading_dimension = matrix.leading_dimension (); if (matrix.numel () != 0) require (values != nullptr, "nonempty data pointer is null"); require (leading_dimension == static_cast ( matrix.rows () == 0 ? 1 : matrix.rows ()), "leading dimension mismatch"); } void test_layout_and_precision () { const std::vector values { "11", "21", "12", "22", "13", "23" }; Matrix matrix (2, 3, 333, values); require (matrix.rows () == 2 && matrix.columns () == 3, "2x3 shape mismatch"); require (matrix.numel () == 6, "2x3 element count mismatch"); require (matrix.leading_dimension () == 2, "2x3 leading dimension mismatch"); require (matrix.all_elements_have_uniform_precision (), "matrix element precision is not uniform"); for (std::size_t index = 0; index < values.size (); ++index) { const std::size_t row = index % 2; const std::size_t column = index / 2; require (matrix.element_exactly_equal_text (row, column, values[index]), "column-major layout mismatch"); } verify_mplapack_arguments (matrix); } void test_copy_move_and_work_buffer () { Matrix original (2, 2, 256, std::vector {"1", "3", "2", "4"}); Matrix copy (original); require (copy.data () != original.data (), "deep copy shares a nonempty data buffer"); require (copy.element_exactly_equal (1, 1, original, 1, 1), "deep copy changed an element"); mpfr_set_si (copy.at (0, 0).mpfr_data (), 99, MPFR_RNDN); require (copy.element_exactly_equal_text (0, 0, "99"), "work-copy mutation failed"); require (original.element_exactly_equal_text (0, 0, "1"), "work-copy mutation changed the original"); Matrix assigned (1, 1, 32, std::vector {"-1"}); assigned = original; require (assigned.precision_bits () == 256, "copy assignment did not preserve precision"); require (assigned.data () != original.data (), "copy assignment shares a nonempty data buffer"); Matrix moved (std::move (copy)); require (moved.rows () == 2 && moved.columns () == 2, "move construction changed shape"); require (moved.element_exactly_equal_text (0, 0, "99"), "move construction changed values"); Matrix move_assigned (0, 0, 128); move_assigned = std::move (moved); require (move_assigned.precision_bits () == 256, "move assignment changed precision"); require (move_assigned.element_exactly_equal_text (0, 0, "99"), "move assignment changed values"); } void test_empty_and_dimension_checks () { Matrix empty_00 (0, 0, 128); Matrix empty_03 (0, 3, 128); Matrix empty_40 (4, 0, 128); require (empty_00.numel () == 0 && empty_00.leading_dimension () == 1, "0x0 metadata mismatch"); require (empty_03.numel () == 0 && empty_03.rows () == 0 && empty_03.columns () == 3 && empty_03.leading_dimension () == 1, "0x3 metadata mismatch"); require (empty_40.numel () == 0 && empty_40.rows () == 4 && empty_40.columns () == 0 && empty_40.leading_dimension () == 4, "4x0 metadata mismatch"); Matrix empty_copy (empty_03); Matrix empty_move (std::move (empty_copy)); require (empty_move.rows () == 0 && empty_move.columns () == 3, "empty copy/move changed shape"); bool overflow_detected = false; try { Matrix::checked_element_count ( std::numeric_limits::max (), 2); } catch (const std::overflow_error&) { overflow_detected = true; } require (overflow_detected, "element-count overflow was not detected"); if (std::numeric_limits::max () > static_cast ( std::numeric_limits::max ())) { bool dimension_overflow_detected = false; try { Matrix::checked_mplapack_dimension ( static_cast ( std::numeric_limits::max ()) + 1); } catch (const std::overflow_error&) { dimension_overflow_detected = true; } require (dimension_overflow_detected, "MPLAPACK dimension overflow was not detected"); } } void test_precision_matrix () { for (mpfr_prec_t precision : {32, 128, 256, 333, 512, 1024}) { Matrix matrix (3, 2, precision, std::vector {0.1, 0.125, -2.25, 1.5, 0.0, -0.0}); require (matrix.precision_bits () == precision, "matrix precision metadata mismatch"); require (matrix.all_elements_have_uniform_precision (), "matrix contains default-precision elements"); if (precision >= std::numeric_limits::digits) require (matrix.element_exactly_equal_double (0, 0, 0.1), "double matrix did not preserve binary64 source value"); require (matrix.element_exactly_equal_double (1, 0, 0.125), "dyadic double matrix source value changed"); } } void test_transactional_error_cleanup () { bool invalid_text_detected = false; try { Matrix bad (2, 2, 512, std::vector {"1", "2", "bad", "4"}); (void) bad; } catch (const std::invalid_argument&) { invalid_text_detected = true; } require (invalid_text_detected, "malformed matrix text was accepted"); } void test_container_reallocation () { std::vector values; for (int index = 0; index < 1000; ++index) { auto value = Matrix::NativeScalar::with_precision (333); mpfr_set_si (value.mpfr_data (), index, MPFR_RNDN); values.push_back (std::move (value)); } for (int index = 0; index < 1000; ++index) { require (values[static_cast (index)].precision () == 333, "container reallocation changed element precision"); require (mpfr_cmp_si ( values[static_cast (index)].mpfr_data (), index) == 0, "container reallocation changed element value"); } } void test_smoke_and_stress () { const std::vector large_values (64 * 64, 0.125); Matrix large (64, 64, 512, large_values); Matrix large_copy (large); require (large_copy.data () != large.data (), "64x64 copy shares its data buffer"); require (large_copy.all_elements_have_uniform_precision (), "64x64 copy lost uniform precision"); for (std::size_t iteration = 0; iteration < 1000; ++iteration) { const std::size_t rows = iteration % 7; const std::size_t columns = (iteration * 3) % 9; const mpfr_prec_t precision = static_cast (32 + (iteration % 5) * 64); Matrix matrix (rows, columns, precision); require (matrix.rows () == rows && matrix.columns () == columns, "lifecycle stress changed shape"); require (matrix.all_elements_have_uniform_precision (), "lifecycle stress lost uniform precision"); } } } // namespace int main () { try { test_layout_and_precision (); test_copy_move_and_work_buffer (); test_empty_and_dimension_checks (); test_precision_matrix (); test_transactional_error_cleanup (); test_container_reallocation (); test_smoke_and_stress (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: native matrix column-major/REAL* compatibility, " "uniform precision, deep copy, empty shapes, and 1000-matrix stress\n"; return 0; } mplapack-interop-0.5.1/test/mp_det_inv_test.cc0000644000230300031750000002202315274353472020713 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_det_inv.h" #include #include #include #include #include namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrComplexScalarStorage; using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrScalarStorage; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } MpfrMatrixStorage real_matrix (std::size_t rows, std::size_t columns, mpfr_prec_t precision, std::initializer_list values) { return MpfrMatrixStorage (rows, columns, precision, std::vector (values.begin (), values.end ())); } MpfrComplexMatrixStorage complex_matrix (std::size_t rows, std::size_t columns, mpfr_prec_t precision, std::initializer_list values) { return MpfrComplexMatrixStorage (rows, columns, precision, std::vector (values.begin (), values.end ())); } void check_real_close (const Real& value, const Real& expected, mpfr_prec_t precision, const char *message) { Real difference = Real::with_precision (precision); Real tolerance = Real::with_precision (precision); mpfr_sub (difference.mpfr_data (), value.mpfr_data (), expected.mpfr_data (), MPFR_RNDN); mpfr_abs (difference.mpfr_data (), difference.mpfr_data (), MPFR_RNDN); mpfr_set_ui_2exp (tolerance.mpfr_data (), 1, -static_cast (precision / 2), MPFR_RNDN); check (mpfr_cmp (difference.mpfr_data (), tolerance.mpfr_data ()) < 0, message); } void check_complex_close (const MpfrComplexScalarStorage::NativeScalar& value, const MpfrComplexScalarStorage::NativeScalar& expected, mpfr_prec_t precision, const char *message) { auto difference = MpfrComplexScalarStorage::NativeScalar::with_precision ( precision); auto magnitude = Real::with_precision (precision); auto tolerance = Real::with_precision (precision); mpc_sub (difference.mpc_data (), value.mpc_data (), expected.mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); mpc_abs (magnitude.mpfr_data (), difference.mpc_data (), MPFR_RNDN); mpfr_set_ui_2exp (tolerance.mpfr_data (), 1, -static_cast (precision / 2), MPFR_RNDN); check (mpfr_cmp (magnitude.mpfr_data (), tolerance.mpfr_data ()) < 0, message); } void check_real_matrix_close (const MpfrMatrixStorage& value, const MpfrMatrixStorage& expected, const char *message) { check (value.rows () == expected.rows () && value.columns () == expected.columns (), message); for (std::size_t index = 0; index < value.numel (); ++index) check_real_close (value.data ()[index], expected.data ()[index], value.precision_bits (), message); } void check_complex_matrix_close (const MpfrComplexMatrixStorage& value, const MpfrComplexMatrixStorage& expected, const char *message) { check (value.rows () == expected.rows () && value.columns () == expected.columns (), message); for (std::size_t index = 0; index < value.numel (); ++index) check_complex_close (value.data ()[index], expected.data ()[index], value.precision_bits (), message); } void test_real_det_and_inverse () { const auto input = real_matrix (2, 2, 256, {"1", "3", "2", "4"}); const auto before = input; const auto determinant = octave_mplapack::mplapack_mpfr_matrix_det (input); auto expected_determinant = Real::with_precision (256); mpfr_set_si (expected_determinant.mpfr_data (), -2, MPFR_RNDN); check_real_close (determinant.native_value (), expected_determinant, 256, "real determinant pivot sign mismatch"); const auto inverse = octave_mplapack::mplapack_mpfr_matrix_inverse (input); const auto expected = real_matrix (2, 2, 256, {"-2", "1.5", "1", "-0.5"}); check_real_matrix_close (inverse, expected, "real inverse values mismatch"); for (std::size_t index = 0; index < input.numel (); ++index) check (mpfr_equal_p (input.data ()[index].mpfr_data (), before.data ()[index].mpfr_data ()) != 0, "real det/inv modified public input"); } void test_complex_det_and_inverse () { const auto input = complex_matrix (2, 2, 256, {"(1,1)", "(3,0)", "(2,0)", "(4,-1)"}); const auto determinant = octave_mplapack::mplapack_mpc_matrix_det (input); auto expected_det = MpfrComplexScalarStorage::NativeScalar::with_precision (256); expected_det.set_str ("(-1,3)", 10); check_complex_close (determinant.native_value (), expected_det, 256, "complex determinant mismatch"); const auto inverse = octave_mplapack::mplapack_mpc_matrix_inverse (input); const auto expected = complex_matrix (2, 2, 256, {"(-0.7,-1.1)", "(0.3,0.9)", "(0.2,0.6)", "(0.2,-0.4)"}); check_complex_matrix_close (inverse, expected, "complex inverse values mismatch"); } void test_singular_shapes_and_empty () { const auto singular = real_matrix (2, 2, 256, {"1", "2", "2", "4"}); const auto determinant = octave_mplapack::mplapack_mpfr_matrix_det (singular); check (determinant.is_zero (), "singular determinant is not exact zero"); bool caught = false; try { (void) octave_mplapack::mplapack_mpfr_matrix_inverse (singular); } catch (const octave_mplapack::MpfrDetInvError& exception) { caught = exception.kind () == octave_mplapack::MpfrDetInvError::Kind::singular; } check (caught, "singular real inverse did not report singularity"); const auto complex_singular = complex_matrix (2, 2, 256, {"(1,0)", "(2,0)", "(2,0)", "(4,0)"}); const auto complex_determinant = octave_mplapack::mplapack_mpc_matrix_det (complex_singular); check (complex_determinant.is_zero (), "singular complex determinant is not exact zero"); caught = false; try { (void) octave_mplapack::mplapack_mpc_matrix_inverse (complex_singular); } catch (const octave_mplapack::MpcDetInvError& exception) { caught = exception.kind () == octave_mplapack::MpcDetInvError::Kind::singular; } check (caught, "singular complex inverse did not report singularity"); const auto empty = real_matrix (0, 3, 256, {}); bool non_square_caught = false; try { (void) octave_mplapack::mplapack_mpfr_matrix_det (empty); } catch (const std::invalid_argument&) { non_square_caught = true; } check (non_square_caught, "non-square determinant was accepted"); const auto empty_square = real_matrix (0, 0, 256, {}); const auto empty_det = octave_mplapack::mplapack_mpfr_matrix_det (empty_square); check (empty_det.exactly_equal_string ("1"), "empty determinant is not one"); const auto empty_inverse = octave_mplapack::mplapack_mpfr_matrix_inverse (empty_square); check (empty_inverse.rows () == 0 && empty_inverse.columns () == 0, "empty inverse shape mismatch"); } void test_precision_and_scope () { mpfrxx::set_default_precision_bits (128); for (const auto setting : {std::pair (1024, -700), std::pair (2048, -1500)}) { const mpfr_prec_t precision = setting.first; auto input = real_matrix (2, 2, precision, {"0", "0", "0", "1"}); mpfr_set_ui_2exp (input.at (0, 0).mpfr_data (), 1, setting.second, MPFR_RNDN); const auto determinant = octave_mplapack::mplapack_mpfr_matrix_det (input); check (mpfr_equal_p (determinant.native_value ().mpfr_data (), input.at (0, 0).mpfr_data ()) != 0, "high-precision determinant tail mismatch"); const auto inverse = octave_mplapack::mplapack_mpfr_matrix_inverse (input); auto expected = Real::with_precision (precision); mpfr_set_ui_2exp (expected.mpfr_data (), 1, -setting.second, MPFR_RNDN); check_real_close (inverse.at (0, 0), expected, precision, "high-precision inverse tail mismatch"); check (inverse.precision_bits () == precision && mpfrxx::default_precision_bits () == 128, "inverse precision or ambient precision mismatch"); } } } // namespace int main () { try { test_real_det_and_inverse (); test_complex_det_and_inverse (); test_singular_shapes_and_empty (); test_precision_and_scope (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: MPLAPACK MPFR/MPC determinant and inverse tests\n"; return 0; } mplapack-interop-0.5.1/test/norm.tst0000644000230300031750000000676015274353472016742 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_fails (thunk, label) %! did_fail = false; %! try %! thunk (); %! catch %! did_fail = true; %! end_try_catch %! assert (did_fail, label); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! v = mp ([3; 4]); %! assert (double (norm (v)), 5, 1e-12); %! assert (double (norm (v, 1)), 7, 1e-12); %! assert (double (norm (v, 2)), 5, 1e-12); %! assert (double (norm (v, Inf)), 4, 1e-12); %! assert (double (norm (v, -Inf)), 3, 1e-12); %! assert (double (norm (v, "fro")), 5, 1e-12); %! assert (double (norm (v, 0)), 2, 1e-12); %! assert (double (norm (mp ([1; 2]), 3)), 9^(1 / 3), 1e-12); %! scalar = mp ("-3.5"); %! assert (double (norm (scalar)), 3.5, 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([3, 0; 0, 4]); %! before = double (A); %! assert (double (norm (A)), 4, 1e-12); %! assert (double (norm (A, 1)), 4, 1e-12); %! assert (double (norm (A, 2)), 4, 1e-12); %! assert (double (norm (A, Inf)), 4, 1e-12); %! assert (double (norm (A, "fro")), 5, 1e-12); %! assert (double (A), before); %! empty = mp (zeros (0, 3)); %! assert (double (norm (empty)), 0, 1e-12); %! assert (double (norm (empty, 1)), 0, 1e-12); %! assert (double (norm (empty, Inf)), 0, 1e-12); %! assert (double (norm (empty, "fro")), 0, 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! z = mp ([3 + 4i; 0]); %! assert (! isreal (z)); %! assert (double (norm (z)), 5, 1e-12); %! assert (double (norm (z, 1)), 5, 1e-12); %! assert (double (norm (z, 2)), 5, 1e-12); %! assert (double (norm (z, Inf)), 5, 1e-12); %! assert (double (norm (z, -Inf)), 0, 1e-12); %! Z = mp ([3 + 0i, 0 + 0i; 0 + 0i, 4 + 0i]); %! assert (double (norm (Z)), 4, 1e-12); %! assert (double (norm (Z, 1)), 4, 1e-12); %! assert (double (norm (Z, Inf)), 4, 1e-12); %! assert (double (norm (Z, "fro")), 5, 1e-12); %! assert (double (norm (Z, 2)), 4, 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! bits = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (bits); %! value = mp ("1"); %! for k = 1:exponent %! value = value ./ mp ("2"); %! endfor %! mpbits (128); %! result = norm (value); %! info = __mplapack_core__ ("scalar_test_info", result); %! assert (info.precision_bits == bits); %! assert (__mplapack_core__ ("scalar_test_equal", result, value)); %! assert (mpbits () == uint64 (128)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! assert (isinf (double (norm (mp ("Inf"))))); %! assert (isnan (double (norm (mp ("NaN"))))); %! A = mp ([1, 2; 3, 4]); %! assert_fails (@() norm (A, 0), "matrix zero norm must fail"); %! assert_fails (@() norm (A, 3), "matrix finite p norm must fail"); %! assert_fails (@() norm (A, -1), "negative finite p norm must fail"); %! assert_fails (@() norm (A, "rows"), "row norm option must fail"); %! assert_fails (@() norm (A, NaN), "NaN norm option must fail"); %! assert_fails (@() norm (A, "cols"), "column norm option must fail"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/test_neigt10.m0000644000230300031750000000267015274353472017713 0ustar rafaelrafael% Focused NEIGT10 Grcar/MKS exact model and reference tests. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect g = net_grcar_audit (6, 3, 128, 256); expected = mp (zeros (6, 6)); for i = 1:6 for j = 1:6 if (j >= i && j - i <= 3) expected(i, j) = mp (1); elseif (i - j == 1) expected(i, j) = mp (-1); endif endfor endfor assert (g.model.A_model == expected); assert (g.reference.agreement.threshold < net_pow2 (-100, 320)); assert (g.metrics.right_residual < net_pow2 (-100, 320)); delta = net_pow2 (-3, 256); m = net_mks_audit (6, 3, delta, 256, 256); assert (m.model.ell == 2); assert (m.model.zero_algebraic_multiplicity == 4); assert (m.model.zero_geometric_multiplicity == 2); expected_q = mp (zeros (1, 3)); expected_q(1) = mp (1); expected_q(2) = -mp (3) / mp (4); expected_q(3) = -mp (3) / mp (8); assert (m.model.q_coefficients == expected_q); assert (all (m.determinant_checks)); assert (m.nonzero_simple_guard); assert (m.reference.nonzero_agreement.threshold < net_pow2 (-160, 320)); assert (m.metrics.absolute_match.threshold < net_pow2 (-100, 320)); fprintf ("PASS: NEIGT10 Grcar references and MKS zero/nonzero audit\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/eig_structured.tst0000644000230300031750000001221415274353472021006 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_rejected (thunk, label) %! rejected = false; %! try %! thunk (); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, label); %!endfunction %!function assert_residual (A, V, D, tolerance, label) %! residual = double (norm (A * V - V * D, "fro")); %! assert (residual < tolerance, label); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([2, 1; 1, 2]); %! values = eig (A); %! [V, D] = eig (A); %! [Vv, d] = eig (A, "vector"); %! [Vm, Dm] = eig (A, "matrix"); %! assert (isa (values, "mp") && isa (V, "mp") && isa (D, "mp")); %! assert (size (values), [2, 1]); %! assert (size (V), [2, 2]); %! assert (size (D), [2, 2]); %! assert (size (Vv), [2, 2]); %! assert (size (d), [2, 1]); %! assert (size (Vm), [2, 2]); %! assert (size (Dm), [2, 2]); %! assert (__mplapack_core__ ("value_is_real", values)); %! assert (__mplapack_core__ ("value_is_real", V)); %! assert (__mplapack_core__ ("value_is_real", D)); %! assert_residual (A, V, D, 1e-12, "real symmetric eig residual"); %! assert_residual (A, Vv, D, 1e-12, "real vector eig residual"); %! assert_residual (A, Vm, Dm, 1e-12, "real matrix eig residual"); %! assert (double (transpose (V) * V), eye (2), 1e-12); %! assert (double (transpose (Vv) * Vv), eye (2), 1e-12); %! assert (double (d (1)), 1, 1e-12); %! assert (double (d (2)), 3, 1e-12); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", A, 1, 2, 1)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! H = mp ([2, 1 + 1i; 1 - 1i, 3]); %! [V, D] = eig (H); %! [Vv, d] = eig (H, "vector"); %! assert (__mplapack_core__ ("value_is_real", D)); %! assert (__mplapack_core__ ("value_is_real", d)); %! assert (! __mplapack_core__ ("value_is_real", V)); %! assert (! __mplapack_core__ ("value_is_real", Vv)); %! assert_residual (H, V, D, 1e-12, "complex Hermitian eig residual"); %! assert_residual (H, Vv, D, 1e-12, "complex Hermitian vector residual"); %! assert (double (ctranspose (V) * V), eye (2), 1e-12); %! assert (size (d), [2, 1]); %! assert (double (d (1)) > 0 && double (d (2)) > double (d (1))); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", H, 2, 1, "(1,-1)")); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! [Vg, Dg] = eig (mp ([1, 2; 3, 4])); %! assert_residual (mp ([1, 2; 3, 4]), Vg, Dg, 1e-12, ... %! "nonsymmetric real eig uses the N05 general path"); %! Cg = mp ([1 + 1i, 2; 3, 4]); %! [Vc, Dc] = eig (Cg); %! assert_residual (Cg, Vc, Dc, 1e-12, ... %! "non-Hermitian complex eig uses the N05 general path"); %! Cdiag = mp ([1 + 1i, 0; 0, 2]); %! [Vdiag, Ddiag] = eig (Cdiag); %! assert_residual (Cdiag, Vdiag, Ddiag, 1e-12, ... %! "complex diagonal non-Hermitian eig uses N05"); %! assert_rejected (@() eig (mp ([1, 2, 3])), ... %! "non-square eig must be rejected"); %! assert_rejected (@() eig (mp ([1, 2; 2, 1]), "bad-option"), ... %! "invalid eig option must be rejected"); %! vector_values = eig (mp ([1, 2; 2, 1]), "vector"); %! diagonal_values = eig (mp ([1, 2; 2, 1]), "matrix"); %! assert (diag (double (diagonal_values)), double (vector_values), 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! repeated = mp ([2, 0; 0, 2]); %! [V, D] = eig (repeated); %! assert_residual (repeated, V, D, 1e-12, "repeated eig residual"); %! assert (double (transpose (V) * V), eye (2), 1e-12); %! delta = mp ("1"); %! for k = 1:300 %! delta = delta * mp ("0.5"); %! endfor %! nearly = mp ([1, 0; 0, 1]); %! nearly (1, 2) = delta; %! nearly (2, 1) = delta; %! [Vn, Dn] = eig (nearly); %! assert_residual (nearly, Vn, Dn, 1e-12, "nearly repeated eig residual"); %! assert (double (transpose (Vn) * Vn), eye (2), 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! for precision = [1024, 2048] %! mpbits (precision); %! tiny = mp ("1"); %! half = mp ("0.5"); %! exponent = 1500; %! if (precision == 1024) %! exponent = 700; %! endif %! for k = 1:exponent %! tiny = tiny * half; %! endfor %! A = mp ([1, 0; 0, 3]); %! A (1, 1) = tiny; %! [V, D] = eig (A); %! assert_residual (A, V, D, 1e-12, "high precision eig residual"); %! assert (__mplapack_core__ ("matrix_test_element_equal", D, 1, 1, A, 1, 1)); %! info = __mplapack_core__ ("matrix_test_info", V); %! assert (info.precision_bits == uint64 (precision)); %! endfor %!test %! saved = mpbits (); %! unwind_protect %! mpbits (192); %! A = mp ([2, 1; 1, 2]); %! mpbits (768); %! [V, D] = eig (A); %! info = __mplapack_core__ ("matrix_test_info", V); %! assert (info.precision_bits == uint64 (192)); %! assert_residual (A, V, D, 1e-12, "ambient precision eig residual"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/assignment.tst0000644000230300031750000002031115274353472020123 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function info = assignment_info (value) %! info = __mplapack_core__ ("value_shape_info", value); %!endfunction %!function assert_matrix_text (value, expected) %! info = assignment_info (value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! value, row, column, expected{row, column})); %! endfor %! endfor %!endfunction %!function ok = raises_id (callable, identifier) %! ok = false; %! try %! callable (); %! catch exception %! ok = strcmp (exception.identifier, identifier); %! end_try_catch %!endfunction %!function ok = raises_any (callable) %! ok = false; %! try %! callable (); %! catch %! ok = true; %! end_try_catch %!endfunction %!function assign_bad_index (value) %! value (0, 1) = mp ("5"); %!endfunction %!function assign_bad_shape (value) %! value (:, 1) = mp ({"5", "6"; "7", "8"}); %!endfunction %!function assign_growth (value) %! value (3, 1) = mp ("5"); %!endfunction %!function assign_delete (value) %! value (1, 1) = []; %!endfunction %!function result = assign_linear_vector (value) %! value ([1, 2]) = mp ([5, 6]); %! result = value; %!endfunction %!function assign_complex (value) %! value (1, 1) = 1 + 2i; %!endfunction %!function assign_sparse (value) %! value (1, 1) = sparse (1); %!endfunction %!function assign_nd (value) %! value (1, 1) = ones (1, 1, 2); %!endfunction %!test %! A = mp ({"11", "12", "13"; "21", "22", "23"; ... %! "31", "32", "33"}); %! B = A; %! B(2, 3) = mp ("99"); %! assert_matrix_text (A, {"11", "12", "13"; "21", "22", "23"; ... %! "31", "32", "33"}); %! assert_matrix_text (B, {"11", "12", "13"; "21", "22", "99"; ... %! "31", "32", "33"}); %! C = A; %! C(:, 2) = mp ({"7"; "8"; "9"}); %! assert_matrix_text (C, {"11", "7", "13"; "21", "8", "23"; ... %! "31", "9", "33"}); %! D = A; %! D(2, :) = [6, 7, 8]; %! assert_matrix_text (D, {"11", "12", "13"; "6", "7", "8"; ... %! "31", "32", "33"}); %! E = A; %! E(1:2, 2:3) = mp ({"41", "42"; "51", "52"}); %! assert_matrix_text (E, {"11", "41", "42"; "21", "51", "52"; ... %! "31", "32", "33"}); %! F = A; %! F([3, 1], [3, 1]) = mp ({"61", "62"; "71", "72"}); %! assert_matrix_text (F, {"72", "12", "71"; "21", "22", "23"; ... %! "62", "32", "61"}); %!test %! A = mp ({"11", "12"; "21", "22"}); %! A(1) = mp ("31"); %! A(4) = 0.125; %! assert_matrix_text (A, {"31", "12"; "21", "0.125"}); %! A(:) = mp ({"1", "2"; "3", "4"}); %! assert_matrix_text (A, {"1", "2"; "3", "4"}); %! A(:) = [5, 6, 7, 8]; %! assert_matrix_text (A, {"5", "7"; "6", "8"}); %! A(:, []) = 99; %! assert_matrix_text (A, {"5", "7"; "6", "8"}); %!test %! x = mp ("1"); %! x(1, 1) = mp ("2"); %! assert (! __mplapack_core__ ("value_is_matrix", x)); %! assert (char (x), "2e+0"); %! x(1) = 0.125; %! assert (char (x), "1.25e-1"); %! x(:) = mp ("3"); %! assert (char (x), "3e+0"); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2"; "3", "4"}); %! mpbits (1024); %! tail = strcat ("1.", repmat ("0", 1, 210), "1"); %! high = mp (tail); %! mpbits (128); %! no_op = A; %! no_op(:, []) = high; %! assert (assignment_info (no_op).precision_bits, uint64 (256)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! no_op, 1, 1, "1")); %! A(1, 1) = high; %! info = assignment_info (A); %! assert (info.precision_bits, uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! A, 1, 1, tail)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! A, 2, 2, "4")); %! assert (mpbits (), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! A(2, 2) = mp ("5"); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! A, 1, 1, tail)); %! assert (assignment_info (A).precision_bits, uint64 (1024)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2048); %! tail = strcat ("1.", repmat ("0", 1, 450), "1"); %! A = mp ({tail, "2"; "3", "4"}); %! mpbits (2048); %! rhs = mp (tail); %! mpbits (128); %! A(2, 2) = rhs; %! assert (assignment_info (A).precision_bits, uint64 (2048)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! A, 1, 1, tail)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! A, 2, 2, tail)); %! assert (mpbits (), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2"; "3", "4"}); %! mpbits (4096); %! A(1, 1) = 0.1; %! assert (assignment_info (A).precision_bits, uint64 (256)); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! A, 1, 1, 0.1)); %! A(2, 2) = -0.0; %! zero = __mplapack_core__ ("scalar_test_info", A(2, 2)); %! assert (zero.is_zero && zero.signbit); %! A(1, 2) = Inf; %! A(2, 1) = NaN; %! assert (__mplapack_core__ ("scalar_test_info", A(1, 2)).is_infinite); %! assert (__mplapack_core__ ("scalar_test_info", A(2, 1)).is_nan); %! assert (mpbits (), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({"11", "12"; "21", "22"}); %! A(end, 1) = mp ("31"); %! A(1, end) = mp ("32"); %! A(:, end) = mp ({"42"; "43"}); %! A(end, :) = [51, 52]; %! assert_matrix_text (A, {"11", "42"; "51", "52"}); %! A(1:2, 1:2) = A([2, 1], [2, 1]); %! assert_matrix_text (A, {"52", "51"; "42", "11"}); %! R = mp ({"1", "2"; "3", "4"}); %! R([1, 1], 2) = [5; 6]; %! assert_matrix_text (R, {"1", "6"; "3", "4"}); %! R(1, [1, 1]) = [7, 8]; %! assert_matrix_text (R, {"8", "6"; "3", "4"}); %!test %! A = mp ({"1", "2"; "3", "4"}); %! assert (raises_any (@() assign_bad_index (A))); %! assert (raises_id (@() assign_bad_shape (A), ... %! "mplapack:mp:DimensionMismatch")); %! assert (raises_id (@() assign_growth (A), ... %! "mplapack:mp:IndexOutOfBounds")); %! assert (raises_id (@() assign_delete (A), ... %! "mplapack:mp:DeletionUnsupported")); %! assigned = assign_linear_vector (A); %! assert_matrix_text (assigned, {"5", "2"; "6", "4"}); %!test %! A = mp ({"1", "2"; "3", "4"}); %! B = A; %! B(:, 1) = A(:, 2); %! assert_matrix_text (A, {"1", "2"; "3", "4"}); %! assert_matrix_text (B, {"2", "2"; "4", "4"}); %! C = [A, B]; %! C(1, 1) = mp ("9"); %! assert_matrix_text (A, {"1", "2"; "3", "4"}); %! assert_matrix_text (C, {"9", "2", "2", "2"; ... %! "3", "4", "4", "4"}); %! S = C(:, 1); %! clear C; %! assert (char (S(1)), "9e+0"); %! T = S + mp ("1"); %! assert (char (T(1)), "1e+1"); %!test %! A = mp ({"1", "2"; "3", "4"}); %! before = double (A); %! A(1, 1) = 1 + 2i; %! assert (__mplapack_core__ ("matrix_test_info", A).is_complex); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! A, 1, 1, 1 + 2i)); %! assert (double (A(:, 2)), before(:, 2)); %! B = mp ({"1", "2"; "3", "4"}); %! bad = {@() assign_sparse (B), ... %! @() assign_nd (B)}; %! for k = 1:numel (bad) %! try %! bad{k} (); %! error ("unsupported assignment unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, ... %! "unsupported assignment unexpectedly succeeded")); %! end_try_catch %! endfor %!test %! A = mp ({"1", "2"; "3", "4"}); %! A(1, 1) = mp ("9"); %! B = A.'; %! C = reshape (A, 1, 4); %! D = [A, A]; %! assert (char (B(1, 1)), "9e+0"); %! assert (char (C(1)), "9e+0"); %! assert (char (D(1, 1)), "9e+0"); %! X = A * mp ({"1"; "0"}); %! assert (char (X(1)), "9e+0"); %! Y = A \ mp ({"13"; "11"}); %! assert (char (Y(1)), "1e+0"); %!error mp (1){1} = mp (2) mplapack-interop-0.5.1/test/pivoted_qr.tst0000644000230300031750000001422115274353472020132 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_pivot_reconstruction (A, Q, R, P, p, tolerance) %! if (nargin < 6) %! tolerance = 1e-10; %! endif %! lhs = double (Q * R); %! if (! isempty (P)) %! rhs = double (A * P); %! else %! rhs = double (A(:, p)); %! endif %! assert (lhs, rhs, tolerance); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1 0 0; 0 4 0; 0 0 2]); %! [Q, R, P] = qr (A); %! [Qv, Rv, p] = qr (A, "vector"); %! assert (strcmp (class (P), "double")); %! assert (strcmp (class (p), "double")); %! assert (size (P), [3 3]); %! assert (size (p), [1 3]); %! assert (P, [0 0 1; 1 0 0; 0 1 0]); %! assert (p, [2 3 1]); %! assert_pivot_reconstruction (A, Q, R, P, [], 1e-12); %! assert_pivot_reconstruction (A, Qv, Rv, [], p, 1e-12); %! assert (double (Q.' * Q), eye (3), 1e-12); %! assert (double (Qv.' * Qv), eye (3), 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (256); %! A = mp ([1 20 3; 4 5 16; 7 8 9; 10 11 12]); %! [Q, R, P] = qr (A); %! [Qe, Re, Pe] = qr (A, "econ"); %! [Q0, R0, p0] = qr (A, 0); %! [Qv, Rv, p] = qr (A, "vector"); %! assert (size (Q), [4 4]); %! assert (size (R), [4 3]); %! assert (size (P), [3 3]); %! assert (size (Qe), [4 3]); %! assert (size (Re), [3 3]); %! assert (size (Pe), [3 3]); %! assert (size (Q0), [4 3]); %! assert (size (R0), [3 3]); %! assert (size (p0), [1 3]); %! assert (size (p), [1 3]); %! assert_pivot_reconstruction (A, Q, R, P, [], 1e-10); %! assert_pivot_reconstruction (A, Qe, Re, Pe, [], 1e-10); %! assert_pivot_reconstruction (A, Q0, R0, [], p0, 1e-10); %! assert_pivot_reconstruction (A, Qv, Rv, [], p, 1e-10); %! assert (P, Pe); %! assert (p, p0); %! assert (sort (p), 1:3); %! assert (double (Q.' * Q), eye (4), 1e-10); %! assert (double (Qe.' * Qe), eye (3), 1e-10); %! mpbits (512); %!test %! mpbits (256); %! A = mp ([1 0 0; 0 4 0; 0 0 2]); %! [Qn, Rn] = qr (A); %! [Qp, Rp, P] = qr (A); %! assert (double (Qn * Rn), double (A), 1e-12); %! assert (double (Qp * Rp), double (A * P), 1e-12); %! assert (! isequal (P, eye (3))); %! mpbits (512); %!test %! mpbits (256); %! wide = mp ([1 0 0 4; 0 2 0 0]); %! [Q, R, P] = qr (wide); %! [Qe, Re, Pe] = qr (wide, "econ"); %! [Qv, Rv, p] = qr (wide, "vector"); %! assert (size (Q), [2 2]); %! assert (size (R), [2 4]); %! assert (size (Qe), [2 2]); %! assert (size (Re), [2 4]); %! assert (size (P), [4 4]); %! assert (size (p), [1 4]); %! assert_pivot_reconstruction (wide, Q, R, P, [], 1e-12); %! assert_pivot_reconstruction (wide, Qe, Re, Pe, [], 1e-12); %! assert_pivot_reconstruction (wide, Qv, Rv, [], p, 1e-12); %! assert (sort (p), 1:4); %! mpbits (512); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! tail = strcat ("1.", repmat ("0", 1, 210), "1"); %! A512 = mp ({"1", tail}); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! A512, 1, 2, "1")); %! [Q512, R512, p512] = qr (A512, "vector"); %! mpbits (1024); %! A1024 = mp ({"1", tail}); %! assert (! __mplapack_core__ ("matrix_test_element_equal_text", ... %! A1024, 1, 2, "1")); %! [Q1024, R1024, p1024] = qr (A1024, "vector"); %! assert (p512, [1 2]); %! assert (p1024, [2 1]); %! assert (__mplapack_core__ ("scalar_test_info", Q512).precision_bits, ... %! int64 (512)); %! assert (__mplapack_core__ ("matrix_test_info", R1024).precision_bits, ... %! uint64 (1024)); %! assert (double (Q512 * R512), double (A512(:,p512)), 1e-12); %! assert (double (Q1024 * R1024), double (A1024(:,p1024)), 1e-12); %! mpbits (4096); %! [Qh, Rh, ph] = qr (A1024, "vector"); %! assert (ph, [2 1]); %! assert (__mplapack_core__ ("scalar_test_info", Qh).precision_bits, ... %! int64 (1024)); %! assert (__mplapack_core__ ("matrix_test_info", Rh).precision_bits, ... %! uint64 (1024)); %! assert (mpbits (), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (256); %! A = mp ([1 2; 3 4]); %! before = double (A); %! [Q, R, P] = qr (A); %! [Qv, Rv, p] = qr (A, "vector"); %! assert (double (A), before); %! B = A; %! [QB, RB, PB] = qr (B); %! clear A B; %! assert (__mplapack_core__ ("matrix_test_element_double", Q, 1, 1) != 0); %! assert (__mplapack_core__ ("matrix_test_element_double", R, 1, 1) != 0); %! assert (PB, P); %! assert (sort (p), 1:2); %! mpbits (512); %!test %! mpbits (256); %! A = mp ([1 2 3; 2 4 6; 3 6 9]); %! [Q, R, P] = qr (A); %! [Qv, Rv, p] = qr (A, "vector"); %! assert (sort (p), 1:3); %! assert (sum (P, 1), ones (1, 3)); %! assert (sum (P, 2), ones (3, 1)); %! assert (double (Q * R), double (A * P), 1e-10); %! assert (double (Qv * Rv), double (A(:, p)), 1e-10); %! mpbits (512); %!test %! mpbits (256); %! for x = [4, -4, 0] %! [Q, R, P] = qr (mp (x)); %! [Qv, Rv, p] = qr (mp (x), "vector"); %! assert (size (Q), [1 1]); %! assert (size (R), [1 1]); %! assert (P, 1); %! assert (p, 1); %! assert (double (Q * R), double (mp (x)) * P, 1e-12); %! assert (double (Qv * Rv), double (mp (x))(:,p), 1e-12); %! endfor %! mpbits (512); %!test %! mpbits (256); %! for shape_cell = {[0, 0], [0, 3], [3, 0]} %! shape = shape_cell{1}; %! A = mp (zeros (shape(1), shape(2))); %! [Q, R, P] = qr (A); %! [Qv, Rv, p] = qr (A, "vector"); %! [Qe, Re, Pe] = qr (A, "econ"); %! [Q0, R0, p0] = qr (A, 0); %! assert (size (P), [shape(2), shape(2)]); %! assert (size (p), [1, shape(2)]); %! assert (size (Pe), [shape(2), shape(2)]); %! assert (size (p0), [1, shape(2)]); %! assert (size (Q), [shape(1), shape(1)]); %! assert (size (R), [shape(1), shape(2)]); %! assert (size (Qv), size (Q)); %! assert (size (Rv), size (R)); %! if (shape(1) > shape(2)) %! assert (size (Qe), [shape(1), shape(2)]); %! assert (size (Re), [shape(2), shape(2)]); %! else %! assert (size (Qe), [shape(1), shape(1)]); %! assert (size (Re), [shape(1), shape(2)]); %! endif %! assert (size (Q0), size (Qe)); %! assert (size (R0), size (Re)); %! endfor %! mpbits (512); %!error qr (mp ([1 2]), "foo") %!error [a,b,c,d] = qr (mp ([1 2])) mplapack-interop-0.5.1/test/t01_dense_utilities.tst0000644000230300031750000000470115274353472021635 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({'1','2';'3','4'}); %! X = pinv (A); %! I = eye (2, "like", A); %! assert (double (norm (A*X-I, "fro")) < 1e-50); %! assert (double (norm (X*A-I, "fro")) < 1e-50); %! assert (double (norm (A*X*A-A, "fro")) < 1e-50); %! assert (double (norm (X*A*X-X, "fro")) < 1e-50); %! Xe = pinv (A, mp ('1e-100')); %! assert (double (norm (Xe-X, "fro")) < 1e-50); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({'1','2','3';'2','4','6'}); %! Z = null (A); %! assert (size (Z) == [3, 2]); %! assert (double (norm (A*Z, "fro")) < 1e-50); %! assert (double (norm (Z'*Z-eye (2, "like", Z), "fro")) < 1e-50); %! O = orth (A); %! assert (size (O) == [2, 1]); %! assert (double (norm (O'*O-eye (1, "like", O), "fro")) < 1e-50); %! assert (double (norm (O*O'*A-A, "fro")) < 1e-50); %! Ztol = null (A, mp ('1e-10')); %! assert (size (Ztol) == [3, 2]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({'1','2','3';'2','4','6'}); %! [R,k] = rref (A); %! assert (k == 1); %! assert (double (norm (R-mp ({'1','2','3';'0','0','0'}), "fro")) < 1e-50); %! [Rt,kt] = rref (A, mp ('1e-10')); %! assert (kt == 1); %! assert (double (norm (Rt-R, "fro")) < 1e-50); %! K = kron (mp ([1,2]), mp ([3;4])); %! assert (size (K) == [2, 2]); %! assert (double (K(1,1)) == 3 && double (K(2,2)) == 8); %! C = [mp('1','2'),mp('2','-1')]; %! Kc = kron (C, mp ([1;2])); %! assert (! isreal (Kc)); %! assert (double (real (Kc(1,1))) == 1); %! assert (double (imag (Kc(1,1))) == 2); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for bits = [1024, 2048] %! mpbits (bits); %! limit = 1500; %! if (bits == 1024), limit = 700; endif %! tiny = mp ('1'); %! for k = 1:limit, tiny = tiny * mp ('0.5'); endfor %! A = mp ({'1','1';'1','1'}); %! A(2,2) = mp (1) + tiny; %! [R,k] = rref (A); %! assert (k == [1,2]); %! assert (double (norm (R-eye (2, "like", R), "fro")) < 1e-12); %! assert (__mplapack_core__ ("matrix_test_info", R).precision_bits == uint64 (bits)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/m22_dependency_probe.cc0000644000230300031750000000267115274353472021524 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include int main () { const mpfr_prec_t saved = mpfrxx::default_precision_bits (); try { mpfrxx::set_default_precision_bits (128); if (mpfrxx::default_precision_bits () != 128) throw std::runtime_error ("unable to set MPFR default precision"); { MplapackMpfrPrecisionScope scope (256); if (mpfrxx::default_precision_bits () != 256) throw std::runtime_error ("precision scope did not establish 256 bits"); } { auto operand = mpfrxx::mpc_class::with_precision (128, 1.0, 0.5); const auto result = mpfrxx::log2 (operand); if (result.real_precision () != 128 || result.imag_precision () != 128) throw std::runtime_error ("gmpfrxx MPC log2 result has wrong precision"); } if (mpfrxx::default_precision_bits () != 128) throw std::runtime_error ("precision scope did not restore 128 bits"); mpfrxx::set_default_precision_bits (saved); std::cout << "PASS: MPLAPACK MPFR uniform-precision interface probe\n"; return 0; } catch (const std::exception& error) { mpfrxx::set_default_precision_bits (saved); std::cerr << "FAIL: incompatible MPLAPACK MPFR uniform-precision " "calling-contract interface: " << error.what () << "\n"; return 1; } } mplapack-interop-0.5.1/test/test_neigt22.m0000644000230300031750000000415115274353472017712 0ustar rafaelrafael% NEIGT22: full ordinary and verification-tier integration per profile. test_root = fileparts (fileparts (mfilename ("fullpath"))); example_root = fullfile (test_root, "examples", "neig_tiers"); private_root = fullfile (example_root, "private"); addpath (example_root); addpath (private_root); saved_bits = mpbits (); unwind_protect smoke_ordinary = mp_neig_tiers ("smoke", struct ("tier", "all")); assert (strcmp (smoke_ordinary.status, "NUMERICS_ONLY_COMPLETE")); assert (smoke_ordinary.coverage.measured_eig_rows == 120); assert (smoke_ordinary.coverage.expected_all_measured_eig_rows == 120); assert (smoke_ordinary.coverage.numerics_only_complete); clear smoke_ordinary; demo_ordinary = mp_neig_tiers ("demo", struct ("tier", "all")); assert (strcmp (demo_ordinary.status, "NUMERICS_ONLY_COMPLETE")); assert (demo_ordinary.coverage.measured_eig_rows == 168); assert (demo_ordinary.coverage.expected_all_measured_eig_rows == 168); assert (demo_ordinary.coverage.numerics_only_complete); clear demo_ordinary; smoke_verify = mp_neig_verify_examples ("smoke", struct ("tier", "V")); assert (smoke_verify.ok && strcmp (smoke_verify.status, "COMPLETE")); assert (smoke_verify.coverage.verification_job_count == 26); assert (smoke_verify.coverage.verification_jobs_implemented == 26); assert (all ([smoke_verify.jobs.pass])); assert (all ([smoke_verify.jobs.milestone_pass])); clear smoke_verify; demo_verify = mp_neig_verify_examples ("demo", struct ("tier", "V")); assert (demo_verify.ok && strcmp (demo_verify.status, "COMPLETE")); assert (demo_verify.coverage.verification_job_count == 26); assert (demo_verify.coverage.verification_jobs_implemented == 26); assert (all ([demo_verify.jobs.pass])); assert (all ([demo_verify.jobs.milestone_pass])); fprintf ("PASS: NEIGT22 full 120/168 ordinary rows and 26+26 verification jobs\n"); unwind_protect_cleanup mpbits (saved_bits); if (any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif if (any (strcmp (strsplit (path (), pathsep), example_root))) rmpath (example_root); endif end_unwind_protect mplapack-interop-0.5.1/test/test_svd_tiers.m0000644000230300031750000000104715274353472020443 0ustar rafaelrafael## SVT18 integration wall for Tier S/A construction and measured SVD helpers. test_root = fileparts (mfilename ("fullpath")); repo_root = fileparts (test_root); suite_dir = fullfile (repo_root, "examples", "svd_tiers"); private_dir = fullfile (suite_dir, "private"); addpath (suite_dir); addpath (private_dir); assert (mp_svd_tiers_selftest ().ok); assert (svt_construction_selftest ().ok); assert (svt_svd_contract_selftest ().ok); fprintf ("PASS: test_svd_tiers (SVT18 Tier S/A and SVD integration)\n"); rmpath (private_dir); rmpath (suite_dir); mplapack-interop-0.5.1/test/build_probe.tst0000644000230300031750000000130615274353472020244 0ustar rafaelrafael%!test %! info = mplapack_version (); %! required = {"octave", "mplapack", "backend", "mpfr", ... %! "probe_routine", "probe_ok", "probe_value"}; %! assert (isstruct (info)); %! assert (all (isfield (info, required))); %! assert (! isempty (info.octave)); %! assert (! isempty (info.mplapack)); %! assert (strcmp (info.backend, "mpfr")); %! assert (! isempty (info.mpfr)); %! assert (strcmp (info.probe_routine, 'Rlamch_mpfr("E")')); %! assert (info.probe_ok); %! assert (isfinite (info.probe_value)); %! assert (info.probe_value > 0 && info.probe_value < 1); %! expected = getenv ("MPLAPACK_EXPECTED_VERSION"); %! if (! isempty (expected)) %! assert (strcmp (info.mplapack, expected)); %! endif mplapack-interop-0.5.1/test/m19_qr_probe.cc0000644000230300031750000001103215274353472020025 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include namespace { using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } Real at_precision (mpfr_prec_t p) { return Real::with_precision (p); } void set_ui (Real& x, unsigned long v) { mpfr_set_ui (x.mpfr_data (), v, MPFR_RNDN); } void set_power (Real& x, mpfr_exp_t e) { mpfr_set_ui_2exp (x.mpfr_data (), 1, e, MPFR_RNDN); } void run_case (mpfr_prec_t p) { constexpr mplapackint m = 3; constexpr mplapackint n = 3; constexpr mplapackint k = 3; std::vector query_a (m*n, at_precision (p)); std::vector query_tau (k, at_precision (p)); std::vector query_work (1, at_precision (p)); set_ui (query_a[0], 1); set_ui (query_a[4], 4); set_ui (query_a[8], 2); std::vector query_jpvt (n, 0); mplapackint info = 0; { MplapackMpfrPrecisionScope scope (p); Rgeqp3 (m, n, query_a.data (), m, query_jpvt.data (), query_tau.data (), query_work.data (), -1, info); } check (info == 0, "Rgeqp3 query failed"); check (mpfr_integer_p (query_work[0].mpfr_data ()) != 0 && mpfr_sgn (query_work[0].mpfr_data ()) > 0, "Rgeqp3 query workspace invalid"); const mplapackint lwork = static_cast ( mpfr_get_si (query_work[0].mpfr_data (), MPFR_RNDZ)); std::vector a (m*n, at_precision (p)); std::vector tau (k, at_precision (p)); std::vector work (lwork, at_precision (p)); std::vector jpvt (n, 0); set_ui (a[0], 1); set_ui (a[4], 4); set_ui (a[8], 2); { MplapackMpfrPrecisionScope scope (p); Rgeqp3 (m, n, a.data (), m, jpvt.data (), tau.data (), work.data (), lwork, info); } check (info == 0, "Rgeqp3 failed"); check (jpvt[0] == 2 && jpvt[1] == 3 && jpvt[2] == 1, "Rgeqp3 JPVT mapping mismatch"); std::vector q (m*m, at_precision (p)); for (mplapackint col = 0; col < m; ++col) for (mplapackint row = 0; row < m; ++row) if (col < n) mpfr_set (q[row + col*m].mpfr_data (), a[row + col*m].mpfr_data (), MPFR_RNDN); else mpfr_set_zero (q[row + col*m].mpfr_data (), 0); std::vector tau_q (tau); std::vector qquery (1, at_precision (p)); { MplapackMpfrPrecisionScope scope (p); Rorgqr (m, m, k, q.data (), m, tau_q.data (), qquery.data (), -1, info); } check (info == 0, "Rorgqr query failed"); const auto qwork_len = static_cast ( mpfr_get_si (qquery[0].mpfr_data (), MPFR_RNDZ)); std::vector qwork (qwork_len, at_precision (p)); { MplapackMpfrPrecisionScope scope (p); Rorgqr (m, m, k, q.data (), m, tau_q.data (), qwork.data (), qwork_len, info); } check (info == 0, "Rorgqr failed"); } void run_precision_canary () { const mpfr_prec_t p = 1024; const mpfr_exp_t e = -700; std::vector a (2, at_precision (p)); std::vector tau (1, at_precision (p)); std::vector work_query (1, at_precision (p)); set_ui (a[0], 1); set_power (a[1], e); mpfr_add_ui (a[1].mpfr_data (), a[1].mpfr_data (), 1, MPFR_RNDN); std::vector jpvt (2, 0); mplapackint info = 0; { MplapackMpfrPrecisionScope scope (p); Rgeqp3 (1, 2, a.data (), 1, jpvt.data (), tau.data (), work_query.data (), -1, info); } check (info == 0, "Rgeqp3 canary query failed"); const auto lwork = static_cast ( mpfr_get_si (work_query[0].mpfr_data (), MPFR_RNDZ)); std::vector work (lwork, at_precision (p)); a[0] = at_precision (p); set_ui (a[0], 1); set_power (a[1], e); mpfr_add_ui (a[1].mpfr_data (), a[1].mpfr_data (), 1, MPFR_RNDN); jpvt.assign (2, 0); { MplapackMpfrPrecisionScope scope (p); Rgeqp3 (1, 2, a.data (), 1, jpvt.data (), tau.data (), work.data (), lwork, info); } check (info == 0 && jpvt[0] == 2 && jpvt[1] == 1, "Rgeqp3 precision pivot canary failed"); check (mpfrxx::default_precision_bits () == 512, "Rgeqp3 precision probe leaked default"); } } // namespace int main () { try { mpfrxx::set_default_precision_bits (512); run_case (1024); run_case (2048); run_precision_canary (); } catch (const std::exception& e) { std::cerr << "FAIL: " << e.what () << '\n'; return 1; } std::cout << "PASS: installed MPLAPACK MPFR Rgeqp3/JPVT precision probe\n"; return 0; } mplapack-interop-0.5.1/test/mp_lapack_rgels_probe.cc0000644000230300031750000001263515274353472022052 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include namespace { using Real = mpfrxx::mpfr_class; void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } Real real_at (mpfr_prec_t precision) { return Real::with_precision (precision); } void set_power_two (Real& value, long exponent) { mpfr_set_ui_2exp (value.mpfr_data (), 1, exponent, MPFR_RNDN); } mplapackint workspace_size (std::vector& a, mplapackint m, mplapackint n, mplapackint nrhs, std::vector& b, mplapackint lda, mplapackint ldb, mpfr_prec_t precision) { Real query = real_at (precision); mplapackint info = -1; { MplapackMpfrPrecisionScope scope (precision); Rgels ("N", m, n, nrhs, a.data (), lda, b.data (), ldb, &query, -1, info); } require (info == 0 && mpfr_integer_p (query.mpfr_data ()) != 0 && mpfr_sgn (query.mpfr_data ()) > 0, "Rgels workspace query failed"); mpz_t value; mpz_init (value); mpfr_get_z (value, query.mpfr_data (), MPFR_RNDZ); require (mpz_fits_slong_p (value) != 0, "Rgels workspace is too large"); const long result = mpz_get_si (value); mpz_clear (value); require (result > 0, "Rgels workspace is not positive"); return static_cast (result); } void check_tail (const Real& value, unsigned long base, long exponent) { Real expected = real_at (value.precision ()); mpfr_set_ui (expected.mpfr_data (), base, MPFR_RNDN); Real difference = real_at (value.precision ()); mpfr_sub (difference.mpfr_data (), value.mpfr_data (), expected.mpfr_data (), MPFR_RNDN); require (mpfr_zero_p (difference.mpfr_data ()) == 0, "Rgels collapsed a precision-sensitive tail"); require (std::abs (mpfr_get_exp (difference.mpfr_data ()) - static_cast (exponent)) <= 20, "Rgels returned an unexpected precision-sensitive tail"); } void run_case (mpfr_prec_t precision, long exponent) { Real t = real_at (precision); set_power_two (t, exponent); std::vector qr_a (6, real_at (precision)); std::vector qr_b (3, real_at (precision)); for (auto& value : qr_a) mpfr_set_zero (value.mpfr_data (), 0); mpfr_set_ui (qr_a[0].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (qr_a[2].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (qr_a[4].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (qr_a[5].mpfr_data (), 1, MPFR_RNDN); mpfr_set (qr_b[0].mpfr_data (), t.mpfr_data (), MPFR_RNDN); mpfr_set_ui (qr_b[1].mpfr_data (), 1, MPFR_RNDN); mpfr_sub (qr_b[1].mpfr_data (), qr_b[1].mpfr_data (), t.mpfr_data (), MPFR_RNDN); mpfr_set_ui (qr_b[2].mpfr_data (), 4, MPFR_RNDN); auto qr_query_a = qr_a; auto qr_query_b = qr_b; const mplapackint qr_lwork = workspace_size (qr_query_a, 3, 2, 1, qr_query_b, 3, 3, precision); std::vector qr_work (static_cast (qr_lwork), real_at (precision)); mplapackint info = -1; { MplapackMpfrPrecisionScope scope (precision); Rgels ("N", 3, 2, 1, qr_a.data (), 3, qr_b.data (), 3, qr_work.data (), qr_lwork, info); require (mpfrxx::default_precision_bits () == precision, "Rgels changed scoped precision"); } require (info == 0, "overdetermined Rgels solve failed"); check_tail (qr_b[0], 1, exponent); check_tail (qr_b[1], 2, exponent); std::vector lq_a (6, real_at (precision)); std::vector lq_b (3, real_at (precision)); for (auto& value : lq_a) mpfr_set_zero (value.mpfr_data (), 0); mpfr_set_ui (lq_a[0].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (lq_a[3].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (lq_a[4].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (lq_a[5].mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (lq_b[0].mpfr_data (), 3, MPFR_RNDN); Real three_t = real_at (precision); mpfr_mul_ui (three_t.mpfr_data (), t.mpfr_data (), 3, MPFR_RNDN); mpfr_add (lq_b[0].mpfr_data (), lq_b[0].mpfr_data (), three_t.mpfr_data (), MPFR_RNDN); mpfr_set_ui (lq_b[1].mpfr_data (), 3, MPFR_RNDN); mpfr_set_zero (lq_b[2].mpfr_data (), 0); auto lq_query_a = lq_a; auto lq_query_b = lq_b; const mplapackint lq_lwork = workspace_size (lq_query_a, 2, 3, 1, lq_query_b, 2, 3, precision); std::vector lq_work (static_cast (lq_lwork), real_at (precision)); info = -1; { MplapackMpfrPrecisionScope scope (precision); Rgels ("N", 2, 3, 1, lq_a.data (), 2, lq_b.data (), 3, lq_work.data (), lq_lwork, info); require (mpfrxx::default_precision_bits () == precision, "Rgels changed scoped precision"); } require (info == 0, "underdetermined Rgels solve failed"); check_tail (lq_b[0], 1, exponent); check_tail (lq_b[1], 1, exponent); check_tail (lq_b[2], 2, exponent); } } // namespace int main () { try { mpfrxx::set_default_precision_bits (128); run_case (1024, -700); run_case (2048, -1500); require (mpfrxx::default_precision_bits () == 128, "Rgels did not restore outside precision"); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: installed MPLAPACK MPFR Rgels precision probe\n"; return 0; } mplapack-interop-0.5.1/test/complex_cholesky.tst0000644000230300031750000000602315274353472021327 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_complex_matrix_close (value, expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! assert (info.is_complex && info.all_elements_same_precision); %! assert (double (value), expected, 1e-12); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! upper_input = mp ([4 + 9i, 2 + 1i; 777 + 888i, 10 - 7i]); %! upper_before = double (upper_input); %! [R, p] = chol (upper_input, "upper"); %! assert (p, 0); %! assert_complex_matrix_close (R, [2, 1 + 0.5i; 0, 2.958039891549808]); %! assert (double (upper_input), upper_before); %! lower_input = mp ([4 + 9i, 777 + 888i; 2 - 1i, 10 - 7i]); %! [L, p_lower] = chol (lower_input, "lower"); %! assert (p_lower, 0); %! assert_complex_matrix_close (L, [2, 0; 1 - 0.5i, 2.958039891549808]); %! assert (! isreal (R) && ! isreal (L)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! diagonal_imaginary = mp ([4 + 123i, 0 + 0i; 0 + 0i, 9 - 77i]); %! [R, p] = chol (diagonal_imaginary); %! assert (p, 0); %! assert_complex_matrix_close (R, [2, 0; 0, 3]); %! assert (! __mplapack_core__ ("matrix_test_element_equal_double", ... %! R, 1, 1, 2 + 1i)); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! R, 1, 1, 2 + 0i)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! semidefinite = mp ([1 + 7i, 1 + 0i; 1 + 0i, 1 - 8i]); %! [R, p] = chol (semidefinite); %! assert (p, 2); %! assert (size (R), [1, 1]); %! assert (__mplapack_core__ ("scalar_test_info", R).is_complex); %! assert (double (R), 1); %! fail ("chol (semidefinite)", "not positive definite"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! delta = mp ("1", "0"); %! for k = 1:exponent %! delta = delta ./ mp ("2", "0"); %! endfor %! A = mp (complex (ones (2, 2), zeros (2, 2))); %! A(2, 2) = mp ("1", "0") + delta; %! mpbits (128); %! [R, p] = chol (A); %! assert (p, 0); %! assert (__mplapack_core__ ("matrix_test_info", R).precision_bits, ... %! uint64 (precision)); %! assert (__mplapack_core__ ("matrix_test_element_double", R, 2, 2) > 0); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp (complex (ones (2, 1), zeros (2, 1))); %! fail ("chol (A)", "requires a square"); mplapack-interop-0.5.1/test/mp_lapack_cholesky_test.cc0000644000230300031750000001526615274353472022432 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_lapack.h" #include #include #include #include #include #include namespace { using octave_mplapack::MpfrCholeskyResult; using octave_mplapack::MpfrMatrixStorage; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } MpfrMatrixStorage matrix (std::size_t rows, std::size_t columns, mpfr_prec_t precision, std::initializer_list values) { return MpfrMatrixStorage (rows, columns, precision, std::vector (values.begin (), values.end ())); } void check_factor (const MpfrCholeskyResult& result, std::size_t rows, std::size_t columns, const char *message) { check (result.info == 0 && result.factor.rows () == rows && result.factor.columns () == columns, message); check (result.factor.precision_bits () == 1024, "Cholesky result precision mismatch"); } void test_triangle_selection () { const auto upper_input = matrix (2, 2, 1024, {"4", "999", "2", "10"}); const auto upper_before = upper_input; const auto upper = octave_mplapack::mplapack_mpfr_matrix_cholesky (upper_input, false); check_factor (upper, 2, 2, "upper factor metadata mismatch"); check (upper.factor.element_exactly_equal_text (0, 0, "2") && upper.factor.element_exactly_equal_text (0, 1, "1") && upper.factor.element_exactly_equal_text (1, 1, "3") && mpfr_zero_p (upper.factor.at (1, 0).mpfr_data ()) != 0, "upper factor values mismatch"); check (upper_input.element_exactly_equal (0, 0, upper_before, 0, 0) && upper_input.element_exactly_equal (1, 1, upper_before, 1, 1), "upper Cholesky modified input"); const auto lower_input = matrix (2, 2, 1024, {"4", "2", "999", "10"}); const auto lower = octave_mplapack::mplapack_mpfr_matrix_cholesky (lower_input, true); check_factor (lower, 2, 2, "lower factor metadata mismatch"); check (lower.factor.element_exactly_equal_text (0, 0, "2") && lower.factor.element_exactly_equal_text (1, 0, "1") && lower.factor.element_exactly_equal_text (1, 1, "3") && mpfr_zero_p (lower.factor.at (0, 1).mpfr_data ()) != 0, "lower factor values mismatch"); } void test_precision_and_empty () { mpfrxx::set_default_precision_bits (128); for (const auto case_data : {std::pair (1024, -700), std::pair (2048, -1500)}) { const mpfr_prec_t precision = case_data.first; auto input = MpfrMatrixStorage (2, 2, precision); mpfr_set_ui (input.at (0, 0).mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (input.at (1, 0).mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (input.at (0, 1).mpfr_data (), 1, MPFR_RNDN); Real delta = Real::with_precision (precision); mpfr_set_ui_2exp (delta.mpfr_data (), 1, case_data.second, MPFR_RNDN); mpfr_add (input.at (1, 1).mpfr_data (), delta.mpfr_data (), input.at (0, 0).mpfr_data (), MPFR_RNDN); const auto result = octave_mplapack::mplapack_mpfr_matrix_cholesky (input, false); check (result.info == 0 && result.factor.precision_bits () == precision, "precision Cholesky metadata mismatch"); Real expected = Real::with_precision (precision); mpfr_set_ui_2exp (expected.mpfr_data (), 1, case_data.second / 2, MPFR_RNDN); check (mpfr_equal_p (result.factor.at (1, 1).mpfr_data (), expected.mpfr_data ()) != 0, "precision Cholesky tail mismatch"); check (mpfrxx::default_precision_bits () == 128, "Cholesky leaked ambient precision"); } const auto empty = MpfrMatrixStorage (0, 0, 2048); const auto empty_result = octave_mplapack::mplapack_mpfr_matrix_cholesky (empty, false); check (empty_result.info == 0 && empty_result.factor.rows () == 0 && empty_result.factor.columns () == 0 && empty_result.factor.precision_bits () == 2048, "empty Cholesky result mismatch"); } void test_precision_dependent_pd () { MpfrMatrixStorage low (2, 2, 512); MpfrMatrixStorage high (2, 2, 1024); for (MpfrMatrixStorage* input : {&low, &high}) { mpfr_set_ui (input->at (0, 0).mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (input->at (1, 0).mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (input->at (0, 1).mpfr_data (), 1, MPFR_RNDN); Real delta = Real::with_precision (input->precision_bits ()); mpfr_set_ui_2exp (delta.mpfr_data (), 1, -700, MPFR_RNDN); mpfr_add (input->at (1, 1).mpfr_data (), delta.mpfr_data (), input->at (0, 0).mpfr_data (), MPFR_RNDN); } const auto low_result = octave_mplapack::mplapack_mpfr_matrix_cholesky (low, false); const auto high_result = octave_mplapack::mplapack_mpfr_matrix_cholesky (high, false); check (low_result.info > 0 && high_result.info == 0, "precision-dependent PD classification mismatch"); } void test_failure_and_alias_safety () { const auto input = matrix (3, 3, 1024, {"4", "0", "0", "0", "9", "0", "0", "0", "-1"}); const auto before = input; const auto result = octave_mplapack::mplapack_mpfr_matrix_cholesky (input, false); check (result.info == 3 && result.factor.rows () == 2 && result.factor.columns () == 2, "partial Cholesky factor metadata mismatch"); check (result.factor.element_exactly_equal_text (0, 0, "2") && result.factor.element_exactly_equal_text (1, 1, "3"), "partial Cholesky factor values mismatch"); check (input.element_exactly_equal (2, 2, before, 2, 2), "failed Cholesky modified input"); const auto semidefinite = matrix (2, 2, 1024, {"1", "1", "1", "1"}); const auto partial = octave_mplapack::mplapack_mpfr_matrix_cholesky (semidefinite, true); check (partial.info == 2 && partial.factor.rows () == 1 && partial.factor.columns () == 1, "semidefinite partial lower factor mismatch"); check (mpfrxx::default_precision_bits () == 128, "failure Cholesky changed ambient precision"); } } // namespace int main () { try { test_triangle_selection (); test_precision_and_empty (); test_precision_dependent_pd (); test_failure_and_alias_safety (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: MPLAPACK MPFR Rpotrf Cholesky tests\n"; return 0; } mplapack-interop-0.5.1/test/mp_complex_arithmetic_test.cc0000644000230300031750000000752615274353472023156 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include "mp_complex_arithmetic.h" namespace { void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } } // namespace int main () { try { for (mpfr_prec_t precision : {128, 512, 1024, 2048}) { octave_mplapack::MpfrComplexScalarStorage lhs ( "(1.5,2)", precision); octave_mplapack::MpfrComplexScalarStorage rhs ( "(2,-1)", precision); octave_mplapack::MpfrScalarStorage real_rhs ("2", precision); const auto sum = octave_mplapack::mpc_matrix_elementwise_binary ( octave_mplapack::MpcElementwiseOperand::from_complex_scalar (lhs), octave_mplapack::MpcElementwiseOperand::from_complex_scalar (rhs), octave_mplapack::MpcElementwiseBinaryOperation::add); const auto product = octave_mplapack::mpc_matrix_elementwise_binary ( octave_mplapack::MpcElementwiseOperand::from_complex_scalar (lhs), octave_mplapack::MpcElementwiseOperand::from_real_scalar (real_rhs), octave_mplapack::MpcElementwiseBinaryOperation::multiply); check (sum.precision_bits () == precision && product.precision_bits () == precision, "scalar result precision changed"); check (sum.element_exactly_equal_double (0, 0, {3.5, 1.0}), "complex scalar sum mismatch"); check (product.element_exactly_equal_double (0, 0, {3.0, 4.0}), "mixed scalar product mismatch"); const std::vector> matrix_values { {1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}, {7.0, 8.0} }; const std::vector> row_values { {10.0, 1.0}, {20.0, 2.0} }; octave_mplapack::MpfrComplexMatrixStorage matrix ( 2, 2, precision, matrix_values); octave_mplapack::MpfrComplexMatrixStorage row ( 1, 2, precision, row_values); const auto broadcast = octave_mplapack::mpc_matrix_elementwise_binary ( octave_mplapack::MpcElementwiseOperand::from_complex_matrix (matrix), octave_mplapack::MpcElementwiseOperand::from_complex_matrix (row), octave_mplapack::MpcElementwiseBinaryOperation::add); check (broadcast.rows () == 2 && broadcast.columns () == 2, "complex broadcast shape mismatch"); check (broadcast.element_exactly_equal_double (1, 1, {27.0, 10.0}), "complex broadcast value mismatch"); const auto negated = octave_mplapack::mpc_matrix_negate (matrix); check (negated.element_exactly_equal_double (0, 1, {-5.0, -6.0}), "complex matrix negate mismatch"); octave_mplapack::MpfrComplexMatrixStorage zero ( 1, 1, precision, std::vector> {{0.0, 0.0}}); const auto quotient = octave_mplapack::mpc_matrix_elementwise_binary ( octave_mplapack::MpcElementwiseOperand::from_complex_scalar (lhs), octave_mplapack::MpcElementwiseOperand::from_complex_matrix (zero), octave_mplapack::MpcElementwiseBinaryOperation::divide); const octave_mplapack::MpfrComplexScalarStorage quotient_scalar ( quotient.at (0, 0)); check (quotient_scalar.is_nan () || quotient_scalar.is_infinite (), "complex division by zero was not deterministic"); } std::cout << "PASS: complex element-wise arithmetic, mixed real operands, broadcasting, precision, special values, and sanitizer coverage\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/mp_complex_rank_test.cc0000644000230300031750000003617015274353472021755 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include #include #include #include #include "mp_complex_blas.h" #include "mp_complex_precision.h" #include "mp_complex_rank.h" namespace { using Matrix = octave_mplapack::MpfrComplexMatrixStorage; using Integer = Matrix::MplapackInteger; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } Integer workspace_length (const mpfrxx::mpfr_class& value, const char *name) { if (mpfr_nan_p (value.mpfr_data ()) != 0 || mpfr_inf_p (value.mpfr_data ()) != 0 || mpfr_integer_p (value.mpfr_data ()) == 0 || mpfr_sgn (value.mpfr_data ()) <= 0) throw std::runtime_error (std::string (name) + " workspace query was invalid"); const auto result = mpfr_get_ui (value.mpfr_data (), MPFR_RNDZ); if (result > static_cast ( std::numeric_limits::max ()) || result > static_cast ( std::numeric_limits::max ())) throw std::runtime_error (std::string (name) + " workspace query overflowed"); return static_cast (result); } void fill_rhs (Matrix& destination, const Matrix& source) { for (std::size_t index = 0; index < destination.numel (); ++index) mpc_set_ui_ui (destination.data ()[index].mpc_data (), 0, 0, MPC_RND (MPFR_RNDN, MPFR_RNDN)); for (std::size_t column = 0; column < source.columns (); ++column) for (std::size_t row = 0; row < source.rows (); ++row) mpc_set (destination.at (row, column).mpc_data (), source.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); } struct CandidateResult { Matrix solution; Integer rank = 0; }; enum class Candidate { gelsy, gelss, gelsd }; const char * candidate_name (Candidate candidate) { switch (candidate) { case Candidate::gelsy: return "Cgelsy"; case Candidate::gelss: return "Cgelss"; case Candidate::gelsd: return "Cgelsd"; } return "unknown"; } CandidateResult run_candidate (Candidate candidate, const Matrix& lhs, const Matrix& rhs, mpfr_prec_t precision) { const std::size_t m = lhs.rows (); const std::size_t n = lhs.columns (); const std::size_t nrhs = rhs.columns (); const std::size_t padded_rows = std::max (m, n); const std::size_t minmn = std::min (m, n); const auto m_arg = Matrix::checked_mplapack_dimension (m); const auto n_arg = Matrix::checked_mplapack_dimension (n); const auto nrhs_arg = Matrix::checked_mplapack_dimension (nrhs); auto make_a = [&] () { return octave_mplapack::mplapack_mpc_matrix_copy_at_precision ( lhs, precision); }; auto make_b = [&] () { Matrix result (padded_rows, nrhs, precision); fill_rhs (result, rhs); return result; }; auto run_gelsy = [&] () { auto a = make_a (); auto b = make_b (); std::vector jpvt (n, 0); Matrix work_query (1, 1, precision); octave_mplapack::MpfrMatrixStorage rwork_query ( std::max (1, 2 * n), 1, precision); Integer rank = 0; Integer info = 0; octave_mplapack::MpfrMpcPrecisionScope scope (precision); mpfrxx::mpfr_class rcond = mpfrxx::mpfr_class::with_precision (precision); const mpfrxx::mpfr_class epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); Cgelsy (m_arg, n_arg, nrhs_arg, a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), jpvt.data (), rcond, rank, work_query.data (), -1, rwork_query.data (), info); check (info == 0, "Cgelsy workspace query failed"); const Integer lwork = workspace_length (work_query.at (0, 0).real (), "Cgelsy"); a = make_a (); b = make_b (); jpvt.assign (n, 0); Matrix work (static_cast (lwork), 1, precision); octave_mplapack::MpfrMatrixStorage rwork ( std::max (1, 2 * n), 1, precision); rank = 0; info = 0; Cgelsy (m_arg, n_arg, nrhs_arg, a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), jpvt.data (), rcond, rank, work.data (), lwork, rwork.data (), info); check (info == 0, "Cgelsy solve failed"); Matrix result (n, nrhs, precision); for (std::size_t column = 0; column < nrhs; ++column) for (std::size_t row = 0; row < n; ++row) mpc_set (result.at (row, column).mpc_data (), b.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return CandidateResult {std::move (result), rank}; }; auto run_gelss = [&] () { auto a = make_a (); auto b = make_b (); octave_mplapack::MpfrMatrixStorage singular_values (minmn, 1, precision); Matrix work_query (1, 1, precision); octave_mplapack::MpfrMatrixStorage rwork_query ( std::max (1, 4 * padded_rows + 32), 1, precision); Integer rank = 0; Integer info = 0; octave_mplapack::MpfrMpcPrecisionScope scope (precision); mpfrxx::mpfr_class rcond = mpfrxx::mpfr_class::with_precision (precision); const mpfrxx::mpfr_class epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); Cgelss (m_arg, n_arg, nrhs_arg, a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), singular_values.data (), rcond, rank, work_query.data (), -1, rwork_query.data (), info); check (info == 0, "Cgelss workspace query failed"); const Integer lwork = workspace_length (work_query.at (0, 0).real (), "Cgelss"); a = make_a (); b = make_b (); singular_values = octave_mplapack::MpfrMatrixStorage (minmn, 1, precision); Matrix work (static_cast (lwork), 1, precision); octave_mplapack::MpfrMatrixStorage rwork ( std::max (1, 4 * padded_rows + 32), 1, precision); rank = 0; info = 0; Cgelss (m_arg, n_arg, nrhs_arg, a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), singular_values.data (), rcond, rank, work.data (), lwork, rwork.data (), info); check (info == 0, "Cgelss solve failed"); Matrix result (n, nrhs, precision); for (std::size_t column = 0; column < nrhs; ++column) for (std::size_t row = 0; row < n; ++row) mpc_set (result.at (row, column).mpc_data (), b.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return CandidateResult {std::move (result), rank}; }; auto run_gelsd = [&] () { auto a = make_a (); auto b = make_b (); octave_mplapack::MpfrMatrixStorage singular_values (minmn, 1, precision); Matrix work_query (1, 1, precision); octave_mplapack::MpfrMatrixStorage rwork_query (1, 1, precision); std::vector iwork_query (1, 0); Integer rank = 0; Integer info = 0; octave_mplapack::MpfrMpcPrecisionScope scope (precision); mpfrxx::mpfr_class rcond = mpfrxx::mpfr_class::with_precision (precision); const mpfrxx::mpfr_class epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); Cgelsd (m_arg, n_arg, nrhs_arg, a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), singular_values.data (), rcond, rank, work_query.data (), -1, rwork_query.data (), iwork_query.data (), info); check (info == 0, "Cgelsd workspace query failed"); const Integer lwork = workspace_length (work_query.at (0, 0).real (), "Cgelsd complex"); const Integer lrwork = workspace_length (rwork_query.at (0, 0), "Cgelsd real"); const Integer liwork = iwork_query.at (0); check (liwork > 0, "Cgelsd integer workspace query failed"); a = make_a (); b = make_b (); singular_values = octave_mplapack::MpfrMatrixStorage (minmn, 1, precision); Matrix work (static_cast (lwork), 1, precision); octave_mplapack::MpfrMatrixStorage rwork ( static_cast (lrwork), 1, precision); std::vector iwork (static_cast (liwork)); rank = 0; info = 0; Cgelsd (m_arg, n_arg, nrhs_arg, a.data (), a.leading_dimension (), b.data (), b.leading_dimension (), singular_values.data (), rcond, rank, work.data (), lwork, rwork.data (), iwork.data (), info); check (info == 0, "Cgelsd solve failed"); Matrix result (n, nrhs, precision); for (std::size_t column = 0; column < nrhs; ++column) for (std::size_t row = 0; row < n; ++row) mpc_set (result.at (row, column).mpc_data (), b.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); return CandidateResult {std::move (result), rank}; }; switch (candidate) { case Candidate::gelsy: return run_gelsy (); case Candidate::gelss: return run_gelss (); case Candidate::gelsd: return run_gelsd (); } throw std::logic_error ("unknown complex rank candidate"); } void check_solution (const CandidateResult& result, const std::vector>& expected, Integer expected_rank, const char *label) { check (result.rank == expected_rank, label); for (std::size_t column = 0; column < result.solution.columns (); ++column) for (std::size_t row = 0; row < result.solution.rows (); ++row) { const octave_mplapack::MpfrComplexScalarStorage actual ( result.solution.at (row, column)); check (std::abs (actual.to_double () - expected[row + result.solution.rows () * column]) < 1.0e-9, label); } } void set_power_of_two (mpc_ptr value, unsigned long exponent) { mpfr_set_ui (mpc_realref (value), 1, MPFR_RNDN); mpfr_div_2si (mpc_realref (value), mpc_realref (value), exponent, MPFR_RNDN); mpfr_set (mpc_imagref (value), mpc_realref (value), MPFR_RNDN); mpfr_neg (mpc_imagref (value), mpc_imagref (value), MPFR_RNDN); } } // namespace int main () { try { const mpfr_prec_t precision = 256; const Matrix overdetermined ( 3, 2, precision, std::vector> { {1.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}}); const Matrix over_rhs ( 3, 2, precision, std::vector> { {1.0, 2.0}, {3.0, 0.0}, {4.0, 2.0}, {2.0, -1.0}, {-1.0, 4.0}, {1.0, 3.0}}); const std::vector> over_expected { {1.0, 2.0}, {3.0, 0.0}, {2.0, -1.0}, {-1.0, 4.0}}; for (Candidate candidate : {Candidate::gelsy, Candidate::gelss, Candidate::gelsd}) { const CandidateResult result = run_candidate ( candidate, overdetermined, over_rhs, precision); check_solution (result, over_expected, 2, candidate_name (candidate)); std::cout << "PASS: " << candidate_name (candidate) << " full-column-rank multiple-RHS audit\n"; } const Matrix underdetermined ( 2, 3, precision, std::vector> { {1.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}}); const Matrix under_rhs ( 2, 1, precision, std::vector> {{3.0, 3.0}, {3.0, 3.0}}); const std::vector> under_expected { {1.0, 1.0}, {1.0, 1.0}, {2.0, 2.0}}; for (Candidate candidate : {Candidate::gelsy, Candidate::gelss, Candidate::gelsd}) check_solution (run_candidate (candidate, underdetermined, under_rhs, precision), under_expected, 2, candidate_name (candidate)); const Matrix rank_deficient ( 3, 2, precision, std::vector> { {1.0, 0.0}, {2.0, 0.0}, {3.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}); const Matrix rank_deficient_rhs ( 3, 1, precision, std::vector> {{1.0, 2.0}, {2.0, 4.0}, {3.0, 6.0}}); const std::vector> rank_expected { {1.0, 2.0}, {0.0, 0.0}}; for (Candidate candidate : {Candidate::gelsy, Candidate::gelss, Candidate::gelsd}) check_solution (run_candidate (candidate, rank_deficient, rank_deficient_rhs, precision), rank_expected, 1, candidate_name (candidate)); for (const std::array settings : { std::array {{1024, 700}}, std::array {{2048, 1500}}}) { const mpfr_prec_t canary_precision = static_cast (settings[0]); Matrix lhs ( 3, 2, canary_precision, std::vector> { {1.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}}); Matrix rhs (3, 1, canary_precision); set_power_of_two (rhs.at (0, 0).mpc_data (), settings[1]); set_power_of_two (rhs.at (1, 0).mpc_data (), settings[1]); const Matrix lhs_before (lhs); const Matrix rhs_before (rhs); mpfrxx::set_default_precision_bits (128); const auto result = octave_mplapack::mplapack_mpc_matrix_rank_solve ( lhs, rhs); check (result.rank == 2, "Cgelsy canary rank mismatch"); check (result.solution.precision_bits () == canary_precision, "Cgelsy canary precision mismatch"); check (result.solution.element_exactly_equal ( 0, 0, rhs_before, 0, 0), "Cgelsy real canary changed"); check (result.solution.element_exactly_equal ( 1, 0, rhs_before, 1, 0), "Cgelsy imaginary canary changed"); check (lhs.element_exactly_equal (0, 0, lhs_before, 0, 0) && rhs.element_exactly_equal (0, 0, rhs_before, 0, 0), "Cgelsy mutated public operands"); check (mpfrxx::default_precision_bits () == 128, "Cgelsy changed ambient precision"); } const Matrix empty_lhs (0, 2, 256); const Matrix empty_rhs (0, 1, 256); const auto empty = octave_mplapack::mplapack_mpc_matrix_rank_solve ( empty_lhs, empty_rhs); check (empty.solution.rows () == 2 && empty.solution.columns () == 1 && empty.rank == 0, "Cgelsy empty shape mismatch"); std::cout << "PASS: complex rank-revealing candidate audit, Cgelsy selection, minimum norm, precision, workspace, shapes, and immutability\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/native_value.tst0000644000230300031750000001125615274353472020445 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function value = m02_pass_through (value) %!endfunction %!test %! v = __mplapack_core__ ("scalar_test_create", "0.125", 128); %! info = __mplapack_core__ ("scalar_test_info", v); %! assert (strcmp (info.internal_type, "mplapack_mpfr_scalar_internal")); %! assert (strcmp (info.backend, "mpfr")); %! assert (info.precision_bits == 128); %! assert (info.is_scalar); %! assert (strcmp (typeinfo (v), info.internal_type)); %! assert (__mplapack_core__ ("scalar_test_equal_string", v, "0.125")); %! clear v; %!test %! a = __mplapack_core__ ("scalar_test_create", "1.5", 256); %! b = a; %! clear a; %! info = __mplapack_core__ ("scalar_test_info", b); %! assert (info.precision_bits == 256); %! assert (__mplapack_core__ ("scalar_test_equal_string", b, "1.5")); %!test %! a = __mplapack_core__ ("scalar_test_create", "-2.25", 512); %! b = __mplapack_core__ ("scalar_test_clone", a); %! clear a; %! info = __mplapack_core__ ("scalar_test_info", b); %! assert (info.precision_bits == 512); %! assert (__mplapack_core__ ("scalar_test_equal_string", b, "-2.25")); %!test %! a = __mplapack_core__ ("scalar_test_create", "0.125", 128); %! values = {a, a}; %! clear a; %! info1 = __mplapack_core__ ("scalar_test_info", values{1}); %! info2 = __mplapack_core__ ("scalar_test_info", values{2}); %! assert (info1.precision_bits == 128); %! assert (info2.precision_bits == 128); %! assert (__mplapack_core__ ("scalar_test_equal", values{1}, values{2})); %!test %! a = __mplapack_core__ ("scalar_test_create", "0.125", 128); %! b = __mplapack_core__ ("scalar_test_create", "1.5", 256); %! c = __mplapack_core__ ("scalar_test_create", "-2.25", 512); %! ai = __mplapack_core__ ("scalar_test_info", a); %! bi = __mplapack_core__ ("scalar_test_info", b); %! ci = __mplapack_core__ ("scalar_test_info", c); %! assert ([ai.precision_bits, bi.precision_bits, ci.precision_bits], ... %! int64 ([128, 256, 512])); %! copied = __mplapack_core__ ("scalar_test_clone", a); %! clear a; %! copied_info = __mplapack_core__ ("scalar_test_info", copied); %! assert (copied_info.precision_bits == 128); %! assert (__mplapack_core__ ("scalar_test_equal_string", copied, "0.125")); %!test %! value = m02_pass_through (__mplapack_core__ ( %! "scalar_test_create", "0.1", 512)); %! info = __mplapack_core__ ("scalar_test_info", value); %! assert (info.precision_bits == 512); %! assert (__mplapack_core__ ("scalar_test_equal_string", value, "0.1")); %!test %! count = 500; %! values = cell (1, count); %! for i = 1:count %! precision = [128, 256, 512](mod (i - 1, 3) + 1); %! values{i} = __mplapack_core__ ( %! "scalar_test_create", "0.125", precision); %! endfor %! copied = values; %! clear values; %! for i = 1:37:count %! info = __mplapack_core__ ("scalar_test_info", copied{i}); %! assert (info.precision_bits == [128, 256, 512](mod (i - 1, 3) + 1)); %! assert (__mplapack_core__ ( %! "scalar_test_equal_string", copied{i}, "0.125")); %! endfor %! clear copied; %!test %! first = __mplapack_core__ ("scalar_test_create", "0.125", 128); %! expected_type = typeinfo (first); %! for i = 1:500 %! value = __mplapack_core__ ("scalar_test_create", "0.125", 128); %! assert (strcmp (typeinfo (value), expected_type)); %! assert (__mplapack_core__ ("scalar_test_equal", first, value)); %! endfor %!error %! __mplapack_core__ ("scalar_test_create", "1"); %!error %! __mplapack_core__ ("scalar_test_create", 1, 128); %!error %! __mplapack_core__ ("scalar_test_create", "1", "128"); %!error %! __mplapack_core__ ("scalar_test_create", "1", 128.5); %!error %! __mplapack_core__ ("scalar_test_create", "1", 0); %!error %! __mplapack_core__ ("scalar_test_create", "1", -1); %!error %! __mplapack_core__ ("scalar_test_create", "1", Inf); %!error %! __mplapack_core__ ("scalar_test_create", "not-a-number", 128); %!error %! __mplapack_core__ ("scalar_test_info", 1.0); %!error %! __mplapack_core__ ("scalar_test_clone", "ordinary string"); %!error %! __mplapack_core__ ("scalar_test_equal", {}, struct ()); %!error %! __mplapack_core__ ("scalar_test_equal_string", {1}, "1"); %!error %! v = __mplapack_core__ ("scalar_test_create", "1.5", 256); %! __mplapack_core__ ("scalar_test_equal_string", v, "invalid"); %!error %! __mplapack_core__ ("not_a_command"); mplapack-interop-0.5.1/test/mp_structured_eig_test.cc0000644000230300031750000000760715274353472022326 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_structured_eig.h" #include #include #include #include #include #include using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; namespace { void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } bool close_to (const MpfrMatrixStorage::NativeScalar& lhs, const MpfrMatrixStorage::NativeScalar& rhs, double tolerance) { auto difference = MpfrMatrixStorage::NativeScalar::with_precision ( lhs.precision ()); mpfr_sub (difference.mpfr_data (), lhs.mpfr_data (), rhs.mpfr_data (), MPFR_RNDN); return std::abs (mpfr_get_d (difference.mpfr_data (), MPFR_RNDN)) <= tolerance; } } // namespace int main () { try { MpfrMatrixStorage real (2, 2, 256, std::vector {2.0, 1.0, 1.0, 2.0}); const auto real_result = octave_mplapack::mplapack_mpfr_matrix_structured_eig (real); require (real_result.eigenvalues.rows () == 2 && real_result.eigenvalues.columns () == 1, "real eigenvalue shape mismatch"); require (real_result.vectors.rows () == 2 && real_result.vectors.columns () == 2, "real eigenvector shape mismatch"); require (close_to (real_result.eigenvalues.at (0, 0), MpfrMatrixStorage::NativeScalar (1.0, 256), 1e-60), "real first eigenvalue mismatch"); require (close_to (real_result.eigenvalues.at (1, 0), MpfrMatrixStorage::NativeScalar (3.0, 256), 1e-60), "real second eigenvalue mismatch"); require (real.element_exactly_equal_double (0, 1, 1.0), "real structured eig modified its input"); MpfrComplexMatrixStorage complex (2, 2, 256, std::vector {"(2,0)", "(1,-1)", "(1,1)", "(3,0)"}); const auto complex_result = octave_mplapack::mplapack_mpc_matrix_structured_eig (complex); require (complex_result.eigenvalues.rows () == 2 && complex_result.vectors.columns () == 2, "complex structured eig shape mismatch"); require (complex_result.eigenvalues.precision_bits () == 256 && complex_result.vectors.precision_bits () == 256, "structured eig precision mismatch"); require (complex.element_exactly_equal_text (1, 0, "(1,-1)"), "complex structured eig modified its input"); MpfrMatrixStorage nonsymmetric (2, 2, 256, std::vector {1.0, 2.0, 3.0, 4.0}); bool rejected = false; try { (void) octave_mplapack::mplapack_mpfr_matrix_structured_eig ( nonsymmetric); } catch (const std::invalid_argument&) { rejected = true; } require (rejected, "nonsymmetric input was not rejected"); MpfrComplexMatrixStorage nonhermitian (2, 2, 256, std::vector {"(1,1)", "(2,0)", "(3,0)", "(4,0)"}); rejected = false; try { (void) octave_mplapack::mplapack_mpc_matrix_structured_eig ( nonhermitian); } catch (const std::invalid_argument&) { rejected = true; } require (rejected, "non-Hermitian input was not rejected"); std::cout << "PASS: structured real symmetric and complex Hermitian " "Rsyevd/Cheevd eigenvalue QA, precision, rejection, " "and immutability\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/test_neigt15.m0000644000230300031750000000672515274353472017725 0ustar rafaelrafael% NEIGT15: bounded candidate preparation and verified invariant graphs. test_root = fileparts (fileparts (mfilename ("fullpath"))); private_root = fullfile (test_root, "examples", "neig_tiers", "private"); addpath (private_root); saved_bits = mpbits (); unwind_protect mpbits (256); % An exact synthetic graph with a nonzero quadratic term. Its invariant % graph is used only as an independent construction check, never as input % to the computed verification jobs. Z_true = mp ([1/16, -1/32; 1/64, 1/128]); C11 = mp ([1, 0; 0, 2]); C22 = mp ([4, 0; 0, 5]); C12 = mp ([1, 1/2; 1/4, 1]); C21 = -(C22 * Z_true) + Z_true * C11 + Z_true * C12 * Z_true; C = [C11, C12; C21, C22]; newton = net_v_s2_newton (C, 2, mp (zeros (2)), 256); assert (newton.candidate_only && newton.success); assert (newton.steps_used <= 4); assert (newton.steps(end).residual_after < net_pow2 (-64, 256)); graph = net_v_s2_graph (C, mp (eye (4)), 2, 256); assert (graph.pass && graph.nontrivial); assert (strcmp (graph.status, "CERTIFIED_INVARIANT_BASIS")); assert (strcmp (graph.method, "neigt_riccati_graph_v1")); assert (! graph.paper_algorithm_reproduction); assert (graph.preconditioner_residual_pass && graph.contraction_pass); assert (numel (graph.trials) >= 1 && numel (graph.trials) <= 8); assert (graph.trials(end).self_map && graph.trials(end).contraction); assert (isequal (size (graph.Z_box.rl), [2, 2])); assert (isequal (size (graph.Y1_box.rl), [4, 2])); wrong_transpose = net_v_s2_graph (C, mp (eye (4)), 2, 256, ... struct ("transpose_mode", "conjugating")); assert (! wrong_transpose.pass); assert (strcmp (wrong_transpose.status, ... "UNSUPPORTED_WRONG_KRONECKER_TRANSPOSE")); singular_preconditioner = net_v_s2_graph ... (C, mp (eye (4)), 2, 256, struct ("preconditioner", mp (zeros (4)))); assert (! singular_preconditioner.pass); assert (! singular_preconditioner.preconditioner_residual_pass); C_large = C; C_large(1,3) = net_pow2 (200, 256); failed_contraction = net_v_s2_graph (C_large, mp (eye (4)), 2, 256); assert (! failed_contraction.pass); assert (strcmp (failed_contraction.status, "INCONCLUSIVE_CONTRACTION")); manifest = net_manifest (); for job_index = 9:10 job = manifest.jobs.profiles.smoke.jobs{job_index}; computed = net_v_s2_job (job, manifest.cases.profiles.smoke, "smoke"); assert (computed.milestone_pass); assert (any (strcmp (computed.claim_status, ... {"CERTIFIED_INVARIANT_BASIS", "CERTIFIED_CLUSTER"}))); assert (strcmp (computed.graph.claim_status, "CERTIFIED_INVARIANT_BASIS")); assert (computed.graph.nontrivial); assert (strcmp (computed.candidate_source, ... "computed_subspace_bounded_schedule")); assert (numel (computed.candidate_preparation.records) == 3); assert (computed.candidate_preparation.records(1).node_count == 16); assert (computed.candidate_preparation.records(2).node_count == 32); assert (computed.candidate_preparation.records(3).node_count == 64); assert (computed.candidate_preparation.records(3).failed_nodes == 0); assert (computed.selected_strategy >= 1 && computed.selected_strategy <= 2); endfor fprintf ("PASS: NEIGT15 bounded candidates, Riccati graph, and fail-closed negatives\n"); unwind_protect_cleanup mpbits (saved_bits); if (any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect mplapack-interop-0.5.1/test/test_neigt14.m0000644000230300031750000000516515274353472017721 0ustar rafaelrafael% NEIGT14: counted all-spectrum verification on raw highest-work candidates. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect result = mp_neig_verify_examples ("smoke", struct ("tier", "V-S")); assert (result.scope_ok); assert (result.coverage.verification_job_count == 16); assert (result.coverage.vs1_job_count == 8); assert (result.coverage.vs1_complete); vs1 = result.jobs (strncmp ({result.jobs.id}, "VS1-", 4)); assert (numel (vs1) == 8); for index = 1:numel (vs1) certificate = vs1(index).certificate; assert (strcmp (vs1(index).status, "PASS")); assert (vs1(index).pass); assert (strcmp (certificate.method, "neigt_similarity_gershgorin_v1")); assert (! certificate.paper_algorithm_reproduction); assert (certificate.all_roots); assert (certificate.counted_roots == certificate.n); assert (certificate.singleton_count == certificate.n); assert (certificate.singleton_useful); assert (certificate.useful); assert (certificate.max_radius / certificate.verified_frobenius_upper ... <= certificate.usefulness_target); assert (! isempty (vs1(index).raw_V_hash)); assert (! isempty (vs1(index).raw_D_hash)); assert (! isempty (vs1(index).raw_W_hash)); endfor % A singular inverse candidate must fail closed and never create a count. mpbits (256); A = mp ([1, 2; 0, 3]); X = mp (eye (2)); T = A; R = mp (zeros (2)); failed = net_v_s1_gershgorin (A, X, T, R, 256, -40); assert (! failed.coverage); assert (! failed.inverse_residual_pass); assert (strcmp (failed.status, "INCONCLUSIVE_INVERSE_RESIDUAL")); % A touching pair is a connected component, not two certified singletons. R = mp (eye (2)); touching = net_v_s1_gershgorin (A, X, T, R, 256, -40); assert (touching.counted_roots == 2); assert (touching.component_count == 1); assert (! touching.singleton_useful); assert (strcmp (touching.status, "CERTIFIED_ALL_NOT_USEFUL")); fprintf ("PASS: NEIGT14 counted all-spectrum certificates and fail-closed negatives\n"); unwind_protect_cleanup mpbits (saved_bits); if (any (strcmp (strsplit (path (), pathsep), ... fullfile (test_root, "examples", "neig_tiers", "private")))) rmpath (fullfile (test_root, "examples", "neig_tiers", "private")); endif if (any (strcmp (strsplit (path (), pathsep), ... fullfile (test_root, "examples", "neig_tiers")))) rmpath (fullfile (test_root, "examples", "neig_tiers")); endif end_unwind_protect mplapack-interop-0.5.1/test/mp_blas_test.cc0000644000230300031750000003202115274353472020203 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_blas.h" #include #include #include #include #include #include namespace { using Matrix = octave_mplapack::MpfrMatrixStorage; using NativeScalar = mpfrxx::mpfr_class; void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void set_unsigned (NativeScalar& value, unsigned long number) { mpfr_set_ui (value.mpfr_data (), number, MPFR_RNDN); } void add_power_of_two (NativeScalar& value, long exponent) { NativeScalar increment = NativeScalar::with_precision (value.precision ()); mpfr_set_ui_2exp (increment.mpfr_data (), 1, exponent, MPFR_RNDN); mpfr_add (value.mpfr_data (), value.mpfr_data (), increment.mpfr_data (), MPFR_RNDN); } NativeScalar explicit_value (mpfr_prec_t precision, unsigned long number) { NativeScalar value = NativeScalar::with_precision (precision); set_unsigned (value, number); return value; } class DefaultPrecisionGuard { public: explicit DefaultPrecisionGuard (mpfr_prec_t precision) : m_saved (mpfrxx::default_precision_bits ()) { mpfrxx::set_default_precision_bits (precision); require (mpfrxx::default_precision_bits () == precision, "failed to set native test MPFR default"); } ~DefaultPrecisionGuard () noexcept { mpfrxx::set_default_precision_bits (m_saved); } private: mpfr_prec_t m_saved; }; void test_scope_basic_nested_exception_and_stress () { DefaultPrecisionGuard guard (128); { MplapackMpfrPrecisionScope outer (1024); require (mpfrxx::default_precision_bits () == 1024, "basic scope did not set the requested precision"); NativeScalar value; require (value.precision () == 1024, "default construction ignored the scope precision"); { MplapackMpfrPrecisionScope inner (2048); require (mpfrxx::default_precision_bits () == 2048, "nested scope did not set the requested precision"); NativeScalar nested_value; require (nested_value.precision () == 2048, "nested default construction ignored the scope precision"); } require (mpfrxx::default_precision_bits () == 1024, "nested scope did not restore the outer precision"); } require (mpfrxx::default_precision_bits () == 128, "basic scope did not restore the outside precision"); { MplapackMpfrPrecisionScope scope (256); require (mpfrxx::default_precision_bits () == 256, "reverse scope did not set the requested precision"); } require (mpfrxx::default_precision_bits () == 128, "reverse scope did not restore the outside precision"); try { MplapackMpfrPrecisionScope scope (4096); throw std::runtime_error ("deliberate scope exception"); } catch (const std::runtime_error&) { } require (mpfrxx::default_precision_bits () == 128, "scope did not restore precision during exception unwinding"); NativeScalar explicit_value_1024 = NativeScalar::with_precision (1024); { MplapackMpfrPrecisionScope scope (512); require (explicit_value_1024.precision () == 1024, "explicit object changed inside a scope"); } require (explicit_value_1024.precision () == 1024, "explicit object changed after a scope"); bool invalid_rejected = false; try { MplapackMpfrPrecisionScope invalid (0); } catch (const std::invalid_argument&) { invalid_rejected = true; } require (invalid_rejected, "invalid scope precision was accepted"); require (mpfrxx::default_precision_bits () == 128, "invalid scope changed the outside precision"); for (int iteration = 0; iteration < 10000; ++iteration) { const mpfr_prec_t precision = (iteration & 1) == 0 ? 256 : 2048; MplapackMpfrPrecisionScope scope (precision); NativeScalar value; require (value.precision () == precision, "repeated scope lost the requested precision"); } require (mpfrxx::default_precision_bits () == 128, "repeated scopes did not restore the outside precision"); } void test_contract_checker () { constexpr mpfr_prec_t precision = 1024; Matrix a (1, 1, precision, std::vector {"1"}); Matrix b (1, 1, precision, std::vector {"1"}); Matrix c (1, 1, precision); NativeScalar alpha = explicit_value (precision, 1); NativeScalar beta = explicit_value (precision, 0); DefaultPrecisionGuard guard (512); bool rejected = false; bool rgemm_entered = false; try { octave_mplapack::require_mplapack_mpfr_precision_contract ( precision, alpha, a, b, beta, c); rgemm_entered = true; } catch (const std::runtime_error&) { rejected = true; } require (rejected && ! rgemm_entered, "TLS mismatch was not rejected before the Rgemm seam"); DefaultPrecisionGuard valid_guard (precision); Matrix short_b (1, 1, 512, std::vector {"1"}); rejected = false; try { octave_mplapack::require_mplapack_mpfr_precision_contract ( precision, alpha, a, short_b, beta, c); } catch (const std::runtime_error&) { rejected = true; } require (rejected, "matrix precision mismatch was not rejected"); NativeScalar short_alpha = explicit_value (512, 1); rejected = false; try { octave_mplapack::require_mplapack_mpfr_precision_contract ( precision, short_alpha, a, b, beta, c); } catch (const std::runtime_error&) { rejected = true; } require (rejected, "scalar precision mismatch was not rejected"); octave_mplapack::require_mplapack_mpfr_precision_contract ( precision, alpha, a, b, beta, c); } void test_rgemm_precision_and_shapes () { { DefaultPrecisionGuard guard (128); constexpr mpfr_prec_t precision = 1024; Matrix a (1, 1, precision, std::vector {"1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"}); Matrix b (1, 1, precision, std::vector {"1"}); Matrix result = octave_mplapack::mplapack_mpfr_matrix_multiply (a, b); require (result.precision_bits () == precision, "1024-bit Rgemm result precision mismatch"); require (result.element_exactly_equal (0, 0, a, 0, 0), "1024-bit Rgemm lost the low-order contribution"); require (mpfrxx::default_precision_bits () == 128, "Rgemm did not restore the outer default precision"); } { DefaultPrecisionGuard guard (4096); constexpr mpfr_prec_t precision = 256; Matrix a (1, 1, precision, std::vector {"1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"}); Matrix b (1, 1, precision, std::vector {"1"}); Matrix result = octave_mplapack::mplapack_mpfr_matrix_multiply (a, b); require (result.precision_bits () == precision, "256-bit Rgemm used the outside 4096-bit precision"); require (result.element_exactly_equal (0, 0, a, 0, 0), "256-bit Rgemm changed the rounding context"); require (mpfrxx::default_precision_bits () == 4096, "high outside default was not restored after Rgemm"); } { DefaultPrecisionGuard guard (128); constexpr mpfr_prec_t precision = 2048; Matrix a (1, 1, precision); Matrix b (1, 1, precision, std::vector {"1"}); set_unsigned (a.at (0, 0), 1); add_power_of_two (a.at (0, 0), -1500); Matrix result = octave_mplapack::mplapack_mpfr_matrix_multiply (a, b); require (result.precision_bits () == precision, "2048-bit Rgemm result precision mismatch"); require (result.element_exactly_equal (0, 0, a, 0, 0), "2048-bit Rgemm lost the low-order contribution"); require (mpfrxx::default_precision_bits () == 128, "2048-bit Rgemm did not restore the outer default"); } Matrix left (2, 3, 256, std::vector {"1", "4", "2", "5", "3", "6"}); Matrix right (3, 2, 256, std::vector {"7", "9", "11", "8", "10", "12"}); Matrix product = octave_mplapack::mplapack_mpfr_matrix_multiply (left, right); require (product.rows () == 2 && product.columns () == 2, "rectangular Rgemm result shape mismatch"); require (product.element_exactly_equal_text (0, 0, "58"), "rectangular Rgemm result (1,1) mismatch"); require (product.element_exactly_equal_text (1, 0, "139"), "rectangular Rgemm result (2,1) mismatch"); require (product.element_exactly_equal_text (0, 1, "64"), "rectangular Rgemm result (1,2) mismatch"); require (product.element_exactly_equal_text (1, 1, "154"), "rectangular Rgemm result (2,2) mismatch"); Matrix empty (0, 3, 777); Matrix empty_result = octave_mplapack::mplapack_mpfr_matrix_multiply ( empty, Matrix (3, 2, 333)); require (empty_result.rows () == 0 && empty_result.columns () == 2 && empty_result.precision_bits () == 777, "empty Rgemm result metadata mismatch"); bool dimension_rejected = false; try { (void) octave_mplapack::mplapack_mpfr_matrix_multiply ( Matrix (2, 2, 128), Matrix (3, 1, 128)); } catch (const std::invalid_argument&) { dimension_rejected = true; } require (dimension_rejected, "incompatible Rgemm dimensions were accepted"); } void test_native_scaling () { Matrix matrix (2, 1, 256, std::vector {"1", "2"}); NativeScalar scalar = explicit_value (1024, 3); Matrix result = octave_mplapack::mplapack_mpfr_matrix_scale ( matrix, scalar); require (result.precision_bits () == 1024, "scalar/matrix operation did not use the greater precision"); require (result.element_exactly_equal_text (0, 0, "3"), "scalar/matrix scaling first value mismatch"); require (result.element_exactly_equal_text (1, 0, "6"), "scalar/matrix scaling second value mismatch"); require (matrix.precision_bits () == 256 && matrix.element_exactly_equal_text (0, 0, "1"), "scalar/matrix scaling mutated its input"); } void test_concurrent_thread_scopes () { if (mpfr_buildopt_tls_p () == 0) { std::cout << "SKIP: concurrent precision scopes (MPFR TLS disabled)\n"; return; } DefaultPrecisionGuard guard (512); std::mutex mutex; std::condition_variable condition; int ready = 0; bool release = false; mpfr_prec_t thread_a_initial = 0; mpfr_prec_t thread_b_initial = 0; mpfr_prec_t thread_a_after = 0; mpfr_prec_t thread_b_after = 0; bool thread_a_ok = false; bool thread_b_ok = false; auto worker = [&] (mpfr_prec_t precision, mpfr_prec_t& initial, mpfr_prec_t& after, bool& ok) { initial = mpfrxx::default_precision_bits (); { MplapackMpfrPrecisionScope scope (precision); NativeScalar value; std::unique_lock lock (mutex); ok = value.precision () == precision && mpfrxx::default_precision_bits () == precision; ++ready; condition.notify_all (); condition.wait (lock, [&] { return release; }); ok = ok && mpfrxx::default_precision_bits () == precision; } after = mpfrxx::default_precision_bits (); }; std::thread thread_a (worker, 256, std::ref (thread_a_initial), std::ref (thread_a_after), std::ref (thread_a_ok)); std::thread thread_b (worker, 2048, std::ref (thread_b_initial), std::ref (thread_b_after), std::ref (thread_b_ok)); { std::unique_lock lock (mutex); condition.wait (lock, [&] { return ready == 2; }); require (mpfrxx::default_precision_bits () == 512, "worker scope changed the main-thread precision"); release = true; condition.notify_all (); } thread_a.join (); thread_b.join (); require (thread_a_ok && thread_b_ok, "concurrent independent precision scopes interfered"); require (thread_a_after == thread_a_initial && thread_b_after == thread_b_initial, "worker scope did not restore each worker's initial precision"); require (mpfrxx::default_precision_bits () == 512, "concurrent scopes changed the main-thread precision after join"); (void) thread_a_after; (void) thread_b_after; } } // namespace int main () { try { test_scope_basic_nested_exception_and_stress (); test_contract_checker (); test_rgemm_precision_and_shapes (); test_native_scaling (); test_concurrent_thread_scopes (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: private MPFR scope, contract checker, reference Rgemm, " "native scaling, shapes, and thread QA\n"; return 0; } mplapack-interop-0.5.1/test/complex_scalar.tst0000644000230300031750000000137515274353472020760 0ustar rafaelrafael%!test %! mpbits (512); %! z = mp ("1.25", "-0"); %! assert (! isreal (z)); %! assert (strcmp (class (z), "mp")); %! text = char (z); %! assert (strcmp (text, "(1.25e+0,-0)")); %! assert (strcmp (char (mp (text)), text)); %! assert (double (z) == complex (1.25, -0.0)); %!test %! for bits = [1024, 2048] %! mpbits (bits); %! z = mp ("1", "1e-211"); %! info = __mplapack_core__ ("scalar_test_info", z); %! assert (info.precision_bits == bits); %! assert (info.is_complex); %! assert (strcmp (char (mp (char (z))), char (z))); %! endfor %!test %! z = mp (complex (1, -2)); %! assert (! isreal (z)); %! assert (double (z) == complex (1, -2)); %! r = mp ("0.1"); %! assert (isreal (r)); %! assert (! __mplapack_core__ ("value_shape_info", r).is_complex); mplapack-interop-0.5.1/test/eig_generalized.tst0000644000230300031750000001136515274353472021101 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_generalized_right_residual (A, B, V, D, tolerance, label) %! residual = double (norm (A * V - B * V * D, "fro")); %! assert (residual < tolerance, label); %!endfunction %!function assert_generalized_left_residual (A, B, D, W, tolerance, label) %! residual = double (norm (ctranspose (W) * A ... %! - D * ctranspose (W) * B, "fro")); %! assert (residual < tolerance, label); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([2, 1; 1, 3]); %! B = mp ([3, 0; 0, 2]); %! A_before = double (A); %! [V, D, W] = eig (A, B); %! assert_generalized_right_residual (A, B, V, D, 1e-12, ... %! "real definite generalized right residual"); %! assert_generalized_left_residual (A, B, D, W, 1e-12, ... %! "real definite generalized left residual"); %! assert (sort (diag (double (D))), [0.5; 5/3], 1e-12); %! [Vc, Dc] = eig (A, B, "chol", "vector"); %! assert_generalized_right_residual (A, B, Vc, diag (double (Dc)), 1e-12, ... %! "real chol vector residual"); %! [Vq, Dq] = eig (A, B, "qz"); %! assert_generalized_right_residual (A, B, Vq, Dq, 1e-12, ... %! "real forced QZ residual"); %! assert (__mplapack_core__ ("matrix_test_info", Vq).is_complex); %! assert (double (A), A_before); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([0, 1; -1, 0]); %! B = mp (eye (2)); %! [V, d, W] = eig (A, B, "qz", "vector"); %! assert_generalized_right_residual (A, B, V, diag (double (d)), 1e-12, ... %! "real QZ conjugate-pair residual"); %! assert_generalized_left_residual (A, B, diag (double (d)), W, 1e-12, ... %! "real QZ conjugate-pair left residual"); %! values = sort (double (d)); %! assert (values, [-1i; 1i], 1e-12); %! one_output = eig (A, B, "vector"); %! assert (sort (double (one_output)), values, 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1, 1i; -1i, 3]); %! B = mp ([2, 0; 0, 1]); %! [V, D, W] = eig (A, B, "chol"); %! assert_generalized_right_residual (A, B, V, D, 1e-12, ... %! "complex definite generalized residual"); %! assert_generalized_left_residual (A, B, D, W, 1e-12, ... %! "complex definite generalized left residual"); %! assert (__mplapack_core__ ("matrix_test_info", V).is_complex); %! assert (! __mplapack_core__ ("matrix_test_info", D).is_complex); %! [Vq, Dq] = eig (A, B, "qz", "matrix"); %! assert_generalized_right_residual (A, B, Vq, Dq, 1e-12, ... %! "complex forced QZ residual"); %! mixed_a = mp ([2, 0; 0, 3]); %! mixed_b = mp ([1 + 1i, 0; 0, 1]); %! [Vm, Dm] = eig (mixed_a, mixed_b, "qz"); %! assert_generalized_right_residual (mixed_a, mixed_b, Vm, Dm, 1e-12, ... %! "mixed real/complex generalized residual"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp (eye (2)); %! B = mp ([1, 0; 0, 0]); %! values = eig (A, B); %! assert (any (isinf (double (values)))); %! rejected = false; %! try %! eig (mp ([1, 1; 0, 1]), B, "chol"); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, "chol must reject a nonsymmetric generalized pair"); %! rejected = false; %! try %! eig (A, B, "balance"); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, "balance must be rejected for generalized eig"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! tiny = mp ("1"); %! for k = 1:exponent %! tiny = tiny * mp ("0.5"); %! endfor %! A = mp ([1, 1; 0, 3]); %! A (1, 1) = tiny; %! B = mp (eye (2)); %! ambient = mpbits (128); %! [V, D] = eig (A, B, "qz"); %! assert_generalized_right_residual (A, B, V, D, 1e-12, ... %! "generalized high precision residual"); %! assert (__mplapack_core__ ("matrix_test_info", D).precision_bits ... %! == uint64 (precision)); %! assert (mpbits () == ambient); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/run_tests.m0000644000230300031750000002234015274353472017427 0ustar rafaelrafaeltest_dir = fileparts (mfilename ("fullpath")); repo_root = fileparts (test_dir); addpath (fullfile (repo_root, "inst")); addpath (fullfile (repo_root, "src")); addpath (test_dir); assert (test (fullfile (test_dir, "build_probe.tst"), "quiet", stdout)); fprintf ("PASS: M01 build probe tests\n"); assert (test (fullfile (test_dir, "native_value.tst"), "quiet", stdout)); fprintf ("PASS: M02 native-value tests\n"); assert (test (fullfile (test_dir, "constructor.tst"), "quiet", stdout)); fprintf ("PASS: M03 public scalar constructor tests\n"); assert (test (fullfile (test_dir, "precision.tst"), "quiet", stdout)); fprintf ("PASS: M04 public precision tests\n"); assert (test (fullfile (test_dir, "conversion.tst"), "quiet", stdout)); fprintf ("PASS: M05 scalar conversion and display tests\n"); assert (test (fullfile (test_dir, "arithmetic.tst"), "quiet", stdout)); fprintf ("PASS: M06 scalar arithmetic tests\n"); assert (test (fullfile (test_dir, "matrix_storage.tst"), "quiet", stdout)); fprintf ("PASS: M07 native dense matrix storage tests\n"); assert (test (fullfile (test_dir, "gemm.tst"), "quiet", stdout)); fprintf ("PASS: M08 native MPFR Rgemm matrix multiplication tests\n"); assert (test (fullfile (test_dir, "gesv.tst"), "quiet", stdout)); fprintf ("PASS: M09 native MPFR Rgesv linear solve tests\n"); assert (test (fullfile (test_dir, "rgels.tst"), "quiet", stdout)); fprintf ("PASS: M15 native MPFR Rgels rectangular solve tests\n"); assert (test (fullfile (test_dir, "rank.tst"), "quiet", stdout)); fprintf ("PASS: M16 native rank-revealing rectangular solve tests\n"); assert (test (fullfile (test_dir, "chol.tst"), "quiet", stdout)); fprintf ("PASS: M17 native MPFR Rpotrf Cholesky tests\n"); assert (test (fullfile (test_dir, "qr.tst"), "quiet", stdout)); fprintf ("PASS: M18 native MPFR Rgeqrf/Rorgqr QR tests\n"); assert (test (fullfile (test_dir, "pivoted_qr.tst"), "quiet", stdout)); fprintf ("PASS: M19 native MPFR Rgeqp3/Rorgqr pivoted QR tests\n"); assert (test (fullfile (test_dir, "lu.tst"), "quiet", stdout)); fprintf ("PASS: M21 native MPFR Rgetrf LU tests\n"); assert (test (fullfile (test_dir, "matrix_inspection.tst"), "quiet", stdout)); fprintf ("PASS: M10 dense matrix inspection tests\n"); assert (test (fullfile (test_dir, "elementwise.tst"), "quiet", stdout)); fprintf ("PASS: M11 dense element-wise arithmetic tests\n"); assert (test (fullfile (test_dir, "structure.tst"), "quiet", stdout)); fprintf ("PASS: M12 dense transpose and reshape tests\n"); assert (test (fullfile (test_dir, "concat.tst"), "quiet", stdout)); fprintf ("PASS: M13 dense concatenation tests\n"); assert (test (fullfile (test_dir, "assignment.tst"), "quiet", stdout)); fprintf ("PASS: M14 dense indexed assignment tests\n"); assert (test (fullfile (test_dir, "release_closure.tst"), "quiet", stdout)); fprintf ("PASS: M22 real API and release closure tests\n"); assert (test (fullfile (test_dir, "complex_scalar.tst"), "quiet", stdout)); fprintf ("PASS: C01 complex scalar construction and conversion tests\n"); assert (test (fullfile (test_dir, "complex_matrix.tst"), "quiet", stdout)); fprintf ("PASS: C02 complex dense matrix tests\n"); assert (test (fullfile (test_dir, "complex_structural.tst"), "quiet", stdout)); fprintf ("PASS: C03 complex structural tests\n"); assert (test (fullfile (test_dir, "complex_elementwise.tst"), "quiet", stdout)); fprintf ("PASS: C04 complex element-wise tests\n"); assert (test (fullfile (test_dir, "complex_gemm.tst"), "quiet", stdout)); fprintf ("PASS: C05 complex Cgemm tests\n"); assert (test (fullfile (test_dir, "complex_gesv.tst"), "quiet", stdout)); fprintf ("PASS: C06 complex Cgesv tests\n"); assert (test (fullfile (test_dir, "complex_rank.tst"), "quiet", stdout)); fprintf ("PASS: C07 complex rank-revealing tests\n"); assert (test (fullfile (test_dir, "complex_cholesky.tst"), "quiet", stdout)); fprintf ("PASS: C08 complex Cholesky tests\n"); assert (test (fullfile (test_dir, "complex_qr.tst"), "quiet", stdout)); fprintf ("PASS: C09 complex QR tests\n"); assert (test (fullfile (test_dir, "complex_pivoted_qr.tst"), "quiet", stdout)); fprintf ("PASS: C10 complex pivoted QR tests\n"); assert (test (fullfile (test_dir, "complex_mixed_closure.tst"), "quiet", stdout)); fprintf ("PASS: C11 mixed real/complex closure tests\n"); assert (test (fullfile (test_dir, "complex_lu.tst"), "quiet", stdout)); fprintf ("PASS: C11L complex Cgetrf LU tests\n"); assert (test (fullfile (test_dir, "complex_release_firewall.tst"), "quiet", stdout)); fprintf ("PASS: C12 complex compatibility firewall tests\n"); assert (test (fullfile (test_dir, "norm.tst"), "quiet", stdout)); fprintf ("PASS: N00 norm tests\n"); assert (test (fullfile (test_dir, "det_inv.tst"), "quiet", stdout)); fprintf ("PASS: N01 determinant and inverse tests\n"); assert (test (fullfile (test_dir, "svd.tst"), "quiet", stdout)); fprintf ("PASS: N02 SVD tests\n"); run (fullfile (test_dir, "test_svd_tiers.m")); run (fullfile (test_dir, "test_svd_verification.m")); assert (test (fullfile (test_dir, "rank_condition.tst"), "quiet", stdout)); fprintf ("PASS: N03 rank and condition tests\n"); assert (test (fullfile (test_dir, "eig_structured.tst"), "quiet", stdout)); fprintf ("PASS: N04 structured symmetric/Hermitian eig tests\n"); assert (test (fullfile (test_dir, "eig_general.tst"), "quiet", stdout)); fprintf ("PASS: N05 general eig and Grcar tests\n"); assert (test (fullfile (test_dir, "eig_generalized.tst"), "quiet", stdout)); fprintf ("PASS: N06 generalized eig and QZ/Cholesky tests\n"); run (fullfile (test_dir, "test_nonsymmetric_eig_suite.m")); fprintf ("PASS: NEIG difficult nonsymmetric eigensystem suite\n"); run (fullfile (test_dir, "test_neigt23.m")); fprintf ("PASS: NEIGT23 exact output and independent replay tests\n"); run (fullfile (test_dir, "test_neigt24.m")); fprintf ("PASS: NEIGT24 numbered examples and documentation integration tests\n"); assert (test (fullfile (test_dir, "t00_schur_qz.tst"), "quiet", stdout)); fprintf ("PASS: T00 Hessenberg, balance, Schur, and QZ tests\n"); assert (test (fullfile (test_dir, "t01_dense_utilities.tst"), "quiet", stdout)); fprintf ("PASS: T01 pinv, null, orth, rref, and kron tests\n"); assert (test (fullfile (test_dir, "t02_matrix_functions.tst"), "quiet", stdout)); fprintf ("PASS: T02 expm, logm, and sqrtm tests\n"); assert (test (fullfile (test_dir, "t03_polynomial_core.tst"), "quiet", stdout)); fprintf ("PASS: T03 polynomial core tests\n"); assert (test (fullfile (test_dir, "t04_exact_sets.tst"), "quiet", stdout)); fprintf ("PASS: T04 exact set-operation tests\n"); assert (test (fullfile (test_dir, "t05_gamma_erf.tst"), "quiet", stdout)); fprintf ("PASS: T05 gamma and erf-family tests\n"); assert (test (fullfile (test_dir, "t06_special_function_firewall.tst"), "quiet", stdout)); fprintf ("PASS: T06 special-function backend audit and firewall tests\n"); assert (test (fullfile (test_dir, "t07_serialization.tst"), "quiet", stdout)); fprintf ("PASS: T07 exact serialization tests\n"); assert (test (fullfile (test_dir, "t08_graphics_3d.tst"), "quiet", stdout)); fprintf ("PASS: T08 3-D graphics boundary tests\n"); assert (test (fullfile (test_dir, "t09_random.tst"), "quiet", stdout)); fprintf ("PASS: T09 arbitrary-precision random-generation tests\n"); assert (test (fullfile (test_dir, "t10_interpolation.tst"), "quiet", stdout)); fprintf ("PASS: T10 one-dimensional interpolation tests\n"); assert (test (fullfile (test_dir, "t11_interp2.tst"), "quiet", stdout)); fprintf ("PASS: T11 two-dimensional interpolation tests\n"); assert (test (fullfile (test_dir, "t12_solvers.tst"), "quiet", stdout)); fprintf ("PASS: T12 nonlinear solver tests\n"); assert (test (fullfile (test_dir, "t13_quadrature.tst"), "quiet", stdout)); fprintf ("PASS: T13 arbitrary-precision quadrature tests\n"); assert (test (fullfile (test_dir, "t14_optimization.tst"), "quiet", stdout)); fprintf ("PASS: T14 arbitrary-precision optimization tests\n"); assert (test (fullfile (test_dir, "n07_closure.tst"), "quiet", stdout)); fprintf ("PASS: N07 numerical API closure and compatibility firewall tests\n"); assert (test (fullfile (test_dir, "mrdivide.tst"), "quiet", stdout)); fprintf ("PASS: N08 dense real and complex right-division tests\n"); assert (test (fullfile (test_dir, "script-compat", "s00.tst"), "quiet", stdout)); fprintf ("PASS: S00 script compatibility tests\n"); assert (test (fullfile (test_dir, "script-compat", "s01.tst"), "quiet", stdout)); fprintf ("PASS: S01 script compatibility tests\n"); assert (test (fullfile (test_dir, "script-compat", "s02.tst"), "quiet", stdout)); fprintf ("PASS: S02 script compatibility tests\n"); assert (test (fullfile (test_dir, "script-compat", "s03.tst"), "quiet", stdout)); fprintf ("PASS: S03 script compatibility tests\n"); assert (test (fullfile (test_dir, "script-compat", "s04.tst"), "quiet", stdout)); fprintf ("PASS: S04 script compatibility tests\n"); assert (test (fullfile (test_dir, "script-compat", "s05.tst"), "quiet", stdout)); fprintf ("PASS: S05 script compatibility tests\n"); assert (test (fullfile (test_dir, "script-compat", "s06.tst"), "quiet", stdout)); fprintf ("PASS: S06 script compatibility tests\n"); assert (test (fullfile (test_dir, "script-compat", "s07.tst"), "quiet", stdout)); fprintf ("PASS: S07 script compatibility tests\n"); assert (test (fullfile (test_dir, "script-compat", "s08.tst"), "quiet", stdout)); fprintf ("PASS: S08 script compatibility tests\n"); mplapack-interop-0.5.1/test/complex_pivoted_qr.tst0000644000230300031750000001251115274353472021661 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_complex_pivot_shapes (Q, R, P, q_rows, q_columns, r_rows, r_columns) %! q_info = __mplapack_core__ ("matrix_test_info", Q); %! r_info = __mplapack_core__ ("matrix_test_info", R); %! assert (q_info.rows == uint64 (q_rows)); %! assert (q_info.columns == uint64 (q_columns)); %! assert (r_info.rows == uint64 (r_rows)); %! assert (r_info.columns == uint64 (r_columns)); %! assert (q_info.is_complex && r_info.is_complex); %! assert (q_info.all_elements_same_precision && ... %! r_info.all_elements_same_precision); %! assert (class (P), "double"); %!endfunction %!function assert_complex_pivot_reconstruction (A, Q, R, P, p, tolerance) %! if (! isempty (P)) %! expected = double (A) * P; %! else %! expected = double (A(:, p)); %! endif %! assert (double (Q * R), expected, tolerance); %!endfunction %!function assert_permutation_pair (P, p) %! expected = zeros (size (P)); %! for column = 1:numel (p) %! expected(p(column), column) = 1; %! endfor %! assert (P, expected); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1 + 1i, 2 - 1i, 0 + 1i; ... %! 2 + 0i, 1 + 2i, 1 - 2i; ... %! 0 + 1i, 1 + 0i, 3 + 1i]); %! [Q, R, P] = qr (A); %! [Qv, Rv, p] = qr (A, "vector"); %! assert_complex_pivot_shapes (Q, R, P, 3, 3, 3, 3); %! assert_complex_pivot_shapes (Qv, Rv, p, 3, 3, 3, 3); %! assert (size (p), [1, 3]); %! assert (sort (p), 1:3); %! assert_permutation_pair (P, p); %! assert_complex_pivot_reconstruction (A, Q, R, P, [], 1e-10); %! assert_complex_pivot_reconstruction (A, Qv, Rv, [], p, 1e-10); %! assert (double (Q' * Q), eye (3), 1e-10); %! assert (double (Qv' * Qv), eye (3), 1e-10); %! A_before = double (A); %! clear Q R P Qv Rv p; %! assert (double (A), A_before); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1 + 1i, 2 - 1i, 0 + 1i; ... %! 2 + 0i, 1 + 2i, 1 - 2i; ... %! 0 + 1i, 1 + 0i, 3 + 1i; ... %! 1 - 1i, 0 + 2i, 2 + 0i]); %! [Qe, Re, Pe] = qr (A, "econ"); %! [Q0, R0, p0] = qr (A, 0); %! assert_complex_pivot_shapes (Qe, Re, Pe, 4, 3, 3, 3); %! assert_complex_pivot_shapes (Q0, R0, p0, 4, 3, 3, 3); %! assert (size (p0), [1, 3]); %! assert (sort (p0), 1:3); %! assert_permutation_pair (Pe, p0); %! assert_complex_pivot_reconstruction (A, Qe, Re, Pe, [], 1e-10); %! assert_complex_pivot_reconstruction (A, Q0, R0, [], p0, 1e-10); %! assert (double (Qe' * Qe), eye (3), 1e-10); %! assert (double (Q0' * Q0), eye (3), 1e-10); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! wide = mp ([1 + 1i, 2 - 1i, 0 + 1i, 1 - 1i; ... %! 2 + 0i, 1 + 2i, 1 + 0i, 0 + 2i]); %! [Q, R, P] = qr (wide); %! [Qe, Re, Pe] = qr (wide, "econ"); %! [Qv, Rv, p] = qr (wide, "vector"); %! assert_complex_pivot_shapes (Q, R, P, 2, 2, 2, 4); %! assert_complex_pivot_shapes (Qe, Re, Pe, 2, 2, 2, 4); %! assert_complex_pivot_shapes (Qv, Rv, p, 2, 2, 2, 4); %! assert (size (P), [4, 4]); %! assert (size (p), [1, 4]); %! assert (sort (p), 1:4); %! assert_complex_pivot_reconstruction (wide, Q, R, P, [], 1e-10); %! assert_complex_pivot_reconstruction (wide, Qe, Re, Pe, [], 1e-10); %! assert_complex_pivot_reconstruction (wide, Qv, Rv, [], p, 1e-10); %! assert (double (Q' * Q), eye (2), 1e-10); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 1500], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! delta = mp ("1", "0"); %! for k = 1:exponent %! delta = delta ./ mp ("2", "0"); %! endfor %! A = mp (complex (ones (1, 2), zeros (1, 2))); %! A(1, 2) = mp ("1", "0") + delta; %! mpbits (128); %! [Q, R, p] = qr (A, "vector"); %! expected_first = 1; %! if (precision == 2048) %! expected_first = 2; %! endif %! assert (p(1), expected_first); %! assert (__mplapack_core__ ("matrix_test_info", R).precision_bits, ... %! uint64 (precision)); %! assert (__mplapack_core__ ("scalar_test_info", Q).is_complex); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (256); %! A = mp (complex (zeros (0, 3), zeros (0, 3))); %! [Q, R, P] = qr (A); %! [Qv, Rv, p] = qr (A, "vector"); %! assert (size (Q), [0, 0]); %! assert (size (R), [0, 3]); %! assert (size (P), [3, 3]); %! assert (size (Qv), [0, 0]); %! assert (size (Rv), [0, 3]); %! assert (size (p), [1, 3]); %! assert (P, diag (ones (1, 3))); %! assert (p, 1:3); %!test %! mpbits (256); %! real_input = mp ([1, 0, 0; 0, 4, 0; 0, 0, 2]); %! [Q, R, P] = qr (real_input); %! assert (P, [0, 0, 1; 1, 0, 0; 0, 1, 0]); %! assert (! __mplapack_core__ ("matrix_test_info", Q).is_complex); %! assert (! __mplapack_core__ ("matrix_test_info", R).is_complex); %! assert (double (Q * R), double (real_input) * P, 1e-12); %!error qr (mp (complex ([1, 2], [0, 0])), "foo") mplapack-interop-0.5.1/test/mp_rank_condition_test.cc0000644000230300031750000001246315274353472022273 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_rank_condition.h" #include #include #include #include #include using octave_mplapack::MpfrConditionKind; using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrScalarStorage; namespace { void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void test_real_rank_and_conditions () { const MpfrMatrixStorage a (2, 2, 512, std::vector {"1", "3", "2", "4"}); check (octave_mplapack::mplapack_mpfr_matrix_rank (a) == 2, "real full rank mismatch"); const MpfrScalarStorage zero ("0", 512); check (octave_mplapack::mplapack_mpfr_matrix_rank (a, &zero) == 2, "explicit zero rank tolerance mismatch"); const auto cond2 = octave_mplapack::mplapack_mpfr_matrix_condition ( a, MpfrConditionKind::two); const auto cond1 = octave_mplapack::mplapack_mpfr_matrix_condition ( a, MpfrConditionKind::one); const auto condinf = octave_mplapack::mplapack_mpfr_matrix_condition ( a, MpfrConditionKind::infinity); const auto condfro = octave_mplapack::mplapack_mpfr_matrix_condition ( a, MpfrConditionKind::frobenius); const auto reciprocal = octave_mplapack::mplapack_mpfr_matrix_rcond (a); check (cond2.to_double () > 14.0 && cond2.to_double () < 15.0, "real 2-norm condition mismatch"); check (cond1.to_double () > 20.0 && cond1.to_double () < 22.0, "real 1-norm condition mismatch"); check (condinf.to_double () > 20.0 && condinf.to_double () < 22.0, "real infinity-norm condition mismatch"); check (condfro.to_double () > 14.0 && condfro.to_double () < 16.0, "real Frobenius condition mismatch"); check (reciprocal.to_double () > 0.04 && reciprocal.to_double () < 0.05, "real reciprocal condition mismatch"); check (std::abs (cond1.to_double () * reciprocal.to_double () - 1.0) < 1e-12, "real reciprocal condition is not reciprocal"); } void test_complex_rank_and_conditions () { const MpfrComplexMatrixStorage a ( 2, 2, 512, std::vector {"1+2i", "3", "2-1i", "4+3i"}); check (octave_mplapack::mplapack_mpc_matrix_rank (a) == 2, "complex full rank mismatch"); const auto cond2 = octave_mplapack::mplapack_mpc_matrix_condition ( a, MpfrConditionKind::two); const auto cond1 = octave_mplapack::mplapack_mpc_matrix_condition ( a, MpfrConditionKind::one); const auto condinf = octave_mplapack::mplapack_mpc_matrix_condition ( a, MpfrConditionKind::infinity); const auto condfro = octave_mplapack::mplapack_mpc_matrix_condition ( a, MpfrConditionKind::frobenius); const auto reciprocal = octave_mplapack::mplapack_mpc_matrix_rcond (a); check (cond2.to_double () > 1.0, "complex 2-norm condition mismatch"); check (cond1.to_double () > 1.0, "complex 1-norm condition mismatch"); check (condinf.to_double () > 1.0, "complex infinity-norm condition mismatch"); check (condfro.to_double () > 1.0, "complex Frobenius condition mismatch"); check (reciprocal.to_double () > 0.0 && reciprocal.to_double () < 1.0, "complex reciprocal condition mismatch"); } void test_precision_and_singular_edges () { MpfrMatrixStorage low (2, 2, 512, std::vector {"1", "0", "0", "0"}); mpfr_set_ui_2exp (low.at (1, 1).mpfr_data (), 1, -700, MPFR_RNDN); check (octave_mplapack::mplapack_mpfr_matrix_rank (low) == 1, "512-bit rank canary mismatch"); MpfrMatrixStorage middle (2, 2, 1024, std::vector {"1", "0", "0", "0"}); mpfr_set_ui_2exp (middle.at (1, 1).mpfr_data (), 1, -700, MPFR_RNDN); check (octave_mplapack::mplapack_mpfr_matrix_rank (middle) == 2, "1024-bit rank canary mismatch"); MpfrMatrixStorage high (2, 2, 2048, std::vector {"1", "0", "0", "0"}); mpfr_set_ui_2exp (high.at (1, 1).mpfr_data (), 1, -1500, MPFR_RNDN); check (octave_mplapack::mplapack_mpfr_matrix_rank (high) == 2, "2048-bit rank canary mismatch"); const MpfrMatrixStorage singular ( 2, 2, 512, std::vector {"1", "2", "2", "4"}); const auto cond = octave_mplapack::mplapack_mpfr_matrix_condition ( singular, MpfrConditionKind::two); const auto reciprocal = octave_mplapack::mplapack_mpfr_matrix_rcond ( singular); check (cond.is_infinite (), "singular condition must be infinite"); check (reciprocal.is_zero (), "singular reciprocal condition must be zero"); const MpfrMatrixStorage empty (0, 0, 512); check (octave_mplapack::mplapack_mpfr_matrix_condition ( empty, MpfrConditionKind::two) .is_zero (), "empty condition must be zero"); check (octave_mplapack::mplapack_mpfr_matrix_rcond (empty).is_infinite (), "empty reciprocal condition must be infinite"); } } // namespace int main () { try { test_real_rank_and_conditions (); test_complex_rank_and_conditions (); test_precision_and_singular_edges (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: MPLAPACK MPFR/MPC rank and condition tests\n"; return 0; } mplapack-interop-0.5.1/test/m16_driver_probe.cc0000644000230300031750000002107715274353472020705 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause // M16 rank-revealing MPLAPACK driver comparison probe. #include #include #include #include #include #include #include #include #include namespace { using Real = mpfrxx::mpfr_class; Real at_precision (mpfr_prec_t precision) { return Real::with_precision (precision); } void set_int (Real& value, long source) { mpfr_set_si (value.mpfr_data (), source, MPFR_RNDN); } void set_pow2 (Real& value, long exponent) { mpfr_set_ui_2exp (value.mpfr_data (), 1, exponent, MPFR_RNDN); } mplapackint workspace (std::vector& a, mplapackint m, mplapackint n, mplapackint nrhs, std::vector& b, mplapackint lda, mplapackint ldb, mpfr_prec_t precision, int driver) { Real query = at_precision (precision); Real rcond = at_precision (precision); std::vector s (static_cast (std::max (1, std::min (m, n))), at_precision (precision)); std::vector jpvt (static_cast (std::max (1, n)), 0); std::vector iwork (1024, 0); mplapackint rank = -1; mplapackint info = -1; { MplapackMpfrPrecisionScope scope (precision); const Real epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); if (driver == 0) Rgelsy (m, n, nrhs, a.data (), lda, b.data (), ldb, jpvt.data (), rcond, rank, &query, -1, info); else if (driver == 1) Rgelss (m, n, nrhs, a.data (), lda, b.data (), ldb, s.data (), rcond, rank, &query, -1, info); else Rgelsd (m, n, nrhs, a.data (), lda, b.data (), ldb, s.data (), rcond, rank, &query, -1, iwork.data (), info); } if (info != 0) throw std::runtime_error ("workspace query failed"); if (mpfr_integer_p (query.mpfr_data ()) == 0 || mpfr_sgn (query.mpfr_data ()) <= 0) throw std::runtime_error ("invalid workspace query result"); const auto result = mpfr_get_uj (query.mpfr_data (), MPFR_RNDZ); if (result == 0 || result > static_cast ( std::numeric_limits::max ())) throw std::runtime_error ("workspace query out of range"); return static_cast (result); } void run_driver (int driver, const char *name, mpfr_prec_t precision) { // A = [1 2; 2 4; 3 6], B = [1;2;3], min-norm X = [1/5;2/5]. std::vector a (6, at_precision (precision)); std::vector b (3, at_precision (precision)); for (auto& x : a) set_int (x, 0); set_int (a[0], 1); set_int (a[1], 2); set_int (a[2], 3); set_int (a[3], 2); set_int (a[4], 4); set_int (a[5], 6); set_int (b[0], 1); set_int (b[1], 2); set_int (b[2], 3); auto aq = a; auto bq = b; const mplapackint lwork = workspace (aq, 3, 2, 1, bq, 3, 3, precision, driver); std::vector s (2, at_precision (precision)); std::vector jpvt (2, 0); std::vector iwork (1024, 0); std::vector work (static_cast (lwork), at_precision (precision)); mplapackint rank = -1; mplapackint info = -1; { MplapackMpfrPrecisionScope scope (precision); Real rcond = at_precision (precision); const Real epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); if (driver == 0) Rgelsy (3, 2, 1, a.data (), 3, b.data (), 3, jpvt.data (), rcond, rank, work.data (), lwork, info); else if (driver == 1) Rgelss (3, 2, 1, a.data (), 3, b.data (), 3, s.data (), rcond, rank, work.data (), lwork, info); else Rgelsd (3, 2, 1, a.data (), 3, b.data (), 3, s.data (), rcond, rank, work.data (), lwork, iwork.data (), info); } std::cout << name << " p=" << precision << " rank=" << rank << " info=" << info << " x0=" << mpfr_get_d (b[0].mpfr_data (), MPFR_RNDN) << " x1=" << mpfr_get_d (b[1].mpfr_data (), MPFR_RNDN) << '\n'; } void run_rank_canary (int driver, const char *name, mpfr_prec_t precision) { const long exponent = -700; std::vector a (6, at_precision (precision)); std::vector b (3, at_precision (precision)); for (auto& x : a) set_int (x, 0); for (auto& x : b) set_int (x, 0); set_int (a[0], 1); Real delta = at_precision (precision); set_pow2 (delta, exponent); mpfr_set (a[4].mpfr_data (), delta.mpfr_data (), MPFR_RNDN); mpfr_set (b[1].mpfr_data (), delta.mpfr_data (), MPFR_RNDN); auto aq = a; auto bq = b; const mplapackint lwork = workspace (aq, 3, 2, 1, bq, 3, 3, precision, driver); std::vector s (2, at_precision (precision)); std::vector jpvt (2, 0); std::vector iwork (1024, 0); std::vector work (static_cast (lwork), at_precision (precision)); mplapackint rank = -1; mplapackint info = -1; { MplapackMpfrPrecisionScope scope (precision); Real rcond = at_precision (precision); const Real epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); if (driver == 0) Rgelsy (3, 2, 1, a.data (), 3, b.data (), 3, jpvt.data (), rcond, rank, work.data (), lwork, info); else if (driver == 1) Rgelss (3, 2, 1, a.data (), 3, b.data (), 3, s.data (), rcond, rank, work.data (), lwork, info); else Rgelsd (3, 2, 1, a.data (), 3, b.data (), 3, s.data (), rcond, rank, work.data (), lwork, iwork.data (), info); } std::cout << name << " canary p=" << precision << " rank=" << rank << " info=" << info << " x1exp=" << mpfr_get_exp (b[1].mpfr_data ()) << '\n'; } void run_underdetermined (int driver, const char *name, mpfr_prec_t precision) { // A = [1 2 3; 2 4 6], B = [1;2]. The rank-one minimum-norm // solution is [1/14; 2/14; 3/14]. std::vector a (6, at_precision (precision)); std::vector b (3, at_precision (precision)); set_int (a[0], 1); set_int (a[1], 2); set_int (a[2], 2); set_int (a[3], 4); set_int (a[4], 3); set_int (a[5], 6); set_int (b[0], 1); set_int (b[1], 2); set_int (b[2], 0); auto aq = a; auto bq = b; const mplapackint lwork = workspace (aq, 2, 3, 1, bq, 2, 3, precision, driver); std::vector s (3, at_precision (precision)); std::vector jpvt (3, 0); std::vector iwork (1024, 0); std::vector work (static_cast (lwork), at_precision (precision)); mplapackint rank = -1; mplapackint info = -1; { MplapackMpfrPrecisionScope scope (precision); Real rcond = at_precision (precision); const Real epsilon = Rlamch_mpfr ("E"); mpfr_set (rcond.mpfr_data (), epsilon.mpfr_data (), MPFR_RNDN); if (driver == 0) Rgelsy (2, 3, 1, a.data (), 2, b.data (), 3, jpvt.data (), rcond, rank, work.data (), lwork, info); else if (driver == 1) Rgelss (2, 3, 1, a.data (), 2, b.data (), 3, s.data (), rcond, rank, work.data (), lwork, info); else Rgelsd (2, 3, 1, a.data (), 2, b.data (), 3, s.data (), rcond, rank, work.data (), lwork, iwork.data (), info); } std::cout << name << " under p=" << precision << " rank=" << rank << " info=" << info << " x=" << mpfr_get_d (b[0].mpfr_data (), MPFR_RNDN) << "," << mpfr_get_d (b[1].mpfr_data (), MPFR_RNDN) << "," << mpfr_get_d (b[2].mpfr_data (), MPFR_RNDN) << '\n'; } } // namespace int main () { try { mpfrxx::set_default_precision_bits (128); for (int driver = 0; driver < 3; ++driver) { const char *name = driver == 0 ? "Rgelsy" : driver == 1 ? "Rgelss" : "Rgelsd"; run_driver (driver, name, 1024); run_driver (driver, name, 512); run_underdetermined (driver, name, 1024); run_driver (driver, name, 2048); run_underdetermined (driver, name, 2048); run_rank_canary (driver, name, 512); run_rank_canary (driver, name, 1024); } if (mpfrxx::default_precision_bits () != 128) throw std::runtime_error ("ambient precision was not restored"); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: rank-revealing MPLAPACK MPFR driver comparison probe\n"; return 0; } mplapack-interop-0.5.1/test/test_neigt20.m0000644000230300031750000000510615274353472017711 0ustar rafaelrafael% NEIGT20: finite generalized-pencil reduction and original-pencil binding. test_root = fileparts (fileparts (mfilename ("fullpath"))); private_root = fullfile (test_root, "examples", "neig_tiers", "private"); addpath (private_root); saved_bits = mpbits (); unwind_protect mpbits (128); exact = net_v_a2_model ("real_simple", 6, 128); assert (norm (exact.A_frozen - exact.B_frozen * exact.C_frozen, "fro") == mp (0)); bundle = net_manifest (); profile_data = bundle.jobs.profiles.smoke; real_job = net_v_a2_job (profile_data.jobs{20}, profile_data, "smoke"); complex_job = net_v_a2_job (profile_data.jobs{21}, profile_data, "smoke"); defective_job = net_v_a2_job (profile_data.jobs{22}, profile_data, "smoke"); for item = {real_job, complex_job} current = item{1}; assert (current.pass && current.milestone_pass); assert (strcmp (current.status, "CERTIFIED_ALL_FINITE")); assert (current.B_nonsingular_proof && current.finite_root_coverage); assert (current.finite_root_count == 6); assert (current.residual_accuracy_pass); assert (current.right_residual_norm_upper <= current.residual_target); assert (current.left_residual_norm_upper <= current.residual_target); assert (numel (current.input_hash_A) == 64 && numel (current.input_hash_B) == 64); assert (strcmp (current.reduction_method, ... "proved_solve_reduction_finite_pencil")); endfor assert (defective_job.pass && defective_job.milestone_pass); assert (strcmp (defective_job.claim_status, ... "CERTIFIED_ALL_FINITE_AND_CLUSTER")); assert (defective_job.graph.pass && defective_job.graph.nontrivial); assert (defective_job.cluster.pass); assert (defective_job.original_pencil_graph_encloses_zero); assert (defective_job.finite_root_count == 6); % Singular B and a deliberately useless inverse candidate must fail closed. A = mp (eye (3)); B = A; B(3,3) = mp (0); singular = net_v_a2_reduction (A, B, A, A, 128); assert (! singular.pass); assert (strcmp (singular.status, "INCONCLUSIVE_B_NONSINGULARITY")); B = mp (eye (3)); zero_R = mp (zeros (3)); zero_candidate = net_v_a2_reduction (A, B, zero_R, zero_R, 128); assert (! zero_candidate.pass); assert (zero_candidate.eB >= mp (1)); assert (strcmp (zero_candidate.status, "INCONCLUSIVE_B_NONSINGULARITY")); fprintf ("PASS: NEIGT20 finite pencils, mapped residuals, defective cluster, and fail-closed reductions\n"); unwind_protect_cleanup mpbits (saved_bits); if (any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect mplapack-interop-0.5.1/test/mp_lapack_rgels_test.cc0000644000230300031750000001306215274353472021715 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_lapack.h" #include #include #include #include #include namespace { using octave_mplapack::MpfrMatrixStorage; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } MpfrMatrixStorage make_qr_system (mpfr_prec_t precision, mpfr_exp_t exponent) { MpfrMatrixStorage b (3, 1, precision); Real t = Real::with_precision (precision); mpfr_set_ui_2exp (t.mpfr_data (), 1, exponent, MPFR_RNDN); mpfr_set (b.at (0, 0).mpfr_data (), t.mpfr_data (), MPFR_RNDN); mpfr_set_ui (b.at (1, 0).mpfr_data (), 1, MPFR_RNDN); mpfr_sub (b.at (1, 0).mpfr_data (), b.at (1, 0).mpfr_data (), t.mpfr_data (), MPFR_RNDN); mpfr_set_ui (b.at (2, 0).mpfr_data (), 4, MPFR_RNDN); return b; } MpfrMatrixStorage make_qr_matrix (mpfr_prec_t precision) { return MpfrMatrixStorage (3, 2, precision, std::vector {"1", "0", "1", "0", "1", "1"}); } MpfrMatrixStorage make_lq_matrix (mpfr_prec_t precision) { return MpfrMatrixStorage (2, 3, precision, std::vector {"1", "0", "0", "1", "1", "1"}); } MpfrMatrixStorage make_lq_system (mpfr_prec_t precision, mpfr_exp_t exponent) { MpfrMatrixStorage b (2, 1, precision); Real t = Real::with_precision (precision); mpfr_set_ui_2exp (t.mpfr_data (), 1, exponent, MPFR_RNDN); mpfr_set_ui (b.at (0, 0).mpfr_data (), 3, MPFR_RNDN); Real three_t = Real::with_precision (precision); mpfr_mul_ui (three_t.mpfr_data (), t.mpfr_data (), 3, MPFR_RNDN); mpfr_add (b.at (0, 0).mpfr_data (), b.at (0, 0).mpfr_data (), three_t.mpfr_data (), MPFR_RNDN); mpfr_set_ui (b.at (1, 0).mpfr_data (), 3, MPFR_RNDN); return b; } void check_tail (const Real& value, unsigned long base, long exponent, const char *message) { Real one = Real::with_precision (value.precision ()); mpfr_set_ui (one.mpfr_data (), base, MPFR_RNDN); Real difference = Real::with_precision (value.precision ()); mpfr_sub (difference.mpfr_data (), value.mpfr_data (), one.mpfr_data (), MPFR_RNDN); check (mpfr_zero_p (difference.mpfr_data ()) == 0, message); const mpfr_exp_t observed = mpfr_get_exp (difference.mpfr_data ()); check (std::abs (observed - static_cast (exponent)) <= 3, message); } void test_qr_and_lq (mpfr_prec_t precision, mpfr_exp_t exponent) { mpfrxx::set_default_precision_bits (128); const auto qr_a = make_qr_matrix (precision); const auto qr_b = make_qr_system (precision, exponent); const auto qr_x = octave_mplapack::mplapack_mpfr_matrix_rectangular_solve (qr_a, qr_b); check (qr_x.rows () == 2 && qr_x.columns () == 1, "overdetermined shape mismatch"); check (qr_x.precision_bits () == precision, "overdetermined precision mismatch"); check_tail (qr_x.at (0, 0), 1, exponent, "overdetermined first tail lost"); check_tail (qr_x.at (1, 0), 2, exponent, "overdetermined second tail lost"); check (mpfrxx::default_precision_bits () == 128, "overdetermined scope leaked"); const auto lq_a = make_lq_matrix (precision); const auto lq_b = make_lq_system (precision, exponent); const auto lq_x = octave_mplapack::mplapack_mpfr_matrix_rectangular_solve (lq_a, lq_b); check (lq_x.rows () == 3 && lq_x.columns () == 1, "underdetermined shape mismatch"); check (lq_x.precision_bits () == precision, "underdetermined precision mismatch"); check_tail (lq_x.at (0, 0), 1, exponent, "underdetermined first tail lost"); check_tail (lq_x.at (1, 0), 1, exponent, "underdetermined second tail lost"); check_tail (lq_x.at (2, 0), 2, exponent, "underdetermined third tail lost"); check (mpfrxx::default_precision_bits () == 128, "underdetermined scope leaked"); } void test_mixed_precision () { const auto a = make_qr_matrix (256); const auto b = make_qr_system (1024, -700); const auto x = octave_mplapack::mplapack_mpfr_matrix_rectangular_solve (a, b); check (x.precision_bits () == 1024, "mixed rectangular precision mismatch"); const auto reverse = octave_mplapack::mplapack_mpfr_matrix_rectangular_solve ( make_qr_matrix (1024), make_qr_system (256, -100)); check (reverse.precision_bits () == 1024, "reverse mixed rectangular precision mismatch"); } void test_empty () { const MpfrMatrixStorage a (2, 0, 256); const MpfrMatrixStorage b (2, 3, 1024); const auto x = octave_mplapack::mplapack_mpfr_matrix_rectangular_solve (a, b); check (x.rows () == 0 && x.columns () == 3 && x.precision_bits () == 1024, "empty Mx0 shape/precision mismatch"); const MpfrMatrixStorage a0 (0, 2, 256); const MpfrMatrixStorage b0 (0, 1, 256); const auto x0 = octave_mplapack::mplapack_mpfr_matrix_rectangular_solve (a0, b0); check (x0.rows () == 2 && x0.columns () == 1, "empty 0xN shape mismatch"); check (mpfr_zero_p (x0.at (0, 0).mpfr_data ()) != 0 && mpfr_zero_p (x0.at (1, 0).mpfr_data ()) != 0, "empty 0xN solution not zero"); } } // namespace int main () { try { test_qr_and_lq (1024, -700); test_qr_and_lq (2048, -1500); test_mixed_precision (); test_empty (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: MPLAPACK MPFR Rgels rectangular solve tests\n"; return 0; } mplapack-interop-0.5.1/test/t02_matrix_functions.tst0000644000230300031750000000367315274353472022050 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! Z = mp ({'0','0';'0','0'}); %! assert (double (norm (expm (Z)-eye (2, "like", Z), "fro")) < 1e-50); %! D = mp ({'1','0';'0','2'}); %! ED = expm (D); %! assert (double (ED(1,1)-exp (mp ('1'))) < 1e-50); %! assert (double (ED(2,2)-exp (mp ('2'))) < 1e-50); %! SD = sqrtm (D); %! assert (double (norm (SD*SD-D, "fro")) < 1e-50); %! [SD, sqrt_error] = sqrtm (D); %! assert (double (sqrt_error) < 1e-50); %! LD = logm (D); %! assert (double (norm (expm (LD)-D, "fro")) < 1e-45); %! A = mp ({'0','1';'-2','-3'}); %! EA = expm (A); %! assert (double (norm (EA*expm (-A)-eye (2, "like", EA), "fro")) < 1e-45); %! C1 = mp ({'1','0';'0','2'}); %! C2 = mp ({'3','0';'0','4'}); %! assert (double (norm (expm (C1+C2)-expm (C1)*expm (C2), "fro")) < 1e-45); %! N = mp ({'1','10';'0','1'}); %! EN = expm (N); %! assert (double (EN(1,1)-exp (mp ('1'))) < 1e-45); %! assert (double (EN(1,2)-mp ('10')*exp (mp ('1'))) < 1e-45); %! MN = mp ({'-1','0';'0','4'}); %! SMN = sqrtm (MN); %! assert (double (norm (SMN*SMN-MN, "fro")) < 1e-45); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for bits = [1024, 2048] %! mpbits (bits); %! limit = 1500; %! if (bits == 1024), limit = 700; endif %! tiny = mp ('1'); %! for k = 1:limit, tiny = tiny * mp ('0.5'); endfor %! A = mp ({'0','0';'0','0'}); %! A(1,1) = tiny; %! A(2,2) = -tiny; %! E = expm (A); %! assert (double (norm (E*expm (-A)-eye (2, "like", E), "fro")) < 1e-12); %! assert (__mplapack_core__ ("matrix_test_info", E).precision_bits == uint64 (bits)); %! L = logm (mp ({'1','0';'0','2'})); %! assert (__mplapack_core__ ("matrix_test_info", L).precision_bits == uint64 (bits)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/complex_gesv.tst0000644000230300031750000000632015274353472020452 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_solve_info (value, expected_rows, expected_columns, ... %! expected_precision) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (expected_rows)); %! assert (info.columns, uint64 (expected_columns)); %! assert (info.precision_bits, uint64 (expected_precision)); %! assert (info.is_complex && info.all_elements_same_precision); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([3 + 1i, 1 - 1i; 2 + 0i, 4 + 2i]); %! B = mp ([4 + 4i, 10 + 4i; 14 + 10i, -8 + 12i]); %! A_before = double (A); %! B_before = double (B); %! X = A \ B; %! assert_solve_info (X, 2, 2, 512); %! assert (double (X), [1 + 2i, 2 - 1i; 3 + 0i, -1 + 4i], 1e-12); %! assert (! isreal (X)); %! assert (double (A), A_before); %! assert (double (B), B_before); %! clear A B; %! assert (double (X), [1 + 2i, 2 - 1i; 3 + 0i, -1 + 4i], 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([3, 1; 2, 4]); %! mpbits (512); %! B = mp ([6 + 6i, 5 + 1i; 14 + 4i, 0 + 14i]); %! mpbits (1024); %! X = A \ B; %! assert_solve_info (X, 2, 2, 512); %! assert (double (X), [1 + 2i, 2 - 1i; 3 + 0i, -1 + 4i], 1e-12); %! assert (mpbits (), uint64 (1024)); %! builtin_rhs = [6 + 6i; 14 + 4i]; %! builtin_solution = A \ builtin_rhs; %! assert_solve_info (builtin_solution, 2, 1, 256); %! assert (double (builtin_solution), [1 + 2i; 3 + 0i], 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! A = mp (complex (eye (2), zeros (2))); %! B = mp (complex (zeros (2, 1), zeros (2, 1))); %! tail = mp ("1", "-1"); %! for k = 1:exponent %! tail = tail ./ mp ("2"); %! endfor %! B(1, 1) = tail; %! B(2, 1) = tail; %! mpbits (128); %! X = A \ B; %! assert_solve_info (X, 2, 1, precision); %! assert (strcmp (char (X(1, 1)), char (tail))); %! assert (strcmp (char (X(2, 1)), char (tail))); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! singular = mp ([1 + 0i, 2 + 0i; 2 + 0i, 4 + 0i]); %! rhs = mp ([1 + 0i; 2 + 0i]); %! caught = false; %! try %! singular \ rhs; %! catch exception %! caught = true; %! assert (strcmp (exception.identifier, "mplapack:mp:SingularMatrix")); %! end_try_catch %! assert (caught); %! nonsquare = mp (complex (ones (2, 1), zeros (2, 1))); %! nonsquare_solution = nonsquare \ rhs; %! assert (__mplapack_core__ ("scalar_test_info", nonsquare_solution).precision_bits == 256); %! assert (__mplapack_core__ ("scalar_test_info", nonsquare_solution).is_complex); %! assert (double (nonsquare_solution), 1.5, 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/arithmetic.tst0000644000230300031750000002607015274353472020114 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function info = m06_info (value) %! info = __mplapack_core__ ("scalar_test_info", value); %!endfunction %!function m06_expect_binary_error (operation, lhs, rhs, identifier) %! try %! switch (operation) %! case "plus" %! plus (lhs, rhs); %! case "minus" %! minus (lhs, rhs); %! case "times" %! times (lhs, rhs); %! case "rdivide" %! rdivide (lhs, rhs); %! otherwise %! error ("unknown M06 test operation"); %! endswitch %! error ("M06 operation unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, ... %! "M06 operation unexpectedly succeeded")); %! assert (strcmp (exception.identifier, identifier)); %! end_try_catch %!endfunction %!function m06_assert_equal (lhs, rhs) %! assert (__mplapack_core__ ("scalar_test_equal", lhs, rhs)); %!endfunction %!function m06_assert_equal_text (value, text) %! assert (__mplapack_core__ ("scalar_test_equal_string", value, text)); %!endfunction %!function m06_expect_error (operation, identifier) %! try %! operation (); %! error ("M06 operation unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, ... %! "M06 operation unexpectedly succeeded")); %! if (! isempty (identifier)) %! assert (strcmp (exception.identifier, identifier)); %! endif %! end_try_catch %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! a = mp ("0.125"); %! b = mp ("0.25"); %! a_text = char (a); %! b_text = char (b); %! default_before = mpbits (); %! sum_value = a + b; %! difference = b - a; %! product = a .* b; %! quotient = b ./ a; %! assert (strcmp (class (sum_value), "mp")); %! m06_assert_equal_text (sum_value, "0.375"); %! m06_assert_equal_text (difference, "0.125"); %! m06_assert_equal_text (product, "0.03125"); %! m06_assert_equal_text (quotient, "2"); %! assert (m06_info (sum_value).precision_bits, int64 (128)); %! assert (char (a), a_text); %! assert (char (b), b_text); %! assert (mpbits (), default_before); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! a128 = mp ("0.125"); %! mpbits (256); %! b256 = mp ("0.25"); %! mpbits (512); %! c512 = mp ("0.5"); %! mpbits (4096); %! operations = {a128 + b256, b256 + a128, ... %! a128 - b256, b256 - a128, ... %! a128 .* c512, c512 .* a128, ... %! c512 ./ b256, b256 ./ c512}; %! expected_precision = int64 ([256, 256, 256, 256, ... %! 512, 512, 512, 512]); %! expected_text = {"0.375", "0.375", "-0.125", "0.125", ... %! "0.0625", "0.0625", "2", "0.5"}; %! for i = 1:numel (operations) %! assert (m06_info (operations{i}).precision_bits, ... %! expected_precision(i)); %! m06_assert_equal_text (operations{i}, expected_text{i}); %! endfor %! assert (m06_info (a128).precision_bits, int64 (128)); %! assert (m06_info (b256).precision_bits, int64 (256)); %! assert (m06_info (c512).precision_bits, int64 (512)); %! assert (mpbits (), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! lhs = mp ("0.1"); %! mpbits (256); %! rhs = mp ("0.2"); %! mpbits (4096); %! first = {lhs + rhs, lhs - rhs, lhs .* rhs, lhs ./ rhs}; %! mpbits (32); %! second = {lhs + rhs, lhs - rhs, lhs .* rhs, lhs ./ rhs}; %! for i = 1:numel (first) %! assert (m06_info (first{i}).precision_bits, int64 (256)); %! assert (m06_info (second{i}).precision_bits, int64 (256)); %! m06_assert_equal (first{i}, second{i}); %! text = char (first{i}); %! mpbits (256); %! round_trip = mp (text); %! m06_assert_equal (first{i}, round_trip); %! mpbits (32); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! value = mp ("1.25"); %! mpbits (4096); %! results = {value + 0.5, 0.5 + value, ... %! value - 0.5, 0.5 - value, ... %! value .* 0.5, 0.5 .* value, ... %! value ./ 0.5, 0.5 ./ value}; %! expected = {"1.75", "1.75", "0.75", "-0.75", ... %! "0.625", "0.625", "2.5", "0.4"}; %! for i = 1:numel (results) %! assert (strcmp (class (results{i}), "mp")); %! assert (m06_info (results{i}).precision_bits, int64 (128)); %! m06_assert_equal_text (results{i}, expected{i}); %! endfor %! first = value + 0.1; %! mpbits (32); %! second = value + 0.1; %! m06_assert_equal (first, second); %! assert (m06_info (first).precision_bits, int64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! base = mp ("1"); %! decimal_result = base + mp ("0.1"); %! binary64_result = base + 0.1; %! assert (! __mplapack_core__ ( %! "scalar_test_equal", decimal_result, binary64_result)); %! dyadic_text = base + mp ("0.125"); %! dyadic_double = base + 0.125; %! m06_assert_equal (dyadic_text, dyadic_double); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2); %! lhs = mp ("1"); %! rhs = mp ("0.25"); %! tied = lhs + rhs; %! assert (m06_info (tied).precision_bits, int64 (2)); %! m06_assert_equal_text (tied, "1"); %! for bits = [2, 8, 32] %! mpbits (bits); %! a = mp ("0.1"); %! b = mp ("0.2"); %! values = {a + b, a - b, a .* b, a ./ b}; %! for i = 1:numel (values) %! assert (m06_info (values{i}).precision_bits, int64 (bits)); %! text = char (values{i}); %! m06_assert_equal (values{i}, mp (text)); %! endfor %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (333); %! finite = mp ("1.5"); %! positive_zero = mp (0.0); %! negative_zero = mp (-0.0); %! positive_infinity = mp (Inf); %! negative_infinity = mp (-Inf); %! not_a_number = mp (NaN); %! positive = +finite; %! negative = -finite; %! m06_assert_equal (positive, finite); %! m06_assert_equal_text (negative, "-1.5"); %! assert (m06_info (positive).precision_bits, int64 (333)); %! assert (m06_info (negative).precision_bits, int64 (333)); %! assert (m06_info (-positive_zero).is_zero); %! assert (m06_info (-positive_zero).signbit); %! assert (m06_info (-negative_zero).is_zero); %! assert (! m06_info (-negative_zero).signbit); %! assert (m06_info (-positive_infinity).is_infinite); %! assert (m06_info (-positive_infinity).signbit); %! assert (m06_info (-negative_infinity).is_infinite); %! assert (! m06_info (-negative_infinity).signbit); %! assert (m06_info (-not_a_number).is_nan); %! alias = +finite; %! clear finite; %! m06_assert_equal_text (alias, "1.5"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! one = mp ("1"); %! negative_one = mp ("-1"); %! positive_zero = mp (0.0); %! negative_zero = mp (-0.0); %! positive_infinity = mp (Inf); %! negative_infinity = mp (-Inf); %! not_a_number = mp (NaN); %! assert (m06_info (positive_infinity + one).is_infinite); %! assert (m06_info (positive_infinity + negative_infinity).is_nan); %! assert (m06_info (not_a_number + one).is_nan); %! assert (m06_info (not_a_number - one).is_nan); %! assert (m06_info (positive_infinity - positive_infinity).is_nan); %! assert (m06_info (positive_infinity - negative_infinity).is_infinite); %! assert (m06_info (one - positive_infinity).is_infinite); %! assert (m06_info (one - positive_infinity).signbit); %! assert (m06_info (one .* positive_infinity).is_infinite); %! assert (m06_info (positive_zero .* positive_infinity).is_nan); %! assert (m06_info (not_a_number .* one).is_nan); %! assert (m06_info (not_a_number ./ one).is_nan); %! result = one ./ positive_zero; %! assert (m06_info (result).is_infinite && ! m06_info (result).signbit); %! result = one ./ negative_zero; %! assert (m06_info (result).is_infinite && m06_info (result).signbit); %! result = negative_one ./ positive_zero; %! assert (m06_info (result).is_infinite && m06_info (result).signbit); %! result = negative_one ./ negative_zero; %! assert (m06_info (result).is_infinite && ! m06_info (result).signbit); %! assert (m06_info (positive_zero ./ positive_zero).is_nan); %! result = one ./ positive_infinity; %! assert (m06_info (result).is_zero && ! m06_info (result).signbit); %! assert (m06_info (positive_infinity ./ positive_infinity).is_nan); %! assert (m06_info (positive_infinity ./ one).is_infinite); %! result = positive_zero + negative_zero; %! assert (m06_info (result).is_zero && ! m06_info (result).signbit); %! result = negative_zero + negative_zero; %! assert (m06_info (result).is_zero && m06_info (result).signbit); %! result = positive_zero - positive_zero; %! assert (m06_info (result).is_zero && ! m06_info (result).signbit); %! result = negative_zero - positive_zero; %! assert (m06_info (result).is_zero && m06_info (result).signbit); %! result = negative_zero .* one; %! assert (m06_info (result).is_zero && m06_info (result).signbit); %! result = negative_zero .* negative_one; %! assert (m06_info (result).is_zero && ! m06_info (result).signbit); %!test %! a = mp ("1"); %! unsupported_id = "mplapack:mp:UnsupportedOperand"; %! single_value = ones (1, 1, "single"); %! int8_value = ones (1, 1, "int8"); %! uint64_value = ones (1, 1, "uint64"); %! values = {single_value, int8_value, uint64_value, true}; %! operations = {"plus", "minus", "times", "rdivide"}; %! for i = 1:numel (operations) %! for j = 1:numel (values) %! operand = values{j}; %! m06_expect_binary_error ( %! operations{i}, a, operand, unsupported_id); %! m06_expect_binary_error ( %! operations{i}, operand, a, unsupported_id); %! endfor %! endfor %! m06_expect_binary_error ("plus", a, cell (1, 1), unsupported_id); %! m06_expect_binary_error ("plus", cell (1, 1), a, unsupported_id); %! m06_expect_binary_error ("plus", a, struct (), unsupported_id); %! m06_expect_binary_error ("plus", struct (), a, unsupported_id); %!test %! a = mp ("1"); %! b = mp ("2"); %! supported = {@() a ^ b, @() a .^ b, @() sin (a), ... %! @() exp (a), @() sqrt (a)}; %! for i = 1:numel (supported) %! assert (isa (supported{i} (), "mp")); %! endfor %! assert (a == b, false); %! assert (a ~= b, true); %! assert (a < b, true); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! a = mp ("1.25"); %! b = mp ("0.5"); %! result = a + b; %! expected_text = char (result); %! assert (double (result), 1.75); %! assert (evalc ("disp (result)"), [expected_text, "\n"]); %! round_trip = mp (expected_text); %! m06_assert_equal (result, round_trip); %! clear a b; %! m06_assert_equal_text (result, "1.75"); %! assigned = result; %! clear result; %! m06_assert_equal_text (assigned, "1.75"); %! assert (mpbits (), uint64 (512)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/m20_complex_probe.cc0000644000230300031750000002054115274353472021047 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include #include #include #include #include #include namespace { using Real = mpfrxx::mpfr_class; using Complex = mpfrxx::mpc_class; static_assert (std::is_same_v ().mpc_data ()), mpc_t&>); static_assert (sizeof (Complex) == sizeof (mpc_t)); static_assert (alignof (Complex) == alignof (mpc_t)); void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } Real real_at (mpfr_prec_t precision) { return Real::with_precision (precision); } Complex complex_at (mpfr_prec_t precision) { return Complex::with_precision (precision); } void set_ui (Real& value, unsigned long number) { mpfr_set_ui (value.mpfr_data (), number, MPFR_RNDN); } void set_power (Real& value, mpfr_exp_t exponent) { mpfr_set_ui_2exp (value.mpfr_data (), 1, exponent, MPFR_RNDN); } Complex make_complex (mpfr_prec_t precision, unsigned long real_number, mpfr_exp_t imag_exponent) { Real real = real_at (precision); Real imag = real_at (precision); set_ui (real, real_number); set_power (imag, imag_exponent); return Complex (real, imag); } void check_equal (const Complex& lhs, const Complex& rhs, const char *message) { check (mpfr_equal_p (mpc_realref (lhs.mpc_data ()), mpc_realref (rhs.mpc_data ())) != 0 && mpfr_equal_p (mpc_imagref (lhs.mpc_data ()), mpc_imagref (rhs.mpc_data ())) != 0, message); } void check_precision (const Complex& value, mpfr_prec_t precision, const char *message) { check (value.real_precision () == precision && value.imag_precision () == precision, message); } void run_basic_backend (mpfr_prec_t precision, mpfr_exp_t tail_exponent) { const Complex one_tail = make_complex (precision, 1, tail_exponent); const Complex identity = Complex::with_precision (precision, 1.0, 0.0); const Complex zero = Complex::with_precision (precision, 0.0, 0.0); check_precision (one_tail, precision, "complex component precision mismatch"); check (one_tail.real_precision () == one_tail.imag_precision (), "complex object has mixed component precision"); // Cgemm: identity multiplication must preserve both MPFR component tails. std::vector a (1, one_tail), b (1, identity), c (1, zero); { MplapackMpfrPrecisionScope scope (precision); Cgemm ("N", "N", 1, 1, 1, identity, a.data (), 1, b.data (), 1, zero, c.data (), 1); } check_equal (c[0], one_tail, "complex Cgemm identity lost tail"); check_precision (c[0], precision, "Cgemm result precision mismatch"); // Cgesv: one-by-one complex solve. std::vector as (1, identity), bs (1, Complex::with_precision (precision, 2.0, 0.0)); mplapackint pivot = 0; mplapackint info = 0; { MplapackMpfrPrecisionScope scope (precision); as[0] = Complex::with_precision (precision, 2.0, 0.0); Cgesv (1, 1, as.data (), 1, &pivot, bs.data (), 1, info); } check (info == 0, "complex Cgesv failed"); check_equal (bs[0], identity, "complex Cgesv result mismatch"); // Cpotrf: one-by-one positive definite factorization. std::vector ap (1, Complex::with_precision (precision, 4.0, 0.0)); info = 0; { MplapackMpfrPrecisionScope scope (precision); Cpotrf ("U", 1, ap.data (), 1, info); } check (info == 0, "complex Cpotrf failed"); check_equal (ap[0], Complex::with_precision (precision, 2.0, 0.0), "complex Cpotrf result mismatch"); // Cgeqrf/Cungqr: exercise both QR entry points and their workspaces. std::vector aq (1, one_tail), tau (1, complex_at (precision)); std::vector query (1, complex_at (precision)); info = 0; { MplapackMpfrPrecisionScope scope (precision); Cgeqrf (1, 1, aq.data (), 1, tau.data (), query.data (), -1, info); } check (info == 0 && mpfr_integer_p (mpc_realref (query[0].mpc_data ())) != 0, "complex Cgeqrf workspace query failed"); const mplapackint lwork = static_cast ( mpfr_get_si (mpc_realref (query[0].mpc_data ()), MPFR_RNDZ)); check (lwork > 0, "complex Cgeqrf workspace length invalid"); aq[0] = one_tail; tau[0] = complex_at (precision); std::vector work (static_cast (lwork), complex_at (precision)); { MplapackMpfrPrecisionScope scope (precision); Cgeqrf (1, 1, aq.data (), 1, tau.data (), work.data (), lwork, info); } check (info == 0, "complex Cgeqrf failed"); std::vector qquery (1, complex_at (precision)); { MplapackMpfrPrecisionScope scope (precision); Cungqr (1, 1, 1, aq.data (), 1, tau.data (), qquery.data (), -1, info); } check (info == 0 && mpfr_integer_p (mpc_realref (qquery[0].mpc_data ())) != 0, "complex Cungqr workspace query failed"); const mplapackint qwork_length = static_cast ( mpfr_get_si (mpc_realref (qquery[0].mpc_data ()), MPFR_RNDZ)); check (qwork_length > 0, "complex Cungqr workspace length invalid"); std::vector qwork (static_cast (qwork_length), complex_at (precision)); { MplapackMpfrPrecisionScope scope (precision); Cungqr (1, 1, 1, aq.data (), 1, tau.data (), qwork.data (), qwork_length, info); } check (info == 0, "complex Cungqr failed"); check_precision (aq[0], precision, "complex Cungqr precision mismatch"); } void run_thread_probe () { mpfrxx::set_default_precision_bits (128); const auto main_before = mpfrxx::default_precision_bits (); std::atomic worker_ok (false); std::thread worker ([&] { mpfrxx::set_default_precision_bits (2048); const Complex value; worker_ok.store (value.real_precision () == 2048 && value.imag_precision () == 2048 && mpfrxx::default_precision_bits () == 2048, std::memory_order_release); }); worker.join (); check (worker_ok.load (std::memory_order_acquire), "complex worker precision was not independent"); check (main_before == 128 && mpfrxx::default_precision_bits () == 128, "complex worker changed main-thread precision"); } void run_special_value_probe () { const mpfr_prec_t precision = 256; Real plus_zero = real_at (precision); Real minus_zero = real_at (precision); mpfr_set_zero (plus_zero.mpfr_data (), 0); // MPFR uses a negative sign value for negative zero; +1 is positive. mpfr_set_zero (minus_zero.mpfr_data (), -1); const Complex signed_zero (plus_zero, minus_zero); const Complex signed_zero_copy (signed_zero); check (mpfr_zero_p (mpc_realref (signed_zero_copy.mpc_data ())) != 0 && mpfr_zero_p (mpc_imagref (signed_zero_copy.mpc_data ())) != 0 && mpfr_signbit (mpc_imagref (signed_zero_copy.mpc_data ())) != 0, "complex signed zero value was not preserved by copy"); const bool imaginary_negative_zero_preserved = mpfr_signbit (mpc_imagref (signed_zero_copy.mpc_data ())) != 0; std::cout << "INFO: complex copy preserves imaginary negative zero: " << (imaginary_negative_zero_preserved ? "yes" : "no") << '\n'; Real infinity = real_at (precision); Real nan = real_at (precision); mpfr_set_inf (infinity.mpfr_data (), 1); mpfr_set_nan (nan.mpfr_data ()); const Complex special (infinity, nan); const Complex special_copy (special); check (mpfr_inf_p (mpc_realref (special_copy.mpc_data ())) != 0 && mpfr_nan_p (mpc_imagref (special_copy.mpc_data ())) != 0, "complex Inf/NaN state was not preserved by copy"); } } // namespace int main () { try { mpfrxx::set_default_precision_bits (128); const Complex default_value; check_precision (default_value, 128, "default complex precision mismatch"); run_basic_backend (1024, -700); run_basic_backend (2048, -1500); run_special_value_probe (); run_thread_probe (); check (mpfrxx::default_precision_bits () == 128, "complex probe leaked ambient precision"); } catch (const std::exception& error) { std::cerr << "FAIL: " << error.what () << '\n'; return 1; } std::cout << "PASS: installed MPLAPACK MPFR complex type/backend precision probe\n"; return 0; } mplapack-interop-0.5.1/test/matrix_inspection.tst0000644000230300031750000001301015274353472021510 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_matrix_text (value, expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! value, row, column, expected{row, column})); %! endfor %! endfor %!endfunction %!test %! A = mp ({"11", "12", "13"; "21", "22", "23"; ... %! "31", "32", "33"; "41", "42", "43"}); %! assert (char (A(3, 2)), "3.2e+1"); %! assert_matrix_text (A(:, 3), {"13"; "23"; "33"; "43"}); %! assert_matrix_text (A(4, :), {"41", "42", "43"}); %! assert_matrix_text (A(1:2, 2:3), {"12", "13"; "22", "23"}); %! assert_matrix_text (A([4, 1], [3, 1]), ... %! {"43", "41"; "13", "11"}); %! assert_matrix_text (A([2, 2, 1], [3, 3]), ... %! {"23", "23"; "23", "23"; "13", "13"}); %! assert_matrix_text (A([], :), cell (0, 3)); %! assert_matrix_text (A(:, []), cell (4, 0)); %!test %! A = mp ({"11", "12", "13"; "21", "22", "23"; ... %! "31", "32", "33"; "41", "42", "43"}); %! assert (char (A(6)), "2.2e+1"); %! assert_matrix_text (A(:), {"11"; "21"; "31"; "41"; ... %! "12"; "22"; "32"; "42"; ... %! "13"; "23"; "33"; "43"}); %! assert (char (A(end)), "4.3e+1"); %! assert (char (A(end, 1)), "4.1e+1"); %! assert (char (A(1, end)), "1.3e+1"); %! assert_matrix_text (A(:, end), {"13"; "23"; "33"; "43"}); %! assert_matrix_text (A(end, :), {"41", "42", "43"}); %! assert_matrix_text (A(end-1:end, 1:end), ... %! {"31", "32", "33"; "41", "42", "43"}); %! assert (char (A(:, 2)(1)), "1.2e+1"); %!test %! A = mp ({"1", "2"; "3", "4"}); %! invalid = {@() A(0, 1), @() A(-1, 1), @() A(1.5, 1), ... %! @() A(NaN, 1), @() A(Inf, 1), @() A(3, 1), ... %! @() A(1, 3), @() A(1, 1, 1)}; %! for i = 1:numel (invalid) %! try %! invalid{i} (); %! error ("invalid indexing unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, ... %! "invalid indexing unexpectedly succeeded")); %! end_try_catch %! endfor %! A(1, 1) = mp ("5"); %! assert (char (A(1, 1)), "5e+0"); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! tail = strcat ("1.", repmat ("0", 1, 210), "1"); %! A = mp ({"1", "2"; "3", tail}); %! mpbits (128); %! x = A(2, 2); %! column = A(:, 2); %! assert (__mplapack_core__ ("scalar_test_info", x).precision_bits, ... %! int64 (1024)); %! assert (__mplapack_core__ ("matrix_test_info", column).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("scalar_test_equal_string", x, tail)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! column, 2, 1, tail)); %! assert (mpbits (), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2048); %! tail = strcat ("1.", repmat ("0", 1, 450), "1"); %! A = mp ({tail, "0"}); %! mpbits (128); %! x = A(1, 1); %! assert (__mplapack_core__ ("scalar_test_info", x).precision_bits, ... %! int64 (2048)); %! assert (__mplapack_core__ ("scalar_test_equal_string", x, tail)); %! assert (mpbits (), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"0.1", "0.125"; "-0", "Inf"}); %! mpbits (4096); %! D = double (A); %! assert (isa (D, "double")); %! assert (size (D), [2, 2]); %! assert (typecast (D(2, 1), "uint64"), typecast (-0.0, "uint64")); %! assert (D(1, 2), 0.125); %! assert (isinf (D(2, 2)) && D(2, 2) > 0); %! assert (D(1, 1), 0.1); %! assert (mpbits (), uint64 (4096)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (4096)); %! special = mp ([-Inf, NaN]); %! special_double = double (special); %! assert (isinf (special_double (1, 1)) && special_double (1, 1) < 0); %! assert (isnan (special_double (1, 2))); %! empty = mp (zeros (0, 3)); %! assert (size (double (empty)), [0, 3]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! A = mp ({"11", "12"; "21", "22"}); %! expected = "[1.1e+1 1.2e+1\n 2.1e+1 2.2e+1]"; %! mpbits (128); %! format short; %! short_output = strtrim (evalc ("disp (A)")); %! format long; %! long_output = strtrim (evalc ("disp (A)")); %! assert (short_output, expected); %! assert (long_output, expected); %! assert (isempty (strfind (short_output, "payload_"))); %! assert (mpbits (), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! empty_output = strtrim (evalc ("disp (mp (zeros (0, 3)))")); %! assert (empty_output, "mp 0x3 matrix []"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({"1", "2"; "3", "4"}); %! B = A(:, 1); %! clear A; %! assert (char (B(2)), "3e+0"); %! x = B * mp ("2"); %! assert (char (x(1)), "2e+0"); %! S = mp ({"3", "1"; "1", "2"}); %! rhs = mp ({"9"; "8"}); %! solution = S \ rhs; %! assert (char (solution(2)), "3e+0"); %!error char (mp ([1, 2])) mplapack-interop-0.5.1/test/mp_lapack_lu_test.cc0000644000230300031750000002232215274353472021220 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_lapack.h" #include #include #include #include #include #include namespace { using octave_mplapack::MpfrLuResult; using octave_mplapack::MpfrMatrixStorage; using Real = mpfrxx::mpfr_class; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } MpfrMatrixStorage matrix (std::size_t rows, std::size_t columns, mpfr_prec_t precision, std::initializer_list values) { return MpfrMatrixStorage (rows, columns, precision, std::vector (values.begin (), values.end ())); } void check_fraction (const Real& value, unsigned long numerator, unsigned long denominator, mpfr_prec_t precision, const char *message) { Real expected = Real::with_precision (precision); mpfr_set_ui (expected.mpfr_data (), numerator, MPFR_RNDN); mpfr_div_ui (expected.mpfr_data (), expected.mpfr_data (), denominator, MPFR_RNDN); Real difference = Real::with_precision (precision); mpfr_sub (difference.mpfr_data (), value.mpfr_data (), expected.mpfr_data (), MPFR_RNDN); mpfr_abs (difference.mpfr_data (), difference.mpfr_data (), MPFR_RNDN); Real tolerance = Real::with_precision (precision); mpfr_set_ui_2exp (tolerance.mpfr_data (), 1, -static_cast (precision * 3 / 4), MPFR_RNDN); check (mpfr_cmp (difference.mpfr_data (), tolerance.mpfr_data ()) < 0, message); } bool same (const MpfrMatrixStorage& lhs, const MpfrMatrixStorage& rhs) { if (lhs.rows () != rhs.rows () || lhs.columns () != rhs.columns () || lhs.precision_bits () != rhs.precision_bits ()) return false; for (std::size_t index = 0; index < lhs.numel (); ++index) if (mpfr_equal_p (lhs.data ()[index].mpfr_data (), rhs.data ()[index].mpfr_data ()) == 0) return false; return true; } void check_permutation (const MpfrLuResult& result, std::initializer_list expected) { check (result.permutation.size () == expected.size (), "LU permutation length mismatch"); std::size_t index = 0; for (const auto value : expected) { check (result.permutation[index++] == value, "LU permutation value mismatch"); } } void test_square_and_rectangular_shapes () { const auto square = matrix (2, 2, 256, {"1", "3", "2", "4"}); const auto result = octave_mplapack::mplapack_mpfr_matrix_lu (square); check (result.info == 0, "square LU unexpectedly failed"); check_permutation (result, {2, 1}); check (result.packed.rows () == 2 && result.packed.columns () == 2, "packed square LU shape mismatch"); check (result.packed.element_exactly_equal_text (0, 0, "3") && result.packed.element_exactly_equal_text (0, 1, "4"), "packed square LU integer values mismatch"); check_fraction (result.packed.at (1, 0), 1, 3, 256, "packed square LU multiplier mismatch"); check_fraction (result.packed.at (1, 1), 2, 3, 256, "packed square LU diagonal mismatch"); check (result.lower.element_exactly_equal_text (0, 0, "1") && result.lower.element_exactly_equal_text (0, 1, "0") && result.lower.element_exactly_equal_text (1, 1, "1"), "canonical L integer values mismatch"); check_fraction (result.lower.at (1, 0), 1, 3, 256, "canonical L multiplier mismatch"); check (result.upper.element_exactly_equal_text (0, 0, "3") && result.upper.element_exactly_equal_text (1, 0, "0") && result.upper.element_exactly_equal_text (0, 1, "4"), "canonical U integer values mismatch"); check_fraction (result.upper.at (1, 1), 2, 3, 256, "canonical U diagonal mismatch"); const auto tall = matrix (3, 2, 256, {"1", "3", "5", "2", "4", "6"}); const auto tall_result = octave_mplapack::mplapack_mpfr_matrix_lu (tall); check (tall_result.lower.rows () == 3 && tall_result.lower.columns () == 2 && tall_result.upper.rows () == 2 && tall_result.upper.columns () == 2, "tall LU shape mismatch"); check_permutation (tall_result, {3, 1, 2}); const auto wide = matrix (2, 3, 256, {"1", "3", "2", "4", "5", "6"}); const auto wide_result = octave_mplapack::mplapack_mpfr_matrix_lu (wide); check (wide_result.lower.rows () == 2 && wide_result.lower.columns () == 2 && wide_result.upper.rows () == 2 && wide_result.upper.columns () == 3, "wide LU shape mismatch"); check_permutation (wide_result, {2, 1}); } void test_precision_and_scope () { mpfrxx::set_default_precision_bits (128); for (const auto case_data : {std::pair (1024, -700), std::pair (2048, -1500)}) { const mpfr_prec_t precision = case_data.first; MpfrMatrixStorage input (2, 2, precision); mpfr_set_ui (input.at (0, 0).mpfr_data (), 4, MPFR_RNDN); mpfr_set_ui (input.at (0, 1).mpfr_data (), 2, MPFR_RNDN); Real delta = Real::with_precision (precision); mpfr_set_ui_2exp (delta.mpfr_data (), 1, case_data.second, MPFR_RNDN); // Set the lower-left entry directly to 1+delta without relying on a // default-precision temporary. mpfr_set_ui (input.at (1, 0).mpfr_data (), 1, MPFR_RNDN); mpfr_add (input.at (1, 0).mpfr_data (), input.at (1, 0).mpfr_data (), delta.mpfr_data (), MPFR_RNDN); mpfr_set_ui (input.at (1, 1).mpfr_data (), 3, MPFR_RNDN); const auto before = input; const auto result = octave_mplapack::mplapack_mpfr_matrix_lu (input); check (result.info == 0 && result.packed.precision_bits () == precision && result.lower.precision_bits () == precision && result.upper.precision_bits () == precision, "LU precision metadata mismatch"); Real expected = Real::with_precision (precision); mpfr_set_ui (expected.mpfr_data (), 1, MPFR_RNDN); mpfr_div_ui (expected.mpfr_data (), expected.mpfr_data (), 4, MPFR_RNDN); Real tail = Real::with_precision (precision); mpfr_set_ui_2exp (tail.mpfr_data (), 1, case_data.second - 2, MPFR_RNDN); mpfr_add (expected.mpfr_data (), expected.mpfr_data (), tail.mpfr_data (), MPFR_RNDN); check (mpfr_equal_p (result.lower.at (1, 0).mpfr_data (), expected.mpfr_data ()) != 0, "LU multiplier tail was not preserved"); check (same (input, before), "Rgetrf modified public input storage"); check (mpfrxx::default_precision_bits () == 128, "Rgetrf leaked ambient precision"); } mpfrxx::set_default_precision_bits (4096); const auto high_ambient = matrix (2, 2, 256, {"1", "0", "0", "2"}); const auto result = octave_mplapack::mplapack_mpfr_matrix_lu (high_ambient); check (result.packed.precision_bits () == 256 && mpfrxx::default_precision_bits () == 4096, "high ambient LU changed operation precision"); mpfrxx::set_default_precision_bits (128); } void test_precision_dependent_pivot () { MpfrMatrixStorage low (2, 2, 512); MpfrMatrixStorage high (2, 2, 1024); for (MpfrMatrixStorage* input : {&low, &high}) { mpfr_set_ui (input->at (0, 0).mpfr_data (), 1, MPFR_RNDN); mpfr_set_ui (input->at (1, 0).mpfr_data (), 1, MPFR_RNDN); Real delta = Real::with_precision (input->precision_bits ()); mpfr_set_ui_2exp (delta.mpfr_data (), 1, -700, MPFR_RNDN); mpfr_add (input->at (1, 0).mpfr_data (), input->at (1, 0).mpfr_data (), delta.mpfr_data (), MPFR_RNDN); mpfr_set_ui (input->at (0, 1).mpfr_data (), 0, MPFR_RNDN); mpfr_set_ui (input->at (1, 1).mpfr_data (), 1, MPFR_RNDN); } const auto low_result = octave_mplapack::mplapack_mpfr_matrix_lu (low); const auto high_result = octave_mplapack::mplapack_mpfr_matrix_lu (high); check (low_result.permutation.at (0) == 1 && high_result.permutation.at (0) == 2, "precision-dependent LU pivot mismatch"); } void test_singular_and_empty () { const auto singular = matrix (2, 2, 256, {"1", "2", "2", "4"}); const auto result = octave_mplapack::mplapack_mpfr_matrix_lu (singular); check (result.info == 2, "singular LU INFO mismatch"); check_permutation (result, {2, 1}); const auto empty = matrix (0, 3, 512, {}); const auto empty_result = octave_mplapack::mplapack_mpfr_matrix_lu (empty); check (empty_result.info == 0 && empty_result.packed.rows () == 0 && empty_result.packed.columns () == 0 && empty_result.permutation.empty (), "empty LU result mismatch"); } } // namespace int main () { try { test_square_and_rectangular_shapes (); test_precision_and_scope (); test_precision_dependent_pivot (); test_singular_and_empty (); } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } std::cout << "PASS: MPLAPACK MPFR Rgetrf LU tests\n"; return 0; } mplapack-interop-0.5.1/test/complex_structural.tst0000644000230300031750000000376215274353472021725 0ustar rafaelrafael%!test %! mpbits (512); %! z = mp ("1.25", "-2.5"); %! r = real (z); %! i = imag (z); %! c = conj (z); %! assert (isreal (r) && isreal (i) && ! isreal (c)); %! assert (__mplapack_core__ ("value_shape_info", r).precision_bits == 512); %! assert (__mplapack_core__ ("value_shape_info", i).precision_bits == 512); %! assert (strcmp (char (r), "1.25e+0")); %! assert (strcmp (char (i), "-2.5e+0")); %! assert (strcmp (char (c), "(1.25e+0,2.5e+0)")); %! assert (double (r) == 1.25 && double (i) == -2.5); %! assert (double (c) == complex (1.25, 2.5)); %!test %! mpbits (512); %! A = mp ([1 + 2i, 3 - 4i; 5 + 6i, 7 - 8i]); %! R = real (A); %! I = imag (A); %! C = conj (A); %! assert (size (R), [2, 2]); %! assert (size (I), [2, 2]); %! assert (size (C), [2, 2]); %! assert (isreal (R) && isreal (I) && ! isreal (C)); %! assert (double (R), [1, 3; 5, 7]); %! assert (double (I), [2, -4; 6, -8]); %! assert (double (C), [1 - 2i, 3 + 4i; 5 - 6i, 7 + 8i]); %! T = A.'; %! H = A'; %! assert (double (T), [1 + 2i, 5 + 6i; 3 - 4i, 7 - 8i]); %! assert (double (H), [1 - 2i, 5 - 6i; 3 + 4i, 7 + 8i]); %! assert (__mplapack_core__ ("matrix_test_info", T).precision_bits == 512); %!test %! z = mp ("0", "-0"); %! cz = conj (z); %! zi = __mplapack_core__ ("scalar_test_info", z); %! czi = __mplapack_core__ ("scalar_test_info", cz); %! assert (zi.is_zero && zi.imag_signbit); %! assert (czi.is_zero && ! czi.imag_signbit); %! assert (strcmp (char (cz), "(0,0)")); %!test %! mpbits (1024); %! A = mp (complex ([1, 3], [2, 4])); %! assert (__mplapack_core__ ("value_shape_info", real (A)).precision_bits == 1024); %! mpbits (2048); %! B = mp (complex ([5, 7], [6, 8])); %! assert (__mplapack_core__ ("value_shape_info", imag (B)).precision_bits == 2048); %! assert (__mplapack_core__ ("value_shape_info", conj (B)).precision_bits == 2048); %!test %! r = mp ([1, 2; 3, 4]); %! assert (isreal (real (r)) && isreal (conj (r))); %! assert (double (imag (r)), zeros (2, 2)); %! assert (double (r.'), [1, 3; 2, 4]); %! assert (double (r'), [1, 3; 2, 4]); mplapack-interop-0.5.1/test/t14_optimization.tst0000644000230300031750000000650215274353472021177 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (256); %! target = mp ("1.25"); %! options = struct ("TolX", mp ("1e-45"), "TolFun", mp ("1e-45"), ... %! "MaxIter", 500); %! [argument, value, info, output] = fminbnd ( ... %! @(x) (x - target) * (x - target), mp ("0"), mp ("2"), options); %! assert (info == 1); %! assert (abs (argument - target) < mp ("1e-35")); %! assert (value < mp ("1e-65")); %! assert (output.funcCount >= 2); %! rejected = false; %! try %! fminbnd (@(x) double (x), mp ("0"), mp ("1")); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, "double-valued objectives must be rejected"); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (256); %! options = struct ("TolX", mp ("1e-22"), "TolFun", mp ("1e-30"), ... %! "MaxIter", 2000, "MaxFunEvals", 10000); %! [argument, value, info] = fminsearch ( ... %! @(x) mp ("100") * (x(2) - x(1) * x(1)) ^ 2 ... %! + (mp ("1") - x(1)) ^ 2, mp ({"-1.2"; "1"}), options); %! assert (info == 1); %! assert (abs (argument(1) - mp ("1")) < mp ("1e-12")); %! assert (abs (argument(2) - mp ("1")) < mp ("1e-12")); %! assert (value < mp ("1e-25")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (256); %! target = mp ({"1.25"; "-0.75"}); %! options = struct ("TolX", mp ("1e-28"), "TolFun", mp ("1e-35"), ... %! "MaxIter", 800, "MaxFunEvals", 4000); %! [argument, value, info] = fminsearch ( ... %! @(x) (x(1) - target(1)) ^ 2 + (x(2) - target(2)) ^ 2, ... %! mp ({"0"; "0"}), options); %! assert (info == 1); %! assert (abs (argument(1) - target(1)) < mp ("1e-20")); %! assert (abs (argument(2) - target(2)) < mp ("1e-20")); %! assert (value < mp ("1e-35")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (512); %! options = struct ("TolX", mp ("1e-70"), "TolFun", mp ("1e-100"), ... %! "MaxIter", 1200); %! tiny = mp ("1"); %! for k = 1:700, tiny = tiny * mp ("0.5"); endfor %! target = mp ("1") + tiny; %! [argument, value, info] = fminbnd ( ... %! @(x) (x - target) * (x - target), mp ("0"), mp ("2"), options); %! assert (info == 1); %! assert (abs (argument - target) < mp ("1e-60")); %! assert (double (target) == 1); %! assert (value < mp ("1e-115")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (256); %! options = struct ("TolX", mp ("1e-18"), "TolFun", mp ("1e-25"), ... %! "MaxIter", 1200, "MaxFunEvals", 6000); %! [argument, value, info] = fminsearch ( ... %! @(x) (mp ("1000000") * x(1) - mp ("3")) ^ 2 ... %! + (x(2) - mp ("0.000002")) ^ 2, ... %! mp ({"0"; "0"}), options); %! assert (info == 1); %! assert (abs (mp ("1000000") * argument(1) - mp ("3")) < mp ("1e-10")); %! assert (abs (argument(2) - mp ("0.000002")) < mp ("1e-12")); %! assert (value < mp ("1e-20")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect mplapack-interop-0.5.1/test/test_neigt09.m0000644000230300031750000000260515274353472017721 0ustar rafaelrafael% Focused NEIGT09 Wilkinson recurrence and polynomial error tests. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect w4 = net_wilkinson_model (4, 128); assert (w4.guard_bits == 4 * net_ceil_log2_integer (5) + 2); assert (w4.coefficients == mp ([1, -10, 35, -50, 24])); assert (w4.A_model(1, :) == mp ([10, -35, 50, -24])); r4 = net_wilkinson_reference (4, 256); assert (all (r4.horner_exact_zero)); w6 = net_wilkinson_audit (6, 256, 512); assert (all (w6.reference.horner_exact_zero)); assert (w6.metrics.absolute_match.threshold < net_pow2 (-180, 256)); assert (all (w6.model_eta_poly < net_pow2 (-180, 512))); assert (all (w6.frozen_eta_poly < net_pow2 (-180, 512))); z = net_mp_complex (mp (2), net_pow2 (-700, 512)); indicator = net_polynomial_backward_error (z, w6.model.coefficients, 512); assert (indicator.eta >= mp (0) && strcmp (indicator.status, "finite")); zero_case = net_polynomial_backward_error (mp (0), mp ([0, 0]), 128); assert (zero_case.eta == mp (0)); assert (strcmp (zero_case.status, "denominator_zero_exact_zero")); fprintf ("PASS: NEIGT09 Wilkinson recurrence, Horner zeros, and polynomial backward error\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/mp_generalized_eig_test.cc0000644000230300031750000001751415274353472022411 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_generalized_eig.h" #include #include #include #include #include #include using octave_mplapack::MpGeneralizedComplexDefiniteEigResult; using octave_mplapack::MpGeneralizedEigResult; using octave_mplapack::MpGeneralizedQzEigResult; using octave_mplapack::MpGeneralizedRealDefiniteEigResult; using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; namespace { void require (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } double real_component (const MpfrComplexMatrixStorage::NativeScalar& value) { return mpfr_get_d (mpc_realref (value.mpc_data ()), MPFR_RNDN); } double imag_component (const MpfrComplexMatrixStorage::NativeScalar& value) { return mpfr_get_d (mpc_imagref (value.mpc_data ()), MPFR_RNDN); } void check_precision (const MpfrMatrixStorage& matrix, mpfr_prec_t precision) { require (matrix.precision_bits () == precision && matrix.all_elements_have_uniform_precision (), "real generalized eig precision contract mismatch"); } void check_precision (const MpfrComplexMatrixStorage& matrix, mpfr_prec_t precision) { require (matrix.precision_bits () == precision && matrix.all_elements_have_uniform_precision (), "complex generalized eig precision contract mismatch"); } } // namespace int main () { try { MpfrMatrixStorage real_a (2, 2, 256, std::vector {2.0, 1.0, 1.0, 3.0}); MpfrMatrixStorage real_b (2, 2, 256, std::vector {3.0, 0.0, 0.0, 2.0}); const auto real_before = real_a; const MpGeneralizedEigResult real_definite = octave_mplapack::mplapack_mpfr_matrix_generalized_eig ( real_a, real_b, octave_mplapack::GeneralizedEigAlgorithm::auto_select); const auto& definite = std::get (real_definite); require (std::abs (mpfr_get_d (definite.eigenvalues.at (0, 0).mpfr_data (), MPFR_RNDN) - 0.5) < 1e-12, "real definite generalized eigenvalue mismatch"); require (std::abs (mpfr_get_d (definite.eigenvalues.at (1, 0).mpfr_data (), MPFR_RNDN) - 5.0 / 3.0) < 1e-12, "real definite generalized eigenvalue mismatch"); check_precision (definite.eigenvalues, 256); check_precision (definite.right_vectors, 256); require (real_a.element_exactly_equal (0, 0, real_before, 0, 0) && real_a.element_exactly_equal (1, 0, real_before, 1, 0), "Rsygvd modified generalized eig input"); const auto real_qz = octave_mplapack::mplapack_mpfr_matrix_generalized_eig ( MpfrMatrixStorage (2, 2, 256, std::vector {0.0, -1.0, 1.0, 0.0}), MpfrMatrixStorage (2, 2, 256, std::vector {1.0, 0.0, 0.0, 1.0}), octave_mplapack::GeneralizedEigAlgorithm::qz); const auto& qz = std::get (real_qz); require (qz.eigenvalues.rows () == 2 && qz.right_vectors.columns () == 2 && qz.left_vectors.columns () == 2, "real generalized QZ shape mismatch"); require (std::abs (std::abs (imag_component (qz.eigenvalues.at (0, 0))) - 1.0) < 1e-12, "real generalized QZ conjugate pair mismatch"); check_precision (qz.eigenvalues, 256); MpfrComplexMatrixStorage complex_a (2, 2, 256, std::vector {"(1,0)", "(0,-1)", "(0,1)", "(3,0)"}); MpfrComplexMatrixStorage complex_b (2, 2, 256, std::vector {"(2,0)", "(0,0)", "(0,0)", "(1,0)"}); const auto complex_definite = octave_mplapack::mplapack_mpc_matrix_generalized_eig ( complex_a, complex_b, octave_mplapack::GeneralizedEigAlgorithm::chol); const auto& cdefinite = std::get (complex_definite); require (cdefinite.eigenvalues.rows () == 2 && cdefinite.right_vectors.columns () == 2, "complex definite generalized eig shape mismatch"); require (real_component (cdefinite.right_vectors.at (0, 0)) == real_component (cdefinite.right_vectors.at (0, 0)), "complex definite generalized eig returned invalid data"); check_precision (cdefinite.eigenvalues, 256); check_precision (cdefinite.right_vectors, 256); const auto complex_qz = octave_mplapack::mplapack_mpc_matrix_generalized_eig ( MpfrComplexMatrixStorage (2, 2, 256, std::vector {"(0,0)", "(-1,0)", "(1,0)", "(0,0)"}), MpfrComplexMatrixStorage (2, 2, 256, std::vector {"(1,0)", "(0,0)", "(0,0)", "(1,0)"}), octave_mplapack::GeneralizedEigAlgorithm::qz); const auto& cqz = std::get (complex_qz); require (std::abs (real_component (cqz.eigenvalues.at (0, 0))) < 1e-12 && std::abs (std::abs (imag_component ( cqz.eigenvalues.at (0, 0))) - 1.0) < 1e-12, "complex generalized QZ eigenvalue mismatch"); check_precision (cqz.eigenvalues, 256); const auto infinite = octave_mplapack::mplapack_mpfr_matrix_generalized_eig ( MpfrMatrixStorage (2, 2, 256, std::vector {1.0, 0.0, 0.0, 1.0}), MpfrMatrixStorage (2, 2, 256, std::vector {1.0, 0.0, 0.0, 0.0}), octave_mplapack::GeneralizedEigAlgorithm::auto_select); const auto& infinite_qz = std::get (infinite); require (mpfr_inf_p (mpc_realref ( infinite_qz.eigenvalues.at (1, 0).mpc_data ())) != 0, "singular-B generalized eig did not preserve infinity"); bool rejected = false; try { octave_mplapack::mplapack_mpfr_matrix_generalized_eig ( MpfrMatrixStorage (2, 2, 256, std::vector {1.0, 1.0, 0.0, 1.0}), real_b, octave_mplapack::GeneralizedEigAlgorithm::chol); } catch (const std::invalid_argument&) { rejected = true; } require (rejected, "chol accepted a nonsymmetric generalized pair"); for (mpfr_prec_t precision : {1024, 2048}) { MpfrMatrixStorage high_a (2, 2, precision, std::vector {1.0, 0.0, 0.0, 3.0}); MpfrMatrixStorage high_b (2, 2, precision, std::vector {1.0, 0.0, 0.0, 1.0}); const auto high = octave_mplapack::mplapack_mpfr_matrix_generalized_eig ( high_a, high_b, octave_mplapack::GeneralizedEigAlgorithm::qz); const auto& high_qz = std::get (high); check_precision (high_qz.eigenvalues, precision); require (std::abs (real_component (high_qz.eigenvalues.at (0, 0)) - 1.0) < 1e-12, "high precision generalized QZ canary mismatch"); } std::cout << "PASS: real/complex generalized eig, definite/QZ dispatch, " "singular-B infinity, precision canaries, immutability, " "and option validation\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/gemm.tst0000644000230300031750000001664315274353472016715 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_matrix_text (value, expected) %! for column = 1:columns (value) %! for row = 1:rows (value) %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! value, row, column, expected{row, column})); %! endfor %! endfor %!endfunction %!function assert_scalar_text (value, expected) %! assert (__mplapack_core__ ("scalar_test_equal_string", value, expected)); %!endfunction %!function assert_matrix_shape (value, expected_rows, expected_columns, ... %! expected_precision) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (expected_rows)); %! assert (info.columns, uint64 (expected_columns)); %! assert (info.precision_bits, uint64 (expected_precision)); %! assert (info.all_elements_same_precision); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2"; "3", "4"}); %! B = mp ({"5", "6"; "7", "8"}); %! C = A * B; %! assert (strcmp (class (C), "mp")); %! assert_matrix_shape (C, 2, 2, 256); %! assert_matrix_text (C, {"19", "22"; "43", "50"}); %! assert_matrix_text (A, {"1", "2"; "3", "4"}); %! assert_matrix_text (B, {"5", "6"; "7", "8"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! A = mp ({"1", "2", "3"; "4", "5", "6"}); %! B = mp ({"7", "8", "9", "10"; "11", "12", "13", "14"; ... %! "15", "16", "17", "18"}); %! C = A * B; %! assert_matrix_shape (C, 2, 4, 128); %! assert_matrix_text (C, {"74", "80", "86", "92"; ... %! "173", "188", "203", "218"}); %! row = mp ({"1", "2", "3"}); %! column = mp ({"4"; "5"; "6"}); %! scalar_result = row * column; %! assert_scalar_text (scalar_result, "32"); %! assert (! __mplapack_core__ ("value_is_matrix", scalar_result)); %! outer = column * row; %! assert_matrix_shape (outer, 3, 3, 128); %! assert_matrix_text (outer, {"4", "8", "12"; ... %! "5", "10", "15"; "6", "12", "18"}); %! outer_wide = mp ({"1"; "2"; "3"}) * ... %! mp ({"4", "5", "6", "7", "8"}); %! assert_matrix_shape (outer_wide, 3, 5, 128); %! assert_matrix_text (outer_wide, {"4", "5", "6", "7", "8"; ... %! "8", "10", "12", "14", "16"; ... %! "12", "15", "18", "21", "24"}); %! dot_wide = mp ({"1", "2", "3", "4"}) * ... %! mp ({"5"; "6"; "7"; "8"}); %! assert_scalar_text (dot_wide, "70"); %! A_wide = mp ({"1", "2", "3"; "4", "5", "6"; ... %! "7", "8", "9"; "10", "11", "12"}); %! B_wide = mp ({"2", "3"; "4", "5"; "6", "7"}); %! product_wide = A_wide * B_wide; %! assert_matrix_shape (product_wide, 4, 2, 128); %! assert_matrix_text (product_wide, {"28", "34"; "64", "79"; ... %! "100", "124"; "136", "169"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (333); %! A = mp ([1, 2; 3, 4]); %! B = [5, 6; 7, 8]; %! C = A * B; %! assert_matrix_shape (C, 2, 2, 333); %! assert_matrix_text (C, {"19", "22"; "43", "50"}); %! D = B * A; %! assert_matrix_text (D, {"23", "34"; "31", "46"}); %! E = mp ("2") * B; %! assert_matrix_text (E, {"10", "12"; "14", "16"}); %! F = B * mp ("2"); %! assert_matrix_text (F, {"10", "12"; "14", "16"}); %! G = A * 0.125; %! assert_matrix_text (G, {"0.125", "0.25"; "0.375", "0.5"}); %! H = 0.125 * A; %! assert_matrix_text (H, {"0.125", "0.25"; "0.375", "0.5"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! B = mp ([5, 6; 7, 8]); %! mpbits (128); %! C = A * B; %! assert_matrix_shape (C, 2, 2, 256); %! assert_matrix_text (C, {"19", "22"; "43", "50"}); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! mpbits (512); %! D = A * B; %! assert_matrix_text (D, {"19", "22"; "43", "50"}); %! assert_matrix_shape (D, 2, 2, 256); %! assert (__mplapack_core__ ("matrix_test_element_equal", C, 1, 1, ... %! D, 1, 1)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! tail = strcat ("1.", repmat ("0", 1, 210), "1"); %! A = mp ({tail, "0"; "0", "1"}); %! I = mp ({"1", "0"; "0", "1"}); %! mpbits (128); %! C = A * I; %! assert_matrix_shape (C, 2, 2, 1024); %! assert (__mplapack_core__ ("matrix_test_element_equal", C, 1, 1, ... %! A, 1, 1)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! mpbits (4096); %! D = A * I; %! assert_matrix_shape (D, 2, 2, 1024); %! assert (__mplapack_core__ ("matrix_test_element_equal", D, 1, 1, ... %! A, 1, 1)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2048); %! tail = strcat ("1.", repmat ("0", 1, 450), "1"); %! A = mp ({tail, "0"; "0", "1"}); %! I = mp ({"1", "0"; "0", "1"}); %! mpbits (128); %! C = A * I; %! assert_matrix_shape (C, 2, 2, 2048); %! assert (__mplapack_core__ ("matrix_test_element_equal", C, 1, 1, ... %! A, 1, 1)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp (zeros (2, 0)); %! B = mp (zeros (0, 3)); %! C = A * B; %! assert_matrix_shape (C, 2, 3, 256); %! assert_matrix_text (C, {"0", "0", "0"; "0", "0", "0"}); %! D = mp (zeros (0, 3)) * mp (ones (3, 2)); %! assert_matrix_shape (D, 0, 2, 256); %! E = mp (ones (2, 3)) * mp (zeros (3, 0)); %! assert_matrix_shape (E, 2, 0, 256); %! F = mp (zeros (0, 0)) * mp (zeros (0, 0)); %! assert_matrix_shape (F, 0, 0, 256); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({"1", "2"; "3", "4"}); %! B = mp ({"1", "2", "3"}); %! try %! A * B; %! error ("M08 dimension mismatch unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, ... %! "M08 dimension mismatch unexpectedly succeeded")); %! assert (strcmp (exception.identifier, "mplapack:mp:DimensionMismatch")); %! end_try_catch %! assert (double (A / A), eye (2), 1e-12); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! decimal = mp ({"0.1", "0.125"}); %! binary = mp ([0.1, 0.125]); %! decimal_product = decimal * mp ("1"); %! binary_product = binary * mp ("1"); %! assert (! __mplapack_core__ ("matrix_test_element_equal", ... %! decimal_product, 1, 1, ... %! binary_product, 1, 1)); %! assert (__mplapack_core__ ("matrix_test_element_equal", ... %! decimal_product, 1, 2, ... %! binary_product, 1, 2)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/t08_graphics_3d.tst0000644000230300031750000000532115274353472020640 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! mpbits (1024); %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! t = linspace (mp ("0"), mp ("6.283185307179586476925286766559"), 17); %! x = cos (t); %! y = sin (t); %! z = t; %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! h = plot3 (ax, x, y, z, "o-", "linewidth", 2); %! assert (isgraphics (h, "line")); %! assert (get (h, "linewidth"), 2); %! assert (get (h, "xdata"), double (x)); %! assert (get (h, "ydata"), double (y)); %! assert (get (h, "zdata"), double (z)); %! hs = scatter3 (ax, x, y, z, 12, "filled"); %! assert (isgraphics (hs)); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! mpbits (1024); %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! X = mp ({"0", "1"; "0", "1"}); %! Y = mp ({"0", "0"; "1", "1"}); %! tiny = mp ("1"); %! for k = 1:700, tiny = tiny * mp ("0.5"); endfor %! Z = mp ({"0", "1"; "1", "2"}); %! Z(1, 1) = tiny; %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! hm = mesh (ax, X, Y, Z, "edgecolor", [0, 0, 1]); %! assert (isgraphics (hm)); %! assert (get (hm, "xdata"), double (X)); %! assert (get (hm, "zdata"), double (Z)); %! hf = surf (ax, X, Y, Z); %! assert (isgraphics (hf)); %! [contour_matrix, hline] = contour3 (ax, X, Y, Z); %! assert (isnumeric (contour_matrix) && isgraphics (hline)); %! hmc = meshc (ax, X, Y, Z); %! hsc = surfc (ax, X, Y, Z); %! hw = waterfall (ax, X, Y, Z); %! assert (numel (hmc) >= 1 && numel (hsc) >= 1 && isgraphics (hw)); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! old_visible = get (0, "defaultfigurevisible"); %! unwind_protect %! mpbits (512); %! graphics_toolkit ("gnuplot"); %! set (0, "defaultfigurevisible", "off"); %! w = mp ([1 + 2i, 2 - 1i, 3 + 3i]); %! fig = figure ("visible", "off"); %! ax = axes ("parent", fig); %! h = plot3 (ax, real (w), imag (w), mp ([1, 2, 3]), "x-"); %! assert (isgraphics (h, "line")); %! assert (get (h, "xdata"), [1, 2, 3]); %! assert (get (h, "ydata"), [2, -1, 3]); %! assert (get (h, "zdata"), [1, 2, 3]); %! close (fig); %! unwind_protect_cleanup %! set (0, "defaultfigurevisible", old_visible); %! close all; %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/concat.tst0000644000230300031750000002344415274353472017234 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function info = concat_info (value) %! info = __mplapack_core__ ("value_shape_info", value); %!endfunction %!function assert_matrix_text (value, expected) %! info = concat_info (value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! value, row, column, expected{row, column})); %! endfor %! endfor %!endfunction %!function ok = expect_horzcat_error (lhs, rhs) %! ok = false; %! try %! unused = horzcat (lhs, rhs); %! catch %! ok = true; %! end_try_catch %!endfunction %!function ok = expect_vertcat_error (lhs, rhs) %! ok = false; %! try %! unused = vertcat (lhs, rhs); %! catch %! ok = true; %! end_try_catch %!endfunction %!function ok = expect_native_concat_error () %! ok = false; %! try %! unused = __mplapack_core__ ("matrix_horzcat", 1.0, 2.0); %! catch %! ok = true; %! end_try_catch %!endfunction %!test %! A = mp ({"11", "12"; "21", "22"}); %! B = mp ({"31", "32", "33"; "41", "42", "43"}); %! H = [A, B]; %! V = [A; A]; %! assert (isa (H, "mp")); %! assert_matrix_text (H, {"11", "12", "31", "32", "33"; ... %! "21", "22", "41", "42", "43"}); %! assert_matrix_text (V, {"11", "12"; "21", "22"; ... %! "11", "12"; "21", "22"}); %! assert_matrix_text (horzcat (A, B, A), ... %! {"11", "12", "31", "32", "33", "11", "12"; ... %! "21", "22", "41", "42", "43", "21", "22"}); %! assert_matrix_text (vertcat (A, A, A), ... %! {"11", "12"; "21", "22"; "11", "12"; ... %! "21", "22"; "11", "12"; "21", "22"}); %! assert_matrix_text (horzcat (A), {"11", "12"; "21", "22"}); %! assert_matrix_text (vertcat (A), {"11", "12"; "21", "22"}); %!test %! A = mp ({"11", "12"; "21", "22"}); %! B = mp ({"31", "32"; "41", "42"}); %! assert_matrix_text ([A, B], {"11", "12", "31", "32"; ... %! "21", "22", "41", "42"}); %! assert_matrix_text ([B, A], {"31", "32", "11", "12"; ... %! "41", "42", "21", "22"}); %! assert_matrix_text ([A; B], {"11", "12"; "21", "22"; ... %! "31", "32"; "41", "42"}); %! nested_h = [A, [B, A]]; %! nested_v = [A; [B; A]]; %! assert_matrix_text (nested_h, {"11", "12", "31", "32", "11", "12"; ... %! "21", "22", "41", "42", "21", "22"}); %! assert_matrix_text (nested_v, {"11", "12"; "21", "22"; ... %! "31", "32"; "41", "42"; ... %! "11", "12"; "21", "22"}); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2"; "3", "4"}); %! mpbits (1024); %! B = mp ({"5", "6"; "7", "8"}); %! mpbits (128); %! H = [A, B]; %! V = [A; B]; %! assert (concat_info (H).precision_bits, uint64 (1024)); %! assert (concat_info (V).precision_bits, uint64 (1024)); %! assert (concat_info (A).precision_bits, uint64 (256)); %! assert (concat_info (B).precision_bits, uint64 (1024)); %! assert (mpbits (), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! tail = strcat ("1.", repmat ("0", 1, 210), "1"); %! A = mp ({tail; "0"}); %! mpbits (128); %! H_rhs = mp ({"2"; "3"}); %! V_rhs = mp ({"4"; "5"}); %! H = [A, H_rhs]; %! V = [A; V_rhs]; %! assert (concat_info (H).precision_bits, uint64 (1024)); %! assert (concat_info (V).precision_bits, uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! H, 1, 1, tail)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! V, 1, 1, tail)); %! mpbits (4096); %! assert (concat_info ([A, A]).precision_bits, uint64 (1024)); %! assert (mpbits (), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2048); %! tail = strcat ("1.", repmat ("0", 1, 450), "1"); %! A = mp ({tail; "0"}); %! mpbits (128); %! H_rhs = mp ({"2"; "3"}); %! V_rhs = mp ({"4"; "5"}); %! H = [A, H_rhs]; %! V = [A; V_rhs]; %! assert (concat_info (H).precision_bits, uint64 (2048)); %! assert (concat_info (V).precision_bits, uint64 (2048)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! H, 1, 1, tail)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! V, 1, 1, tail)); %! assert (mpbits (), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({"0", "-0", "Inf", "NaN"}); %! B = [A, A]; %! zero_positive = __mplapack_core__ ("scalar_test_info", B(1, 1)); %! zero_negative = __mplapack_core__ ("scalar_test_info", B(1, 2)); %! inf_info = __mplapack_core__ ("scalar_test_info", B(1, 3)); %! nan_info = __mplapack_core__ ("scalar_test_info", B(1, 4)); %! assert (! zero_positive.signbit && zero_positive.is_zero); %! assert (zero_negative.signbit && zero_negative.is_zero); %! assert (inf_info.is_infinite && ! inf_info.signbit); %! assert (nan_info.is_nan); %!test %! A = mp ({"1", "2"; "3", "4"}); %! builtin_empty = []; %! assert_matrix_text ([A, builtin_empty], {"1", "2"; "3", "4"}); %! assert_matrix_text ([builtin_empty, A], {"1", "2"; "3", "4"}); %! assert_matrix_text ([A; builtin_empty], {"1", "2"; "3", "4"}); %! assert_matrix_text ([builtin_empty; A], {"1", "2"; "3", "4"}); %! assert (expect_horzcat_error (A, 1 + 2i)); %! assert (expect_vertcat_error (A, ones (2, 2, 2))); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2"; "3", "4"}); %! D = [A, [5.0, 0.1; 6.0, 0.125]]; %! E = [[5.0, 0.1; 6.0, 0.125], A]; %! F = [A; [5.0, 0.1]]; %! G = [[5.0, 0.1]; A]; %! assert (isa (D, "mp") && isa (E, "mp")); %! assert (concat_info (D).precision_bits, uint64 (256)); %! assert (concat_info (E).precision_bits, uint64 (256)); %! assert (concat_info (F).precision_bits, uint64 (256)); %! assert (concat_info (G).precision_bits, uint64 (256)); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! D, 1, 3, 5.0)); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! D, 2, 4, 0.125)); %! assert (__mplapack_core__ ("scalar_test_equal", D (1, 4), mp (0.1))); %! assert (mpbits (), uint64 (256)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({"11", "12"; "21", "22"}); %! H_rhs = [2.0; 4.0]; %! V_rhs = [5.0, 6.0]; %! H = [A, H_rhs]; %! V = [A; V_rhs]; %! assert_matrix_text (H, {"11", "12", "2"; "21", "22", "4"}); %! assert_matrix_text (V, {"11", "12"; "21", "22"; "5", "6"}); %! assert (size (double (H)), [2, 3]); %! assert (size (double (V)), [3, 2]); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ({"1", "2"; "3", "4"}); %! empty = mp (zeros (0, 0)); %! empty_row = mp (zeros (0, 1)); %! empty_cols = mp (zeros (2, 0)); %! empty_one_row = mp (zeros (1, 0)); %! assert (size ([A, empty]), [2, 2]); %! assert (size ([A, empty_row]), [2, 2]); %! assert (size ([empty, A]), [2, 2]); %! assert (size ([A; empty]), [2, 2]); %! assert (size ([A; empty_one_row]), [2, 2]); %! assert (size ([empty_cols, A]), [2, 2]); %! empty_h_left = mp (zeros (0, 2)); %! empty_h_right = mp (zeros (0, 3)); %! empty_v_top = mp (zeros (2, 0)); %! empty_v_bottom = mp (zeros (3, 0)); %! zeros_h = [empty_h_left, empty_h_right]; %! zeros_v = [empty_v_top; empty_v_bottom]; %! assert (size (zeros_h), [0, 5]); %! assert (size (zeros_v), [5, 0]); %! assert (concat_info (zeros_h).precision_bits, uint64 (512)); %! assert (concat_info (zeros_v).precision_bits, uint64 (512)); %! try %! invalid_h = mp (zeros (0, 2)); %! [A, invalid_h]; %! error ("horizontal empty mismatch unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, ... %! "horizontal empty mismatch unexpectedly succeeded")); %! end_try_catch %! try %! invalid_v = mp (zeros (2, 0)); %! [A; invalid_v]; %! error ("vertical empty mismatch unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, ... %! "vertical empty mismatch unexpectedly succeeded")); %! end_try_catch %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2048); %! high_empty = mp (zeros (0, 1)); %! mpbits (128); %! empty_double = zeros (0, 2); %! R = [high_empty, empty_double]; %! assert (isa (R, "mp")); %! assert (concat_info (R).precision_bits, uint64 (2048)); %! assert (size (R), [0, 3]); %! assert (mpbits (), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({"1", "2"; "3", "4"}); %! before = concat_info (A); %! C = [A, A]; %! clear A; %! assert_matrix_text (C, {"1", "2", "1", "2"; "3", "4", "3", "4"}); %! assert (concat_info (C).precision_bits, before.precision_bits); %! S_left = mp ("1"); %! S_right = mp ("2"); %! S = [S_left, S_right]; %! singleton = horzcat (S_left); %! assert (! __mplapack_core__ ("value_is_matrix", singleton)); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! S, 1, 1, "1")); %!test %! A = mp ({"1", "2"; "3", "4"}); %! assert (expect_horzcat_error (A, ones (3, 1))); %! assert (expect_vertcat_error (A, ones (1, 3))); %! assert (expect_native_concat_error ()); mplapack-interop-0.5.1/test/mp_matrix_inspection_test.cc0000644000230300031750000000406215274353472023025 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_matrix_inspection.h" #include #include #include #include namespace { using octave_mplapack::MpfrMatrixStorage; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void check_text (const MpfrMatrixStorage& value, const std::vector& expected) { check (value.numel () == expected.size (), "unexpected element count"); for (std::size_t index = 0; index < expected.size (); ++index) check (value.element_exactly_equal_text (index % value.rows (), index / value.rows (), expected[index]), "unexpected selected value"); } } // namespace int main () { try { const MpfrMatrixStorage source ( 4, 3, 512, std::vector {"11", "21", "31", "41", "12", "22", "32", "42", "13", "23", "33", "43"}); const auto selected = octave_mplapack::select_matrix ( source, {3, 0}, {2, 0}); check_text (selected, {"43", "13", "41", "11"}); const auto linear = octave_mplapack::select_linear (source, {0, 5, 11}); check_text (linear, {"11", "22", "43"}); const auto empty = octave_mplapack::select_matrix (source, {}, {0, 1}); check (empty.rows () == 0 && empty.columns () == 2, "empty row selection shape mismatch"); check (empty.precision_bits () == 512, "empty row selection precision mismatch"); const std::string display = octave_mplapack::format_matrix (selected); check (display == "[4.3e+1 4.1e+1\n 1.3e+1 1.1e+1]", "matrix display formatting mismatch"); std::cout << "PASS: native matrix selection, linear order, precision, " "empty shapes, and canonical display\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/release_closure.tst0000644000230300031750000000633215274353472021136 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_fails (thunk, label) %! did_fail = false; %! try %! thunk (); %! catch %! did_fail = true; %! end_try_catch %! assert (did_fail, label); %!endfunction %!function result = reference_square (value) %! d = double (value); %! result = [d(1, 1) * d(1, 1) + d(1, 2) * d(2, 1), ... %! d(1, 1) * d(1, 2) + d(1, 2) * d(2, 2); ... %! d(2, 1) * d(1, 1) + d(2, 2) * d(2, 1), ... %! d(2, 1) * d(1, 2) + d(2, 2) * d(2, 2)]; %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! text_value = mp ("0.1"); %! binary_value = mp (0.1); %! assert (! __mplapack_core__ ("scalar_test_equal", text_value, binary_value)); %! assert (__mplapack_core__ ("scalar_test_equal_string", text_value, "0.1")); %! A = mp ([1, 2; 3, 4]); %! assert (size (A), [2, 2]); %! assert (rows (A), 2); %! assert (columns (A), 2); %! assert (numel (A), 4); %! assert (ndims (A), 2); %! assert (! isempty (A)); %! assert (size (A, 3), 1); %! B = A; %! B(1, 1) = mp (9); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", A, 1, 1, 1)); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", B, 1, 1, 9)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([2, 1; 1, 3]); %! b = mp ([1; 2]); %! x = A \ b; %! assert (size (x), [2, 1]); %! [Q, R] = qr (A); %! assert (size (Q), [2, 2]); %! assert (size (R), [2, 2]); %! [L, U, P] = lu (A); %! assert (size (L), [2, 2]); %! assert (size (U), [2, 2]); %! assert (size (P), [2, 2]); %! C = chol (A); %! assert (size (C), [2, 2]); %! assert (isa (x, "mp") && isa (Q, "mp") && isa (R, "mp") ... %! && isa (L, "mp") && isa (U, "mp") && isa (C, "mp")); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ([1, 2; 3, 4]); %! [Vg, Dg] = eig (A); %! assert (double (norm (A * Vg - Vg * Dg, "fro")) < 1e-12, ... %! "N05 general eig real residual"); %! assert (double (norm (sin (A) - sin (double (A)), "fro")) < 1e-12); %! assert (double (norm (exp (A) - exp (double (A)), "fro")) < 1e-12); %! assert (double (norm (sqrt (A) - sqrt (double (A)), "fro")) < 1e-12); %! assert (double (norm (A ^ 2 - mp (reference_square (A)), "fro")) < 1e-12); %! assert (isequal (A == A, true (2)), "real matrix equality compatibility"); %! assert (double (A / A), eye (2), 1e-12); %! assert (double (det (A)), -2, 1e-12); %! assert (double (A * inv (A)), eye (2), 1e-12); %! [U, S, V] = svd (A); %! assert (double (norm (A - U * S * transpose (V), "fro")) < 1e-12); %! assert (rank (A), 2); %! assert (double (cond (A)) > 14); %! assert (double (rcond (A)) > 0); %! S = mp ([2, 1; 1, 2]); %! [Vs, Ds] = eig (S); %! assert (double (norm (S * Vs - Vs * Ds, "fro")) < 1e-12); %!test %! help_text = evalc ("help @mp/qr"); %! assert (! isempty (strfind (help_text, "qr"))); %! help_text = evalc ("help @mp/lu"); %! assert (! isempty (strfind (help_text, "lu"))); %! help_text = evalc ("help @mp/rows"); %! assert (! isempty (strfind (help_text, "rows"))); %! help_text = evalc ("help @mp/rank"); %! assert (! isempty (strfind (help_text, "rank"))); mplapack-interop-0.5.1/test/t12_solvers.tst0000644000230300031750000000602315274353472020142 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (1024); %! tiny = mp ("1"); %! for k = 1:700, tiny = tiny * mp ("0.5"); endfor %! target = mp ("1") + tiny; %! [root, fval, info, output] = fzero (@(value) value - target, ... %! mp ({"0", "2"})); %! assert (info == 1); %! assert (root == target); %! assert (fval == mp ("0")); %! assert (output.iterations >= 0 && output.funcCount >= 2); %! assert (double (target) == 1); %! [expanded, unused, expanded_info] = fzero (@(value) value - mp ("1"), mp ("0")); %! assert (expanded == mp ("1") && expanded_info == 1); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (512); %! target = mp ("1.25"); %! options = struct ("TolX", mp ("1e-100"), "MaxIter", 600); %! [root, fval, info] = fzero (@(value) value * value - target * target, ... %! mp ({"0", "2"}), options); %! assert (info == 1); %! assert (abs (root - target) < mp ("1e-100")); %! assert (abs (fval) < mp ("1e-100")); %! rejected = false; %! try %! fzero (@(value) double (value), mp ({"-1", "1"})); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, "double-valued fzero callbacks must be rejected"); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (512); %! initial = mp ([0.8, 1.2]); %! target_a = mp ("1.125"); %! target_b = mp ("0.75"); %! [solution, residual, info, output] = fsolve ( ... %! @(value) [value(1) - target_a; value(2) + target_b], initial); %! assert (info == 1); %! assert (abs (solution(1) - target_a) < mp ("1e-60")); %! assert (abs (solution(2) + target_b) < mp ("1e-60")); %! assert (norm (residual) < mp ("1e-60")); %! assert (output.iterations >= 1 && output.funcCount >= 3); %! jacobian_options = struct ("Jacobian", "on"); %! [with_jacobian, jacobian_residual, jacobian_info] = fsolve ( ... %! @t12_linear_system_callback, mp (zeros (2, 1)), jacobian_options); %! assert (jacobian_info == 1); %! assert (with_jacobian(1) == mp ("1.375")); %! assert (with_jacobian(2) == mp ("2.75")); %! assert (norm (jacobian_residual) == mp ("0")); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect %!test %! saved_bits = mpbits (); %! unwind_protect %! mpbits (1024); %! tiny = mp ("1"); %! for k = 1:700, tiny = tiny * mp ("0.5"); endfor %! target = mp ("1") + tiny; %! [solution, residual] = fsolve (@(value) value - target, mp ("0")); %! assert (abs (solution - target) < mp ("1e-150")); %! assert (abs (residual) < mp ("1e-150")); %! rejected = false; %! try %! fsolve (@(value) double (value), mp ("0")); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, "double-valued fsolve callbacks must be rejected"); %! unwind_protect_cleanup %! mpbits (saved_bits); %! end_unwind_protect mplapack-interop-0.5.1/test/elementwise.tst0000644000230300031750000001704015274353472020301 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function info = elementwise_info (value) %! if (__mplapack_core__ ("value_is_matrix", value)) %! info = __mplapack_core__ ("matrix_test_info", value); %! else %! info = __mplapack_core__ ("scalar_test_info", value); %! endif %!endfunction %!function assert_matrix_text (value, expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! value, row, column, expected{row, column})); %! endfor %! endfor %!endfunction %!function assert_scalar_text (value, expected) %! assert (__mplapack_core__ ("scalar_test_equal_string", value, expected)); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2", "3"; "4", "5", "6"}); %! B = mp ({"10", "20", "30"; "40", "50", "60"}); %! assert_matrix_text (A + B, {"11", "22", "33"; "44", "55", "66"}); %! assert_matrix_text (A - B, {"-9", "-18", "-27"; "-36", "-45", "-54"}); %! assert_matrix_text (A .* B, {"10", "40", "90"; "160", "250", "360"}); %! assert_matrix_text (B ./ A, {"10", "10", "10"; "10", "10", "10"}); %! assert_matrix_text (+A, {"1", "2", "3"; "4", "5", "6"}); %! assert_matrix_text (-A, {"-1", "-2", "-3"; "-4", "-5", "-6"}); %! assert (elementwise_info (A + B).precision_bits, uint64 (256)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (128); %! A = mp ({"1", "2", "3"; "4", "5", "6"}); %! row = mp ({"10", "20", "30"}); %! column = mp ({"100"; "200"}); %! assert_matrix_text (A + row, {"11", "22", "33"; "14", "25", "36"}); %! assert_matrix_text (A + column, {"101", "102", "103"; ... %! "204", "205", "206"}); %! assert_matrix_text (column + row, {"110", "120", "130"; ... %! "210", "220", "230"}); %! assert_matrix_text (column - row, {"90", "80", "70"; ... %! "190", "180", "170"}); %! assert_matrix_text (row - column, {"-90", "-80", "-70"; ... %! "-190", "-180", "-170"}); %! quotient_row = mp ({"10", "20", "50"}); %! assert_matrix_text (column ./ quotient_row, {"10", "5", "2"; ... %! "20", "10", "4"}); %! assert (size (A + row), [2, 3]); %! assert (size (row + column), [2, 3]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2"; "3", "4"}); %! assert_matrix_text (A + [10, 20; 30, 40], ... %! {"11", "22"; "33", "44"}); %! assert_matrix_text ([10, 20; 30, 40] - A, ... %! {"9", "18"; "27", "36"}); %! assert_matrix_text (A .* [10, 20; 30, 40], ... %! {"10", "40"; "90", "160"}); %! assert_matrix_text ([10, 20; 30, 40] ./ A, ... %! {"10", "10"; "10", "10"}); %! assert_matrix_text (A + [10, 20], {"11", "22"; "13", "24"}); %! assert_matrix_text ([10; 20] + A, {"11", "12"; "23", "24"}); %! assert_matrix_text (A + 0.125, {"1.125", "2.125"; "3.125", "4.125"}); %! assert_matrix_text (0.125 + A, {"1.125", "2.125"; "3.125", "4.125"}); %! decimal = mp ({"0.1", "0.125"}); %! binary = [0.1, 0.125]; %! decimal_sum = decimal + 0.1; %! exact_sum = decimal + mp ("0.1"); %! assert (! __mplapack_core__ ("matrix_test_element_equal", ... %! decimal_sum, 1, 1, exact_sum, 1, 1)); %! assert (__mplapack_core__ ("matrix_test_element_equal", ... %! decimal + binary, 1, 2, ... %! decimal + mp ("0.125"), 1, 2)); %! assert (elementwise_info (A + 0.1).precision_bits, uint64 (256)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "2"; "3", "4"}); %! B = mp ({"5", "6"; "7", "8"}); %! mpbits (128); %! results = {A + B, A - B, A .* B, A ./ B, -A}; %! for i = 1:numel (results) %! assert (elementwise_info (results{i}).precision_bits, uint64 (256)); %! endfor %! assert (mpbits (), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! mpbits (4096); %! high_default = A + B; %! assert (elementwise_info (high_default).precision_bits, uint64 (256)); %! assert (__mplapack_core__ ("matrix_test_element_equal", high_default, ... %! 1, 1, results{1}, 1, 1)); %! assert (mpbits (), uint64 (4096)); %! tail = strcat ("1.", repmat ("0", 1, 210), "1"); %! mpbits (1024); %! sensitive = mp ({tail, "0"; "0", "1"}); %! mpbits (128); %! preserved = sensitive + mp ("0"); %! assert (elementwise_info (preserved).precision_bits, uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_element_equal", preserved, ... %! 1, 1, sensitive, 1, 1)); %! deep_tail = strcat ("1.", repmat ("0", 1, 450), "1"); %! mpbits (2048); %! deep = mp ({deep_tail, "0"; "0", "1"}); %! mpbits (128); %! deep_result = deep - mp ("0"); %! assert (elementwise_info (deep_result).precision_bits, uint64 (2048)); %! assert (__mplapack_core__ ("matrix_test_element_equal", deep_result, ... %! 1, 1, deep, 1, 1)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! positive_zero = mp (0.0); %! negative_zero = mp (-0.0); %! positive_one = mp ("1"); %! negative_one = mp ("-1"); %! assert (__mplapack_core__ ("scalar_test_info", -positive_zero).signbit); %! assert (! __mplapack_core__ ("scalar_test_info", -negative_zero).signbit); %! assert (__mplapack_core__ ("scalar_test_info", ... %! (positive_one ./ positive_zero)).is_infinite); %! assert (__mplapack_core__ ("scalar_test_info", ... %! (negative_one ./ positive_zero)).signbit); %! assert (__mplapack_core__ ("scalar_test_info", ... %! (positive_zero ./ positive_zero)).is_nan); %! A = mp ({"1", "-1"; "0", "0"}); %! Z = mp ({"0", "-0"; "0", "0"}); %! assert (__mplapack_core__ ("scalar_test_info", (A ./ Z)(1, 1)).is_infinite); %! assert (__mplapack_core__ ("scalar_test_info", (A ./ Z)(1, 2)).is_infinite); %! assert (__mplapack_core__ ("scalar_test_info", (A ./ Z)(2, 1)).is_nan); %!test %! A = mp (zeros (0, 3)); %! B = mp (ones (1, 3)); %! C = A + B; %! assert (size (C), [0, 3]); %! D = mp (zeros (2, 0)); %! E = mp (ones (1, 0)); %! F = D .* E; %! assert (size (F), [2, 0]); %! try %! mp (zeros (2, 3)) + mp (zeros (4, 3)); %! error ("incompatible element-wise shape unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, ... %! "incompatible element-wise shape unexpectedly succeeded")); %! assert (strcmp (exception.identifier, "mplapack:mp:DimensionMismatch")); %! end_try_catch %!test %! A = mp ({"1", "2"; "3", "4"}); %! B = mp ({"5", "6"; "7", "8"}); %! S = A + B; %! assert (char (S(1, 1)), "6e+0"); %! assert (size (double (S)), [2, 2]); %! P = S * mp ({"1"; "1"}); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! P, 1, 1, "14")); %! Q = (A + mp ("1")) \ mp ({"5"; "9"}); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! Q, 1, 1, 1)); mplapack-interop-0.5.1/test/rgels.tst0000644000230300031750000001410615274353472017074 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_matrix_text (value, expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! value, row, column, expected{row, column})); %! endfor %! endfor %!endfunction %!function assert_matrix_close (value, expected) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! got = __mplapack_core__ ("matrix_test_element_double", ... %! value, row, column); %! assert (got, expected(row, column), 1e-12); %! endfor %! endfor %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1"; "2"; "3"}); %! B = mp ({"1"; "2"; "3"}); %! X = A \ B; %! assert (double (X), 1, 1e-12); %! A_row = mp ({"1", "2", "3"}); %! B_row = mp ({"14"}); %! X_row = A_row \ B_row; %! assert_matrix_close (X_row, [1; 2; 3]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "0"; "0", "1"; "1", "1"}); %! B = mp ({"0"; "1"; "4"}); %! X = A \ B; %! assert_matrix_close (X, [1; 2]); %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (256)); %! assert_matrix_text (A, {"1", "0"; "0", "1"; "1", "1"}); %! assert_matrix_text (B, {"0"; "1"; "4"}); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "0", "1"; "0", "1", "1"}); %! B = mp ({"3"; "3"}); %! X = A \ B; %! assert_matrix_close (X, [1; 1; 2]); %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (256)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! t = strcat ("0.", repmat ("0", 1, 210), "1"); %! A = mp ({"1", "0"; "0", "1"; "1", "1"}); %! B = mp ({"0"; "1"; "4"}); %! B(1) = mp (t); %! B(2) = mp ("1") - mp (t); %! mpbits (128); %! X = A \ B; %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (1024)); %! assert (! __mplapack_core__ ("matrix_test_element_equal_double", ... %! X, 1, 1, 1)); %! assert (! __mplapack_core__ ("matrix_test_element_equal_double", ... %! X, 2, 1, 2)); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "0"; "0", "1"; "1", "1"}); %! B = [0; 1; 4]; %! X = A \ B; %! assert_matrix_close (X, [1; 2]); %! X2 = [1, 0; 0, 1; 1, 1] \ mp ({"0"; "1"; "4"}); %! assert_matrix_close (X2, [1; 2]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "0"; "0", "1"; "1", "1"}); %! X_expected = mp ({"1", "2"; "2", "1"}); %! B = A * X_expected + mp ({"-1", "-1"; "-1", "-1"; "1", "1"}); %! X = A \ B; %! assert_matrix_close (X, [1, 2; 2, 1]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "0", "1"; "0", "1", "1"}); %! B = mp ({"3", "6"; "3", "3"}); %! X = A \ B; %! assert_matrix_close (X, [1, 3; 1, 0; 2, 3]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "0", "1"; "0", "1", "1"}); %! B = mp ({"3"; "3"}); %! X = A \ B; %! assert_matrix_close (A * X, [3; 3]); %! assert_matrix_close (X, [1; 1; 2]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ({"1", "0"; "0", "1"; "1", "1"}); %! B = mp ({"0"; "1"; "4"}); %! mpbits (4096); %! X = A \ B; %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits, ... %! uint64 (256)); %! assert (__mplapack_core__ ("precision_get_bits"), uint64 (4096)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp (zeros (2, 0)); %! B = mp (zeros (2, 3)); %! X = A \ B; %! info = __mplapack_core__ ("matrix_test_info", X); %! assert (info.rows, uint64 (0)); %! assert (info.columns, uint64 (3)); %! assert (info.precision_bits, uint64 (256)); %! A0 = mp (zeros (0, 2)); %! B0 = mp (zeros (0, 1)); %! X0 = A0 \ B0; %! info0 = __mplapack_core__ ("matrix_test_info", X0); %! assert (info0.rows, uint64 (2)); %! assert (info0.columns, uint64 (1)); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! X0, 1, 1, 0)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! A = mp ({"1", "2"; "2", "4"}); %! B = mp ({"1"; "2"}); %! try %! A \ B; %! error ("singular solve unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, "singular solve unexpectedly succeeded")); %! assert (strcmp (exception.identifier, "mplapack:mp:SingularMatrix")); %! end_try_catch %!test %! A = mp ({"1", "2"; "3", "4"; "5", "6"}); %! B = mp ({"1"; "2"}); %! try %! A \ B; %! error ("dimension mismatch unexpectedly succeeded"); %! catch exception %! assert (! strcmp (exception.message, "dimension mismatch unexpectedly succeeded")); %! assert (strcmp (exception.identifier, "mplapack:mp:DimensionMismatch")); %! end_try_catch mplapack-interop-0.5.1/test/t06_special_function_firewall.tst0000644000230300031750000000463715274353472023673 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_rejected (thunk, label) %! rejected = false; %! try %! thunk (); %! catch %! rejected = true; %! end_try_catch %! assert (rejected, label); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! x = mp ('0.5'); %! %! ## These APIs are deliberately not mapped to @mp yet. The calls must %! ## fail at the package boundary instead of converting x to binary64. %! assert_rejected (@() gammainc (x, x), ... %! "gammainc must remain behind the semantic audit"); %! assert_rejected (@() betainc (x, x, x), ... %! "betainc must remain behind the backend audit"); %! assert_rejected (@() erfinv (x), ... %! "erfinv must remain behind the arbitrary-precision audit"); %! assert_rejected (@() erfcinv (x), ... %! "erfcinv must remain behind the arbitrary-precision audit"); %! assert_rejected (@() erfcx (x), ... %! "erfcx must remain behind the arbitrary-precision audit"); %! assert_rejected (@() expint (x), ... %! "expint must remain behind the semantic audit"); %! assert_rejected (@() besselj (0, x), ... %! "besselj must remain behind the order audit"); %! assert_rejected (@() bessely (0, x), ... %! "bessely must remain behind the order audit"); %! assert_rejected (@() besseli (0, x), ... %! "besseli must remain behind the backend audit"); %! assert_rejected (@() besselk (0, x), ... %! "besselk must remain behind the backend audit"); %! assert_rejected (@() airy (0, x), ... %! "airy must remain behind the multi-output audit"); %! assert_rejected (@() psi (x), ... %! "psi must remain behind the signature audit"); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! tiny = mp ('1'); %! for k = 1:700, tiny = tiny * mp ('0.5'); endfor %! ## The implemented T05 family remains the only special-function path %! ## exercised by this milestone and still preserves the operation p-bit. %! value = erfc (tiny); %! assert (__mplapack_core__ ("scalar_test_info", value).precision_bits == uint64 (1024)); %! assert (value > mp ('0.9')); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/complex_rank.tst0000644000230300031750000000753315274353472020450 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_rank_info (value, expected_rows, expected_columns, ... %! expected_precision) %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (expected_rows)); %! assert (info.columns, uint64 (expected_columns)); %! assert (info.precision_bits, uint64 (expected_precision)); %! assert (info.is_complex && info.all_elements_same_precision); %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! A = mp ([1 + 0i, 0 + 0i; 0 + 0i, 1 + 0i; 1 + 0i, 1 + 0i]); %! B = mp ([1 + 2i, 2 - 1i; 3 + 0i, -1 + 4i; ... %! 4 + 2i, 1 + 3i]); %! A_before = double (A); %! B_before = double (B); %! X = A \ B; %! assert_rank_info (X, 2, 2, 512); %! assert (double (X), [1 + 2i, 2 - 1i; 3 + 0i, -1 + 4i], 1e-12); %! assert (double (A), A_before); %! assert (double (B), B_before); %! clear A B; %! assert (double (X), [1 + 2i, 2 - 1i; 3 + 0i, -1 + 4i], 1e-12); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1 + 0i, 0 + 0i, 1 + 0i; ... %! 0 + 0i, 1 + 0i, 1 + 0i]); %! B = mp ([3 + 3i; 3 + 3i]); %! X = A \ B; %! assert_rank_info (X, 3, 1, 256); %! assert (double (X), [1 + 1i; 1 + 1i; 2 + 2i], 1e-12); %! rank_deficient = mp ([1 + 0i, 0 + 0i; ... %! 2 + 0i, 0 + 0i; 3 + 0i, 0 + 0i]); %! rank_rhs = mp ([1 + 2i; 2 + 4i; 3 + 6i]); %! rank_solution = rank_deficient \ rank_rhs; %! assert_rank_info (rank_solution, 2, 1, 256); %! assert (double (rank_solution), [1 + 2i; 0 + 0i], 1e-12); %! zero_solution = mp (complex (zeros (3, 2), zeros (3, 2))) \ ... %! mp (complex (zeros (3, 1), zeros (3, 1))); %! assert_rank_info (zero_solution, 2, 1, 256); %! assert (double (zero_solution), [0; 0]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 0; 0, 1; 1, 1]); %! mpbits (512); %! B = mp ([1 + 2i; 3 + 0i; 4 + 2i]); %! mpbits (1024); %! X = A \ B; %! assert_rank_info (X, 2, 1, 512); %! assert (double (X), [1 + 2i; 3 + 0i], 1e-12); %! builtin_B = [1 + 2i; 3 + 0i; 4 + 2i]; %! builtin_X = A \ builtin_B; %! assert_rank_info (builtin_X, 2, 1, 256); %! assert (double (builtin_X), [1 + 2i; 3 + 0i], 1e-12); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (1024)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! A = mp ([1 + 0i, 0 + 0i; 0 + 0i, 1 + 0i; ... %! 0 + 0i, 0 + 0i]); %! B = mp (complex (zeros (3, 1), zeros (3, 1))); %! tail = mp ("1", "-1"); %! for k = 1:exponent %! tail = tail ./ mp ("2"); %! endfor %! B(1, 1) = tail; %! B(2, 1) = tail; %! mpbits (128); %! X = A \ B; %! assert_rank_info (X, 2, 1, precision); %! assert (strcmp (char (X(1, 1)), char (tail))); %! assert (strcmp (char (X(2, 1)), char (tail))); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp (complex (ones (3, 2), zeros (3, 2))); %! B = mp (complex (ones (2, 1), zeros (2, 1))); %! caught = false; %! try %! A \ B; %! catch exception %! caught = true; %! assert (strcmp (exception.identifier, "mplapack:mp:DimensionMismatch")); %! end_try_catch %! assert (caught); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect mplapack-interop-0.5.1/test/public_lifetime.m0000644000230300031750000000220315274353472020531 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause assert (! isempty (which ("mp"))); assert (! isempty (which ("__mplapack_core__"))); saved_precision = mpbits (); mpbits (128); original = mp ("1.25"); assigned = original; copied = mp (original); collection = {original, assigned}; record.value = copied; assert (__mplapack_core__ ("module_test_locked")); clear original __mplapack_core__; assigned_info = __mplapack_core__ ("scalar_test_info", assigned); copied_info = __mplapack_core__ ("scalar_test_info", copied); cell_info = __mplapack_core__ ("scalar_test_info", collection{1}); struct_info = __mplapack_core__ ("scalar_test_info", record.value); for info = {assigned_info, copied_info, cell_info, struct_info} assert (info{1}.precision_bits, int64 (128)); endfor assert (__mplapack_core__ ( "scalar_test_equal_string", assigned, "1.25")); assert (__mplapack_core__ ("scalar_test_equal", assigned, copied)); assert (__mplapack_core__ ("module_test_locked")); clear assigned copied collection record; assert (__mplapack_core__ ("module_test_locked")); mpbits (saved_precision); fprintf ("PASS: public wrapper clear and native payload lifecycle\n"); mplapack-interop-0.5.1/test/test_neigt05.m0000644000230300031750000000400315274353472017707 0ustar rafaelrafael% Focused NEIGT05 exact similarity regimes and nontrivial subspace checks. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect regimes = {"simple", "semisimple", "jordan", "two_jordan"}; for regime_index = 1:numel (regimes) regime = regimes{regime_index}; if (strcmp (regime, "two_jordan")) gap = 12; else gap = 24; endif fixture = net_similarity_model (regime, 8, gap, 512); audit = net_similarity_audit (fixture); assert (audit.exact_intertwining); assert (all (audit.characteristic_checks)); assert (all (cellfun (@(x) x.status, audit.nilpotent_checks))); assert (all (cellfun (@(x) x.status, audit.subspace_checks))); assert (strcmp (audit.multiplicity_source, ... "exact_J_structure_not_disk_count")); if (strcmp (regime, "simple") || strcmp (regime, "semisimple")) assert (audit.diagonalizable && audit.full_eigenbasis_exists); else assert (! audit.diagonalizable && ! audit.full_eigenbasis_exists); assert (audit.nilpotent_checks{1}.first_power_nonzero); endif if (strcmp (regime, "semisimple")) assert (audit.groups(1).geometric_multiplicity == 2); assert (! audit.nilpotent_checks{1}.first_power_nonzero); endif if (strcmp (regime, "simple")) assert (! audit.coordinate_columns_diagonalize ... || strcmp (regime, "semisimple")); endif endfor merged = net_similarity_model ("two_jordan", 16, 40, 512); merged_audit = net_similarity_audit (merged, [0, 1, 2, 4, 16, 17]); assert (merged_audit.groups(1).algebraic_multiplicity == 2); assert (merged_audit.groups(2).algebraic_multiplicity == 2); assert (! merged_audit.full_eigenbasis_exists); fprintf ("PASS: NEIGT05 exact similarity multiplicities, Jordan orders, and subspaces\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/test_neigt13.m0000644000230300031750000000737615274353472017726 0ustar rafaelrafael% NEIGT13: outward primitive, rectangle, range, and exact replay checks. test_root = fileparts (fileparts (mfilename ("fullpath"))); private_root = fullfile (test_root, "examples", "neig_tiers", "private"); addpath (private_root); saved_bits = mpbits (); unwind_protect for q = [64, 128, 256] mpbits (q); one = mp (1); three = mp (3); quotient = net_iv_primitive ("div", one, three, q); assert (three * quotient.lo <= one); assert (three * quotient.hi >= one); radical = net_iv_primitive ("sqrt", mp (2), mp (0), q); assert (radical.lo * radical.lo <= mp (2)); assert (radical.hi * radical.hi >= mp (2)); cancellation = net_iv_primitive ("add", one, -one, q); assert (cancellation.lo == mp (0) && cancellation.hi == mp (0)); caught = false; try net_iv_round (mp (0), q, false, "adversarial-zero"); catch caught = true; end_try_catch assert (caught); endfor q = 256; mpbits (q); real_box = net_iv_point (mp ("1.25"), q); complex_box = net_iv_complex_point (net_mp_complex (mp ("1.25"), mp ("-0.75")), q); product = net_iv_complex_mul (complex_box, ... net_iv_complex_point (net_mp_complex (mp ("-2"), mp ("0.5")), q), q); conjugated = net_iv_complex_conj (complex_box); assert (conjugated.il == -complex_box.ih && conjugated.ih == -complex_box.il); modulus = net_iv_complex_abs (complex_box, q); assert (modulus.lo >= mp (0) && modulus.hi >= modulus.lo); assert (product.rl <= mp ("-2.125") && product.rh >= mp ("-2.125")); matrix = mp ([2, 1; -1, 3]) + net_mp_complex (mp (0), mp (0)); inverse_candidate = mp ([3, -1; 1, 2]) / mp (7); inverse_witness = net_iv_inverse_residual (matrix, inverse_candidate, q); assert (inverse_witness.nonsingular); assert (inverse_witness.e < mp ("0.01")); product_box = net_iv_cmatrix_mul (net_iv_cmatrix_point (matrix, q), ... net_iv_cmatrix_point (inverse_candidate, q), q); assert (product_box.rl(1,1) <= mp (1) && product_box.rh(1,1) >= mp (1)); assert (net_iv_cmatrix_inf_upper (product_box, q) > mp (0)); assert (net_iv_cmatrix_fro_upper (product_box, q) > mp (0)); caught = false; try net_iv_primitive ("div", mp (1), mp (0), q); catch caught = true; end_try_catch assert (caught); caught = false; try net_iv_real_sqrt (net_iv_real (mp ("-1"), mp ("1")), q); catch caught = true; end_try_catch assert (caught); caught = false; try net_iv_primitive ("add", net_pow2 (-9000, q), mp (0), q); catch caught = true; end_try_catch assert (caught); tiny = net_pow2 (-1500, q); dyadic = net_dyadic_encode_matrix ... (mp ([1, -2; 3, 4]) + tiny * mp ([0, 1; -1, 0]), q); witness = strcat (tempname (), ".json"); net_dyadic_write_json (dyadic, witness); loaded = net_dyadic_read_json (witness); decoded = net_dyadic_decode_matrix (loaded, 512); assert (isequal (size (decoded), [2, 2])); for index = 1:numel (decoded) assert (isequal (net_dyadic_encode_scalar (decoded(index), 512), ... dyadic.values{index})); endfor caught = false; tampered = strcat (tempname (), ".json"); text = fileread (witness); text = strrep (text, "neigt-dyadic-v1", "neigt-dyadic-tampered"); h = fopen (tampered, "w"); fwrite (h, text); fclose (h); try net_dyadic_read_json (tampered); catch caught = true; end_try_catch assert (caught); caught = false; try net_dyadic_decode_matrix (loaded, q - 1); catch caught = true; end_try_catch assert (caught); fprintf ("PASS: NEIGT13 outward primitives, complex rectangles, range checks, and replay hash\n"); unwind_protect_cleanup mpbits (saved_bits); if (any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect mplapack-interop-0.5.1/test/mp_complex_matrix_concat_test.cc0000644000230300031750000001164415274353473023655 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include #include #include #include #include "mp_complex_matrix_concat.h" #include "mp_matrix_storage.h" namespace { using ComplexMatrix = octave_mplapack::MpfrComplexMatrixStorage; using RealMatrix = octave_mplapack::MpfrMatrixStorage; void check (bool condition, const char *message) { if (! condition) throw std::runtime_error (message); } void test_horizontal_mixed_concat () { const RealMatrix real (2, 1, 256, std::vector {1.0, 2.0}); const ComplexMatrix complex (2, 1, 1024, std::vector> { {3.0, 4.0}, {5.0, -6.0}}); octave_mplapack::MpcConcatOperand real_operand; real_operand.rows = real.rows (); real_operand.columns = real.columns (); real_operand.precision_bits = real.precision_bits (); real_operand.has_mp_precision = true; real_operand.copy_element = [&real] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { mpc_set_fr (destination.mpc_data (), real.at (row, column).mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; octave_mplapack::MpcConcatOperand complex_operand; complex_operand.rows = complex.rows (); complex_operand.columns = complex.columns (); complex_operand.precision_bits = complex.precision_bits (); complex_operand.has_mp_precision = true; complex_operand.copy_element = [&complex] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { mpc_set (destination.mpc_data (), complex.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; const auto result = octave_mplapack::mpc_matrix_concatenate ( {real_operand, complex_operand}, 1, 2, 2, 1024); check (result.rows () == 2 && result.columns () == 2 && result.precision_bits () == 1024 && result.all_elements_have_uniform_precision (), "mixed horizontal complex concatenation metadata mismatch"); check (result.element_exactly_equal_double (0, 0, {1.0, 0.0}) && result.element_exactly_equal_double (1, 0, {2.0, 0.0}) && result.element_exactly_equal_double (0, 1, {3.0, 4.0}) && result.element_exactly_equal_double (1, 1, {5.0, -6.0}), "mixed horizontal complex concatenation values mismatch"); } void test_vertical_and_empty_concat () { const RealMatrix real (1, 2, 512, std::vector {1.0, 2.0}); const ComplexMatrix complex (1, 2, 512, std::vector> { {3.0, 1.0}, {4.0, -1.0}}); octave_mplapack::MpcConcatOperand real_operand; real_operand.rows = 1; real_operand.columns = 2; real_operand.precision_bits = 512; real_operand.has_mp_precision = true; real_operand.copy_element = [&real] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { mpc_set_fr (destination.mpc_data (), real.at (row, column).mpfr_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; octave_mplapack::MpcConcatOperand complex_operand; complex_operand.rows = 1; complex_operand.columns = 2; complex_operand.precision_bits = 512; complex_operand.has_mp_precision = true; complex_operand.copy_element = [&complex] (mpfrxx::mpc_class& destination, std::size_t row, std::size_t column) { mpc_set (destination.mpc_data (), complex.at (row, column).mpc_data (), MPC_RND (MPFR_RNDN, MPFR_RNDN)); }; const auto result = octave_mplapack::mpc_matrix_concatenate ( {real_operand, complex_operand}, 0, 2, 2, 512); check (result.element_exactly_equal_double (0, 0, {1.0, 0.0}) && result.element_exactly_equal_double (0, 1, {2.0, 0.0}) && result.element_exactly_equal_double (1, 0, {3.0, 1.0}) && result.element_exactly_equal_double (1, 1, {4.0, -1.0}), "mixed vertical complex concatenation values mismatch"); octave_mplapack::MpcConcatOperand empty_operand; empty_operand.rows = 0; empty_operand.columns = 2; empty_operand.precision_bits = 2048; empty_operand.has_mp_precision = true; empty_operand.copy_element = [] (mpfrxx::mpc_class&, std::size_t, std::size_t) {}; const auto empty_result = octave_mplapack::mpc_matrix_concatenate ( {empty_operand}, 0, 0, 2, 2048); check (empty_result.rows () == 0 && empty_result.columns () == 2 && empty_result.precision_bits () == 2048, "empty complex concatenation shape mismatch"); } } // namespace int main () { try { test_horizontal_mixed_concat (); test_vertical_and_empty_concat (); std::cout << "PASS: native mixed real/complex concatenation, precision, values, and empty shapes\n"; return 0; } catch (const std::exception& exception) { std::cerr << "FAIL: " << exception.what () << '\n'; return 1; } } mplapack-interop-0.5.1/test/test_neigt21.m0000644000230300031750000000516715274353473017722 0ustar rafaelrafael% NEIGT21: positive Perron root, normalized pair, and stationary-vector checks. test_root = fileparts (fileparts (mfilename ("fullpath"))); private_root = fullfile (test_root, "examples", "neig_tiers", "private"); addpath (private_root); saved_bits = mpbits (); unwind_protect bundle = net_manifest (); profile_data = bundle.jobs.profiles.smoke; jobs = profile_data.jobs; checked = cell (1, 4); for index = 1:4 checked{index} = net_v_a3_job (jobs{22 + index}, profile_data, "smoke"); current = checked{index}; assert (current.pass && current.milestone_pass); assert (strcmp (current.status, "CERTIFIED_PERRON_PAIR")); assert (current.collatz.pass && current.collatz.irreducible ... && current.collatz.strictly_positive); assert (current.root_width_pass && current.pair.pass); assert (current.lambda_intersection.nonempty); assert (current.left_strictly_positive); assert (current.left_residual_norm_upper <= current.root_width_target); if (index <= 2) assert (current.stationary.pass); assert (current.stationary.positive); endif endfor assert (checked{1}.collatz.cw_lower > mp (0)); assert (checked{3}.collatz.cw_lower > mp (1)); % Negative entry, reducibility, and nonpositive trial vectors fail closed. negative = mp (ones (3)); negative(1,2) = mp (-1); neg_result = net_v_a3_collatz (negative, mp (ones (3,1)), 128); assert (! neg_result.pass && strcmp (neg_result.status, ... "UNSUPPORTED_NEGATIVE_ENTRY")); reducible = mp (eye (3)); red_result = net_v_a3_collatz (reducible, mp (ones (3,1)), 128); assert (! red_result.pass && strcmp (red_result.status, ... "INCONCLUSIVE_NOT_IRREDUCIBLE")); nonpositive = net_v_a3_collatz (mp (ones (3)), ... mp ([-1; 1; 1]), 128); assert (! nonpositive.pass && strcmp (nonpositive.status, ... "INCONCLUSIVE_NONPOSITIVE_TRIAL")); A = mp (ones (3)); x = mp (ones (3, 1)) / mp (3); mpbits (128); good_pair = net_v_a3_pair (A, x, mp (3), 128); bad_R = mp (2) * good_pair.R; bad_pair = net_v_a3_pair (A, x, mp (3), 128, struct ("R", bad_R)); assert (! bad_pair.pass); assert (strcmp (bad_pair.status, "INCONCLUSIVE_PAIR_CONTRACTION")); assert (bad_pair.trials(end).e >= mp (1)); fprintf ("PASS: NEIGT21 positive graph, Collatz--Wielandt, Perron pair, stationary vector, and fail-closed negatives\n"); unwind_protect_cleanup mpbits (saved_bits); if (any (strcmp (strsplit (path (), pathsep), private_root))) rmpath (private_root); endif end_unwind_protect mplapack-interop-0.5.1/test/det_inv.tst0000644000230300031750000000532315274353473017412 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! A_before = double (A); %! d = det (A); %! assert (double (d), -2, 1e-12); %! assert (__mplapack_core__ ("scalar_test_info", d).precision_bits == 256); %! X = inv (A); %! assert (size (X), [2, 2]); %! assert (double (X), [-2, 1; 1.5, -0.5], 1e-12); %! assert (double (A), A_before); %! assert (__mplapack_core__ ("matrix_test_info", X).precision_bits == 256); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! Z = mp ([1 + 1i, 2; 3, 4 - 1i]); %! d = det (Z); %! assert (double (d), -1 + 3i, 1e-12); %! X = inv (Z); %! expected = [-0.7 - 1.1i, 0.2 + 0.6i; ... %! 0.3 + 0.9i, 0.2 - 0.4i]; %! assert (double (X), expected, 1e-12); %! assert (! isreal (d) && ! isreal (X)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! for setting = {[1024, 700], [2048, 1500]} %! precision = setting{1}(1); %! exponent = setting{1}(2); %! mpbits (precision); %! tail = mp ("1"); %! for k = 1:exponent %! tail = tail ./ 2; %! endfor %! reciprocal = mp ("1"); %! for k = 1:exponent %! reciprocal = reciprocal .* 2; %! endfor %! A = mp ([1, 0; 0, 1]); %! A(1, 1) = tail; %! mpbits (128); %! d = det (A); %! X = inv (A); %! assert (strcmp (char (d), char (tail))); %! assert (strcmp (char (X(1, 1)), char (reciprocal))); %! assert (mpbits () == 128); %! endfor %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (256); %! singular = mp ([1, 2; 2, 4]); %! assert (double (det (singular)), 0); %! caught = false; %! try %! inv (singular); %! catch exception %! caught = true; %! assert (strcmp (exception.identifier, "mplapack:mp:SingularMatrix")); %! end_try_catch %! assert (caught); %! complex_singular = mp ([1 + 0i, 2; 2, 4 + 0i]); %! assert (double (det (complex_singular)), 0); %! caught = false; %! try %! inv (complex_singular); %! catch exception %! caught = true; %! assert (strcmp (exception.identifier, "mplapack:mp:SingularMatrix")); %! end_try_catch %! assert (caught); %!test %! A = mp ([1, 2; 3, 4]); %! nonsquare = mp ([1, 2, 3]); %! fail ("det (nonsquare)", "square"); %! fail ("inv (nonsquare)", "square"); %! [d, c] = det (A); %! assert (double (d), -2, 1e-12); %! assert (double (c) > 0 && double (c) < 1); %! fail ("[x, y] = inv (A)", "too many outputs"); %!test %! empty = mp (zeros (0, 0)); %! assert (double (det (empty)), 1); %! inverse = inv (empty); %! assert (size (inverse), [0, 0]); mplapack-interop-0.5.1/test/test_neigt11.m0000644000230300031750000000301415274353473017706 0ustar rafaelrafael% Focused NEIGT11 stochastic and positive-Perron tests. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect result = net_markov_audit (8, 24, 256, 256); assert (result.row_sum_exact); assert (result.positive_markov && result.positive_perron); assert (result.r_difference_max > net_pow2 (-20, 320)); assert (max (abs (result.markov_reference.stationary_difference)) ... < net_pow2 (-180, 320)); assert (max (abs (result.markov_reference.stationary_equation)) ... < net_pow2 (-180, 320)); assert (max (abs (result.markov_reference.independent_equation)) ... < net_pow2 (-180, 320)); assert (result.markov_metrics.absolute_match.threshold < net_pow2 (-150, 320)); assert (result.perron_metrics.absolute_match.threshold < net_pow2 (-150, 320)); assert (max (abs (result.perron_right_equation)) < net_pow2 (-180, 320)); assert (max (abs (result.perron_left_equation)) < net_pow2 (-180, 320)); assert (all (result.perron_right > mp (0))); assert (all (result.perron_left > mp (0))); assert (abs (sum (result.perron_right) - mp (1)) < net_pow2 (-200, 320)); assert (abs (transpose (result.perron_left) * result.perron_right - mp (1)) ... < net_pow2 (-200, 320)); fprintf ("PASS: NEIGT11 Markov spectrum, stationary solves, and Perron pair\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/test_neigt04.m0000644000230300031750000000522615274353473017717 0ustar rafaelrafael% Focused NEIGT04 Ozaki--Ogita generator test. test_root = fileparts (fileparts (mfilename ("fullpath"))); addpath (fullfile (test_root, "examples", "neig_tiers")); addpath (fullfile (test_root, "examples", "neig_tiers", "private")); saved_bits = mpbits (); unwind_protect kinds = {"OO53_REAL", "OO53_PAIR", "OO128_CLOSE"}; dimensions = [8, 16]; hashes = cell (numel (kinds), numel (dimensions)); for kind_index = 1:numel (kinds) for dimension_index = 1:numel (dimensions) kind = kinds{kind_index}; n = dimensions(dimension_index); model = net_oo_generator (kind, n); assert (model.generation_bits == 53 || model.generation_bits == 128); assert (model.theorem_predicate); assert (model.xy_exact && model.yx_exact && model.products_exact); assert (model.quantization_changed); assert (strcmp (model.method, ... "fixed_precision_two_step_RN_triple_product_v1")); assert (model.A == model.A_exact); assert (any (model.S_requested(:) == mp (0))); if (strcmp (kind, "OO53_PAIR")) assert (any (model.S_requested(:) < mp (0))); endif pair = net_oo_validate_pair (model.X, model.Y, model.generation_bits); assert (pair.valid); hashes{kind_index, dimension_index} = model.model_hash; repeat = net_oo_generator (kind, n); assert (strcmp (repeat.model_hash, model.model_hash)); assert (repeat.A == model.A); if (strcmp (kind, "OO53_PAIR")) for block = 0:(n / 2 - 1) first = 2 * block + 1; assert (model.S_realized(first + 1, first + 1) ... == model.S_realized(first, first)); assert (model.S_realized(first + 1, first) ... == -model.S_realized(first, first + 1)); endfor assert (any (model.S_realized(2:2:n, 1:2:n) != mp (0))); elseif (strcmp (kind, "OO128_CLOSE")) assert (model.realized_gap == net_pow2 (-80, 128)); assert (model.S_requested(2, 2) - model.S_requested(1, 1) ... == net_pow2 (-80, 128) + net_pow2 (-120, 128)); assert (model.S_realized(2, 2) != model.S_requested(2, 2)); endif endfor endfor bad_Y = model.Y; bad_Y(1, 1) = bad_Y(1, 1) + mp (1); caught = false; try net_oo_validate_pair (model.X, bad_Y, model.generation_bits); catch caught = true; end_try_catch assert (caught); caught = false; try net_exact_product_dyadic (mp ("0.1"), mp (1), 128); catch caught = true; end_try_catch assert (caught); fprintf ("PASS: NEIGT04 Ozaki--Ogita exact triple-product generator and paired rule\n"); unwind_protect_cleanup mpbits (saved_bits); end_unwind_protect mplapack-interop-0.5.1/test/complex_matrix.tst0000644000230300031750000000327015274353473021014 0ustar rafaelrafael%!test %! mpbits (256); %! A = mp ([1 + 2i, 3 + 4i; 5 + 6i, 7 + 8i]); %! info = __mplapack_core__ ("matrix_test_info", A); %! assert (info.rows == 2 && info.columns == 2); %! assert (info.precision_bits == 256 && info.is_complex); %! assert (info.all_elements_same_precision); %! assert (double (A), [1 + 2i, 3 + 4i; 5 + 6i, 7 + 8i]); %! assert (double (A([2, 1], [2, 1])), [7 + 8i, 5 + 6i; 3 + 4i, 1 + 2i]); %! assert (strcmp (char (A(2, 1)), "(5e+0,6e+0)")); %! assert (__mplapack_core__ ("matrix_test_element_equal_text", ... %! A, 2, 1, "(5,6)")); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! A, 1, 2, 3 + 4i)); %!test %! mpbits (512); %! A = mp ([1 + 2i, 3 + 4i; 5 + 6i, 7 + 8i]); %! assert (double (A(:, 2)), [3 + 4i; 7 + 8i]); %! assert (double (A(1, :)), [1 + 2i, 3 + 4i]); %! assert (double (A(:)), [1 + 2i; 5 + 6i; 3 + 4i; 7 + 8i]); %! B = A; %! B(1, 1) = mp (9 + 10i); %! assert (double (A(1, 1)) == 1 + 2i); %! assert (double (B(1, 1)) == 9 + 10i); %! mpbits (1024); %! C = A; %! C(2, 2) = mp (11 + 12i); %! assert (__mplapack_core__ ("matrix_test_info", C).precision_bits == 1024); %! assert (__mplapack_core__ ("matrix_test_element_equal_double", ... %! C, 2, 2, 11 + 12i)); %!test %! A = mp (complex (zeros (0, 0), zeros (0, 0))); %! B = mp (complex (zeros (0, 3), zeros (0, 3))); %! C = mp (complex (zeros (4, 0), zeros (4, 0))); %! assert (size (A), [0, 0]); %! assert (size (B), [0, 3]); %! assert (size (C), [4, 0]); %! assert (! isreal (A) && ! isreal (B) && ! isreal (C)); %! assert (isempty (A) && isempty (B) && isempty (C)); %! assert (strfind (evalc ("disp (B)"), "complex matrix")); mplapack-interop-0.5.1/test/mp_norm_test.cc0000644000230300031750000000724315274353473020246 0ustar rafaelrafael// SPDX-License-Identifier: BSD-2-Clause #include "mp_norm.h" #include #include #include #include #include #include #include "mp_complex_precision.h" namespace { using octave_mplapack::MpfrComplexMatrixStorage; using octave_mplapack::MpfrMatrixStorage; using octave_mplapack::MpfrNormRequest; MpfrNormRequest request (MpfrNormRequest::Kind kind) { return {kind, 2.0}; } void assert_double (const octave_mplapack::MpfrScalarStorage& value, double expected) { assert (mpfr_cmp_d (value.native_value ().mpfr_data (), expected) == 0); } } // namespace int main () { const auto vector = MpfrMatrixStorage ( 2, 1, 512, std::vector {"3", "4"}); assert_double (octave_mplapack::mplapack_mpfr_norm ( vector, request (MpfrNormRequest::Kind::one)), 7.0); assert_double (octave_mplapack::mplapack_mpfr_norm ( vector, request (MpfrNormRequest::Kind::two)), 5.0); assert_double (octave_mplapack::mplapack_mpfr_norm ( vector, request (MpfrNormRequest::Kind::infinity)), 4.0); assert_double (octave_mplapack::mplapack_mpfr_norm ( vector, request (MpfrNormRequest::Kind::negative_infinity)), 3.0); assert_double (octave_mplapack::mplapack_mpfr_norm ( vector, request (MpfrNormRequest::Kind::zero)), 2.0); const auto matrix = MpfrMatrixStorage ( 2, 2, 512, std::vector {"3", "0", "0", "4"}); assert_double (octave_mplapack::mplapack_mpfr_norm ( matrix, request (MpfrNormRequest::Kind::one)), 4.0); assert_double (octave_mplapack::mplapack_mpfr_norm ( matrix, request (MpfrNormRequest::Kind::two)), 4.0); assert_double (octave_mplapack::mplapack_mpfr_norm ( matrix, request (MpfrNormRequest::Kind::infinity)), 4.0); assert_double (octave_mplapack::mplapack_mpfr_norm ( matrix, request (MpfrNormRequest::Kind::frobenius)), 5.0); const auto complex_vector = MpfrComplexMatrixStorage ( 2, 1, 512, std::vector {"(3,4)", "(0,0)"}); assert_double (octave_mplapack::mplapack_mpc_norm ( complex_vector, request (MpfrNormRequest::Kind::one)), 5.0); assert_double (octave_mplapack::mplapack_mpc_norm ( complex_vector, request (MpfrNormRequest::Kind::two)), 5.0); const auto complex_matrix = MpfrComplexMatrixStorage ( 2, 2, 512, std::vector {"(3,0)", "(0,0)", "(0,0)", "(4,0)"}); assert_double (octave_mplapack::mplapack_mpc_norm ( complex_matrix, request (MpfrNormRequest::Kind::two)), 4.0); assert_double (octave_mplapack::mplapack_mpc_norm ( complex_matrix, request (MpfrNormRequest::Kind::frobenius)), 5.0); for (mpfr_prec_t precision : {1024, 2048}) { MpfrMatrixStorage canary (1, 1, precision); mpfr_set_si_2exp (canary.at (0, 0).mpfr_data (), 1, -700, MPFR_RNDN); const auto before = mpfrxx::default_precision_bits (); const auto value = octave_mplapack::mplapack_mpfr_norm ( canary, request (MpfrNormRequest::Kind::two)); assert (value.precision_bits () == precision); assert (mpfr_cmp (value.native_value ().mpfr_data (), canary.at (0, 0).mpfr_data ()) == 0); assert (mpfrxx::default_precision_bits () == before); } mpfrxx::set_default_precision_bits (333); const auto ambient = octave_mplapack::mplapack_mpfr_norm ( vector, request (MpfrNormRequest::Kind::two)); assert (ambient.precision_bits () == 512); assert (mpfrxx::default_precision_bits () == 333); std::puts ("N00 native norm PASS"); } mplapack-interop-0.5.1/test/lu.tst0000644000230300031750000001343015274353473016400 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause %!function assert_matrix_close (value, expected, tolerance) %! if (nargin < 3) %! tolerance = 1e-11; %! endif %! if (isa (expected, "mp")) %! expected = double (expected); %! endif %! info = __mplapack_core__ ("matrix_test_info", value); %! assert (info.rows, uint64 (rows (expected))); %! assert (info.columns, uint64 (columns (expected))); %! for column = 1:columns (expected) %! for row = 1:rows (expected) %! got = __mplapack_core__ ("matrix_test_element_double", ... %! value, row, column); %! assert (got, expected(row, column), tolerance); %! endfor %! endfor %!endfunction %!test %! saved = mpbits (); %! unwind_protect %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! Y = lu (A); %! assert (size (Y), [2, 2]); %! assert_matrix_close (Y, [3, 4; 1/3, 2/3]); %! assert (__mplapack_core__ ("matrix_test_info", Y).precision_bits, ... %! uint64 (256)); %! assert (double (A), [1, 2; 3, 4]); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (256); %! A = mp ([1, 2; 3, 4]); %! [L, U] = lu (A); %! assert (size (L), [2, 2]); %! assert (size (U), [2, 2]); %! assert_matrix_close (L * U, [1, 2; 3, 4]); %! assert_matrix_close (L, [1/3, 1; 1, 0]); %! assert_matrix_close (U, [3, 4; 0, 2/3]); %! [Lc, Uc, P] = lu (A); %! assert (strcmp (class (P), "double")); %! assert (size (P), [2, 2]); %! assert (P, [0, 1; 1, 0]); %! assert_matrix_close (P * A, [3, 4; 1, 2]); %! assert_matrix_close (Lc * Uc, P * A); %! [Lv, Uv, p] = lu (A, "vector"); %! assert (strcmp (class (p), "double")); %! assert (size (p), [2, 1]); %! assert (p, [2; 1]); %! assert_matrix_close (A(p, :), Lv * Uv); %! assert_matrix_close (Lc, Lv); %! assert_matrix_close (Uc, Uv); %! mpbits (512); %!test %! mpbits (256); %! tall = mp ([1, 2; 5, 4; 3, 6]); %! [L, U, P] = lu (tall); %! assert (size (L), [3, 2]); %! assert (size (U), [2, 2]); %! assert (size (P), [3, 3]); %! assert_matrix_close (P * tall, L * U); %! [L2, U2] = lu (tall); %! assert (size (L2), [3, 2]); %! assert (size (U2), [2, 2]); %! assert_matrix_close (tall, L2 * U2); %! wide = mp ([1, 2, 3; 5, 4, 6]); %! [Lw, Uw, Pw] = lu (wide); %! assert (size (Lw), [2, 2]); %! assert (size (Uw), [2, 3]); %! assert (size (Pw), [2, 2]); %! assert_matrix_close (Pw * wide, Lw * Uw); %! [Lw2, Uw2] = lu (wide); %! assert_matrix_close (wide, Lw2 * Uw2); %! mpbits (512); %!test %! mpbits (256); %! S = mp ([1, 2; 2, 4]); %! [L, U, P] = lu (S); %! assert (P, [0, 1; 1, 0]); %! assert_matrix_close (P * S, L * U); %! [Lv, Uv, p] = lu (S, "vector"); %! assert (p, [2; 1]); %! assert_matrix_close (S(p, :), Lv * Uv); %! mpbits (512); %!test %! saved = mpbits (); %! unwind_protect %! mpbits (1024); %! delta = strcat (".", repmat ("0", 1, 210), "1"); %! text = {"4", "2"; "1", "3"}; %! text{2,1} = strcat ("1", delta); %! A = mp (text); %! expected_text = {"1"; "1"}; %! expected_text{2} = strcat ("1", delta); %! expected_tail = mp (expected_text) ./ 4; %! mpbits (128); %! [L, U, P] = lu (A); %! assert (P, eye (2)); %! assert (__mplapack_core__ ("matrix_test_info", L).precision_bits, ... %! uint64 (1024)); %! assert (__mplapack_core__ ("matrix_test_element_equal", ... %! L, 2, 1, expected_tail, 2, 1)); %! assert_matrix_close (P * A, L * U, 1e-12); %! assert (mpbits (), uint64 (128)); %! assert (__mplapack_core__ ("precision_test_mpfr_global_bits"), ... %! uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (2048); %! delta = strcat (".", repmat ("0", 1, 451), "1"); %! text = {"4", "2"; "1", "3"}; %! text{2,1} = strcat ("1", delta); %! A = mp (text); %! expected_text = {"1"; "1"}; %! expected_text{2} = strcat ("1", delta); %! expected_tail = mp (expected_text) ./ 4; %! mpbits (128); %! [L, U] = lu (A); %! assert (__mplapack_core__ ("matrix_test_info", U).precision_bits, ... %! uint64 (2048)); %! assert (__mplapack_core__ ("matrix_test_element_equal", ... %! L, 2, 1, expected_tail, 2, 1)); %! assert (mpbits (), uint64 (128)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! saved = mpbits (); %! unwind_protect %! mpbits (512); %! low = mp ({"1", "0"; "1", "1"}); %! [~, ~, plow] = lu (low, "vector"); %! assert (plow(1), 1); %! mpbits (1024); %! high = mp ({"1", "0"; "1", "1"}); %! high(2, 1) = mp (strcat ("1.", repmat ("0", 1, 210), "1")); %! [~, ~, phigh] = lu (high, "vector"); %! assert (phigh(1), 2); %! mpbits (4096); %! [~, ~, phigh_ambient] = lu (high, "vector"); %! assert (phigh_ambient, phigh); %! assert (mpbits (), uint64 (4096)); %! unwind_protect_cleanup %! mpbits (saved); %! end_unwind_protect %!test %! mpbits (256); %! for value = [4, -4, 0] %! Y = lu (mp (value)); %! [L, U, P] = lu (mp (value)); %! [Lv, Uv, p] = lu (mp (value), "vector"); %! assert (size (Y), [1, 1]); %! assert (size (L), [1, 1]); %! assert (size (U), [1, 1]); %! assert (P, 1); %! assert (p, 1); %! assert (double (L * U), value); %! assert (double (Lv * Uv), value); %! endfor %! mpbits (512); %!test %! mpbits (256); %! for shape_cell = {[0, 0], [0, 3], [3, 0]} %! shape = shape_cell{1}; %! A = mp (zeros (shape(1), shape(2))); %! Y = lu (A); %! [L, U, P] = lu (A); %! [Lv, Uv, p] = lu (A, "vector"); %! assert (size (Y), [0, 0]); %! assert (size (L), [0, 0]); %! assert (size (U), [0, 0]); %! assert (size (P), [0, 0]); %! assert (size (p), [0, 0]); %! assert (size (Lv), [0, 0]); %! assert (size (Uv), [0, 0]); %! endfor %! mpbits (512); %!test %! A = mp ([1, 2; 3, 4]); %! fail ("lu (A, \"matrix\")", "vector"); %! fail ("lu (A, \"econ\")", "vector"); %! fail ("lu (A, 0)", "vector"); %! fail ("[a,b,c,d] = lu (A)", "at most three outputs"); mplapack-interop-0.5.1/tools/0000755000230300031750000000000015274353473015404 5ustar rafaelrafaelmplapack-interop-0.5.1/tools/verify-release-candidate.sh0000755000230300031750000000372315274353473022604 0ustar rafaelrafael#!/bin/sh set -eu repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" commit=${1:-HEAD} git rev-parse --verify "$commit^{commit}" >/dev/null commit_sha=$(git rev-parse "$commit^{commit}") package_name=$(sed -n 's/^Name: *//p' DESCRIPTION) package_version=$(sed -n 's/^Version: *//p' DESCRIPTION) package_dir=$package_name-$package_version qa_root=$(mktemp -d) cleanup () { find "$qa_root" -depth -delete } trap cleanup EXIT trap 'exit 1' HUP INT TERM for label in A B; do checkout=$qa_root/$label mkdir -p "$checkout" git archive --format=tar --prefix=source/ "$commit_sha" \ | tar -xf - -C "$checkout" ( cd "$checkout/source" SOURCE_DATE_EPOCH=0 tools/build-package.sh ) archive=$checkout/source/dist/$package_dir.tar.gz [ -f "$archive" ] || { echo "FAIL: build $label did not produce $archive" >&2 exit 1 } sha256sum "$archive" > "$qa_root/$label.sha256" stat -c '%s' "$archive" > "$qa_root/$label.size" tar tzf "$archive" > "$qa_root/$label.list" top_levels=$(cut -d/ -f1 "$qa_root/$label.list" | LC_ALL=C sort -u) if [ "$top_levels" != "$package_dir" ]; then echo "FAIL: build $label does not have one top-level directory" >&2 exit 1 fi if grep -Eq '(^|/)docs/v0\.1-release-manifest\.md$|(^|/)m23-report\.md$' \ "$qa_root/$label.list"; then echo "FAIL: handoff/report metadata leaked into the runtime archive" >&2 exit 1 fi done hash_a=$(awk '{print $1}' "$qa_root/A.sha256") hash_b=$(awk '{print $1}' "$qa_root/B.sha256") if [ "$hash_a" != "$hash_b" ]; then echo "FAIL: clean release-candidate archives differ" >&2 cat "$qa_root/A.sha256" "$qa_root/B.sha256" >&2 exit 1 fi if ! cmp -s "$qa_root/A.list" "$qa_root/B.list"; then echo "FAIL: clean release-candidate archive file lists differ" >&2 exit 1 fi echo "PASS: reproducible source package $commit_sha" echo "Archive: $package_dir.tar.gz" echo "SHA256: $hash_a" echo "Size: $(cat "$qa_root/A.size") bytes" echo "File list: identical" mplapack-interop-0.5.1/tools/test-doc-examples.sh0000755000230300031750000001105715274353473021305 0ustar rafaelrafael#!/usr/bin/env bash set -euo pipefail # Execute the public runnable examples and a representative help-text wall. # The package itself must already be installed, or OCTAVE_BIN must point to a # wrapper/environment that can load mplapack-interop. repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" octave_bin="${OCTAVE_BIN:-}" package_load='pkg load mplapack-interop;' if [[ -z "$octave_bin" && -x "$repo_root/tools/dev-octave.sh" ]]; then octave_bin="$repo_root/tools/dev-octave.sh" # The source-tree wrapper exposes inst/ and src/ directly. A temporary # HOME deliberately has no Octave package database, so pkg load would # reject the source-tree test even though the package files are present. package_load='' if [[ -f /home/docker/opt/octave-mplapack-stack/lib/pkgconfig/mplapack_mpfr.pc ]]; then export PKG_CONFIG_PATH="/home/docker/opt/octave-mplapack-stack/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" export LD_LIBRARY_PATH="/home/docker/opt/octave-mplapack-stack/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" export CPATH="/home/docker/opt/octave-mplapack-stack/include${CPATH:+:$CPATH}" fi fi if [[ -z "$octave_bin" && -x /home/docker/opt/octave-mplapack-stack/bin/octave-mplapack ]]; then octave_bin=/home/docker/opt/octave-mplapack-stack/bin/octave-mplapack stack_root=$(CDPATH= cd "$(dirname "$octave_bin")/.." && pwd) package_load="pkg ('local_list', '$stack_root/octave_packages'); pkg load mplapack-interop;" fi octave_bin="${octave_bin:-octave}" if [[ "$octave_bin" == */octave-mplapack ]]; then stack_root=$(CDPATH= cd "$(dirname "$octave_bin")/.." && pwd) package_load="pkg ('local_list', '$stack_root/octave_packages'); pkg load mplapack-interop;" fi command -v "${octave_bin##*/}" >/dev/null 2>&1 || [[ -x "$octave_bin" ]] || { echo "ERROR: Octave executable not found: $octave_bin" >&2 exit 1 } test_home=$(mktemp -d "${TMPDIR:-/tmp}/mplapack-doc-home.XXXXXX") trap 'rm -rf "$test_home"' EXIT run_octave() { HOME="$test_home" "$octave_bin" --no-gui --quiet --no-init-file "$@" } for example in examples/01_scalar_precision.m \ examples/02_matrix_arithmetic.m \ examples/03_linear_solve.m \ examples/04_factorizations.m \ examples/05_hilbert_inverse.m \ examples/06_grcar_eig.m \ examples/07_svd_hilbert.m \ examples/08_advanced_dense.m \ examples/09_serialization_rng.m \ examples/10_interpolation.m \ examples/11_solvers_quadrature_optimization.m \ examples/12_graphics_boundary.m \ examples/13_nonsymmetric_eig_suite.m \ examples/14_neig_tier_s.m \ examples/15_neig_tier_a.m \ examples/18_complex_log2.m \ examples/14_svd_tier_s.m \ examples/15_svd_tier_a.m \ examples/16_svd_verified.m; do [[ -f "$example" ]] || { echo "ERROR: missing example: $example" >&2; exit 1; } echo "RUN: $example" run_octave --eval "$package_load run ('$repo_root/$example');" done if [[ "${EXDOC01_SKIP_HEAVY_VERIFICATION:-0}" != "1" ]]; then for example in examples/16_neig_verified_vs.m examples/17_neig_verified_va.m; do [[ -f "$example" ]] || { echo "ERROR: missing example: $example" >&2; exit 1; } echo "RUN: $example" run_octave --eval "$package_load run ('$repo_root/$example');" done else echo "SKIP: NEIGT V-S/V-A heavy verification (EXDOC01_SKIP_HEAVY_VERIFICATION=1)" fi # EXDOC01 split examples are intentionally executed one file at a time. Each # selects one manifest case through the existing full runner, so this wall # checks the pedagogical entry points without replacing the counted profile # regression tests. while IFS= read -r example; do [[ -f "$example" ]] || { echo "ERROR: missing split example: $example" >&2; exit 1; } echo "RUN: $example" run_octave --eval "$package_load run ('$repo_root/$example');" done < <(find examples/tiered -type f -name '*.m' | LC_ALL=C sort) help_list=(mp mpbits mpdigits mplapack_version \ fminbnd fminsearch fsolve fzero integral interp1 interp2 mprand mprng \ @mp/abs @mp/chol @mp/eig @mp/log2 @mp/lu @mp/mldivide @mp/mrdivide @mp/norm \ @mp/qr @mp/svd @mp/schur @mp/qz @mp/saveobj @mp/loadobj) for name in "${help_list[@]}"; do echo "HELP: $name" output=$(run_octave --eval "$package_load txt = evalc ('help $name'); assert (! isempty (strtrim (txt)));" 2>&1) || { echo "$output" >&2 echo "ERROR: help lookup failed: $name" >&2 exit 1 } done echo "PASS: runnable documentation examples and selected help lookups" mplapack-interop-0.5.1/tools/check-docs.sh0000755000230300031750000002031015274353473017742 0ustar rafaelrafael#!/usr/bin/env bash set -euo pipefail # Lightweight deterministic consistency checks for DOC00. repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" fail=0 required=( doc/mplapack-interop.texi docs/public-api-inventory.md docs/backend-map.md docs/advanced-numerics-compatibility.md docs/octave-script-compatibility.md docs/precision-semantics.md docs/doxygen/Doxyfile docs/doxygen/mainpage.dox tools/build-docs.sh tools/test-doc-examples.sh docs/examples/tiered/README.md docs/examples/tiered/MIGRATION.md docs/examples/tiered/GLOSSARY.md docs/math-rendering-migration.md tools/check-tiered-math.sh tools/check-github-math.sh tools/check-smoke-matrices.sh tools/check-smoke-matrices.py tools/dump_smoke_matrices.m tools/format_smoke_matrices.py AGENTS.md ) for path in "${required[@]}"; do if [[ ! -f "$path" ]]; then echo "FAIL: missing documentation artifact: $path" >&2 fail=1 fi done # Keep the GitHub rendering contract permanent rather than relying only on # the current checker implementation. These policy statements are part of # the repository's documentation Definition of Done. agents=AGENTS.md for policy in \ 'GitHub Markdown is the source of truth for mathematical documentation.' \ 'Use fenced math blocks' \ 'Do not put display mathematics inside Markdown table cells' \ 'For piecewise definitions in GitHub Markdown, use the standard'; do if ! grep -Fq "$policy" "$agents"; then echo "FAIL: AGENTS.md is missing GitHub math policy: $policy" >&2 fail=1 fi done agents_policy_text=$(tr '\n' ' ' < "$agents") if [[ "$agents_policy_text" != *"A documentation change is incomplete if its equations do not render correctly on GitHub."* ]]; then echo "FAIL: AGENTS.md is missing GitHub rendering Definition-of-Done rule" >&2 fail=1 fi manual=doc/mplapack-interop.texi tiered_root=docs/examples/tiered families="neig-tier-s neig-tier-a svd-tier-s svd-tier-a" for family in $families; do family_readme="$tiered_root/$family/README.md" if [[ ! -f "$family_readme" ]]; then echo "FAIL: missing tiered family README: $family_readme" >&2 fail=1 continue fi while IFS= read -r example; do stem=$(basename "$example" .m) detail="$tiered_root/$family/$stem.md" if [[ ! -f "$detail" ]]; then echo "FAIL: split example has no matching detail document: $example" >&2 fail=1 continue fi count=$(find "$tiered_root/$family" -maxdepth 1 -type f -name "$stem.md" | wc -l) if [[ "$count" -ne 1 ]]; then echo "FAIL: expected exactly one detail document for $example, got $count" >&2 fail=1 fi if ! grep -Fq "$example" "$detail"; then echo "FAIL: detail document does not name its example: $detail" >&2 fail=1 fi if ! grep -Fq "$stem.m" "$family_readme" || ! grep -Fq "$stem.md" "$family_readme"; then echo "FAIL: family README omits split case: $example" >&2 fail=1 fi done < <(find examples/tiered/"$family" -maxdepth 1 -type f -name '*.m' | LC_ALL=C sort) while IFS= read -r detail; do detail_example=$(grep -o 'examples/[A-Za-z0-9_./-]*\.m' "$detail" | head -1 || true) if [[ -z "$detail_example" ]] || [[ ! -f "$detail_example" ]]; then echo "FAIL: detail document has no existing corresponding example: $detail" >&2 fail=1 fi done < <(find "$tiered_root/$family" -maxdepth 1 -type f -name '*.md' ! -name README.md | LC_ALL=C sort) done for family in $families; do if ! grep -Fq "$family/README.md" "$tiered_root/README.md"; then echo "FAIL: master tiered README omits family: $family" >&2 fail=1 fi done if ! grep -Fq '@section Tiered worked examples' "$manual" \ || ! grep -Fq 'docs/examples/tiered/README.md' "$manual"; then echo "FAIL: manual does not point to the tiered worked-example section" >&2 fail=1 fi # The four historical entry points remain indexes. Every split case must be # reachable from its original tier file, while the full runners retain QA. for family in $families; do case "$family" in neig-tier-s) index_file=examples/14_neig_tier_s.m ;; neig-tier-a) index_file=examples/15_neig_tier_a.m ;; svd-tier-s) index_file=examples/14_svd_tier_s.m ;; svd-tier-a) index_file=examples/15_svd_tier_a.m ;; esac while IFS= read -r example; do if ! grep -Fq "$example" "$index_file"; then echo "FAIL: historical index omits split example: $example" >&2 fail=1 fi done < <(find examples/tiered/"$family" -maxdepth 1 -type f -name '*.m' | LC_ALL=C sort) done inventory=docs/public-api-inventory.md for chapter in \ "Introduction" "Installation and package loading" "Creating @code{mp} values" \ "Precision model" "Real and complex values" "Arithmetic and comparisons" \ "Dense matrices and indexing" "Matrix factorizations and linear solves" \ "Eigenvalues, SVD, Schur and QZ" "Matrix functions" \ "Elementary and special functions" "Polynomial operations" "Set operations" \ "Serialization and save/load" "Graphics" "Arbitrary-precision random numbers" \ "Interpolation" "Nonlinear equations" "Numerical integration" "Optimization" \ "Performance notes" "Octave compatibility" "Deferred and unsupported functionality" \ "Troubleshooting" "API quick reference"; do if ! grep -Fq "@chapter $chapter" "$manual"; then echo "FAIL: manual chapter missing: $chapter" >&2 fail=1 fi done public_methods=$(find inst/@mp -maxdepth 1 -type f -name '*.m' -printf '%f\n' | sed 's/\.m$//' | LC_ALL=C sort) public_functions=$(find inst -maxdepth 1 -type f -name '*.m' -printf '%f\n' | sed 's/\.m$//' | LC_ALL=C sort) while IFS= read -r name; do [[ -n "$name" ]] || continue if ! grep -Fq "| \`$name\` |" "$inventory"; then echo "FAIL: public @mp method missing from inventory: $name" >&2 fail=1 fi if ! grep -Fq "@code{$name}" "$manual"; then echo "FAIL: public @mp method missing from manual: $name" >&2 fail=1 fi if ! grep -Fq '@deftypefn' "inst/@mp/$name.m"; then echo "FAIL: public @mp method missing help text: $name" >&2 fail=1 fi done <<< "$public_methods" while IFS= read -r name; do [[ -n "$name" ]] || continue if ! grep -Fq "| \`$name\` |" "$inventory"; then echo "FAIL: package function missing from inventory: $name" >&2 fail=1 fi if ! grep -Fq "@code{$name}" "$manual"; then echo "FAIL: package function missing from manual: $name" >&2 fail=1 fi if ! grep -Fq '@deftypefn' "inst/$name.m"; then echo "FAIL: package function missing help text: $name" >&2 fail=1 fi done <<< "$public_functions" for path in $(grep -o 'docs/todo/[A-Za-z0-9._/-]*\.md' "$inventory" | LC_ALL=C sort -u); do if [[ ! -f "$path" ]]; then echo "FAIL: missing TODO link target: $path" >&2 fail=1 fi done for path in docs/public-api-inventory.md docs/backend-map.md \ docs/advanced-numerics-compatibility.md docs/precision-semantics.md; do [[ -f "$path" ]] || continue if grep -Eq 'does not provide inv\(mp\)|builtin[[:space:]]+double[[:space:]]+fallback' "$path"; then echo "FAIL: stale or unsafe precision claim in $path" >&2 fail=1 fi done for link in docs/public-api-inventory.md docs/advanced-numerics-compatibility.md \ doc/mplapack-interop.texi examples/01_scalar_precision.m; do if ! grep -Fq "$link" README.md; then echo "FAIL: README missing documentation landing link/reference: $link" >&2 fail=1 fi done if ! grep -Fq 'official MPLAPACK 3.0.1 release' NEWS.md; then echo "FAIL: NEWS lacks current MPLAPACK release wording" >&2 fail=1 fi if ! grep -Fq 'D04' NEWS.md; then echo "FAIL: NEWS lacks D04 release context" >&2 fail=1 fi if [[ -x tools/check-tiered-math.sh ]]; then if ! tools/check-tiered-math.sh; then fail=1 fi else echo "FAIL: missing tools/check-tiered-math.sh" >&2 fail=1 fi if [[ -x tools/check-github-math.sh ]]; then if ! tools/check-github-math.sh; then fail=1 fi else echo "FAIL: missing tools/check-github-math.sh" >&2 fail=1 fi if [[ -x tools/check-smoke-matrices.sh ]]; then if ! tools/check-smoke-matrices.sh; then fail=1 fi else echo "FAIL: missing tools/check-smoke-matrices.sh" >&2 fail=1 fi if [[ "$fail" -ne 0 ]]; then echo "FAIL: DOC00 documentation consistency checks" >&2 exit 1 fi echo "PASS: DOC00 documentation consistency checks" mplapack-interop-0.5.1/tools/run-nonsymmetric-eig-suite.sh0000755000230300031750000000205015274353473023162 0ustar rafaelrafael#!/bin/sh # Run the repository-local all-family nonsymmetric eigensystem suite. # Usage: tools/run-nonsymmetric-eig-suite.sh [smoke|demo|stress] [output-dir] set -eu repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) profile=${1:-smoke} output_dir=${2:-} case "$profile" in smoke|demo|stress) ;; *) echo "usage: $0 [smoke|demo|stress] [output-dir]" >&2 exit 2 ;; esac if [ "$#" -gt 2 ]; then echo "usage: $0 [smoke|demo|stress] [output-dir]" >&2 exit 2 fi export NEIG_PROFILE="$profile" export NEIG_OUTPUT="$output_dir" cd "$repo_root" exec tools/dev-octave.sh --eval \ 'addpath ("examples/nonsymmetric_eig"); profile = getenv ("NEIG_PROFILE"); output_dir = getenv ("NEIG_OUTPUT"); if (isempty (output_dir)) results = mp_eig_suite (profile); else results = mp_eig_suite (profile, struct ("output_dir", output_dir)); endif fprintf ("NEIG %s: %s (%d rows)\n", profile, results.status, numel (results.rows)); if (! results.ok) error ("NEIG:Failed", "nonsymmetric eigensystem suite failed"); endif' mplapack-interop-0.5.1/tools/format_smoke_matrices.py0000644000230300031750000001077215274353473022342 0ustar rafaelrafael#!/usr/bin/env python3 """Format exact generator output as readable GitHub Math matrix blocks.""" from __future__ import annotations import argparse from fractions import Fraction from pathlib import Path Scalar = tuple[Fraction, Fraction] def value_from_record(sign: int, mantissa_hex: str, exponent: int) -> Fraction: if sign == 0: return Fraction(0) value = Fraction(int(mantissa_hex, 16)) if exponent >= 0: value *= 2**exponent else: value /= 2**(-exponent) return value if sign > 0 else -value def load_records(path: Path): records = {} metadata = {} with path.open(encoding="utf-8") as stream: for raw in stream: if not raw.strip() or raw.startswith("#"): continue fields = raw.rstrip("\n").split("\t") if len(fields) != 10: raise ValueError(f"malformed record: {raw.rstrip()}") case_id, doc, rows, columns, row, column, kind, sign, mantissa, exponent = fields key = (case_id, int(row), int(column)) metadata.setdefault(case_id, (doc, int(rows), int(columns))) value = value_from_record(int(sign), mantissa, int(exponent)) if kind == "real": records[key] = (value, Fraction(0)) elif kind == "complex-real": previous = records.get(key, (Fraction(0), Fraction(0))) records[key] = (value, previous[1]) elif kind == "complex-imag": previous = records.get(key, (Fraction(0), Fraction(0))) records[key] = (previous[0], value) else: raise ValueError(f"unknown record kind {kind!r}") return metadata, records def fraction_text(value: Fraction) -> str: if value.denominator == 1: return str(value.numerator) if value.numerator == 1 and value.denominator & (value.denominator - 1) == 0: return f"2^{{-{value.denominator.bit_length() - 1}}}" if value.numerator == -1 and value.denominator & (value.denominator - 1) == 0: return f"-2^{{-{value.denominator.bit_length() - 1}}}" return rf"\frac{{{value.numerator}}}{{{value.denominator}}}" def scalar_text(value: Scalar) -> str: real, imag = value if imag == 0: return fraction_text(real) if real == 0: unit = fraction_text(abs(imag)) return f"{'-' if imag < 0 else ''}{unit}i" sign = "+" if imag > 0 else "-" return f"{fraction_text(real)}{sign}{fraction_text(abs(imag))}i" def common_power_of_two(values) -> int: denominator_exponents = [] for value in values: for part in value: if part: denominator = part.denominator if denominator & (denominator - 1): return 0 denominator_exponents.append(denominator.bit_length() - 1) return max(denominator_exponents, default=0) def matrix_block(case_id: str, rows: int, columns: int, values) -> str: flat = [values[(row, column)] for row in range(1, rows + 1) for column in range(1, columns + 1)] factor_power = common_power_of_two(flat) nonzero = sum(any(part for part in value) for value in flat) if factor_power and nonzero < max(8, rows * columns // 2): factor_power = 0 factor = 2**factor_power entries = [] for row in range(1, rows + 1): rendered = [] for column in range(1, columns + 1): value = values[(row, column)] if factor_power: value = (value[0] * factor, value[1] * factor) rendered.append(scalar_text(value)) entries.append(" & ".join(rendered)) body = " \\\\\n".join(entries) prefix = f"2^{{-{factor_power}}} " if factor_power else "" return ( f"\n" "```math\n" f"A_{{\\mathrm{{smoke}}}} = {prefix}\\begin{{bmatrix}}\n" f"{body}\n" "\\end{bmatrix}.\n" "```\n" ) def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("records", type=Path) args = parser.parse_args() metadata, records = load_records(args.records) for case_id, (doc, rows, columns) in metadata.items(): values = {(row, column): records[(case_id, row, column)] for row in range(1, rows + 1) for column in range(1, columns + 1)} print(f"===== {doc} =====") print(matrix_block(case_id, rows, columns, values), end="") return 0 if __name__ == "__main__": raise SystemExit(main()) mplapack-interop-0.5.1/tools/build-docs.sh0000755000230300031750000000417215274353473017774 0ustar rafaelrafael#!/usr/bin/env bash set -euo pipefail # Build the source documentation surfaces without root or a package install. # Generated files live under docs/.build and are excluded from release source. repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" manual="doc/mplapack-interop.texi" build_dir="${DOC_BUILD_DIR:-$repo_root/docs/.build}" doxygen_bin="${DOXYGEN_BIN:-doxygen}" [[ -f "$manual" ]] || { echo "ERROR: missing $manual" >&2; exit 1; } command -v makeinfo >/dev/null 2>&1 || { echo "ERROR: makeinfo is required to build the user manual" >&2 exit 1 } if ! command -v "${doxygen_bin##*/}" >/dev/null 2>&1 && [[ ! -x "$doxygen_bin" ]]; then echo "ERROR: doxygen is required to build the developer manual" >&2 echo "Install Doxygen, then rerun tools/build-docs.sh." >&2 exit 1 fi rm -rf "$build_dir" mkdir -p "$build_dir/html" makeinfo --html --no-split "$manual" -o "$build_dir/html/index.html" makeinfo --plaintext "$manual" -o "$build_dir/mplapack-interop.txt" tools/build-manual-markdown.sh "$build_dir/mplapack-interop.md" [[ -f "$repo_root/docs/mplapack-interop.md" ]] || { echo "ERROR: tracked Markdown manual is missing" >&2; exit 1; } cmp -s "$build_dir/mplapack-interop.md" "$repo_root/docs/mplapack-interop.md" || { echo "ERROR: tracked Markdown manual is stale; regenerate it" >&2; exit 1; } if command -v texi2pdf >/dev/null 2>&1 && command -v tex >/dev/null 2>&1; then texi2pdf --batch --quiet --output="$build_dir/mplapack-interop.pdf" "$manual" else echo "INFO: no working TeX toolchain; Info/plaintext output is the manual artifact." >&2 fi "$doxygen_bin" docs/doxygen/Doxyfile [[ -s "$build_dir/html/index.html" ]] || { echo "ERROR: user HTML was not generated" >&2; exit 1; } [[ -s "$build_dir/mplapack-interop.txt" ]] || { echo "ERROR: user Info/plaintext output was not generated" >&2; exit 1; } [[ -s "$build_dir/mplapack-interop.md" ]] || { echo "ERROR: user Markdown output was not generated" >&2; exit 1; } [[ -f "$build_dir/doxygen/html/index.html" ]] || { echo "ERROR: Doxygen HTML was not generated" >&2; exit 1; } echo "PASS: user HTML, Info/plaintext, Markdown, and Doxygen HTML built" mplapack-interop-0.5.1/tools/check-tiered-math.sh0000755000230300031750000001227515274353473021230 0ustar rafaelrafael#!/usr/bin/env bash set -euo pipefail # Static contract checks for the 44 one-case NEIG/SVD mathematical pages. # This checks documentation structure and links only; it does not execute # numerical examples. repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" fail=0 detail_root="docs/examples/tiered" mapfile -t details < <(find "$detail_root"/neig-tier-s "$detail_root"/neig-tier-a \ "$detail_root"/svd-tier-s "$detail_root"/svd-tier-a \ -maxdepth 1 -type f -name '*.md' ! -name README.md | LC_ALL=C sort) if [[ "${#details[@]}" -ne 44 ]]; then echo "FAIL: expected 44 detailed tiered case pages, found ${#details[@]}" >&2 fail=1 fi required_headings=( "## Quick idea" "## Mathematical problem" "## Why this problem is numerically difficult" "## What the Octave example computes" "## Diagnostics" "## Backward error versus forward error" "## What arbitrary precision changes" "## Reading the output" "## Common mistakes" "## References" "## Project provenance" ) for file in "${details[@]}"; do [[ -f "$file" ]] || { echo "FAIL: missing detail page: $file" >&2 fail=1 continue } words=$(wc -w < "$file") if [[ "$words" -lt 1000 ]]; then echo "FAIL: detail page is too short ($words words): $file" >&2 fail=1 fi previous_line=0 for heading in "${required_headings[@]}"; do line=$(rg -n -m1 -F "$heading" "$file" | cut -d: -f1 || true) if [[ -z "$line" ]]; then echo "FAIL: $file missing heading: $heading" >&2 fail=1 elif [[ "$line" -le "$previous_line" ]]; then echo "FAIL: $file headings are out of order near: $heading" >&2 fail=1 else previous_line="$line" fi done dollar_count=$(rg -o '\$\$' "$file" | wc -l || true) math_fence_count=$(rg -c '^```math[[:space:]]*$' "$file" || true) if [[ "$dollar_count" -eq 0 && "${math_fence_count:-0}" -eq 0 ]]; then echo "FAIL: absent display math delimiters: $file" >&2 fail=1 elif [[ $((dollar_count % 2)) -ne 0 ]]; then echo "FAIL: unbalanced $$ math delimiters: $file" >&2 fail=1 fi if rg -n -F -e '\(' -e '\)' -e '\[' -e '\]' "$file" >/dev/null; then echo "FAIL: raw LaTeX delimiters are forbidden; use Markdown \$...\$ or \$\$...\$\$: $file" >&2 fail=1 fi if rg -n -i 'undefined|TODO|PLACEHOLDER|localhost|example\.com' "$file" >/dev/null; then echo "FAIL: placeholder or incomplete content in detail page: $file" >&2 fail=1 fi math_problem=$(awk ' /^## Mathematical problem$/ { inside=1; next } /^## / && inside { exit } inside { print } ' "$file") if [[ -z "$math_problem" ]] || { ! printf '%s\n' "$math_problem" | rg -F -q '$$' && ! printf '%s\n' "$math_problem" | rg -F -q '```math'; }; then echo "FAIL: Mathematical problem section lacks a display equation: $file" >&2 fail=1 fi if [[ "$file" == *"/neig-tier-"* ]]; then if ! rg -q 'A[[:space:]]*V|A V' "$file" || ! rg -F -q 'r_{\mathrm{eig}}' "$file"; then echo "FAIL: NEIG page lacks eigenproblem/residual definition: $file" >&2 fail=1 fi else if ! rg -q 'A=U.*V|A[[:space:]]*=.*U.*V' "$file" || ! rg -F -q 'r_{\mathrm{svd}}' "$file"; then echo "FAIL: SVD page lacks SVD/reconstruction residual definition: $file" >&2 fail=1 fi fi references=$(awk ' /^## References$/ { inside=1; next } /^## / && inside { exit } inside { print } ' "$file") if [[ -z "$references" ]] || ! printf '%s\n' "$references" | rg -q 'https://'; then echo "FAIL: References must contain an external URL: $file" >&2 fail=1 fi if printf '%s\n' "$references" | rg -qi 'TODO|PLACEHOLDER|localhost|example\.com'; then echo "FAIL: placeholder/local URL in References: $file" >&2 fail=1 fi if printf '%s\n' "$references" | rg -q 'DOI[[:space:]]*:' && ! printf '%s\n' "$references" | rg -q 'https://doi\.org/'; then echo "FAIL: DOI citation does not use doi.org: $file" >&2 fail=1 fi while IFS= read -r link; do target=${link#*](} target=${target%)} case "$target" in ""|\#*) continue ;; https://*|http://*|mailto:*) continue ;; esac target=${target%%\#*} target=${target%%\?*} if [[ ! -e "$(dirname "$file")/$target" ]]; then echo "FAIL: broken relative link in $file: $target" >&2 fail=1 fi done < <(rg -o '\]\([^)]*\)' "$file" || true) done # Validate relative links in the family/master indexes and glossary as well. while IFS= read -r file; do while IFS= read -r link; do target=${link#*](} target=${target%)} case "$target" in ""|\#*|https://*|http://*|mailto:*) continue ;; esac target=${target%%\#*} target=${target%%\?*} if [[ ! -e "$(dirname "$file")/$target" ]]; then echo "FAIL: broken relative link in $file: $target" >&2 fail=1 fi done < <(rg -o '\]\([^)]*\)' "$file" || true) done < <(find "$detail_root" -type f -name '*.md' ! -path '*/neig-tier-*/*.md' ! -path '*/svd-tier-*/*.md' | LC_ALL=C sort) if [[ "$fail" -ne 0 ]]; then echo "FAIL: tiered mathematical/reference documentation checks" >&2 exit 1 fi echo "PASS: tiered mathematical/reference documentation checks" mplapack-interop-0.5.1/tools/check-smoke-matrices.sh0000755000230300031750000000376515274353473021754 0ustar rafaelrafael#!/usr/bin/env bash set -euo pipefail # Verify that the explicit small matrices in the detailed documentation are # exactly the matrices produced by the existing NEIGT/SVT example generators. # This is documentation QA; it does not run eig or svd. repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" octave_bin="${OCTAVE_BIN:-}" package_load='pkg load mplapack-interop;' if [[ -z "$octave_bin" && -x /home/docker/opt/octave-mplapack-stack/bin/octave-mplapack ]]; then octave_bin=/home/docker/opt/octave-mplapack-stack/bin/octave-mplapack stack_root=$(CDPATH= cd "$(dirname "$octave_bin")/.." && pwd) package_load="pkg ('local_list', '$stack_root/octave_packages'); pkg load mplapack-interop;" fi if [[ -z "$octave_bin" && -x "$repo_root/tools/dev-octave.sh" ]]; then octave_bin="$repo_root/tools/dev-octave.sh" package_load='' if [[ -f /home/docker/opt/octave-mplapack-stack/lib/pkgconfig/mplapack_mpfr.pc ]]; then export PKG_CONFIG_PATH="/home/docker/opt/octave-mplapack-stack/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" export LD_LIBRARY_PATH="/home/docker/opt/octave-mplapack-stack/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" export CPATH="/home/docker/opt/octave-mplapack-stack/include${CPATH:+:$CPATH}" fi fi octave_bin="${octave_bin:-octave}" command -v "${octave_bin##*/}" >/dev/null 2>&1 || [[ -x "$octave_bin" ]] || { echo "ERROR: Octave executable not found: $octave_bin" >&2 exit 1 } command -v python3 >/dev/null 2>&1 || { echo "ERROR: python3 is required for exact Markdown comparison" >&2 exit 1 } tmp_dir=$(mktemp -d "${TMPDIR:-/tmp}/mplapack-smoke-matrices.XXXXXX") records="$tmp_dir/smoke-matrices.tsv" run_octave() { HOME="$tmp_dir/home" "$octave_bin" --no-gui --quiet --no-init-file "$@" } mkdir -p "$tmp_dir/home" run_octave --eval "$package_load addpath ('$repo_root/tools'); dump_smoke_matrices ('$records');" python3 "$repo_root/tools/check-smoke-matrices.py" "$records" echo "PASS: explicit smoke matrices match the existing NEIGT/SVT generators" mplapack-interop-0.5.1/tools/build-manual-markdown.sh0000755000230300031750000000253215274353473022137 0ustar rafaelrafael#!/bin/sh set -eu repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) manual=$repo_root/doc/mplapack-interop.texi output=${1:-$repo_root/docs/mplapack-interop.md} case $output in /*) ;; *) output=$repo_root/$output ;; esac [ -f "$manual" ] || { echo "ERROR: missing Texinfo manual: $manual" >&2 exit 1 } command -v texi2any >/dev/null 2>&1 || { echo "ERROR: texi2any is required to read the Texinfo manual" >&2 exit 1 } command -v pandoc >/dev/null 2>&1 || { echo "ERROR: pandoc is required to generate Markdown" >&2 exit 1 } build_dir=$(mktemp -d) cleanup () { find "$build_dir" -depth -delete } trap cleanup EXIT trap 'exit 1' HUP INT TERM texi2any --docbook "$manual" -o "$build_dir/manual.xml" pandoc --from=docbook --to=gfm --shift-heading-level-by=1 --wrap=none \ "$build_dir/manual.xml" -o "$build_dir/body.md" sed 's/[[:space:]]*$//' "$build_dir/body.md" > "$build_dir/body-clean.md" mkdir -p "$(dirname "$output")" { printf '%s\n\n' '# mplapack-interop' printf '%s\n\n' 'This Markdown manual is generated from [doc/mplapack-interop.texi](../doc/mplapack-interop.texi) via GNU Texinfo DocBook output and Pandoc. Edit the Texinfo source, then regenerate this file with `tools/build-manual-markdown.sh`.' cat "$build_dir/body-clean.md" } > "$build_dir/output.md" mv "$build_dir/output.md" "$output" echo "PASS: generated $output" mplapack-interop-0.5.1/tools/dump_smoke_matrices.m0000644000230300031750000001157315274353473021623 0ustar rafaelrafaelfunction dump_smoke_matrices (output_path) % Dump the concrete small smoke fixtures produced by the existing % NEIGT/SVT generators in an exact dyadic interchange format. % % This is a documentation QA helper, not a package API. It deliberately % calls the same private example constructors used by the runnable cases. if (nargin != 1 || ! ischar (output_path) || isempty (output_path)) error ("mplapack:docs:SmokeDump", "an output path is required"); endif neig_private = fullfile (pwd (), "examples", "neig_tiers", "private"); svd_private = fullfile (pwd (), "examples", "svd_tiers", "private"); addpath (neig_private); addpath (svd_private); fid = fopen (output_path, "w"); if (fid < 0) error ("mplapack:docs:SmokeDump", ... "could not open output path: %s", output_path); endif cleanup_file = onCleanup (@() fclose (fid)); fprintf (fid, "# case_id\tdoc_path\trows\tcolumns\trow\tcolumn\tkind\tsign\tmantissa_hex\texponent2\n"); mpbits (256); neig = jsondecode (fileread (fullfile ("docs", "codex", "neigt", ... "cases.json"))); neig_ids = {"OO53_REAL", "OO53_PAIR", "OO128_CLOSE", ... "SIM_SIMPLE", "SIM_REPEAT", "SIM_JORDAN", ... "SIM_TWO_JORDAN", "FORSYTHE", "FORSYTHE_SCALED", ... "FORSYTHE_ZERO", "HAD_BIDIAG", "FRANK0", "FRANK1", ... "WILKINSON", "MARKOV", "PERRON_POS"}; neig_docs = {"oo53_real", "oo53_pair", "oo128_close", ... "sim_simple", "sim_repeat", "sim_jordan", ... "sim_two_jordan", "forsythe", "forsythe_scaled", ... "forsythe_zero", "had_bidiag", "frank0", "frank1", ... "wilkinson", "markov", "perron_pos"}; for index = 1:numel (neig_ids) entry = neig.profiles.smoke.cases( ... strcmp ({neig.profiles.smoke.cases.id}, neig_ids{index})); fixture = net_case_model (entry, 256); if (strcmp (entry.tier, "S")) tier_name = "neig-tier-s"; else tier_name = "neig-tier-a"; endif write_fixture (fid, neig_ids{index}, ... ["docs/examples/tiered/", tier_name, "/", ... neig_docs{index}, ".md"], fixture.A_model); endfor svd = svt_load_manifest (); svd_ids = {"S1-NRO-TWO", "S1-NRO-THREE", "S1-NRO-GRADED", ... "S2-JS", "S3-LAH", "S4-DD-SYM", "S4-DD-NONSYM", ... "A1-PASCAL-LOWER", "A1-PASCAL-SYM", "A2-VAND", ... "A3-BDI-RAW", "A3-BDI-MIXED", "A4-LAU-TALL", ... "A4-LAU-WIDE", "A5-GEO", "A5-CLOSE", "A5-REPEAT", ... "A5-RANK4", "A5-RANK5", "A6-NRO-COMPANION"}; svd_docs = {"nro_two", "nro_three", "nro_graded", "jacobi_stirling", ... "lah", "dd_sym", "dd_nonsym", "pascal_lower", ... "pascal_sym", "vandermonde", "bidiag_raw", "bidiag_mixed", ... "lauchli_tall", "lauchli_wide", "hadamard_geometric", ... "hadamard_close", "hadamard_repeat", "hadamard_rank4", ... "hadamard_rank5", "nro_companion"}; for index = 1:numel (svd_ids) entry = svd.profiles.smoke.cases( ... strcmp ({svd.profiles.smoke.cases.id}, svd_ids{index})); fixture = svt_build_case (entry, 256); if (strcmp (entry.tier, "S")) tier_name = "svd-tier-s"; else tier_name = "svd-tier-a"; endif write_fixture (fid, svd_ids{index}, ... ["docs/examples/tiered/", tier_name, "/", ... svd_docs{index}, ".md"], fixture.A); endfor % This is a small fixed demo-only control (9x8), so keep it in the % explicit-matrix audit even though it is not part of the smoke profile. entry = svd.profiles.demo.cases( ... strcmp ({svd.profiles.demo.cases.id}, "A4-LAU-COMPLEX")); fixture = svt_build_case (entry, 256); write_fixture (fid, "A4-LAU-COMPLEX", ... "docs/examples/tiered/svd-tier-a/lauchli_complex.md", fixture.A); endfunction function write_fixture (fid, case_id, doc_path, matrix) stored_bits = 256; for row = 1:rows (matrix) for column = 1:columns (matrix) value = net_dyadic_encode_scalar (matrix(row, column), stored_bits); if (strcmp (value.kind, "real")) fprintf (fid, "%s\t%s\t%d\t%d\t%d\t%d\treal\t%d\t%s\t%d\n", ... case_id, doc_path, rows (matrix), columns (matrix), ... row, column, value.sign, value.mantissa_hex, ... value.exponent2); else fprintf (fid, "%s\t%s\t%d\t%d\t%d\t%d\tcomplex-real\t%d\t%s\t%d\n", ... case_id, doc_path, rows (matrix), columns (matrix), ... row, column, value.real.sign, value.real.mantissa_hex, ... value.real.exponent2); fprintf (fid, "%s\t%s\t%d\t%d\t%d\t%d\tcomplex-imag\t%d\t%s\t%d\n", ... case_id, doc_path, rows (matrix), columns (matrix), ... row, column, value.imag.sign, value.imag.mantissa_hex, ... value.imag.exponent2); endif endfor endfor endfunction mplapack-interop-0.5.1/tools/check-format.sh0000755000230300031750000000306415274353473020311 0ustar rafaelrafael#!/bin/sh set -eu repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" failed=0 for file in $(git ls-files --cached --others --exclude-standard | LC_ALL=C sort); do [ -f "$file" ] || continue case "$file" in src/.build-*/*) continue ;; esac if LC_ALL=C grep -n '[[:blank:]]$' "$file" >/dev/null; then echo "FAIL: trailing whitespace in $file" >&2 LC_ALL=C grep -n '[[:blank:]]$' "$file" >&2 failed=1 fi if LC_ALL=C grep -n "$(printf '\r')" "$file" >/dev/null; then echo "FAIL: carriage return in $file" >&2 failed=1 fi done for script in tools/*.sh; do case "$(sed -n '1{s/^#![[:space:]]*//p;q;}' "$script")" in *bash*|*bash[[:space:]]*) syntax_checker=bash ;; *) syntax_checker=sh ;; esac if ! "$syntax_checker" -n "$script"; then echo "FAIL: shell syntax error in $script" >&2 failed=1 fi done for field in Name Version Date Title Author Maintainer Description License; do if ! grep -q "^${field}: " DESCRIPTION; then echo "FAIL: DESCRIPTION lacks field: $field" >&2 failed=1 fi done if [ "$failed" -ne 0 ]; then echo "FAIL: M00-M23 formatting and sanity checks failed" >&2 exit 1 fi for source in src/*.cc src/*.h test/*.cc; do if ! grep -Fq 'SPDX-License-Identifier: BSD-2-Clause' "$source"; then echo "FAIL: C++ source lacks BSD-2-Clause SPDX identifier: $source" >&2 failed=1 fi done if [ "$failed" -ne 0 ]; then echo "FAIL: M02-M23 source sanity checks failed" >&2 exit 1 fi echo "PASS: M00-M23 formatting and sanity checks" mplapack-interop-0.5.1/tools/dev-octave.sh0000755000230300031750000000212315274353473017776 0ustar rafaelrafael#!/bin/sh set -eu repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" octave_bin=${OCTAVE:-octave} pkg_config_bin=${PKG_CONFIG:-pkg-config} mkoctfile_bin=${MKOCTFILE:-mkoctfile} mplapack_pc=${MPLAPACK_PC:-mplapack_mpfr} command -v "$octave_bin" >/dev/null 2>&1 || { echo "FAIL: Octave command not found: $octave_bin" >&2 exit 1 } command -v "$pkg_config_bin" >/dev/null 2>&1 || { echo "FAIL: pkg-config command not found: $pkg_config_bin" >&2 exit 1 } command -v "$mkoctfile_bin" >/dev/null 2>&1 || { echo "FAIL: mkoctfile command not found: $mkoctfile_bin" >&2 exit 1 } "$pkg_config_bin" --exists "$mplapack_pc" || { echo "FAIL: $mplapack_pc is not available through pkg-config" >&2 exit 1 } make -C src check-dependency make -C src mplapack_libdir=$($pkg_config_bin --variable=libdir "$mplapack_pc") if [ -n "${LD_LIBRARY_PATH:-}" ]; then LD_LIBRARY_PATH=$mplapack_libdir:$LD_LIBRARY_PATH else LD_LIBRARY_PATH=$mplapack_libdir fi export LD_LIBRARY_PATH exec "$octave_bin" --no-gui --quiet --no-init-file \ --path "$repo_root/inst" --path "$repo_root/src" "$@" mplapack-interop-0.5.1/tools/check-github-math.sh0000755000230300031750000002776315274353473021246 0ustar rafaelrafael#!/usr/bin/env bash set -euo pipefail # Static GitHub-Markdown math policy checks for repository documentation. # This intentionally does not parse TeX or execute numerical examples. # GitHub renders inline math with dollar delimiters and multiline math with # fenced `math` blocks. The checker also permits legacy standalone $$ blocks # so that older pages remain source-compatible during migration. repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" fail=0 # Enforce the repository-wide Markdown policy for fragile piecewise displays. # This scanner intentionally understands only Markdown containers: it checks # fenced math and standalone $$ blocks, ignores non-math code fences, and # excludes docs/goals because those files can preserve historical goal text. python3 - "$repo_root" <<'PY' from pathlib import Path import re import sys root = Path(sys.argv[1]) backtick = chr(96) fence_start = re.compile(rf"^\s*({backtick}{{3,}}|~{{3,}})(.*)$") fragile = re.compile( r"\\left(?:\{|\\lbrace)\s*" r"\\begin\{(?:aligned|alignedat|array)\}" r"(?:\s*\{[^{}\n]*\})?" r".{0,12000}?" r"\\end\{(?:aligned|alignedat|array)\}\s*\\right\.", re.DOTALL, ) def math_chunks(text): lines = text.splitlines() chunks = [] mode = None fence_char = "" fence_length = 0 start_line = 0 current = [] for number, line in enumerate(lines, 1): if mode in {"fence", "code"}: closing = re.match( rf"^\s*{re.escape(fence_char)}{{{fence_length},}}\s*$", line ) if closing: if mode == "fence" and current: chunks.append((start_line, "\n".join(current))) mode = None current = [] elif mode == "fence": current.append(line) continue if mode == "dollar": if line.strip() == "$$": if current: chunks.append((start_line, "\n".join(current))) mode = None current = [] else: current.append(line) continue fence = fence_start.match(line) if fence: token = fence.group(1) info = fence.group(2).strip().lower() fence_char = token[0] fence_length = len(token) start_line = number + 1 current = [] mode = "fence" if info.startswith("math") else "code" continue if line.strip() == "$$": mode = "dollar" start_line = number + 1 current = [] continue # Support a compact same-line $$...$$ display without treating an # ordinary single dollar inline expression as a display block. if line.count("$$") >= 2: pieces = line.split("$$") for index in range(1, len(pieces) - 1, 2): chunks.append((number, pieces[index])) if mode == "fence" and current: chunks.append((start_line, "\n".join(current))) elif mode == "dollar" and current: chunks.append((start_line, "\n".join(current))) return chunks files = 0 violations = [] for path in sorted(root.rglob("*")): if not path.is_file() or path.suffix.lower() not in {".md", ".markdown"}: continue relative = path.relative_to(root) if ( ".git" in relative.parts or relative.parts[:2] == ("docs", "goals") or relative.parts[:2] == ("release", "logs") ): continue if "docs/.build" in str(relative): continue files += 1 text = path.read_text(encoding="utf-8") for start_line, chunk in math_chunks(text): match = fragile.search(chunk) if match is not None: line = start_line + chunk[:match.start()].count("\n") violations.append((relative, line)) if violations: for path, line in violations: print( f"FAIL: {path}:{line}: forbidden piecewise brace; " r"use \begin{cases} instead of " r"\left\{+\begin{aligned|alignedat|array}+...\right.", file=sys.stderr, ) raise SystemExit(1) print(f"PASS: Markdown fragile-piecewise scan ({files} live files)") PY mapfile -t documents < <(find docs/examples/tiered -type f -name '*.md' | LC_ALL=C sort) if [[ "${#documents[@]}" -eq 0 ]]; then echo "FAIL: no tiered Markdown documents found" >&2 exit 1 fi for file in "${documents[@]}"; do if rg -n -F -e '\[' -e '\]' -e '\(' -e '\)' "$file" >/dev/null; then echo "FAIL: raw \\[...\\] or \\(...\\) delimiters: $file" >&2 fail=1 fi if rg -n '\\(RR|CC|eps|diagop|newcommand|renewcommand|def)[[:space:]]*([ {]|$)' "$file" >/dev/null; then echo "FAIL: custom preamble macro in GitHub Markdown: $file" >&2 fail=1 fi if rg -n '\\\\(lambda|begin|end|mathbb|operatorname|frac|sqrt|Sigma|pi|varepsilon)' "$file" >/dev/null; then echo "FAIL: doubled LaTeX backslash from string escaping: $file" >&2 fail=1 fi # Catch the small class of obvious mathematical identifiers that are easy # to leave behind as plain Markdown prose during a notation conversion. # This is deliberately conservative: code fences, legacy $$ blocks, # inline code, and inline dollar math are removed before matching. It is # not intended to parse TeX or infer mathematical meaning from arbitrary # English. if ! awk ' function report(line_number) { printf "FAIL: %s:%d: obvious mathematical notation is outside GitHub math delimiters\n", FILENAME, line_number > "/dev/stderr" bad = 1 } { line = $0 if (line ~ /^[[:space:]]*(```|~~~)/) { in_fence = !in_fence next } if (line ~ /^[[:space:]]*\$\$[[:space:]]*$/) { in_dollar_block = !in_dollar_block next } if (in_fence || in_dollar_block) next # Remove inline code and both GitHub inline-math forms before the # intentionally small list of raw-notation checks. gsub(/`[^`]*`/, "", line) gsub(/\$`[^`]*`\$/, "", line) gsub(/\$[^$]*\$/, "", line) if (line ~ /r_eig|r_svd|sigma_min|sigma_max/ || line ~ /A\^H|A\^T|V\^H|U\^H|Q\^T|H\^T/ || line ~ /XY[[:space:]]*=/ || line ~ /YX[[:space:]]*=/ || line ~ /(^|[^[:alnum:]_])lambda[[:space:]]*=/ || line ~ /(^|[^[:alnum:]_])eta[[:space:]]*=/ || line ~ /(^|[^[:alnum:]_])epsilon[[:space:]]*=/ || line ~ /(^|[^[:alnum:]_])kappa[[:space:]]*=/ || line ~ /2\^[-0-9]/ || line ~ /N\^m|P\^n|T\^T/ || line ~ /\\(begin|end|frac|sqrt|sum|prod|operatorname|mathsf|mathbb|lVert|lvert|binom|qquad)/) report(FNR) } END { exit (bad ? 1 : 0) } ' "$file"; then fail=1 fi # Keep the structural checks in one small line-oriented parser. It is not # a TeX parser: it only verifies the Markdown embedding contract that is # relevant to GitHub's MathJax renderer. if ! awk ' function mark_bad(message, line_number) { printf "FAIL: %s:%d: %s\n", FILENAME, line_number, message > "/dev/stderr" bad = 1 } function count_inline_dollars(text, i, c, previous, nextc, total) { total = 0 for (i = 1; i <= length(text); ++i) { c = substr(text, i, 1) previous = (i > 1 ? substr(text, i - 1, 1) : "") nextc = (i < length(text) ? substr(text, i + 1, 1) : "") if (c == "$" && previous != "\\") { if (nextc == "$") ++i else ++total } } return total } { lines[++line_count] = $0 } END { for (i = 1; i <= line_count; ++i) { line = lines[i] previous_line = (i > 1 ? lines[i - 1] : "") following_line = (i < line_count ? lines[i + 1] : "") is_math_marker = 0 was_blockquote = in_blockquote was_details = in_details was_html_table = in_html_table was_markdown_table = in_markdown_table if (line ~ /]|$)/) in_html_table = 1 if (line ~ /]|$)/) in_details = 1 if (line ~ /^[[:space:]]*>/) { in_blockquote = 1 was_blockquote = 1 } # Use a bracket expression for a literal pipe. In awk ERE, escaped # pipes can be interpreted as alternation by some implementations. is_table_row = (line ~ /^[[:space:]]*[|].*[|][[:space:]]*$/) if (is_table_row) { in_markdown_table = 1 was_markdown_table = 1 } if (line ~ /^[[:space:]]*```math[[:space:]]*$/) { is_math_marker = 1 if (in_math_fence) mark_bad("nested ```math block", i) if (was_markdown_table || was_html_table || was_details || was_blockquote) mark_bad("display math inside a table, blockquote, or HTML container", i) if (i > 1 && previous_line !~ /^[[:space:]]*$/) mark_bad("```math block is not isolated from preceding prose", i) in_math_fence = 1 } else if (line ~ /^[[:space:]]*```[[:space:]]*$/ && in_math_fence) { is_math_marker = 1 if (following_line != "" && following_line !~ /^[[:space:]]*$/) mark_bad("```math block is not isolated from following prose", i) in_math_fence = 0 } if (line ~ /^[[:space:]]*\$\$[[:space:]]*$/) { is_math_marker = 1 if (was_markdown_table || was_html_table || was_details || was_blockquote || in_math_fence) mark_bad("$$ display inside a table, blockquote, HTML container, or math block", i) if (!in_dollar_block && i > 1 && previous_line !~ /^[[:space:]]*$/) mark_bad("$$ block is not isolated from preceding prose", i) if (in_dollar_block && following_line != "" && following_line !~ /^[[:space:]]*$/) mark_bad("$$ block is not isolated from following prose", i) in_dollar_block = !in_dollar_block } else if (index(line, "$$") != 0) { mark_bad("$$ must be on a standalone line", i) } if ((index(line, "\\begin{") != 0 || index(line, "\\end{") != 0) && !in_math_fence && !in_dollar_block) mark_bad("LaTeX environment outside a math block", i) if (is_table_row && (in_math_fence || in_dollar_block)) mark_bad("display math inside a Markdown table row", i) if (!is_math_marker && !in_math_fence && !in_dollar_block) inline_dollars += count_inline_dollars(line) if (line ~ /<\/table([[:space:]>]|$)/) in_html_table = 0 if (line ~ /<\/details([[:space:]>]|$)/) in_details = 0 if (line ~ /^[[:space:]]*$/) in_blockquote = 0 if (!is_table_row && was_markdown_table) in_markdown_table = 0 } if (in_math_fence) { mark_bad("unclosed ```math block", line_count) } if (in_dollar_block) { mark_bad("unclosed $$ block", line_count) } if ((inline_dollars % 2) != 0) { mark_bad("unbalanced inline dollar delimiters", line_count) } exit (bad ? 1 : 0) } ' "$file"; then fail=1 fi # Matrix and multiline MathJax environments must be inside a display block. if ! awk ' { lines[++line_count] = $0 } END { for (i = 1; i <= line_count; ++i) { line = lines[i] if (line ~ /^[[:space:]]*```math[[:space:]]*$/) in_math = 1 else if (line ~ /^[[:space:]]*```[[:space:]]*$/ && in_math) in_math = 0 else if (line ~ /^[[:space:]]*\$\$[[:space:]]*$/) in_dollar = !in_dollar else if (line ~ /\\begin\{(bmatrix|pmatrix|matrix|cases|aligned)\}/ && !in_math && !in_dollar) { printf "FAIL: %s:%d: complex math environment is not in a math block\n", FILENAME, i > "/dev/stderr" bad = 1 } } exit (bad ? 1 : 0) } ' "$file"; then fail=1 fi done if [[ "$fail" -ne 0 ]]; then echo "FAIL: GitHub Markdown math checks" >&2 exit 1 fi echo "PASS: GitHub Markdown math checks (${#documents[@]} documents)" mplapack-interop-0.5.1/tools/check-neigt-source-package.sh0000755000230300031750000000456115274353473023021 0ustar rafaelrafael#!/usr/bin/env bash set -euo pipefail # Build the NEIGT source package twice from independent Git extractions. # This deliberately excludes untracked worktree material and does not build # or install a binary package. repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" work_root=$(mktemp -d "${TMPDIR:-/tmp}/neigt-source-package.XXXXXX") trap 'rm -rf "$work_root"' EXIT build_one() { local label=$1 local checkout="$work_root/$label" mkdir -p "$checkout" git archive --format=tar HEAD | tar -xf - -C "$checkout" ( cd "$checkout" SOURCE_DATE_EPOCH=0 tools/build-package.sh >/dev/null ) cp "$checkout/dist/$(sed -n 's/^Name: *//p' "$checkout/DESCRIPTION")-$(sed -n 's/^Version: *//p' "$checkout/DESCRIPTION").tar.gz" \ "$work_root/$label.tar.gz" } build_one A build_one B archive_a="$work_root/A.tar.gz" archive_b="$work_root/B.tar.gz" cmp -s "$archive_a" "$archive_b" || { echo "FAIL: NEIGT source-package archives differ" >&2 exit 1 } listing="$work_root/listing" tar tzf "$archive_a" > "$listing" package_dir=$(cut -d/ -f1 "$listing" | head -n 1) expected=( "examples/14_neig_tier_s.m" "examples/15_neig_tier_a.m" "examples/16_neig_verified_vs.m" "examples/17_neig_verified_va.m" "examples/neig_tiers/" "examples/neig_tiers/private/" "examples/neig_tiers/private/net_v_s1_gershgorin.m" "examples/neig_tiers/private/net_v_a3_job.m" "test/test_neigt23.m" "test/test_neigt24.m" "docs/codex/neigt/cases.json" "docs/codex/neigt/verification-jobs.json" "doc/mplapack-interop.texi" "docs/mplapack-interop.md" "docs/backend-map.md" "docs/advanced-numerics-compatibility.md" "docs/public-api-inventory.md" "docs/doxygen/mainpage.dox" "tools/test-doc-examples.sh" "tools/check-neigt-source-package.sh" "tools/run-neigt-clean-package-qa.sh" ) for path_name in "${expected[@]}"; do grep -Eq "^${package_dir}/${path_name}(\ |$)" "$listing" || { echo "FAIL: source package lacks $path_name" >&2 exit 1 } done if grep -Eq '(^|/)(\.git|dist|\.libs|\.deps)(/|$)|\.(o|oct|lo|la)$|(^|/)octave-workspace$' "$listing"; then echo "FAIL: source package contains a generated/private path" >&2 exit 1 fi hash=$(sha256sum "$archive_a" | awk '{print $1}') size=$(stat -c '%s' "$archive_a") echo "PASS: NEIGT source package contents and reproducibility" echo "Archive: $package_dir.tar.gz" echo "Size: $size" echo "SHA256: $hash" mplapack-interop-0.5.1/tools/run-neigt-clean-package-qa.sh0000755000230300031750000001764415274353473022737 0ustar rafaelrafael#!/usr/bin/env bash set -euo pipefail # NEIGT25 isolated package QA. This script owns every temporary path it # creates, builds the source archive from a clean Git extraction, and installs # only that archive into a temporary Octave package prefix. It never changes # a production prefix, dependency checkout, tag, or published artifact. repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" work_root=$(mktemp -d "${TMPDIR:-/tmp}/neigt25-clean-qa.XXXXXX") qa_home="$work_root/home" pkg_prefix="$work_root/octave-packages" pkg_arch_prefix="$work_root/octave-arch" pkg_db="$work_root/octave_packages" source_checkout="$work_root/source-checkout" source_extract="$work_root/source-extract" proof_dir="$work_root/replayable-proof" mkdir -p "$qa_home" "$pkg_prefix" "$pkg_arch_prefix" \ "$source_checkout" "$source_extract" trap 'rm -rf "$work_root"' EXIT git archive --format=tar HEAD | tar -xf - -C "$source_checkout" ( cd "$source_checkout" SOURCE_DATE_EPOCH=0 tools/build-package.sh >/dev/null ) package_name=$(sed -n 's/^Name: *//p' "$source_checkout/DESCRIPTION") package_version=$(sed -n 's/^Version: *//p' "$source_checkout/DESCRIPTION") package_dir=$package_name-$package_version archive="$source_checkout/dist/$package_dir.tar.gz" [[ -f "$archive" ]] || { echo "FAIL: missing clean source archive" >&2; exit 1; } tar -xzf "$archive" -C "$source_extract" source_root="$source_extract/$package_dir" mplapack_pc=${MPLAPACK_PC:-mplapack_mpfr} pkg_config_bin=${PKG_CONFIG:-pkg-config} "$pkg_config_bin" --exists "$mplapack_pc" || { echo "FAIL: $mplapack_pc is unavailable through pkg-config" >&2 exit 1 } mplapack_version=$($pkg_config_bin --modversion "$mplapack_pc") mplapack_libdir=$($pkg_config_bin --variable=libdir "$mplapack_pc") mplapack_prefix=$($pkg_config_bin --variable=prefix "$mplapack_pc") export NEIGT25_PKG_DB="$pkg_db" export NEIGT25_PKG_PREFIX="$pkg_prefix" export NEIGT25_PKG_ARCH_PREFIX="$pkg_arch_prefix" export NEIGT25_REPO_ROOT="$repo_root" export NEIGT25_SOURCE_ROOT="$source_root" export NEIGT25_PROOF_DIR="$proof_dir" export PKG_CONFIG_PATH="$mplapack_libdir/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" export LD_LIBRARY_PATH="$mplapack_libdir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" export CPATH="$mplapack_prefix/include${CPATH:+:$CPATH}" octave_args=(--no-gui --quiet --no-init-file --path "$source_root/examples/neig_tiers/private" --path "$source_root/examples/neig_tiers") run_octave() { HOME="$qa_home" octave-cli "${octave_args[@]}" --eval "$1" } install_package() { run_octave "pkg ('local_list', '$pkg_db'); pkg ('prefix', '$pkg_prefix', '$pkg_arch_prefix'); pkg ('install', '-local', '$archive');" } install_package run_octave ' pkg ("local_list", getenv ("NEIGT25_PKG_DB")); pkg ("prefix", getenv ("NEIGT25_PKG_PREFIX"), getenv ("NEIGT25_PKG_ARCH_PREFIX")); pkg ("load", "mplapack-interop"); public_path = which ("mp"); helper_path = which ("mp_neig_tiers"); replay_path = which ("mp_neig_replay"); fprintf ("which mp: %s\n", public_path); fprintf ("which mp_neig_tiers: %s\n", helper_path); fprintf ("which mp_neig_replay: %s\n", replay_path); assert (! isempty (public_path)); assert (! isempty (helper_path)); assert (! isempty (replay_path)); assert (! strncmp (public_path, getenv ("NEIGT25_REPO_ROOT"), ... length (getenv ("NEIGT25_REPO_ROOT")))); assert (! strncmp (helper_path, getenv ("NEIGT25_REPO_ROOT"), ... length (getenv ("NEIGT25_REPO_ROOT")))); assert (! strncmp (replay_path, getenv ("NEIGT25_REPO_ROOT"), ... length (getenv ("NEIGT25_REPO_ROOT")))); assert (strncmp (helper_path, getenv ("NEIGT25_SOURCE_ROOT"), ... length (getenv ("NEIGT25_SOURCE_ROOT")))); assert (strncmp (replay_path, getenv ("NEIGT25_SOURCE_ROOT"), ... length (getenv ("NEIGT25_SOURCE_ROOT")))); info = mplapack_version (); assert (strcmp (info.backend, "mpfr")); fprintf ("MPLAPACK version: %s\n", info.mplapack); fprintf ("PASS: isolated which provenance\n"); ' run_octave ' pkg ("local_list", getenv ("NEIGT25_PKG_DB")); pkg ("prefix", getenv ("NEIGT25_PKG_PREFIX"), getenv ("NEIGT25_PKG_ARCH_PREFIX")); pkg ("load", "mplapack-interop"); smoke = mp_neig_tiers ("smoke", struct ("tier", "all", "plot", false)); assert (strcmp (smoke.status, "NUMERICS_ONLY_COMPLETE")); assert (! smoke.ok && smoke.scope_ok); assert (smoke.coverage.measured_eig_rows == 120); demo = mp_neig_tiers ("demo", struct ("tier", "all", "plot", false)); assert (strcmp (demo.status, "NUMERICS_ONLY_COMPLETE")); assert (! demo.ok && demo.scope_ok); assert (demo.coverage.measured_eig_rows == 168); fprintf ("PASS: isolated ordinary smoke=120 demo=168\n"); ' run_octave ' pkg ("local_list", getenv ("NEIGT25_PKG_DB")); pkg ("prefix", getenv ("NEIGT25_PKG_PREFIX"), getenv ("NEIGT25_PKG_ARCH_PREFIX")); pkg ("load", "mplapack-interop"); smoke = mp_neig_verify_examples ("smoke", struct ("tier", "V", "plot", false)); assert (smoke.ok && strcmp (smoke.status, "COMPLETE")); assert (smoke.coverage.verification_job_count == 26); assert (smoke.coverage.verification_jobs_implemented == 26); assert (all ([smoke.jobs.pass]) && all ([smoke.jobs.milestone_pass])); fprintf ("PASS: isolated V smoke=26/26\n"); clear smoke; demo = mp_neig_verify_examples ("demo", struct ("tier", "V", "plot", false)); assert (demo.ok && strcmp (demo.status, "COMPLETE")); assert (demo.coverage.verification_job_count == 26); assert (demo.coverage.verification_jobs_implemented == 26); assert (all ([demo.jobs.pass]) && all ([demo.jobs.milestone_pass])); fprintf ("PASS: isolated V demo=26/26\n"); ' run_octave ' pkg ("local_list", getenv ("NEIGT25_PKG_DB")); pkg ("prefix", getenv ("NEIGT25_PKG_PREFIX"), getenv ("NEIGT25_PKG_ARCH_PREFIX")); pkg ("load", "mplapack-interop"); A = mp ([1, 2; 3, 4]); b = mp ([1; 2]); x = A \ b; assert (norm (double (A * x - b)) < 1e-12); Z = mp ([1+2i, 2-1i; 3, 4+3i]); zb = mp ([1; 2i]); z = Z \ zb; assert (norm (double (Z * z - zb)) < 1e-12); assert (! isempty (strtrim (evalc ("help mp_neig_tiers")))); fprintf ("PASS: isolated package real/complex/help smoke\n"); bundle = mp_neig_write_outputs ("smoke", getenv ("NEIGT25_PROOF_DIR"), ... struct ("tier", "all", "plot", false)); assert (bundle.replay.ok); fprintf ("Replayable proof: %s\n", bundle.output.proof); pkg ("unload", "mplapack-interop"); pkg ("uninstall", "-nodeps", "mplapack-interop"); ' run_octave ' assert (isempty (which ("mp"))); assert (isempty (which ("mpbits"))); helper_path = which ("mp_neig_tiers"); assert (! isempty (helper_path)); assert (strncmp (helper_path, getenv ("NEIGT25_SOURCE_ROOT"), ... length (getenv ("NEIGT25_SOURCE_ROOT")))); fprintf ("PASS: isolated uninstall removes package paths; extracted helper remains\n"); ' install_package run_octave ' pkg ("local_list", getenv ("NEIGT25_PKG_DB")); pkg ("prefix", getenv ("NEIGT25_PKG_PREFIX"), getenv ("NEIGT25_PKG_ARCH_PREFIX")); pkg ("load", "mplapack-interop"); A = mp ([2, 1; 1, 3]); assert (norm (double (A * (A \ mp ([1; 2])) - mp ([1; 2]))) < 1e-12); Z = mp ([2+1i, 1; 1, 3-1i]); assert (norm (double (Z * (Z \ mp ([1; 2i])) - mp ([1; 2i]))) < 1e-12); fprintf ("PASS: isolated reinstall second real/complex smoke\n"); ' echo "PASS: NEIGT25 isolated clean-package QA" echo "Source revision: $(git rev-parse HEAD)" echo "Source archive: $package_dir.tar.gz" echo "Source archive size: $(stat -c '%s' "$archive")" echo "Source archive SHA256: $(sha256sum "$archive" | awk '{print $1}')" echo "MPLAPACK: $mplapack_version ($mplapack_prefix)" echo "Package prefix: $pkg_prefix" echo "Example source: $source_root" echo "Replayable proof: $proof_dir/proof-vs1-01.json" if [[ -n "${NEIGT25_ARTIFACT_DIR:-}" ]]; then mkdir -p "$NEIGT25_ARTIFACT_DIR" cp -a "$proof_dir" "$NEIGT25_ARTIFACT_DIR/" echo "Exported proof artifacts: $NEIGT25_ARTIFACT_DIR/replayable-proof" fi mplapack-interop-0.5.1/tools/build-package.sh0000755000230300031750000000751715274353473020445 0ustar rafaelrafael#!/bin/sh set -eu repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" package_name=$(sed -n 's/^Name: *//p' DESCRIPTION) package_version=$(sed -n 's/^Version: *//p' DESCRIPTION) case $package_name in ''|*[!A-Za-z0-9_-]*) echo "FAIL: invalid package name in DESCRIPTION: $package_name" >&2 exit 1 ;; esac case $package_version in ''|*[!A-Za-z0-9._+-]*) echo "FAIL: invalid package version in DESCRIPTION: $package_version" >&2 exit 1 ;; esac package_dir=$package_name-$package_version dist_dir=$repo_root/dist archive=$dist_dir/$package_dir.tar.gz stage_root=$(mktemp -d) archive_tmp= cleanup () { if [ -n "$archive_tmp" ] && [ -f "$archive_tmp" ]; then rm -f "$archive_tmp" fi find "$stage_root" -depth -delete } trap cleanup EXIT trap 'exit 1' HUP INT TERM package_root=$stage_root/$package_dir manifest=$stage_root/manifest mkdir -p "$package_root" "$dist_dir" source_roots=' DESCRIPTION COPYING INDEX LICENSE NEWS.md README.md CONTRIBUTING.md inst src test doc docs tools examples ' for source_root in $source_roots; do if [ ! -e "$source_root" ]; then echo "FAIL: package source is missing: $source_root" >&2 exit 1 fi done # Repository-only release handoff manifests contain archive checksums and # therefore must not hash themselves into the source archive. find $source_roots -type f \ ! -name '*.o' \ ! -name '*.oct' \ ! -name '*.lo' \ ! -name '*.la' \ ! -path '*/.build-m02/*' \ ! -path '*/.build-m06/*' \ ! -path '*/.build-m07/*' \ ! -path '*/.build-m08/*' \ ! -path '*/.build-m09/*' \ ! -path '*/.build-m10/*' \ ! -path '*/.build-m11/*' \ ! -path '*/.build-m12/*' \ ! -path '*/.build-m13/*' \ ! -path '*/.build-m14/*' \ ! -path '*/.build-m15/*' \ ! -path '*/.build-m16/*' \ ! -path '*/.build-m17/*' \ ! -path '*/.build-m18/*' \ ! -path '*/.build-m19/*' \ ! -path '*/.build-m21/*' \ ! -path '*/.build-m22/*' \ ! -path '*/.build-n00/*' \ ! -path '*/.build-n01/*' \ ! -path '*/.build-n02/*' \ ! -path '*/.build-n03/*' \ ! -path '*/.build-n04/*' \ ! -path '*/.build-n05/*' \ ! -path '*/.build-n06/*' \ ! -path '*/.build-c00/*' \ ! -path '*/.build-c03/*' \ ! -path '*/.build-c04/*' \ ! -path '*/.build-c05/*' \ ! -path '*/.build-c06/*' \ ! -path '*/.build-c07/*' \ ! -path '*/.build-c08/*' \ ! -path '*/.build-c09/*' \ ! -path '*/.build-c10/*' \ ! -path '*/.build-c11/*' \ ! -path '*/.build-c11l/*' \ ! -path '*/.build-m09/*' \ ! -path '*/.build-m10/*' \ ! -path '*/.build-m11/*' \ ! -path '*/.build-m12/*' \ ! -path '*/.build-m13/*' \ ! -path '*/.build-m14/*' \ ! -path '*/.build-m15/*' \ ! -path '*/.build-m16/*' \ ! -path '*/.build-m17/*' \ ! -path '*/.build-m18/*' \ ! -path '*/.build-m19/*' \ ! -path '*/.build-m21/*' \ ! -path 'docs/.build/*' \ ! -path 'docs/v0.1-release-manifest.md' \ ! -path 'docs/dependency-release-stack.md' \ ! -path 'docs/dependency-release-stack-r1.md' \ ! -path 'docs/dependency-release-stack-r2.md' \ ! -path 'docs/goals/D04-0.5.0-release-freeze.md' \ ! -path 'docs/goals/D04-0.5.0-release-freeze-status.md' \ ! -path 'docs/goals/D04R1-mpc-compat.md' \ ! -path 'tools/install-local-octave-mplapack.sh' \ ! -path '*/.libs/*' \ ! -path '*/.deps/*' \ -print | LC_ALL=C sort > "$manifest" while IFS= read -r source_path; do destination_dir=$package_root/$(dirname "$source_path") mkdir -p "$destination_dir" cp "$source_path" "$package_root/$source_path" done < "$manifest" archive_epoch=${SOURCE_DATE_EPOCH:-0} tar_path=$stage_root/$package_dir.tar tar --sort=name --format=ustar --owner=0 --group=0 --numeric-owner \ --mtime="@$archive_epoch" -C "$stage_root" -cf "$tar_path" "$package_dir" archive_tmp=$(mktemp "$dist_dir/.package.XXXXXX") gzip -n -c "$tar_path" > "$archive_tmp" mv "$archive_tmp" "$archive" archive_tmp= echo "PASS: built dist/$package_dir.tar.gz" mplapack-interop-0.5.1/tools/local-ci.sh0000755000230300031750000014761515274353473017444 0ustar rafaelrafael#!/bin/sh set -eu repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" qa_root=$(mktemp -d) cleanup () { make -C "$repo_root/src" clean >/dev/null 2>&1 || true find "$qa_root" -depth -delete } trap cleanup EXIT trap 'exit 1' HUP INT TERM for command_name in git gh octave mkoctfile pkg-config c++ make python3 \ ldd readelf nm tar gzip sha256sum; do if ! command -v "$command_name" >/dev/null 2>&1; then echo "FAIL: mandatory D00 command is unavailable: $command_name" >&2 exit 1 fi done if ! gh auth status >/dev/null 2>&1; then echo "FAIL: mandatory D00 GitHub authentication is unavailable" >&2 exit 1 fi if ! pkg-config --exists 'mplapack_mpfr >= 3.0.0'; then echo "FAIL: mandatory MPLAPACK MPFR development interface is unavailable" >&2 exit 1 fi echo "PASS: mandatory D00 prerequisites" tools/check-tree.sh tools/check-format.sh make -C src check-dependency make -C src check-norm make -C src check-det-inv make -C src check-svd make -C src check-rank-condition make -C src check-structured-eig make -C src check-general-eig make -C src check-generalized-eig make -C src check-script-sequence mplapack_include_dir=$(pkg-config --variable=includedir mplapack_mpfr) if [ ! -f "$mplapack_include_dir/mplapack_mpfr_precision.h" ]; then echo "FAIL: installed MPLAPACK precision scope header is unavailable" >&2 exit 1 fi echo "PASS: installed MPLAPACK uniform-precision scope header" make -C src clean make -C src check-storage-sanitized make -C src check-arithmetic-sanitized make -C src check-matrix-sanitized make -C src check-blas make -C src check-lapack make -C src check-inspection make -C src check-elementwise make -C src check-structure make -C src check-concat make -C src check-assignment make -C src check-rgels make -C src check-rank make -C src check-cholesky make -C src check-qr make -C src check-pivoted-qr make -C src check-lu make -C src check-complex-storage make -C src check-complex-structure make -C src check-complex-arithmetic make -C src check-complex-blas make -C src check-complex-lapack make -C src check-complex-rank make -C src check-complex-cholesky make -C src check-complex-qr make -C src check-complex-pivoted-qr make -C src check-complex-concat make -C src check-complex-lu make -C src check-det-inv make -C src check-svd make -C src check-rank-condition make -C src check-structured-eig make -C src check-general-eig make -C src check-generalized-eig echo "PASS: D00 ASan/UBSan/LSan real and complex storage, arithmetic, BLAS, LAPACK, rank, Cholesky, QR, pivoted QR, concatenation, assignment, LU, structured eig, general eig, generalized eig, and script sequence QA" make -C src clean M01_REPO_ROOT=$repo_root octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M01_REPO_ROOT"); pkg_private = fullfile (fileparts (which ("pkg")), "private"); addpath (pkg_private); metadata = get_description (fullfile (root, "DESCRIPTION")); required = {"name", "version", "date", "title", "author", ... "maintainer", "description", "license"}; assert (all (isfield (metadata, required))); assert (strcmp (metadata.name, "mplapack-interop")); rmpath (pkg_private); ' echo "PASS: Octave DESCRIPTION parser" mplapack_version=$(pkg-config --modversion mplapack_mpfr) mplapack_libdir=$(pkg-config --variable=libdir mplapack_mpfr) mplapack_library=$mplapack_libdir/libmplapack_mpfr.so export LD_LIBRARY_PATH=$mplapack_libdir:/usr/local/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} probe=$qa_root/mp_lapack_probe c++ -std=c++17 -Wall -Wextra -Wpedantic \ $(pkg-config --cflags mplapack_mpfr) test/mp_lapack_probe.cc \ $(pkg-config --libs mplapack_mpfr) -o "$probe" "$probe" echo "PASS: installed MPLAPACK Rgesv precision probe" rgels_probe=$qa_root/mp_lapack_rgels_probe c++ -std=c++17 -Wall -Wextra -Wpedantic \ $(pkg-config --cflags mplapack_mpfr) test/mp_lapack_rgels_probe.cc \ $(pkg-config --libs mplapack_mpfr) -o "$rgels_probe" "$rgels_probe" echo "PASS: installed MPLAPACK Rgels precision probe" rank_driver_probe=$qa_root/m16_driver_probe c++ -std=c++17 -Wall -Wextra -Wpedantic \ $(pkg-config --cflags mplapack_mpfr) test/m16_driver_probe.cc \ $(pkg-config --libs mplapack_mpfr) -o "$rank_driver_probe" "$rank_driver_probe" echo "PASS: installed rank-revealing driver comparison probe" rpotrf_probe=$qa_root/m17_rpotrf_probe c++ -std=c++17 -Wall -Wextra -Wpedantic \ $(pkg-config --cflags mplapack_mpfr) test/m17_rpotrf_probe.cc \ $(pkg-config --libs mplapack_mpfr) -o "$rpotrf_probe" "$rpotrf_probe" echo "PASS: installed MPLAPACK Rpotrf precision probe" qr_probe=$qa_root/m18_qr_probe c++ -std=c++17 -Wall -Wextra -Wpedantic \ $(pkg-config --cflags mplapack_mpfr) test/m18_qr_probe.cc \ $(pkg-config --libs mplapack_mpfr) -o "$qr_probe" "$qr_probe" echo "PASS: installed MPLAPACK Rgeqrf/Rorgqr precision probe" pivoted_qr_probe=$qa_root/m19_qr_probe c++ -std=c++17 -Wall -Wextra -Wpedantic \ $(pkg-config --cflags mplapack_mpfr) test/m19_qr_probe.cc \ $(pkg-config --libs mplapack_mpfr) -o "$pivoted_qr_probe" "$pivoted_qr_probe" echo "PASS: installed MPLAPACK Rgeqp3/Rorgqr precision probe" lu_probe=$qa_root/m21_rgetrf_probe sed '/^[[:space:]]*#include [[:space:]]*$/d' \ test/m21_rgetrf_probe.cc \ | c++ -std=c++17 -Wall -Wextra -Wpedantic -pthread -x c++ - \ $(pkg-config --cflags mplapack_mpfr) \ $(pkg-config --libs mplapack_mpfr) -o "$lu_probe" "$lu_probe" echo "PASS: installed MPLAPACK Rgetrf precision/IPIV probe" complex_probe=$qa_root/m20_complex_probe sed '/^[[:space:]]*#include [[:space:]]*$/d' \ test/m20_complex_probe.cc \ | c++ -std=c++17 -Wall -Wextra -Wpedantic -pthread \ -DMPLAPACK_BUILD_WITH_MPFR -x c++ - \ $(pkg-config --cflags mplapack_mpfr) \ $(pkg-config --libs mplapack_mpfr) -o "$complex_probe" "$complex_probe" echo "PASS: installed MPLAPACK MPFR complex type/backend precision probe" if [ ! -f "$mplapack_library" ]; then echo "FAIL: MPLAPACK MPFR shared library is unavailable: $mplapack_library" >&2 exit 1 fi mplapack_ldd=$(ldd "$mplapack_library" 2>&1) if printf '%s\n' "$mplapack_ldd" | grep -q 'not found'; then printf '%s\n' "$mplapack_ldd" >&2 echo "FAIL: MPLAPACK has a missing shared dependency" >&2 exit 1 fi mplapack_relocations=$(ldd -r "$mplapack_library" 2>&1) if printf '%s\n' "$mplapack_relocations" \ | grep -Eq 'not found|undefined symbol'; then printf '%s\n' "$mplapack_relocations" >&2 echo "FAIL: MPLAPACK has an unresolved relocation" >&2 exit 1 fi for dependency in libmpc libmpfr libgmp; do if ! readelf -d "$mplapack_library" \ | grep NEEDED | grep -q "\[$dependency\.so"; then echo "FAIL: MPLAPACK DT_NEEDED lacks $dependency" >&2 exit 1 fi done mplapack_soname=$(readelf -d "$mplapack_library" \ | sed -n 's/.*(SONAME).*\[\([^]]*\)\].*/\1/p') if [ -z "$mplapack_soname" ]; then echo "FAIL: MPLAPACK shared library has no SONAME" >&2 exit 1 fi M01_MPLAPACK_SONAME=$mplapack_soname python3 - <<'PY' import ctypes import os ctypes.CDLL(os.environ["M01_MPLAPACK_SONAME"]) print("PASS: clean MPLAPACK MPFR load") PY echo "PASS: MPLAPACK dependency relocations and DT_NEEDED" make -C src clean make -C src check-deps make -C src module=$repo_root/src/__mplapack_core__.oct module_ldd=$(ldd "$module" 2>&1) if printf '%s\n' "$module_ldd" | grep -q 'not found'; then printf '%s\n' "$module_ldd" >&2 echo "FAIL: native module has a missing shared dependency" >&2 exit 1 fi if ! readelf -d "$module" | grep NEEDED \ | grep -q '\[libmplapack_mpfr\.so'; then echo "FAIL: native module lacks a direct MPLAPACK MPFR dependency" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rlamch_mpfr\(char const\*\)$'; then echo "FAIL: native module lacks an unresolved Rlamch_mpfr reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgemm\('; then echo "FAIL: native module lacks an unresolved Rgemm reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgesv\('; then echo "FAIL: M09 native module lacks an unresolved Rgesv reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgels\('; then echo "FAIL: M15 native module lacks an unresolved Rgels reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgelss\('; then echo "FAIL: M16 native module lacks an unresolved Rgelss reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rpotrf\('; then echo "FAIL: M17 native module lacks an unresolved Rpotrf reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgeqrf\('; then echo "FAIL: M18 native module lacks an unresolved Rgeqrf reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rorgqr\('; then echo "FAIL: M18 native module lacks an unresolved Rorgqr reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgeqp3\('; then echo "FAIL: M19 native module lacks an unresolved Rgeqp3 reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgetrf\('; then echo "FAIL: M21 native module lacks an unresolved Rgetrf reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgetri\('; then echo "FAIL: N01 native module lacks an unresolved Rgetri reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Cgetrf\('; then echo "FAIL: C11L native module lacks an unresolved Cgetrf reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Cgetri\('; then echo "FAIL: N01 native module lacks an unresolved Cgetri reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgesvd\('; then echo "FAIL: N02 native module lacks an unresolved Rgesvd reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Cgesvd\('; then echo "FAIL: N02 native module lacks an unresolved Cgesvd reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgecon\('; then echo "FAIL: N03 native module lacks an unresolved Rgecon reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Cgecon\('; then echo "FAIL: N03 native module lacks an unresolved Cgecon reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rsyevd\('; then echo "FAIL: N04 native module lacks an unresolved Rsyevd reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Cheevd\('; then echo "FAIL: N04 native module lacks an unresolved Cheevd reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rgeevx\('; then echo "FAIL: N05 native module lacks an unresolved Rgeevx reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Cgeevx\('; then echo "FAIL: N05 native module lacks an unresolved Cgeevx reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rggev\('; then echo "FAIL: N06 native module lacks an unresolved Rggev reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Cggev\('; then echo "FAIL: N06 native module lacks an unresolved Cggev reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Rsygvd\('; then echo "FAIL: N06 native module lacks an unresolved Rsygvd reference" >&2 exit 1 fi if ! nm -D -C "$module" | grep -Eq ' U Chegvd\('; then echo "FAIL: N06 native module lacks an unresolved Chegvd reference" >&2 exit 1 fi if readelf -d "$module" | grep NEEDED | grep -q 'libmplapack_mpfr_opt'; then echo "FAIL: M09 native module links the optimized MPFR backend" >&2 exit 1 fi module_relocations=$(ldd -r "$module" 2>&1) if printf '%s\n' "$module_relocations" | grep -q 'not found'; then printf '%s\n' "$module_relocations" >&2 echo "FAIL: native module relocation check found a missing library" >&2 exit 1 fi undefined_symbols=$qa_root/module-undefined-symbols octave_symbols=$qa_root/octave-defined-symbols printf '%s\n' "$module_relocations" \ | sed -n 's/^undefined symbol: \([^[:space:]]*\).*/\1/p' \ | LC_ALL=C sort -u > "$undefined_symbols" octave_libdir=$(mkoctfile -p OCTLIBDIR) for octave_library in "$octave_libdir/liboctinterp.so" \ "$octave_libdir/liboctave.so"; do if [ ! -f "$octave_library" ]; then echo "FAIL: Octave development library is unavailable: $octave_library" >&2 exit 1 fi done nm -D --defined-only "$octave_libdir/liboctinterp.so" \ "$octave_libdir/liboctave.so" \ | awk 'NF >= 3 { sub (/@.*/, "", $3); print $3 }' \ | LC_ALL=C sort -u > "$octave_symbols" while IFS= read -r symbol; do [ -n "$symbol" ] || continue if ! grep -Fxq "$symbol" "$octave_symbols"; then echo "FAIL: native module has a non-Octave unresolved symbol: $symbol" >&2 exit 1 fi done < "$undefined_symbols" echo "PASS: native linkage and Octave-hosted relocations" M01_REPO_ROOT=$repo_root MPLAPACK_EXPECTED_VERSION=$mplapack_version \ octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M01_REPO_ROOT"); addpath (fullfile (root, "src")); info = __mplapack_core__ ("version"); disp (info); assert (strcmp (info.mplapack, getenv ("MPLAPACK_EXPECTED_VERSION"))); assert (strcmp (info.backend, "mpfr")); assert (! isempty (info.mpfr)); assert (info.probe_ok); assert (isfinite (info.probe_value) && info.probe_value > 0); ' M01_REPO_ROOT=$repo_root MPLAPACK_EXPECTED_VERSION=$mplapack_version \ octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M01_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); public_path = which ("mplapack_version"); native_path = which ("__mplapack_core__"); disp (public_path); disp (native_path); assert (strncmp (public_path, root, length (root))); assert (strncmp (native_path, root, length (root))); info = mplapack_version (); assert (strcmp (info.mplapack, getenv ("MPLAPACK_EXPECTED_VERSION"))); assert (info.probe_ok); run (fullfile (root, "test", "run_tests.m")); ' echo "PASS: direct native/public runtime probes" M03_REPO_ROOT=$repo_root octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M03_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); run (fullfile (root, "test", "native_lifetime.m")); run (fullfile (root, "test", "public_lifetime.m")); run (fullfile (root, "test", "matrix_lifetime.m")); ' M03_REPO_ROOT=$repo_root octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M03_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); values = cell (1, 250); for i = 1:numel (values) values{i} = __mplapack_core__ ( "scalar_test_create", "0.125", [128, 256, 512](mod (i - 1, 3) + 1)); endfor public_values = cell (1, 10000); for i = 1:numel (public_values) if (mod (i, 2) == 0) public_values{i} = mp ("0.1"); else public_values{i} = mp (0.1); endif endfor assert (! __mplapack_core__ ( "scalar_test_equal", public_values{1}, public_values{2})); assert (__mplapack_core__ ("module_test_locked")); fprintf ("PASS: native/public values left for shutdown destruction\n"); ' echo "PASS: M02/M03 source lifecycle, stress, and shutdown QA" M04_REPO_ROOT=$repo_root octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M04_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); assert (mpbits () == uint64 (512)); assert (mpdigits () == uint64 (154)); mpbits (256); assert (mpbits () == uint64 (256)); clear; assert (mpbits () == uint64 (256)); clear functions; assert (mpbits () == uint64 (256)); value = mp ("1"); value_info = __mplapack_core__ ("scalar_test_info", value); assert (value_info.precision_bits == 256); for i = 1:10000 bits = [64, 128, 256, 512, 1024](mod (i - 1, 5) + 1); assert (mpbits (bits) == uint64 (bits)); assert (mpbits () == uint64 (bits)); if (mod (i, 25) == 0) stress_value = mp ("0.125"); stress_info = __mplapack_core__ ( "scalar_test_info", stress_value); assert (stress_info.precision_bits == bits); endif endfor fprintf ("PASS: M04 clear and 10000-operation precision stress QA\n"); ' M04_REPO_ROOT=$repo_root octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M04_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); assert (mpbits () == uint64 (512)); mpbits (1024); assert (mpbits () == uint64 (1024)); ' M04_REPO_ROOT=$repo_root octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M04_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); assert (mpbits () == uint64 (512)); assert (mpdigits () == uint64 (154)); mpdigits (100); assert (mpbits () == uint64 (333)); value = mp ("1"); value_info = __mplapack_core__ ("scalar_test_info", value); assert (value_info.precision_bits == 333); ' echo "PASS: M04 set-before-object, fresh-process reset, and digit construction QA" M05_REPO_ROOT=$repo_root LC_ALL=ja_JP.utf8 \ octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M05_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); mpbits (512); value = mp ("0.1"); text = char (value); assert (! isempty (strfind (text, "."))); assert (isempty (strfind (text, ","))); reconstructed = mp (text); assert (__mplapack_core__ ( "scalar_test_equal", value, reconstructed)); fprintf ("PASS: M05 locale-independent canonical text\n"); ' M05_REPO_ROOT=$repo_root octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M05_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); precisions = [128, 256, 333, 512, 1024]; for i = 1:10000 bits = precisions(mod (i - 1, numel (precisions)) + 1); mpbits (bits); value = mp ("0.1"); text = char (value); assert (ischar (text) && rows (text) == 1); assert (double (value) == 0.1); if (mod (i, 1000) == 0) reconstructed = mp (text); assert (__mplapack_core__ ( "scalar_test_equal", value, reconstructed)); endif endfor shutdown_text = mp ("1.234567890123456789"); shutdown_double = mp (-0.0); assert (! isempty (char (shutdown_text))); assert (typecast (double (shutdown_double), "uint64") == typecast (-0.0, "uint64")); fprintf ("PASS: M05 10000-operation formatting/conversion stress and shutdown QA\n"); ' M06_REPO_ROOT=$repo_root octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M06_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); precisions = [32, 128, 256, 333, 512, 1024]; value = mp ("1"); for i = 1:10000 bits = precisions(mod (i - 1, numel (precisions)) + 1); mpbits (bits); rhs = mp ("0.125"); switch (mod (i - 1, 4)) case 0 value = value + rhs; case 1 value = value - 0.125; case 2 value = value .* rhs; otherwise value = value ./ 0.125; endswitch assert (strcmp (class (value), "mp")); endfor assert (! isempty (char (value))); assert (__mplapack_core__ ("module_test_locked")); fprintf ("PASS: M06 10000-operation public arithmetic stress QA\n"); ' M07_REPO_ROOT=$repo_root octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M07_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); assert (mpbits () == uint64 (512)); for i = 1:1000 rows_count = mod (i, 7); columns_count = mod (i * 3, 9); mpbits ([32, 128, 256, 333, 512, 1024](mod (i - 1, 6) + 1)); if (rows_count * columns_count == 0) value = zeros (rows_count, columns_count); else value = reshape (1:(rows_count * columns_count), rows_count, columns_count); endif matrix = mp (value); assert (size (matrix), [rows_count, columns_count]); info = __mplapack_core__ ("matrix_test_info", matrix); assert (info.all_elements_same_precision); endfor large = mp (ones (64, 64)); large_copy = mp (large); assert (size (large_copy), [64, 64]); assert (__mplapack_core__ ("module_test_locked")); fprintf ("PASS: M07 1000-matrix lifecycle and 64x64 public smoke QA\n"); ' make -C src clean negative_log=$qa_root/negative-dependency.log if make -C src check-deps \ MPLAPACK_PC=mplapack_mpfr_does_not_exist >"$negative_log" 2>&1; then echo "FAIL: missing MPLAPACK pkg-config module did not fail" >&2 exit 1 fi if ! grep -q 'mplapack_mpfr_does_not_exist >= 3.0.0 is required' \ "$negative_log"; then sed -n '1,120p' "$negative_log" >&2 echo "FAIL: missing dependency diagnostic was unclear" >&2 exit 1 fi echo "PASS: negative dependency check" make -C src check-deps make -C src M01_REPO_ROOT=$repo_root MPLAPACK_EXPECTED_VERSION=$mplapack_version \ octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M01_REPO_ROOT"); addpath (fullfile (root, "inst")); addpath (fullfile (root, "src")); info = __mplapack_core__ ("version"); assert (strcmp (info.mplapack, getenv ("MPLAPACK_EXPECTED_VERSION"))); assert (info.probe_ok); run (fullfile (root, "test", "run_tests.m")); value = __mplapack_core__ ("scalar_test_create", "0.1", 512); value_info = __mplapack_core__ ("scalar_test_info", value); assert (value_info.precision_bits == 512); assert (__mplapack_core__ ( "scalar_test_equal_string", value, "0.1")); decimal = mp ("0.1"); binary64 = mp (0.1); assert (! __mplapack_core__ ( "scalar_test_equal", decimal, binary64)); assert (__mplapack_core__ ( "scalar_test_equal_string", decimal, "0.1")); assert (__mplapack_core__ ( "scalar_test_equal_double", binary64, 0.1)); ' echo "PASS: clean rebuild #2 and M01-M21 re-test" make -C src clean tools/build-package.sh package_name=$(sed -n 's/^Name: *//p' DESCRIPTION) package_version=$(sed -n 's/^Version: *//p' DESCRIPTION) if [ "$package_name" != "mplapack-interop" ]; then echo "FAIL: D01R1 requires DESCRIPTION package name mplapack-interop" >&2 exit 1 fi case $package_version in 0.2.1|0.2.1-dev|0.3.0-dev|0.3.0|0.3.1-dev|0.3.1|0.4.0-dev|0.4.0|0.5.0-dev|0.5.0|0.5.1-dev|0.5.1) ;; *) echo "FAIL: release CI requires a recognized DESCRIPTION version" >&2 exit 1 ;; esac package_dir=$package_name-$package_version archive=$repo_root/dist/$package_dir.tar.gz first_hash=$(sha256sum "$archive" | awk '{ print $1 }') tools/build-package.sh second_hash=$(sha256sum "$archive" | awk '{ print $1 }') if [ "$first_hash" != "$second_hash" ]; then echo "FAIL: package archive generation is not deterministic" >&2 exit 1 fi archive_listing=$qa_root/archive-listing tar tzf "$archive" > "$archive_listing" if [ "$(cut -d/ -f1 "$archive_listing" | LC_ALL=C sort -u)" != "$package_dir" ]; then echo "FAIL: package archive lacks one expected top-level directory" >&2 exit 1 fi for required_path in DESCRIPTION COPYING INDEX inst/ src/ \ src/mp_scalar_storage.h src/mp_scalar_storage.cc \ src/mp_precision.h src/mp_precision.cc src/mp_value.h src/mp_value.cc \ inst/@mp/horzcat.m inst/@mp/vertcat.m test/native_value.tst \ inst/mpbits.m inst/mpdigits.m test/constructor.tst test/precision.tst \ test/native_lifetime.m test/public_lifetime.m \ test/mp_scalar_storage_test.cc docs/public-mp-design.md \ test/conversion.tst docs/conversion-display.md \ inst/@mp/char.m inst/@mp/double.m inst/@mp/disp.m \ src/mp_arithmetic.cc test/mp_scalar_arithmetic_test.cc \ test/arithmetic.tst docs/scalar-arithmetic.md \ inst/@mp/uplus.m inst/@mp/uminus.m \ src/mp_matrix_storage.h src/mp_matrix_storage.cc \ src/mp_matrix_value.h src/mp_matrix_value.cc \ test/mp_matrix_storage_test.cc test/matrix_storage.tst \ test/matrix_lifetime.m \ src/mp_blas.h src/mp_blas.cc test/mp_blas_test.cc test/gemm.tst \ docs/matrix-multiplication.md \ src/mp_lapack.h src/mp_lapack.cc test/mp_lapack_test.cc \ test/mp_lapack_probe.cc test/mp_lapack_rgels_probe.cc \ test/mp_lapack_rgels_test.cc test/gesv.tst test/rgels.tst \ test/mp_lapack_rank_test.cc test/rank.tst test/m16_driver_probe.cc \ docs/linear-solve.md docs/rectangular-solve.md \ src/mp_matrix_inspection.h src/mp_matrix_inspection.cc \ test/mp_matrix_inspection_test.cc test/matrix_inspection.tst \ docs/matrix-inspection.md inst/@mp/end.m \ src/mp_matrix_arithmetic.h src/mp_matrix_arithmetic.cc \ test/mp_matrix_arithmetic_test.cc test/elementwise.tst \ docs/elementwise-arithmetic.md docs/milestones/M11-elementwise-arithmetic.md \ src/mp_matrix_structure.h src/mp_matrix_structure.cc \ test/mp_matrix_structure_test.cc test/structure.tst \ docs/matrix-structure.md docs/milestones/M12-transpose-reshape.md \ inst/@mp/transpose.m inst/@mp/ctranspose.m inst/@mp/reshape.m \ src/mp_matrix_concat.h src/mp_matrix_concat.cc \ test/mp_matrix_concat_test.cc test/concat.tst \ docs/matrix-concatenation.md docs/milestones/M13-concatenation.md \ src/mp_matrix_assignment.h src/mp_matrix_assignment.cc \ test/mp_matrix_assignment_test.cc test/assignment.tst \ docs/matrix-assignment.md docs/milestones/M14-indexed-assignment.md \ docs/milestones/M15-rgels.md \ docs/milestones/M16-rank-deficient-lstsq.md docs/rank-deficient-solve.md \ inst/@mp/chol.m test/chol.tst test/mp_lapack_cholesky_test.cc \ test/m17_rpotrf_probe.cc docs/cholesky.md docs/milestones/M17-cholesky.md \ inst/@mp/qr.m test/qr.tst test/mp_lapack_qr_test.cc test/m18_qr_probe.cc \ docs/qr.md docs/milestones/M18-qr.md \ test/pivoted_qr.tst test/mp_lapack_pivoted_qr_test.cc test/m19_qr_probe.cc \ docs/pivoted-qr.md docs/milestones/M19-pivoted-qr.md \ test/m20_complex_probe.cc docs/complex-architecture.md \ docs/milestones/M20-complex-architecture.md \ inst/@mp/lu.m test/lu.tst test/mp_lapack_lu_test.cc \ test/m21_rgetrf_probe.cc docs/lu.md docs/milestones/M21-lu.md \ test/m22_dependency_probe.cc test/release_closure.tst test/mrdivide.tst \ docs/v0.1-api.md docs/octave-compatibility.md docs/ppa-plan.md \ docs/release-checklist.md docs/milestones/M22-real-release-closure.md \ docs/milestones/M23-v0.1-freeze.md \ examples/01_scalar_precision.m examples/02_matrix_arithmetic.m \ examples/03_linear_solve.m examples/04_factorizations.m \ examples/05_hilbert_inverse.m examples/06_grcar_eig.m \ tools/dev-octave.sh tools/verify-release-candidate.sh \ docs/mplapack-interop-hilbert.md docs/binary-distribution.md \ docs/mrdivide.md docs/milestones/N08-mrdivide.md \ docs/binary-redistribution-licenses.md \ inst/@mp/sum.m inst/@mp/prod.m inst/@mp/cumsum.m inst/@mp/cumprod.m \ inst/@mp/sumsq.m inst/@mp/min.m inst/@mp/max.m \ src/mp_script_reductions.h src/mp_script_reductions.cc \ test/script-compat/s00.tst test/script-compat/s01.tst \ test/script-compat/s02.tst test/script-compat/s03.tst \ test/script-compat/s04.tst test/script-compat/s05.tst \ test/script-compat/s06.tst \ test/script-compat/s07.tst \ test/script-compat/s08.tst \ docs/octave-script-compatibility.md \ src/mp_script_logic.h src/mp_script_logic.cc \ inst/@mp/eq.m inst/@mp/ne.m inst/@mp/lt.m inst/@mp/le.m \ inst/@mp/gt.m inst/@mp/ge.m inst/@mp/logical.m inst/@mp/and.m \ inst/@mp/or.m inst/@mp/xor.m inst/@mp/not.m inst/@mp/any.m \ inst/@mp/all.m inst/@mp/find.m \ inst/@mp/diag.m inst/@mp/triu.m inst/@mp/tril.m \ inst/@mp/repmat.m inst/@mp/flip.m inst/@mp/fliplr.m \ inst/@mp/flipud.m inst/@mp/rot90.m inst/@mp/cat.m \ inst/@mp/zeros.m inst/@mp/ones.m inst/@mp/eye.m \ inst/@mp/NaN.m inst/@mp/Inf.m inst/@mp/nan.m inst/@mp/inf.m \ inst/@mp/private/mp_parse_like_constructor.m \ inst/@mp/colon.m inst/@mp/linspace.m inst/@mp/logspace.m \ inst/@mp/floor.m inst/@mp/ceil.m inst/@mp/fix.m inst/@mp/round.m \ inst/@mp/rem.m inst/@mp/mod.m inst/@mp/hypot.m inst/@mp/atan2.m \ inst/@mp/signbit.m inst/@mp/eps.m \ inst/@mp/private/mp_binary_utility.m \ inst/@mp/private/mp_statistic_result.m inst/@mp/mean.m \ inst/@mp/median.m inst/@mp/var.m inst/@mp/std.m \ inst/@mp/range.m inst/@mp/bounds.m \ inst/@mp/private/mp_graphics_args.m inst/@mp/plot.m \ inst/@mp/semilogx.m inst/@mp/semilogy.m inst/@mp/loglog.m \ inst/@mp/scatter.m inst/@mp/stem.m inst/@mp/stairs.m \ inst/@mp/sort.m inst/@mp/diff.m inst/@mp/length.m \ docs/graphics-bridge.md \ src/mp_script_structure.h src/mp_script_structure.cc \ src/mp_script_ranges.h src/mp_script_ranges.cc \ src/mp_script_statistics.h src/mp_script_statistics.cc \ src/mp_script_sequence.h src/mp_script_sequence.cc \ test/mp_script_sequence_test.cc \ docs/dense-matrix-design.md inst/@mp/size.m inst/@mp/rows.m \ inst/@mp/columns.m inst/@mp/numel.m inst/@mp/ndims.m \ inst/@mp/isempty.m inst/@mp/subsref.m inst/@mp/subsasgn.m \ inst/@mp/mrdivide.m inst/@mp/norm.m docs/norm.md \ docs/milestones/N00-norm.md \ src/mp_det_inv.h src/mp_det_inv.cc test/det_inv.tst \ test/mp_det_inv_test.cc docs/determinant-inverse.md \ docs/milestones/N01-det-inv.md inst/@mp/det.m inst/@mp/inv.m \ src/mp_svd.h src/mp_svd.cc test/svd.tst test/mp_svd_test.cc \ docs/svd.md docs/milestones/N02-svd.md inst/@mp/svd.m \ src/mp_rank_condition.h src/mp_rank_condition.cc \ test/rank_condition.tst test/mp_rank_condition_test.cc \ docs/rank-condition.md docs/milestones/N03-rank-condition.md \ inst/@mp/rank.m inst/@mp/cond.m inst/@mp/rcond.m \ src/mp_structured_eig.h src/mp_structured_eig.cc \ test/eig_structured.tst test/mp_structured_eig_test.cc \ src/mp_general_eig.h src/mp_general_eig.cc \ test/eig_general.tst test/mp_general_eig_test.cc \ src/mp_generalized_eig.h src/mp_generalized_eig.cc \ test/eig_generalized.tst test/mp_generalized_eig_test.cc \ test/n07_closure.tst \ inst/@mp/eig.m docs/eig.md docs/generalized-eig.md \ docs/v0.3-api.md \ docs/milestones/N04-eig-structured.md docs/milestones/N05-eig-general.md \ docs/milestones/N06-eig-generalized.md; do if ! grep -Eq "^$package_dir/$required_path" "$archive_listing"; then echo "FAIL: package archive lacks $required_path" >&2 exit 1 fi done if grep -Eq '(^|/)(\.git|dist|\.build-m02|\.build-m06|\.build-m07|\.build-m08|\.build-m09|\.build-m10|\.build-m11|\.build-m12|\.build-m13|\.build-m14|\.build-m15|\.build-m16|\.build-m17|\.build-m18|\.build-m19|\.build-m21|\.build-m22|\.build-n00|\.build-n01|\.build-n02|\.build-n03|\.build-n04|\.build-n05|\.build-n06|\.build-s08)(/|$)|\.(oct|o|lo)$|/\.(libs|deps)/' \ "$archive_listing"; then echo "FAIL: package archive contains a generated or private path" >&2 exit 1 fi if grep -Eq '(^|/)\.build-n0[456]/' "$archive_listing"; then echo "FAIL: package archive contains an N04/N05/N06 native build directory" >&2 exit 1 fi if grep -Eq '(^|/)docs/v0\.1-release-manifest\.md$|(^|/)m23-report\.md$' \ "$archive_listing"; then echo "FAIL: release handoff/report metadata leaked into package archive" >&2 exit 1 fi if grep -q '^/' "$archive_listing"; then echo "FAIL: package archive contains an absolute path" >&2 exit 1 fi echo "PASS: deterministic source package contents" test_home=$qa_root/home neutral_dir=$qa_root/work mkdir -p "$test_home" "$neutral_dir" ( cd "$neutral_dir" HOME=$test_home M01_ARCHIVE=$archive \ octave --no-gui --quiet --no-init-file --eval ' archive = getenv ("M01_ARCHIVE"); pkg ("install", "-verbose", archive); [description, status] = pkg ("describe", "mplapack-interop"); assert (numel (description) == 1); assert (any (strcmp (status, {"Loaded", "Not loaded"}))); metadata = description{1}; required = {"name", "version", "date", "description"}; assert (all (isfield (metadata, required))); ' ) ( cd "$neutral_dir" HOME=$test_home M01_REPO_ROOT=$repo_root \ MPLAPACK_EXPECTED_VERSION=$mplapack_version \ octave --no-gui --quiet --no-init-file --eval ' root = getenv ("M01_REPO_ROOT"); pkg ("load", "mplapack-interop"); assert (test (fullfile (root, "test", "concat.tst"))); assert (test (fullfile (root, "test", "assignment.tst"))); assert (test (fullfile (root, "test", "chol.tst"))); assert (test (fullfile (root, "test", "qr.tst"))); assert (test (fullfile (root, "test", "pivoted_qr.tst"))); assert (test (fullfile (root, "test", "lu.tst"))); assert (test (fullfile (root, "test", "release_closure.tst"))); assert (test (fullfile (root, "test", "mrdivide.tst"))); assert (test (fullfile (root, "test", "script-compat", "s00.tst"))); assert (test (fullfile (root, "test", "script-compat", "s01.tst"))); assert (test (fullfile (root, "test", "script-compat", "s02.tst"))); assert (test (fullfile (root, "test", "script-compat", "s03.tst"))); assert (test (fullfile (root, "test", "script-compat", "s04.tst"))); assert (test (fullfile (root, "test", "script-compat", "s05.tst"))); assert (test (fullfile (root, "test", "script-compat", "s06.tst"))); assert (test (fullfile (root, "test", "script-compat", "s07.tst"))); assert (test (fullfile (root, "test", "script-compat", "s08.tst"))); assert (test (fullfile (root, "test", "rank_condition.tst"))); examples = dir (fullfile (root, "examples", "*.m")); for example = 1:numel (examples) evalc ("run (fullfile (root, \"examples\", examples(example).name));"); endfor assert (! isempty (strfind (evalc ("help @mp/qr"), "QR"))); assert (! isempty (strfind (evalc ("help @mp/lu"), "LU"))); [installed_l, installed_u, installed_p] = lu (mp ([1, 2; 3, 4])); assert (strcmp (class (installed_l), "mp")); assert (strcmp (class (installed_u), "mp")); assert (strcmp (class (installed_p), "double")); [q_pivoted, r_pivoted, p_pivoted] = qr (mp ([1 0; 0 2])); assert (strcmp (class (q_pivoted), "mp")); assert (strcmp (class (r_pivoted), "mp")); assert (strcmp (class (p_pivoted), "double")); public_path = which ("mplapack_version"); native_path = which ("__mplapack_core__"); constructor_path = which ("mp"); mpbits_path = which ("mpbits"); mpdigits_path = which ("mpdigits"); char_method_path = file_in_loadpath ("@mp/char.m"); double_method_path = file_in_loadpath ("@mp/double.m"); disp_method_path = file_in_loadpath ("@mp/disp.m"); plus_method_path = file_in_loadpath ("@mp/plus.m"); minus_method_path = file_in_loadpath ("@mp/minus.m"); times_method_path = file_in_loadpath ("@mp/times.m"); rdivide_method_path = file_in_loadpath ("@mp/rdivide.m"); uplus_method_path = file_in_loadpath ("@mp/uplus.m"); uminus_method_path = file_in_loadpath ("@mp/uminus.m"); horzcat_method_path = file_in_loadpath ("@mp/horzcat.m"); vertcat_method_path = file_in_loadpath ("@mp/vertcat.m"); size_method_path = file_in_loadpath ("@mp/size.m"); mldivide_method_path = file_in_loadpath ("@mp/mldivide.m"); subsref_method_path = file_in_loadpath ("@mp/subsref.m"); subsasgn_method_path = file_in_loadpath ("@mp/subsasgn.m"); end_method_path = file_in_loadpath ("@mp/end.m"); chol_method_path = file_in_loadpath ("@mp/chol.m"); qr_method_path = file_in_loadpath ("@mp/qr.m"); lu_method_path = file_in_loadpath ("@mp/lu.m"); fprintf ("installed mplapack_version: %s\n", public_path); fprintf ("installed __mplapack_core__: %s\n", native_path); fprintf ("installed mp: %s\n", constructor_path); fprintf ("installed mpbits: %s\n", mpbits_path); fprintf ("installed mpdigits: %s\n", mpdigits_path); fprintf ("installed @mp/char: %s\n", char_method_path); fprintf ("installed @mp/double: %s\n", double_method_path); fprintf ("installed @mp/disp: %s\n", disp_method_path); fprintf ("installed @mp/plus: %s\n", plus_method_path); fprintf ("installed @mp/uplus: %s\n", uplus_method_path); fprintf ("installed @mp/uminus: %s\n", uminus_method_path); fprintf ("installed @mp/size: %s\n", size_method_path); fprintf ("installed @mp/subsref: %s\n", subsref_method_path); fprintf ("installed @mp/end: %s\n", end_method_path); fprintf ("installed @mp/chol: %s\n", chol_method_path); fprintf ("installed @mp/qr: %s\n", qr_method_path); fprintf ("installed @mp/lu: %s\n", lu_method_path); assert (! strncmp (public_path, root, length (root))); assert (! strncmp (native_path, root, length (root))); assert (! strncmp (constructor_path, root, length (root))); assert (! strncmp (mpbits_path, root, length (root))); assert (! strncmp (mpdigits_path, root, length (root))); assert (! strncmp (char_method_path, root, length (root))); assert (! strncmp (double_method_path, root, length (root))); assert (! strncmp (disp_method_path, root, length (root))); assert (! strncmp (plus_method_path, root, length (root))); assert (! strncmp (minus_method_path, root, length (root))); assert (! strncmp (times_method_path, root, length (root))); assert (! strncmp (rdivide_method_path, root, length (root))); assert (! strncmp (uplus_method_path, root, length (root))); assert (! strncmp (uminus_method_path, root, length (root))); assert (! strncmp (horzcat_method_path, root, length (root))); assert (! strncmp (vertcat_method_path, root, length (root))); assert (! strncmp (size_method_path, root, length (root))); assert (! strncmp (mldivide_method_path, root, length (root))); assert (! strncmp (subsref_method_path, root, length (root))); assert (! strncmp (subsasgn_method_path, root, length (root))); assert (! strncmp (end_method_path, root, length (root))); assert (! strncmp (chol_method_path, root, length (root))); assert (! strncmp (qr_method_path, root, length (root))); assert (! strncmp (lu_method_path, root, length (root))); info = mplapack_version (); disp (info); assert (strcmp (info.mplapack, getenv ("MPLAPACK_EXPECTED_VERSION"))); assert (strcmp (info.backend, "mpfr")); assert (! isempty (info.mpfr)); assert (info.probe_ok); assert (__mplapack_core__ ("module_test_locked")); run (fullfile (root, "test", "native_lifetime.m")); run (fullfile (root, "test", "public_lifetime.m")); run (fullfile (root, "test", "matrix_lifetime.m")); assert (__mplapack_core__ ("module_test_locked")); assert (test (fullfile (root, "test", "native_value.tst"))); assert (test (fullfile (root, "test", "constructor.tst"))); assert (test (fullfile (root, "test", "precision.tst"))); assert (test (fullfile (root, "test", "conversion.tst"))); assert (test (fullfile (root, "test", "arithmetic.tst"))); assert (test (fullfile (root, "test", "matrix_storage.tst"))); assert (test (fullfile (root, "test", "gemm.tst"))); assert (test (fullfile (root, "test", "gesv.tst"))); assert (test (fullfile (root, "test", "matrix_inspection.tst"))); assert (test (fullfile (root, "test", "elementwise.tst"))); assert (test (fullfile (root, "test", "structure.tst"))); assert (test (fullfile (root, "test", "concat.tst"))); assert (test (fullfile (root, "test", "assignment.tst"))); assert (test (fullfile (root, "test", "chol.tst"))); assert (test (fullfile (root, "test", "qr.tst"))); assert (test (fullfile (root, "test", "pivoted_qr.tst"))); assert (test (fullfile (root, "test", "lu.tst"))); assert (test (fullfile (root, "test", "mrdivide.tst"))); assert (isempty (which ("scalar_test_create"))); assert (isempty (which ("scalar_create_text"))); assert (mpbits () == uint64 (512)); assert (mpdigits () == uint64 (154)); mpbits (256); state_value = mp ("1"); state_info = __mplapack_core__ ( "scalar_test_info", state_value); assert (state_info.precision_bits == 256); unload_value = mp ("-2.25"); unload_matrix = mp ({"1", "2"; "3", "4"}); unload_result = unload_value + mp ("0.25"); unload_result_text = char (unload_result); unload_text = char (unload_value); unload_double = double (unload_value); assert (evalc ("disp (unload_value)"), [unload_text, "\n"]); pkg ("unload", "mplapack-interop"); assert (strcmp (class (unload_value), "mp")); assert (strcmp (class (unload_matrix), "mp")); pkg ("load", "mplapack-interop"); assert (size (unload_matrix), [2, 2]); unload_matrix_info = __mplapack_core__ ( "matrix_test_info", unload_matrix); assert (unload_matrix_info.precision_bits == 256); assert (__mplapack_core__ ( "matrix_test_element_equal_text", unload_matrix, 2, 2, "4")); assert (char (unload_value), unload_text); assert (char (unload_result), unload_result_text); assert (double (unload_value), unload_double); assert (evalc ("disp (unload_value)"), [unload_text, "\n"]); assert (mpbits () == uint64 (256)); assert (mpdigits () == uint64 (77)); reloaded_state_value = mp ("1"); reloaded_state_info = __mplapack_core__ ( "scalar_test_info", reloaded_state_value); assert (reloaded_state_info.precision_bits == 256); unload_info = __mplapack_core__ ( "scalar_test_info", unload_value); assert (unload_info.precision_bits == 256); assert (__mplapack_core__ ( "scalar_test_equal_string", unload_value, "-2.25")); clear unload_value unload_result unload_info state_value state_info; clear unload_matrix unload_matrix_info; clear reloaded_state_value reloaded_state_info; destroy_while_unloaded = mp ("1.5"); destroy_matrix_while_unloaded = mp ([1, 2; 3, 4]); pkg ("unload", "mplapack-interop"); assert (strcmp (class (destroy_while_unloaded), "mp")); clear destroy_while_unloaded; clear destroy_matrix_while_unloaded; pkg ("load", "mplapack-interop"); reloaded_value = __mplapack_core__ ( "scalar_test_create", "1.5", 256); reloaded_info = __mplapack_core__ ( "scalar_test_info", reloaded_value); assert (reloaded_info.precision_bits == 256); assert (__mplapack_core__ ("module_test_locked")); clear reloaded_value; pkg ("unload", "mplapack-interop"); pkg ("uninstall", "mplapack-interop"); ' ) ( cd "$neutral_dir" HOME=$test_home octave --no-gui --quiet --no-init-file --eval ' assert (isempty (which ("mp"))); assert (isempty (which ("mpbits"))); assert (isempty (which ("mpdigits"))); assert (isempty (which ("mplapack_version"))); assert (isempty (which ("__mplapack_core__"))); ' ) ( cd "$neutral_dir" HOME=$test_home M01_ARCHIVE=$archive \ octave --no-gui --quiet --no-init-file --eval ' pkg ("install", getenv ("M01_ARCHIVE")); ' ) ( cd "$neutral_dir" HOME=$test_home M01_REPO_ROOT=$repo_root \ MPLAPACK_EXPECTED_VERSION=$mplapack_version \ octave --no-gui --quiet --no-init-file --eval ' pkg ("load", "mplapack-interop"); root = getenv ("M01_REPO_ROOT"); public_path = which ("mplapack_version"); native_path = which ("__mplapack_core__"); constructor_path = which ("mp"); mpbits_path = which ("mpbits"); mpdigits_path = which ("mpdigits"); char_method_path = file_in_loadpath ("@mp/char.m"); double_method_path = file_in_loadpath ("@mp/double.m"); disp_method_path = file_in_loadpath ("@mp/disp.m"); plus_method_path = file_in_loadpath ("@mp/plus.m"); minus_method_path = file_in_loadpath ("@mp/minus.m"); times_method_path = file_in_loadpath ("@mp/times.m"); rdivide_method_path = file_in_loadpath ("@mp/rdivide.m"); uplus_method_path = file_in_loadpath ("@mp/uplus.m"); uminus_method_path = file_in_loadpath ("@mp/uminus.m"); size_method_path = file_in_loadpath ("@mp/size.m"); mldivide_method_path = file_in_loadpath ("@mp/mldivide.m"); subsref_method_path = file_in_loadpath ("@mp/subsref.m"); subsasgn_method_path = file_in_loadpath ("@mp/subsasgn.m"); end_method_path = file_in_loadpath ("@mp/end.m"); chol_method_path = file_in_loadpath ("@mp/chol.m"); qr_method_path = file_in_loadpath ("@mp/qr.m"); lu_method_path = file_in_loadpath ("@mp/lu.m"); horzcat_method_path = file_in_loadpath ("@mp/horzcat.m"); vertcat_method_path = file_in_loadpath ("@mp/vertcat.m"); assert (! strncmp (public_path, root, length (root))); assert (! strncmp (native_path, root, length (root))); assert (! strncmp (constructor_path, root, length (root))); assert (! strncmp (mpbits_path, root, length (root))); assert (! strncmp (mpdigits_path, root, length (root))); assert (! strncmp (char_method_path, root, length (root))); assert (! strncmp (double_method_path, root, length (root))); assert (! strncmp (disp_method_path, root, length (root))); assert (! strncmp (plus_method_path, root, length (root))); assert (! strncmp (minus_method_path, root, length (root))); assert (! strncmp (times_method_path, root, length (root))); assert (! strncmp (rdivide_method_path, root, length (root))); assert (! strncmp (uplus_method_path, root, length (root))); assert (! strncmp (uminus_method_path, root, length (root))); assert (! strncmp (size_method_path, root, length (root))); assert (! strncmp (mldivide_method_path, root, length (root))); assert (! strncmp (subsref_method_path, root, length (root))); assert (! strncmp (end_method_path, root, length (root))); assert (! strncmp (chol_method_path, root, length (root))); assert (! strncmp (qr_method_path, root, length (root))); assert (! strncmp (lu_method_path, root, length (root))); assert (! strncmp (horzcat_method_path, root, length (root))); assert (! strncmp (vertcat_method_path, root, length (root))); assert (mpbits () == uint64 (512)); assert (mpdigits () == uint64 (154)); info = mplapack_version (); assert (strcmp (info.mplapack, getenv ("MPLAPACK_EXPECTED_VERSION"))); assert (info.probe_ok); shutdown_value = __mplapack_core__ ( "scalar_test_create", "0.1", 512); shutdown_info = __mplapack_core__ ( "scalar_test_info", shutdown_value); assert (shutdown_info.precision_bits == 512); assert (__mplapack_core__ ( "scalar_test_equal_string", shutdown_value, "0.1")); assert (__mplapack_core__ ("module_test_locked")); decimal = mp ("0.1"); binary64 = mp (0.1); assert (strcmp (class (decimal), "mp")); assert (size (decimal), [1, 1]); assert (! __mplapack_core__ ( "scalar_test_equal", decimal, binary64)); assert (__mplapack_core__ ( "scalar_test_equal_string", decimal, "0.1")); assert (__mplapack_core__ ( "scalar_test_equal_double", binary64, 0.1)); assert (mpdigits (100) == uint64 (100)); assert (mpbits () == uint64 (333)); precision_value = mp ("1"); precision_info = __mplapack_core__ ( "scalar_test_info", precision_value); assert (precision_info.precision_bits == 333); conversion_value = mp ("0.1"); conversion_text = char (conversion_value); conversion_round_trip = mp (conversion_text); assert (__mplapack_core__ ( "scalar_test_equal", conversion_value, conversion_round_trip)); assert (double (conversion_value), 0.1); assert (evalc ("disp (conversion_value)"), [conversion_text, "\n"]); arithmetic_lhs = mp ("1.25"); arithmetic_rhs = mp ("0.5"); arithmetic_result = arithmetic_lhs + arithmetic_rhs; assert (__mplapack_core__ ( "scalar_test_equal_string", arithmetic_result, "1.75")); assert (__mplapack_core__ ( "scalar_test_info", arithmetic_result).precision_bits == 333); assert (__mplapack_core__ ( "scalar_test_equal_string", arithmetic_lhs .* arithmetic_rhs, "0.625")); installed_text_matrix = mp ({"1", "2"; "3", "4"}); installed_double_matrix = mp ([1, 2; 3, 4]); assert (size (installed_text_matrix), [2, 2]); assert (rows (installed_double_matrix), 2); assert (columns (installed_double_matrix), 2); assert (numel (installed_double_matrix), 4); assert (__mplapack_core__ ( "matrix_test_element_equal", installed_text_matrix, 2, 2, installed_double_matrix, 2, 2)); installed_product = installed_text_matrix * installed_double_matrix; assert (__mplapack_core__ ( "matrix_test_element_equal_text", installed_product, 1, 1, "7")); assert (__mplapack_core__ ( "matrix_test_element_equal_text", installed_product, 2, 2, "22")); installed_sum = installed_text_matrix + installed_double_matrix; assert (__mplapack_core__ ( "matrix_test_element_equal_text", installed_sum, 1, 1, "2")); assert (__mplapack_core__ ( "matrix_test_element_equal_text", installed_sum, 2, 2, "8")); installed_transpose = transpose (installed_text_matrix); assert (size (installed_transpose), [2, 2]); installed_reshape = reshape (installed_text_matrix, 1, 4); assert (size (installed_reshape), [1, 4]); installed_horzcat = [installed_text_matrix, installed_double_matrix]; installed_vertcat = [installed_text_matrix; installed_double_matrix]; assert (size (installed_horzcat), [2, 4]); assert (size (installed_vertcat), [4, 2]); assert (__mplapack_core__ ( "matrix_test_element_equal_text", installed_horzcat, 1, 3, "1")); assert (__mplapack_core__ ( "matrix_test_element_equal_text", installed_vertcat, 3, 1, "1")); installed_solution = installed_text_matrix \ mp ({"3"; "7"}); assert (__mplapack_core__ ( "matrix_test_element_double", installed_solution, 1, 1), 1); assert (__mplapack_core__ ( "matrix_test_element_double", installed_solution, 2, 1), 1); installed_rectangular = mp ({"1", "0"; "0", "1"; "1", "1"}); installed_rectangular_rhs = mp ({"0"; "1"; "4"}); installed_rectangular_solution = installed_rectangular \ installed_rectangular_rhs; assert (size (installed_rectangular_solution), [2, 1]); assert (__mplapack_core__ ( "matrix_test_element_double", installed_rectangular_solution, 1, 1), 1); assert (__mplapack_core__ ( "matrix_test_element_double", installed_rectangular_solution, 2, 1), 2); installed_qr = qr (mp ([1, 2; 3, 4; 5, 7])); assert (size (installed_qr), [3, 2]); [installed_q, installed_r, installed_p] = qr (mp ([1, 0; 0, 2])); assert (strcmp (class (installed_q), "mp")); assert (strcmp (class (installed_r), "mp")); assert (strcmp (class (installed_p), "double")); [installed_lu_l, installed_lu_u, installed_lu_p] = ... lu (mp ([1, 2; 3, 4])); assert (strcmp (class (installed_lu_l), "mp")); assert (strcmp (class (installed_lu_u), "mp")); assert (strcmp (class (installed_lu_p), "double")); fprintf ("reinstalled mplapack_version: %s\n", public_path); fprintf ("reinstalled __mplapack_core__: %s\n", native_path); fprintf ("reinstalled mp: %s\n", constructor_path); fprintf ("reinstalled mpbits: %s\n", mpbits_path); fprintf ("reinstalled mpdigits: %s\n", mpdigits_path); fprintf ("reinstalled @mp/char: %s\n", char_method_path); fprintf ("reinstalled @mp/double: %s\n", double_method_path); fprintf ("reinstalled @mp/disp: %s\n", disp_method_path); fprintf ("reinstalled @mp/plus: %s\n", plus_method_path); fprintf ("reinstalled @mp/minus: %s\n", minus_method_path); fprintf ("reinstalled @mp/times: %s\n", times_method_path); fprintf ("reinstalled @mp/rdivide: %s\n", rdivide_method_path); fprintf ("reinstalled @mp/uplus: %s\n", uplus_method_path); fprintf ("reinstalled @mp/uminus: %s\n", uminus_method_path); fprintf ("reinstalled @mp/size: %s\n", size_method_path); fprintf ("reinstalled @mp/subsref: %s\n", subsref_method_path); fprintf ("reinstalled @mp/subsasgn: %s\n", subsasgn_method_path); fprintf ("reinstalled @mp/end: %s\n", end_method_path); fprintf ("reinstalled @mp/chol: %s\n", chol_method_path); fprintf ("reinstalled @mp/qr: %s\n", qr_method_path); fprintf ("reinstalled @mp/lu: %s\n", lu_method_path); fprintf ("reinstalled @mp/horzcat: %s\n", horzcat_method_path); fprintf ("reinstalled @mp/vertcat: %s\n", vertcat_method_path); fprintf ("PASS: installed scalar/matrix values left for shutdown destruction\n"); ' ) echo "PASS: isolated package D00 install, matrix/Rgemm/Rgesv/Rgels/Rgelss/Rpotrf/Rgeqrf/Rorgqr/Rgeqp3/Rgetrf/inspection/element-wise/structure/concatenation/assignment/Cholesky/QR/pivoted QR/LU, release closure, and complex audit QA, unload, uninstall, and reinstall" make -C src clean echo "PASS: D00 local CI" mplapack-interop-0.5.1/tools/check-smoke-matrices.py0000755000230300031750000001165415274353473021766 0ustar rafaelrafael#!/usr/bin/env python3 """Compare committed GitHub Math smoke matrices with generator output.""" from __future__ import annotations import argparse import re from fractions import Fraction from pathlib import Path from format_smoke_matrices import load_records MATRIX_RE = re.compile( r"\s*" r"```math\s*\n(?P.*?)\n```\s*", re.DOTALL, ) def parse_atom(text: str): text = text.strip().replace(" ", "") if text == "i": return (Fraction(0), Fraction(1)) if text == "-i": return (Fraction(0), Fraction(-1)) imag = text.endswith("i") if imag: text = text[:-1] if text.startswith(r"\frac{") and text.endswith("}"): numerator, denominator = text[6:-1].split("}{", 1) value = Fraction(int(numerator), int(denominator)) elif text.startswith("2^{") and text.endswith("}"): exponent = int(text[3:-1]) value = Fraction(2**exponent) if exponent >= 0 else Fraction(1, 2**(-exponent)) elif text.startswith("-2^{") and text.endswith("}"): exponent = int(text[4:-1]) value = -Fraction(2**exponent) if exponent >= 0 else -Fraction(1, 2**(-exponent)) else: value = Fraction(int(text)) return (Fraction(0), value) if imag else (value, Fraction(0)) def scale_value(value, scale): return (value[0] * scale, value[1] * scale) def parse_matrix(document: str, case_id: str): matches = [m for m in MATRIX_RE.finditer(document) if m.group("case") == case_id] if len(matches) != 1: raise ValueError( f"{case_id}: expected one marked matrix block, found {len(matches)}" ) body = matches[0].group("body") begin = body.find(r"\begin{bmatrix}") end = body.find(r"\end{bmatrix}") if begin < 0 or end < 0 or end <= begin: raise ValueError(f"{case_id}: matrix must use bmatrix") expression = body[begin + len(r"\begin{bmatrix}"):end].strip() prefix = body[:begin].strip() if "=" in prefix: prefix = prefix.rsplit("=", 1)[1].strip() scale = Fraction(1) if prefix: prefix_match = re.search(r"2\^\{-(\d+)\}\s*$", prefix) if prefix_match is None: raise ValueError(f"{case_id}: unsupported matrix scale {prefix!r}") scale = Fraction(1, 2 ** int(prefix_match.group(1))) rows = [] for raw_row in re.split(r"\\\\", expression): raw_row = raw_row.strip() if not raw_row: continue rows.append([scale_value(parse_atom(entry), scale) for entry in raw_row.split("&")]) if not rows or len({len(row) for row in rows}) != 1: raise ValueError(f"{case_id}: malformed matrix rows") return rows def compare(expected, actual, case_id): rows = len(expected) columns = len(expected[0]) if (rows, columns) != actual["shape"]: raise ValueError( f"{case_id}: shape {rows}x{columns} != " f"{actual['shape'][0]}x{actual['shape'][1]}" ) for row in range(rows): for column in range(columns): expected_value = expected[row][column] actual_value = actual["values"][(row + 1, column + 1)] if expected_value != actual_value: raise ValueError( f"{case_id}: mismatch at ({row + 1},{column + 1}): " f"{expected_value!r} != {actual_value!r}" ) def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("records", type=Path) args = parser.parse_args() metadata, records = load_records(args.records) actual = {} for case_id, (doc, rows, columns) in metadata.items(): actual[case_id] = { "doc": doc, "shape": (rows, columns), "values": { (row, column): records[(case_id, row, column)] for row in range(1, rows + 1) for column in range(1, columns + 1) }, } for case_id, item in actual.items(): document = Path(item["doc"]).read_text(encoding="utf-8") expected = parse_matrix(document, case_id) compare(expected, item, case_id) print(f"PASS: {case_id} {item['shape'][0]}x{item['shape'][1]} {item['doc']}") if case_id == "FRANK0": checks = { (0, 0): (Fraction(8), Fraction(0)), (0, 7): (Fraction(1), Fraction(0)), (3, 2): (Fraction(5), Fraction(0)), (3, 1): (Fraction(0), Fraction(0)), } for (row, column), value in checks.items(): if expected[row][column] != value: raise ValueError( f"FRANK0: focused orientation check failed at " f"({row + 1},{column + 1})" ) print("PASS: FRANK0 focused orientation checks (11, 18, 43, 42)") return 0 if __name__ == "__main__": raise SystemExit(main()) mplapack-interop-0.5.1/tools/check-tree.sh0000755000230300031750000002306515274353473017763 0ustar rafaelrafael#!/bin/sh set -eu repo_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd) cd "$repo_root" failed=0 required_dirs=' .github/workflows inst inst/@mp src test test/script-compat tools docs docs/milestones examples packaging packaging/debian ' required_files=' .github/workflows/ci.yml AGENTS.md README.md LICENSE COPYING NEWS.md m20-report.md m21-report.md m22-report.md m23-report.md CONTRIBUTING.md .gitignore DESCRIPTION INDEX inst/@mp/mp.m inst/@mp/horzcat.m inst/@mp/vertcat.m inst/@mp/disp.m inst/@mp/char.m inst/@mp/double.m inst/@mp/plus.m inst/@mp/minus.m inst/@mp/times.m inst/@mp/rdivide.m inst/@mp/uplus.m inst/@mp/uminus.m inst/@mp/size.m inst/@mp/rows.m inst/@mp/columns.m inst/@mp/numel.m inst/@mp/ndims.m inst/@mp/isempty.m inst/@mp/subsref.m inst/@mp/subsasgn.m inst/@mp/end.m inst/@mp/mtimes.m inst/@mp/mldivide.m inst/@mp/norm.m inst/@mp/svd.m inst/@mp/eig.m inst/@mp/rank.m inst/@mp/cond.m inst/@mp/rcond.m inst/@mp/mrdivide.m inst/@mp/abs.m inst/@mp/angle.m inst/@mp/arg.m inst/@mp/sign.m inst/@mp/isnan.m inst/@mp/isinf.m inst/@mp/isfinite.m inst/@mp/isequal.m inst/@mp/isequaln.m inst/@mp/isnumeric.m inst/@mp/power.m inst/@mp/mpower.m inst/@mp/sqrt.m inst/@mp/exp.m inst/@mp/expm1.m inst/@mp/log.m inst/@mp/log1p.m inst/@mp/log10.m inst/@mp/log2.m inst/@mp/sin.m inst/@mp/cos.m inst/@mp/tan.m inst/@mp/asin.m inst/@mp/acos.m inst/@mp/atan.m inst/@mp/sinh.m inst/@mp/cosh.m inst/@mp/tanh.m inst/@mp/asinh.m inst/@mp/acosh.m inst/@mp/atanh.m inst/@mp/cbrt.m inst/@mp/sum.m inst/@mp/prod.m inst/@mp/cumsum.m inst/@mp/cumprod.m inst/@mp/sumsq.m inst/@mp/min.m inst/@mp/max.m inst/@mp/eq.m inst/@mp/ne.m inst/@mp/lt.m inst/@mp/le.m inst/@mp/gt.m inst/@mp/ge.m inst/@mp/logical.m inst/@mp/and.m inst/@mp/or.m inst/@mp/xor.m inst/@mp/not.m inst/@mp/any.m inst/@mp/all.m inst/@mp/find.m inst/@mp/diag.m inst/@mp/triu.m inst/@mp/tril.m inst/@mp/repmat.m inst/@mp/flip.m inst/@mp/fliplr.m inst/@mp/flipud.m inst/@mp/rot90.m inst/@mp/cat.m inst/@mp/zeros.m inst/@mp/ones.m inst/@mp/eye.m inst/@mp/NaN.m inst/@mp/Inf.m inst/@mp/nan.m inst/@mp/inf.m inst/@mp/private/mp_parse_like_constructor.m inst/@mp/colon.m inst/@mp/linspace.m inst/@mp/logspace.m inst/@mp/floor.m inst/@mp/ceil.m inst/@mp/fix.m inst/@mp/round.m inst/@mp/rem.m inst/@mp/mod.m inst/@mp/hypot.m inst/@mp/atan2.m inst/@mp/signbit.m inst/@mp/eps.m inst/@mp/private/mp_binary_utility.m inst/@mp/private/mp_statistic_result.m inst/@mp/private/mp_graphics_args.m inst/@mp/plot.m inst/@mp/semilogx.m inst/@mp/semilogy.m inst/@mp/loglog.m inst/@mp/scatter.m inst/@mp/stem.m inst/@mp/stairs.m docs/graphics-bridge.md inst/@mp/sort.m inst/@mp/diff.m inst/@mp/length.m inst/@mp/mean.m inst/@mp/median.m inst/@mp/var.m inst/@mp/std.m inst/@mp/range.m inst/@mp/bounds.m inst/@mp/transpose.m inst/@mp/ctranspose.m inst/@mp/reshape.m inst/@mp/chol.m inst/@mp/qr.m inst/mpbits.m inst/mpdigits.m inst/mplapack_version.m src/Makefile src/mp_scalar_storage.h src/mp_scalar_storage.cc src/mp_precision.h src/mp_precision.cc src/mp_value.h src/mp_value.cc src/mp_convert.cc src/mp_arithmetic.cc src/mp_matrix_storage.h src/mp_matrix_storage.cc src/mp_matrix_value.h src/mp_matrix_value.cc src/mp_blas.cc src/mp_lapack.cc src/mp_lapack.h src/mp_matrix_inspection.cc src/mp_matrix_inspection.h src/mp_matrix_arithmetic.cc src/mp_matrix_arithmetic.h src/mp_matrix_structure.cc src/mp_matrix_structure.h src/mp_matrix_concat.cc src/mp_matrix_concat.h src/mp_matrix_assignment.cc src/mp_matrix_assignment.h src/octave_bridge.cc src/mp_script_compat.h src/mp_script_compat.cc src/mp_script_reductions.h src/mp_script_reductions.cc src/mp_script_logic.h src/mp_script_logic.cc src/mp_script_structure.h src/mp_script_structure.cc src/mp_script_ranges.h src/mp_script_ranges.cc src/mp_script_statistics.h src/mp_script_statistics.cc src/mp_script_sequence.h src/mp_script_sequence.cc src/mp_norm.h src/mp_norm.cc src/mp_det_inv.h src/mp_det_inv.cc src/mp_svd.h src/mp_svd.cc src/mp_rank_condition.h src/mp_rank_condition.cc src/mp_structured_eig.h src/mp_structured_eig.cc src/mp_general_eig.h src/mp_general_eig.cc src/mp_generalized_eig.h src/mp_generalized_eig.cc test/run_tests.m test/test_svd_tiers.m test/test_svd_verification.m examples/14_svd_tier_s.m examples/15_svd_tier_a.m examples/16_svd_verified.m test/script-compat/s00.tst test/script-compat/s01.tst test/script-compat/s02.tst test/script-compat/s03.tst test/script-compat/s04.tst test/script-compat/s05.tst test/script-compat/s06.tst test/script-compat/s07.tst test/script-compat/s08.tst test/mp_script_sequence_test.cc test/mrdivide.tst test/build_probe.tst test/native_value.tst test/native_lifetime.m test/public_lifetime.m test/mp_scalar_storage_test.cc test/mp_scalar_arithmetic_test.cc test/mp_matrix_storage_test.cc test/constructor.tst test/precision.tst test/conversion.tst test/arithmetic.tst test/matrix_storage.tst test/matrix_lifetime.m test/gemm.tst test/gesv.tst test/rgels.tst test/rank.tst test/mp_lapack_probe.cc test/mp_lapack_test.cc test/mp_lapack_rgels_test.cc test/mp_lapack_rank_test.cc test/m16_driver_probe.cc test/mp_lapack_cholesky_test.cc test/m17_rpotrf_probe.cc test/chol.tst test/mp_lapack_qr_test.cc test/m18_qr_probe.cc test/qr.tst test/mp_lapack_pivoted_qr_test.cc test/m19_qr_probe.cc test/m20_complex_probe.cc test/mp_lapack_lu_test.cc test/m21_rgetrf_probe.cc test/m22_dependency_probe.cc test/pivoted_qr.tst test/release_closure.tst test/norm.tst test/mp_norm_test.cc test/det_inv.tst test/mp_det_inv_test.cc test/svd.tst test/mp_svd_test.cc test/rank_condition.tst test/mp_rank_condition_test.cc test/mp_structured_eig_test.cc test/eig_structured.tst test/mp_general_eig_test.cc test/eig_general.tst test/mp_generalized_eig_test.cc test/eig_generalized.tst test/n07_closure.tst test/matrix_inspection.tst test/mp_matrix_inspection_test.cc test/elementwise.tst test/mp_matrix_arithmetic_test.cc test/structure.tst test/mp_matrix_structure_test.cc test/concat.tst test/mp_matrix_concat_test.cc test/assignment.tst test/mp_matrix_assignment_test.cc tools/check-format.sh tools/check-tree.sh tools/local-ci.sh tools/build-package.sh tools/verify-release-candidate.sh tools/dev-octave.sh docs/architecture.md docs/svd-tiers.md docs/svd-verification.md docs/native-value-design.md docs/public-mp-design.md docs/conversion-display.md docs/scalar-arithmetic.md docs/dense-matrix-design.md docs/linear-solve.md docs/rectangular-solve.md docs/matrix-inspection.md docs/elementwise-arithmetic.md docs/matrix-structure.md docs/matrix-concatenation.md docs/precision-semantics.md docs/packaging.md docs/milestones/README.md docs/milestones/M00-bootstrap.md docs/milestones/M01-build-probe.md docs/milestones/M02-native-value.md docs/milestones/M03-constructors.md docs/milestones/M04-precision.md docs/milestones/M05-conversion.md docs/milestones/M06-elementwise.md docs/milestones/M07-matrix-storage.md docs/milestones/M08-mtimes.md docs/milestones/M09-mldivide.md docs/milestones/M10-first-functional-baseline.md docs/milestones/M11-elementwise-arithmetic.md docs/milestones/M12-transpose-reshape.md docs/milestones/M13-concatenation.md docs/qr.md docs/milestones/M18-qr.md docs/pivoted-qr.md docs/milestones/M19-pivoted-qr.md docs/complex-architecture.md docs/milestones/M20-complex-architecture.md docs/lu.md docs/v0.1-api.md docs/octave-compatibility.md docs/ppa-plan.md docs/release-checklist.md docs/milestones/M21-lu.md docs/milestones/M22-real-release-closure.md docs/milestones/M23-v0.1-freeze.md docs/norm.md docs/milestones/N00-norm.md docs/determinant-inverse.md docs/milestones/N01-det-inv.md docs/svd.md docs/milestones/N02-svd.md docs/rank-condition.md docs/milestones/N03-rank-condition.md docs/eig.md docs/generalized-eig.md docs/v0.3-api.md docs/octave-script-compatibility.md docs/goals/S00-S08-D03-status.md reports/S00-report.md docs/milestones/N04-eig-structured.md docs/milestones/N05-eig-general.md docs/milestones/N06-eig-generalized.md reports/N05-report.md reports/N06-report.md reports/N07-report.md docs/v0.1-release-manifest.md docs/matrix-assignment.md docs/milestones/M14-indexed-assignment.md docs/milestones/M15-rgels.md docs/milestones/M16-rank-deficient-lstsq.md docs/rank-deficient-solve.md docs/cholesky.md docs/milestones/M17-cholesky.md docs/milestones/P00-packaging-design.md docs/milestones/P01-debian-source-package.md docs/milestones/P02-local-deb-build.md docs/milestones/P03-ppa-staging.md docs/milestones/P04-ppa-autopkgtest.md docs/milestones/P05-ppa-stable.md docs/milestones/P06-ubuntu-series-matrix.md packaging/debian/README.md ' for path in $required_dirs; do if [ ! -d "$path" ]; then echo "FAIL: missing required directory: $path" >&2 failed=1 fi done for path in $required_files; do if [ ! -f "$path" ]; then echo "FAIL: missing required file: $path" >&2 failed=1 fi done for path in tools/check-tree.sh tools/check-format.sh tools/local-ci.sh \ tools/build-package.sh tools/verify-release-candidate.sh; do if [ -f "$path" ] && [ ! -x "$path" ]; then echo "FAIL: required script is not executable: $path" >&2 failed=1 fi done for path in docs/milestones/M??-*.md docs/milestones/P??-*.md; do [ -f "$path" ] || continue for heading in Goal Scope Non-goals "Design constraints" \ "Implementation tasks" "Required tests" Gate "Expected commit"; do if ! grep -Fqx "# $heading" "$path"; then echo "FAIL: $path lacks required heading: # $heading" >&2 failed=1 fi done done if [ "$failed" -ne 0 ]; then echo "FAIL: M00-M23 tree checks failed" >&2 exit 1 fi if ! cmp LICENSE COPYING; then echo "FAIL: LICENSE and COPYING differ" >&2 exit 1 fi if grep -Eq '__mplapack_core__|scalar_' INDEX; then echo "FAIL: private native APIs must not appear in INDEX" >&2 exit 1 fi echo "PASS: M00-M23 tree checks" mplapack-interop-0.5.1/inst/0000755000230300031750000000000015274353473015221 5ustar rafaelrafaelmplapack-interop-0.5.1/inst/mprandi.m0000644000230300031750000000466715274353473017046 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mprandi (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{r} =} mprandi (@var{imax}) ## @deftypefnx {} {@var{r} =} mprandi (@var{imax}, [@var{m} @var{n}]) ## @deftypefnx {} {@var{r} =} mprandi (@var{imin}, @var{imax}) ## @deftypefnx {} {@var{r} =} mprandi (@var{imin}, @var{imax}, [@var{m} @var{n}]) ## Generate exact integer mp values using rejection sampling. The one- ## argument form samples [0,imax]; two bounds sample [imin,imax]. ## @end deftypefn if (nargin < 1 || nargin > 4) error ("mplapack:rng:InvalidArguments", ... "mprandi expects a bound and optional dimensions"); endif lower = mp ("0"); upper = []; dimensions = {}; if (nargin == 1) upper = mp_rng_integer_bound (varargin{1}, "upper bound"); elseif (nargin == 2 && mp_rng_is_dimension_vector (varargin{2})) upper = mp_rng_integer_bound (varargin{1}, "upper bound"); dimensions = {varargin{2}}; else lower = mp_rng_integer_bound (varargin{1}, "lower bound"); upper = mp_rng_integer_bound (varargin{2}, "upper bound"); if (nargin == 3) dimensions = {varargin{3}}; elseif (nargin == 4) dimensions = {varargin{3}, varargin{4}}; endif endif [rows_out, columns_out] = mp_random_dimensions (dimensions, "mprandi"); state = mp_rng_state ("get"); [payload, first, second] = __mplapack_core__ ( "rng_integer", lower, upper, rows_out, columns_out, state.state(1), state.state(2)); state.state = uint64 ([first, second]); mp_rng_state ("set", state); result = mp ("0"); result.payload_ = payload; endfunction function result = mp_rng_is_dimension_vector (value) result = isnumeric (value) && ! islogical (value) && isreal (value) ... && numel (value) == 2; endfunction function result = mp_rng_integer_bound (value, description) if (isa (value, "mp")) if (! isreal (value) || ! isscalar (value) || isnan (value) || ! isfinite (value) || value != fix (value)) error ("mplapack:rng:InvalidBound", ... "%s must be a finite exact integer mp scalar", description); endif result = value; return; endif if (! isnumeric (value) || islogical (value) || ! isreal (value) || ! isscalar (value) || ! isfinite (value) || value != fix (value)) error ("mplapack:rng:InvalidBound", ... "%s must be a finite integer scalar", description); endif result = mp (value); endfunction mplapack-interop-0.5.1/inst/ppint.m0000644000230300031750000000341315274353473016532 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} ppint (@dots{}) ## Differentiate or integrate a supported arbitrary-precision piecewise-polynomial form. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits, mpdigits} ## @end deftypefn function result = ppint (pp, varargin) if (! isstruct (pp) || ! isscalar (pp) || ! isfield (pp, "form") || ! strcmp (pp.form, "pp") || pp.order < 1 || nargin > 2) error ("mplapack:interp:InvalidPP", "ppint expects an pp struct and optional constant"); endif zero = mp_interp_element (pp.coefs, 1, 1) * 0; constant = zero; if (nargin == 2) if (! isa (varargin{1}, "mp")) constant = zero + varargin{1}; else constant = varargin{1}; endif endif new_order = pp.order + 1; coefficients = repmat (zero, pp.pieces, new_order); for piece = 1:pp.pieces for column = 1:pp.order coefficients = mp_interp_put (coefficients, piece, column, ... mp_interp_element (pp.coefs, piece, column) ... / (pp.order - column + 1)); endfor coefficients = mp_interp_put (coefficients, piece, new_order, constant); width = mp_interp_element (pp.breaks, piece + 1) ... - mp_interp_element (pp.breaks, piece); for column = 1:pp.order power = pp.order - column + 1; constant = constant + mp_interp_element (pp.coefs, piece, column) ... / power * width ^ power; endfor endfor result = pp; result.coefs = coefficients; result.order = new_order; endfunction mplapack-interop-0.5.1/inst/unmkpp.m0000644000230300031750000000167015274353473016715 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} unmkpp (@dots{}) ## Decompose a supported arbitrary-precision piecewise-polynomial form into its components. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits, mpdigits} ## @end deftypefn function varargout = unmkpp (pp) if (! isstruct (pp) || ! isscalar (pp) || ! isfield (pp, "form") || ! strcmp (pp.form, "pp")) error ("mplapack:interp:InvalidPP", "unmkpp expects an pp struct"); endif if (nargout > 5) error ("mplapack:interp:InvalidOutput", "unmkpp returns at most five outputs"); endif values = {pp.breaks, pp.coefs, pp.pieces, pp.order, pp.dim}; for index = 1:nargout varargout{index} = values{index}; endfor endfunction mplapack-interop-0.5.1/inst/mprng.m0000644000230300031750000000523615274353473016530 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mprng (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{s} =} mprng () ## @deftypefnx {} {@var{s} =} mprng ("state") ## @deftypefnx {} {@var{s} =} mprng ("state", @var{s}) ## @deftypefnx {} {@var{s} =} mprng ("seed", @var{seed}) ## @deftypefnx {} {@var{s} =} mprng ("reset") ## Return or update the versioned state of the package arbitrary-precision ## numerical random generator. This is not a cryptographic generator. ## @end deftypefn if (nargin == 0 || (nargin == 1 && ischar (varargin{1}) && strcmp (varargin{1}, "state"))) result = mp_rng_state ("get"); return; endif if (! ischar (varargin{1}) || rows (varargin{1}) != 1) error ("mplapack:rng:InvalidState", ... "mprng command must be state, seed, or reset"); endif command = varargin{1}; switch (command) case "state" if (nargin != 2) error ("mplapack:rng:InvalidState", ... "mprng state setter expects one state struct"); endif result = mp_rng_state ("set", varargin{2}); case "seed" if (nargin != 2) error ("mplapack:rng:InvalidState", ... "mprng seed expects one nonnegative integer seed"); endif seed = mp_rng_seed_value (varargin{2}); [first, second] = __mplapack_core__ ("rng_seed", seed); result = mp_rng_state ("set_raw", first, second); case "reset" if (nargin != 1) error ("mplapack:rng:InvalidState", ... "mprng reset takes no arguments"); endif [first, second] = __mplapack_core__ ("rng_seed", uint64 (0)); result = mp_rng_state ("set_raw", first, second); otherwise error ("mplapack:rng:InvalidState", ... "mprng command must be state, seed, or reset"); endswitch endfunction function seed = mp_rng_seed_value (value) if (! isnumeric (value) || islogical (value) || ! isreal (value) || ! isscalar (value)) error ("mplapack:rng:InvalidState", ... "rng seed must be a nonnegative integer scalar"); endif if (isinteger (value)) if ((isa (value, "int8") || isa (value, "int16") || isa (value, "int32") || isa (value, "int64")) && value < 0) error ("mplapack:rng:InvalidState", ... "rng seed must be nonnegative"); endif seed = uint64 (value); return; endif supplied = double (value); if (! isfinite (supplied) || supplied != fix (supplied) || supplied < 0 || supplied > 9007199254740992) error ("mplapack:rng:InvalidState", ... "floating rng seeds must be exact nonnegative integers"); endif seed = uint64 (supplied); endfunction mplapack-interop-0.5.1/inst/fsolve.m0000644000230300031750000001323215274353473016676 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [solution, fval, info, output] = fsolve (fun, x0, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{x} =} fsolve (@var{fun}, @var{x0}) ## @deftypefnx {} {@var{x} =} fsolve (@dots{}, @var{options}) ## Solve a real MP nonlinear system with MP Newton steps and MP finite ## differences. With @code{Jacobian="on"}, the callback returns ## @code{[residual,jacobian]} using MP values. ## @end deftypefn if (nargin < 2 || nargin > 3 || ! isa (fun, "function_handle")) error ("mplapack:solver:InvalidArguments", "fsolve expects a function handle, x0, and options"); endif if (isa (x0, "mp")) template = mp_solver_element (x0, 1); original_rows = rows (x0); original_columns = columns (x0); x = reshape (x0, numel (x0), 1); elseif (isnumeric (x0) && isreal (x0)) template = mp (x0(1)); original_rows = rows (x0); original_columns = columns (x0); x = reshape (template * 0 + x0, numel (x0), 1); else error ("mplapack:solver:InvalidInput", "fsolve x0 must be real mp data"); endif options = []; if (nargin == 3), options = varargin{1}; endif [tolx, tolfun, max_iter] = mp_solver_options (options, x); jacobian_on = false; if (! isempty (options) && isfield (options, "Jacobian") && ischar (options.Jacobian) && strcmp (lower (options.Jacobian), "on")) jacobian_on = true; endif [residual, jacobian, evaluations] = mp_solver_system_call (fun, x, jacobian_on); if (numel (residual) != numel (x)) error ("mplapack:solver:DimensionMismatch", "fsolve residual size must match x0"); endif residual = reshape (residual, numel (residual), 1); info = 0; iterations = 0; for iteration = 1:max_iter iterations = iteration; residual_norm = norm (residual); x_norm = norm (x); if (residual_norm <= tolfun * (1 + x_norm)) info = 1; break; endif if (! jacobian_on) jacobian = mp_solver_fd_jacobian (fun, x, residual); evaluations += numel (x); endif if (! isa (jacobian, "mp") || ! isreal (jacobian) || rows (jacobian) != numel (x) || columns (jacobian) != numel (x)) error ("mplapack:solver:CallbackContract", "fsolve Jacobian must be a real square mp matrix"); endif step = -(jacobian \ residual); if (! isa (step, "mp")), error ("mplapack:solver:CallbackContract", "fsolve step lost mp type"); endif step_norm = norm (step); if (step_norm <= tolx * (1 + x_norm)) x = x + step; [residual, jacobian, calls] = mp_solver_system_call (fun, x, jacobian_on); evaluations += calls; residual = reshape (residual, numel (residual), 1); info = 1; break; endif trial = x + step; [trial_residual, unused_jacobian, calls] = mp_solver_system_call (fun, trial, false); evaluations += calls; trial_residual = reshape (trial_residual, numel (trial_residual), 1); damping = mp ("1"); for backtrack = 1:16 if (norm (trial_residual) <= residual_norm), break; endif damping = damping * mp ("0.5"); trial = x + damping * step; [trial_residual, unused_jacobian, calls] = mp_solver_system_call (fun, trial, false); evaluations += calls; trial_residual = reshape (trial_residual, numel (trial_residual), 1); endfor x = trial; residual = trial_residual; if (jacobian_on) [unused_residual, jacobian, calls] = mp_solver_system_call (fun, x, true); evaluations += calls; endif endfor if (info == 0) [residual, unused_jacobian, calls] = mp_solver_system_call (fun, x, false); evaluations += calls; residual = reshape (residual, numel (residual), 1); endif solution = reshape (x, original_rows, original_columns); fval = reshape (residual, original_rows, original_columns); if (info == 1), message = "converged"; else, message = "maximum iterations reached"; endif output = struct ("iterations", iterations, "funcCount", evaluations, ... "algorithm", "MPFR Newton with MPFR finite differences", ... "message", message); endfunction function [residual, jacobian, evaluations] = mp_solver_system_call (fun, x, request_jacobian) if (request_jacobian) [residual, jacobian] = fun (x); evaluations = 1; else residual = fun (x); jacobian = []; evaluations = 1; endif if (! isa (residual, "mp") || ! isreal (residual) || isempty (residual) || ! isfinite (residual)) error ("mplapack:solver:CallbackContract", "fsolve callback must return finite real mp residuals"); endif if (request_jacobian && (! isa (jacobian, "mp") || ! isreal (jacobian))) error ("mplapack:solver:CallbackContract", "fsolve Jacobian callback result must be real mp data"); endif endfunction function jacobian = mp_solver_fd_jacobian (fun, x, residual) n = numel (x); zero = mp_solver_element (x, 1) * 0; jacobian = repmat (zero, n, n); for column = 1:n coordinate = mp_solver_element (x, column); scale = abs (coordinate); if (scale < 1), scale = coordinate * 0 + 1; endif step = sqrt (eps (scale)) * scale; if (step == 0), step = sqrt (eps (scale)); endif perturbed = mp_solver_put (x, column, 1, coordinate + step); perturbed_residual = fun (perturbed); if (! isa (perturbed_residual, "mp") || ! isreal (perturbed_residual) || numel (perturbed_residual) != n || ! isfinite (perturbed_residual)) error ("mplapack:solver:CallbackContract", "finite-difference callback must return a real mp vector"); endif difference = (reshape (perturbed_residual, n, 1) - residual) / step; for row = 1:n jacobian = mp_solver_put (jacobian, row, column, mp_solver_element (difference, row)); endfor endfor endfunction mplapack-interop-0.5.1/inst/fzero.m0000644000230300031750000001074615274353473016534 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [root, fval, info, output] = fzero (fun, x0, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{x} =} fzero (@var{fun}, @var{x0}) ## @deftypefnx {} {@var{x} =} fzero (@dots{}, @var{options}) ## Solve a real scalar equation with MP callback values. A two-element mp ## x0 supplies a bracket; a scalar x0 is expanded to find one. The callback ## must return a real scalar mp value. ## @end deftypefn if (nargin < 2 || nargin > 3 || ! isa (fun, "function_handle")) error ("mplapack:solver:InvalidArguments", ... "fzero expects a function handle, starting point, and options"); endif if (isa (x0, "mp")) template = mp_solver_element (x0, 1); elseif (isnumeric (x0) && isreal (x0)) template = mp (x0(1)); x0 = template * 0 + x0; else error ("mplapack:solver:InvalidInput", "fzero starting point must be real mp data"); endif options = []; if (nargin == 3), options = varargin{1}; endif [tolx, unused_tolfun, max_iter] = mp_solver_options (options, template); if (numel (x0) == 2) a = mp_solver_element (x0, 1); b = mp_solver_element (x0, 2); if (b < a), temporary = a; a = b; b = temporary; endif elseif (numel (x0) == 1) center = mp_solver_element (x0, 1); step = template * 0 + 1; a = center - step; b = center + step; fa = mp_solver_call (fun, a); fb = mp_solver_call (fun, b); evaluations = 2; for expansion = 1:64 if (fa == 0), root = a; fval = fa; info = 1; output = mp_solver_output (0, evaluations, "exact root"); return; endif if (fb == 0), root = b; fval = fb; info = 1; output = mp_solver_output (0, evaluations, "exact root"); return; endif if ((fa < 0 && fb > 0) || (fa > 0 && fb < 0)), break; endif step = step * 2; a = center - step; b = center + step; fa = mp_solver_call (fun, a); fb = mp_solver_call (fun, b); evaluations += 2; endfor if (! ((fa < 0 && fb > 0) || (fa > 0 && fb < 0))) error ("mplapack:solver:NoBracket", "fzero could not find a sign-changing bracket"); endif else error ("mplapack:solver:InvalidInput", "fzero x0 must be a scalar or two-element bracket"); endif if (! exist ("evaluations", "var")), evaluations = 0; endif if (! exist ("fa", "var")), fa = mp_solver_call (fun, a); fb = mp_solver_call (fun, b); evaluations += 2; endif if (fa == 0), root = a; fval = fa; info = 1; output = mp_solver_output (0, evaluations, "exact root"); return; endif if (fb == 0), root = b; fval = fb; info = 1; output = mp_solver_output (0, evaluations, "exact root"); return; endif info = 0; root = (a + b) / 2; fval = mp_solver_call (fun, root); evaluations += 1; iterations = 0; for iteration = 1:max_iter iterations = iteration; if (abs (b - a) <= tolx * (1 + abs (root)) || fval == 0) info = 1; break; endif denominator = fb - fa; if (denominator != 0) candidate = (a * fb - b * fa) / denominator; else candidate = (a + b) / 2; endif if (!(candidate > a && candidate < b)) candidate = (a + b) / 2; endif root = candidate; fval = mp_solver_call (fun, root); evaluations += 1; if (fval == 0) info = 1; break; endif if ((fa < 0 && fval > 0) || (fa > 0 && fval < 0)) b = root; fb = fval; else a = root; fa = fval; endif if (abs (b - a) <= tolx * (1 + abs (root))) root = (a + b) / 2; fval = mp_solver_call (fun, root); evaluations += 1; info = 1; break; endif endfor if (info == 0) root = (a + b) / 2; fval = mp_solver_call (fun, root); evaluations += 1; endif if (info == 1), message = "converged"; else, message = "maximum iterations reached"; endif output = mp_solver_output (iterations, evaluations, message); endfunction function value = mp_solver_call (fun, argument) value = fun (argument); if (! isa (value, "mp") || ! isreal (value) || ! isscalar (value)) error ("mplapack:solver:CallbackContract", ... "fzero callback must return one real scalar mp value"); endif if (! isfinite (value)) error ("mplapack:solver:CallbackContract", "fzero callback returned a non-finite value"); endif endfunction function output = mp_solver_output (iterations, evaluations, message) output = struct ("iterations", iterations, "funcCount", evaluations, ... "algorithm", "MPFR bracketed secant-bisection", ... "message", message); endfunction mplapack-interop-0.5.1/inst/mprandn.m0000644000230300031750000000147415274353473017044 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mprandn (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{r} =} mprandn () ## @deftypefnx {} {@var{r} =} mprandn (@var{n}) ## @deftypefnx {} {@var{r} =} mprandn (@var{m}, @var{n}) ## Generate deterministic standard-normal arbitrary-precision values. ## Box-Muller is evaluated entirely with MPFR operations. This is a ## numerical PRNG, not a cryptographic generator. ## @end deftypefn [rows_out, columns_out] = mp_random_dimensions (varargin, "mprandn"); state = mp_rng_state ("get"); [payload, first, second] = __mplapack_core__ ( "rng_normal", rows_out, columns_out, state.state(1), state.state(2)); state.state = uint64 ([first, second]); mp_rng_state ("set", state); result = mp ("0"); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/pchip.m0000644000230300031750000000130115274353473016475 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} pchip (@dots{}) ## Construct a piecewise-polynomial interpolant from arbitrary-precision data. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits, mpdigits} ## @end deftypefn function pp = pchip (x, y) if (nargin != 2) error ("mplapack:interp:InvalidArguments", "pchip expects x and y"); endif [x, y, template] = mp_interp_normalize (x, y, "pchip"); pp = mp_interp_make_pp (x, y, "pchip"); endfunction mplapack-interop-0.5.1/inst/private/0000755000230300031750000000000015274353473016673 5ustar rafaelrafaelmplapack-interop-0.5.1/inst/private/mp_solver_options.m0000644000230300031750000000407015274353473022633 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [tolx, tolfun, max_iter] = mp_solver_options (options, template) scale = mp ("1"); for index = 1:numel (template) candidate = abs (mp_solver_element (template, index)); if (candidate > scale), scale = candidate; endif endfor default_tol = scale * sqrt (eps (scale)); tolx = default_tol; tolfun = default_tol; ## A bisection safeguard may need roughly one bit of progress per ## iteration; scale the default budget with the active MP precision. max_iter = max (100, 4 * double (mpbits ())); if (isempty (options)) return; endif if (! isstruct (options) || ! isscalar (options)) error ("mplapack:solver:InvalidOptions", "solver options must be a scalar struct"); endif if (isfield (options, "TolX") && ! isempty (options.TolX)) tolx = mp_solver_option_mp (options.TolX, template, "TolX"); endif if (isfield (options, "TolFun") && ! isempty (options.TolFun)) tolfun = mp_solver_option_mp (options.TolFun, template, "TolFun"); endif if (isfield (options, "MaxIter") && ! isempty (options.MaxIter)) if (! isnumeric (options.MaxIter) || ! isscalar (options.MaxIter) || options.MaxIter < 1 || options.MaxIter != fix (options.MaxIter)) error ("mplapack:solver:InvalidOptions", "MaxIter must be a positive integer"); endif max_iter = double (options.MaxIter); endif if (tolx <= 0 || tolfun <= 0) error ("mplapack:solver:InvalidOptions", "TolX and TolFun must be positive"); endif endfunction function result = mp_solver_option_mp (value, template, name) if (isa (value, "mp")) if (! isreal (value) || ! isscalar (value) || ! isfinite (value) || value <= 0) error ("mplapack:solver:InvalidOptions", "%s must be a positive finite scalar", name); endif result = value; elseif (isnumeric (value) && isreal (value) && isscalar (value) && isfinite (value) && value > 0) result = mp_solver_element (template, 1) * 0 + value; else error ("mplapack:solver:InvalidOptions", "%s must be a positive scalar", name); endif endfunction mplapack-interop-0.5.1/inst/private/mp_quad_tanh_sinh.m0000644000230300031750000001100215274353473022524 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [result, error_estimate] = mp_quad_tanh_sinh (fun, a, b, options) ## Tanh-sinh (double-exponential) quadrature. The construction is from ## the published Mori/Takahasi formula: x=tanh(pi/2*sinh(t)), with its ## derivative used as the weight. Every numerical quantity below is an ## mp value. The level refinement is the adaptive error mechanism. if (a == b) result = a * 0; error_estimate = a * 0; return; endif orientation = mp ("1"); if (! isinf (a) && ! isinf (b) && b < a) temporary = a; a = b; b = temporary; orientation = -orientation; elseif (isinf (a) && isinf (b) && a > b) temporary = a; a = b; b = temporary; orientation = -orientation; endif if (isinf (a) && a > 0) error ("mplapack:quad:InvalidInterval", ... "the left infinite endpoint must be -Inf"); endif if (isinf (b) && b < 0) error ("mplapack:quad:InvalidInterval", ... "the right infinite endpoint must be Inf"); endif if (! isinf (a) && ! isfinite (a)), error ("mplapack:quad:InvalidInterval", ... "invalid left endpoint"); endif if (! isinf (b) && ! isfinite (b)), error ("mplapack:quad:InvalidInterval", ... "invalid right endpoint"); endif pi_value = acos (mp ("-1")); half_pi = pi_value / mp ("2"); previous = []; result = []; error_estimate = []; for level = 0:options.max_levels-1 h = mp ("1") / (mp ("2") ^ (level + 1)); sum_value = []; for integer = 0:4096 k = integer; if (integer == 0) [coordinate, weight] = mp_quad_tanh_sinh_node (mp ("0"), ... half_pi, a, b); value = mp_quad_call (fun, coordinate); sum_value = value * weight; continue; endif t = mp (k) * h; [coordinate_plus, weight_plus, valid_plus] ... = mp_quad_tanh_sinh_node (t, half_pi, a, b); [coordinate_minus, weight_minus, valid_minus] ... = mp_quad_tanh_sinh_node (-t, half_pi, a, b); if (valid_plus) value_plus = mp_quad_call (fun, coordinate_plus); sum_value += value_plus * weight_plus; endif if (valid_minus) value_minus = mp_quad_call (fun, coordinate_minus); sum_value += value_minus * weight_minus; endif if (! valid_plus && ! valid_minus) break; endif endfor if (isempty (result)) result = sum_value * h * orientation; error_estimate = abs (result) * 0; else candidate = sum_value * h * orientation; error_estimate = abs (candidate - result); result = candidate; scale = abs (result); if (scale < mp ("1")), scale = mp ("1"); endif tolerance = options.abs_tol; relative = options.rel_tol * scale; if (relative > tolerance), tolerance = relative; endif if (error_estimate <= tolerance) return; endif endif endfor if (isempty (result)) error ("mplapack:quad:Failure", "quadrature produced no samples"); endif endfunction function [coordinate, weight, valid] = mp_quad_tanh_sinh_node (t, half_pi, a, b) u = tanh (half_pi * sinh (t)); one = mp ("1"); valid = (u > -one && u < one && isfinite (u)); if (! valid) coordinate = a * 0; weight = a * 0; return; endif denominator = cosh (half_pi * sinh (t)); weight_u = half_pi * cosh (t) / (denominator * denominator); if (! isinf (a) && ! isinf (b)) center = (a + b) / mp ("2"); half_width = (b - a) / mp ("2"); coordinate = center + half_width * u; weight = half_width * weight_u; elseif (! isinf (a) && isinf (b)) denominator_map = one - u; coordinate = a + (one + u) / denominator_map; weight = mp ("2") / (denominator_map * denominator_map) * weight_u; elseif (isinf (a) && ! isinf (b)) denominator_map = one + u; coordinate = b - (one - u) / denominator_map; weight = mp ("2") / (denominator_map * denominator_map) * weight_u; else denominator_map = one - u * u; coordinate = u / denominator_map; weight = (one + u * u) / (denominator_map * denominator_map) * weight_u; endif valid = valid && isfinite (coordinate) && isfinite (weight); endfunction function value = mp_quad_call (fun, coordinate) value = fun (coordinate); if (! isa (value, "mp") || ! isscalar (value) || ! isfinite (value)) error ("mplapack:quad:CallbackContract", ... "quadrature callback must return one finite mp scalar"); endif endfunction mplapack-interop-0.5.1/inst/private/mp_interp_make_pp.m0000644000230300031750000001464715274353473022556 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function pp = mp_interp_make_pp (x, y, method) n = rows (x); pieces = n - 1; zero = mp_interp_element (y, 1) * 0; coefficients = repmat (zero, pieces, 4); h = repmat (zero, pieces, 1); delta = repmat (zero, pieces, 1); for index = 1:pieces xi = mp_interp_element (x, index); xnext = mp_interp_element (x, index + 1); yi = mp_interp_element (y, index); ynext = mp_interp_element (y, index + 1); h = mp_interp_put (h, index, 1, xnext - xi); delta = mp_interp_put (delta, index, 1, (ynext - yi) / (xnext - xi)); endfor slopes = repmat (zero, n, 1); if (strcmp (method, "pchip")) if (n == 2) slopes = mp_interp_put (slopes, 1, 1, mp_interp_element (delta, 1)); slopes = mp_interp_put (slopes, 2, 1, mp_interp_element (delta, 1)); elseif (isreal (y)) for index = 2:(n - 1) previous = mp_interp_element (delta, index - 1); next_value = mp_interp_element (delta, index); if (previous * next_value <= 0) slope = zero; else hp = mp_interp_element (h, index - 1); hn = mp_interp_element (h, index); w1 = 2 * hn + hp; w2 = hn + 2 * hp; slope = (w1 + w2) / (w1 / previous + w2 / next_value); endif slopes = mp_interp_put (slopes, index, 1, slope); endfor slopes = mp_interp_put (slopes, 1, 1, ... mp_interp_pchip_endpoint (h, delta, 1)); slopes = mp_interp_put (slopes, n, 1, ... mp_interp_pchip_endpoint (h, delta, n)); else ## Complex shape preservation has no scalar ordering. The same ## weighted Hermite slope is used without a real sign clamp. slopes = mp_interp_put (slopes, 1, 1, mp_interp_element (delta, 1)); slopes = mp_interp_put (slopes, n, 1, mp_interp_element (delta, pieces)); for index = 2:(n - 1) previous = mp_interp_element (delta, index - 1); next_value = mp_interp_element (delta, index); hp = mp_interp_element (h, index - 1); hn = mp_interp_element (h, index); w1 = 2 * hn + hp; w2 = hn + 2 * hp; slopes = mp_interp_put (slopes, index, 1, ... (w1 + w2) / (w1 / previous + w2 / next_value)); endfor endif else ## Spline coefficients use second derivatives from the not-a-knot ## tridiagonal system. The system is assembled with MP arithmetic. if (n == 2) second = repmat (zero, n, 1); else system = repmat (zero, n, n); rhs = repmat (zero, n, 1); if (n == 3) ## With three knots the not-a-knot spline is the unique quadratic. ## The two endpoint conditions reduce to the same equation, so use ## zero third derivative on both intervals explicitly. system = mp_interp_put (system, 1, 1, 1); system = mp_interp_put (system, 1, 2, -1); system = mp_interp_put (system, 2, 1, mp_interp_element (h, 1)); system = mp_interp_put (system, 2, 2, ... 2 * (mp_interp_element (h, 1) ... + mp_interp_element (h, 2))); system = mp_interp_put (system, 2, 3, mp_interp_element (h, 2)); rhs = mp_interp_put (rhs, 2, 1, ... 6 * (mp_interp_element (delta, 2) ... - mp_interp_element (delta, 1))); system = mp_interp_put (system, 3, 2, 1); system = mp_interp_put (system, 3, 3, -1); else h1 = mp_interp_element (h, 1); h2 = mp_interp_element (h, 2); system = mp_interp_put (system, 1, 1, -h2); system = mp_interp_put (system, 1, 2, h1 + h2); system = mp_interp_put (system, 1, 3, -h1); for index = 2:(n - 1) hp = mp_interp_element (h, index - 1); hn = mp_interp_element (h, index); system = mp_interp_put (system, index, index - 1, hp); system = mp_interp_put (system, index, index, 2 * (hp + hn)); system = mp_interp_put (system, index, index + 1, hn); rhs = mp_interp_put (rhs, index, 1, ... 6 * (mp_interp_element (delta, index) ... - mp_interp_element (delta, index - 1))); endfor hm = mp_interp_element (h, pieces); hp = mp_interp_element (h, pieces - 1); system = mp_interp_put (system, n, n - 2, -hm); system = mp_interp_put (system, n, n - 1, hm + hp); system = mp_interp_put (system, n, n, -hp); endif second = system \ rhs; endif endif for index = 1:pieces yi = mp_interp_element (y, index); di = mp_interp_element (delta, index); hi = mp_interp_element (h, index); if (strcmp (method, "pchip")) d0 = mp_interp_element (slopes, index); d1 = mp_interp_element (slopes, index + 1); c2 = (3 * di - 2 * d0 - d1) / hi; c3 = (d0 + d1 - 2 * di) / (hi * hi); c1 = d0; elseif (n == 2) c1 = di; c2 = zero; c3 = zero; else m0 = mp_interp_element (second, index); m1 = mp_interp_element (second, index + 1); c1 = di - hi * (2 * m0 + m1) / 6; c2 = m0 / 2; c3 = (m1 - m0) / (6 * hi); endif coefficients = mp_interp_put (coefficients, index, 1, c3); coefficients = mp_interp_put (coefficients, index, 2, c2); coefficients = mp_interp_put (coefficients, index, 3, c1); coefficients = mp_interp_put (coefficients, index, 4, yi); endfor pp = struct ("form", "pp", "breaks", x, "coefs", coefficients, ... "pieces", pieces, "order", 4, "dim", 1, ... "method", method); endfunction function slope = mp_interp_pchip_endpoint (h, delta, endpoint) if (endpoint == 1) h0 = mp_interp_element (h, 1); h1 = mp_interp_element (h, 2); d0 = mp_interp_element (delta, 1); d1 = mp_interp_element (delta, 2); slope = ((2 * h0 + h1) * d0 - h0 * d1) / (h0 + h1); if (slope * d0 <= 0) slope = d0 * 0; elseif (abs (slope) > 3 * abs (d0)) slope = 3 * d0; endif else count = rows (h); h0 = mp_interp_element (h, count); h1 = mp_interp_element (h, count - 1); d0 = mp_interp_element (delta, count); d1 = mp_interp_element (delta, count - 1); slope = ((2 * h0 + h1) * d0 - h0 * d1) / (h0 + h1); if (slope * d0 <= 0) slope = d0 * 0; elseif (abs (slope) > 3 * abs (d0)) slope = 3 * d0; endif endif endfunction mplapack-interop-0.5.1/inst/private/mp_quad_options.m0000644000230300031750000001155115274353473022255 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function options = mp_quad_options (arguments, template) ## Parse the deliberately small, MP-only integral/quadgk option surface. ## Numeric control values are converted from their supplied representation ## once, at the operation precision; they are never used as binary64 ## quadrature constants. scale = abs (template); if (scale < mp ("1")), scale = mp ("1"); endif options.abs_tol = scale * sqrt (eps (scale)); options.rel_tol = sqrt (eps (scale)); options.waypoints = {}; options.array_valued = false; options.max_levels = 8; if (isempty (arguments)) return; endif if (numel (arguments) == 1 && isstruct (arguments{1})) supplied = arguments{1}; names = fieldnames (supplied); for index = 1:numel (names) name = lower (names{index}); value = supplied.(names{index}); if (strcmp (name, "abstol")) options.abs_tol = mp_quad_option_mp (value, template, "AbsTol"); elseif (strcmp (name, "reltol")) options.rel_tol = mp_quad_option_mp (value, template, "RelTol"); elseif (strcmp (name, "waypoints")) options.waypoints = mp_quad_waypoints (value, template); elseif (strcmp (name, "arrayvalued")) if (! islogical (value) || ! isscalar (value)) error ("mplapack:quad:InvalidOptions", ... "ArrayValued must be a scalar logical"); endif options.array_valued = value; elseif (strcmp (name, "maxlevels")) if (! isnumeric (value) || ! isscalar (value) || value < 1 ... || value != fix (value)) error ("mplapack:quad:InvalidOptions", ... "MaxLevels must be a positive integer"); endif options.max_levels = double (value); else error ("mplapack:quad:InvalidOptions", ... "unsupported quadrature option '%s'", names{index}); endif endfor else if (mod (numel (arguments), 2) != 0) error ("mplapack:quad:InvalidOptions", ... "quadrature options must be a struct or name/value pairs"); endif for index = 1:2:numel (arguments) name = arguments{index}; if (! ischar (name)) error ("mplapack:quad:InvalidOptions", "option names must be text"); endif value = arguments{index + 1}; key = lower (name); if (strcmp (key, "abstol")) options.abs_tol = mp_quad_option_mp (value, template, "AbsTol"); elseif (strcmp (key, "reltol")) options.rel_tol = mp_quad_option_mp (value, template, "RelTol"); elseif (strcmp (key, "waypoints")) options.waypoints = mp_quad_waypoints (value, template); elseif (strcmp (key, "arrayvalued")) if (! islogical (value) || ! isscalar (value)) error ("mplapack:quad:InvalidOptions", ... "ArrayValued must be a scalar logical"); endif options.array_valued = value; else error ("mplapack:quad:InvalidOptions", ... "unsupported quadrature option '%s'", name); endif endfor endif if (options.array_valued) error ("mplapack:quad:Unsupported", ... "ArrayValued integrands are not implemented for mp quadrature"); endif if (options.abs_tol <= 0 || options.rel_tol <= 0) error ("mplapack:quad:InvalidOptions", ... "AbsTol and RelTol must be positive"); endif endfunction function result = mp_quad_option_mp (value, template, name) if (isa (value, "mp")) result = value; elseif (isnumeric (value) && isreal (value) && isscalar (value) ... && isfinite (value)) result = template * 0 + value; else error ("mplapack:quad:InvalidOptions", ... "%s must be a finite scalar", name); endif if (! isreal (result) || ! isscalar (result) || ! isfinite (result) ... || result <= 0) error ("mplapack:quad:InvalidOptions", ... "%s must be a positive finite scalar", name); endif endfunction function result = mp_quad_waypoints (value, template) if (isempty (value)) result = {}; return; endif result = {}; if (isa (value, "mp")) if (! isreal (value)) error ("mplapack:quad:InvalidOptions", ... "Waypoints must be real finite values"); endif for index = 1:numel (value) point = mp_quad_element (value, index); if (! isfinite (point)), error ("mplapack:quad:InvalidOptions", ... "Waypoints must be finite"); endif result{end + 1} = point; endfor elseif (isnumeric (value) && isreal (value)) for index = 1:numel (value) if (! isfinite (value(index))) error ("mplapack:quad:InvalidOptions", ... "Waypoints must be finite"); endif result{end + 1} = template * 0 + value(index); endfor else error ("mplapack:quad:InvalidOptions", ... "Waypoints must be real finite values"); endif endfunction mplapack-interop-0.5.1/inst/private/mp_opt_vertex.m0000644000230300031750000000057315274353473021751 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_opt_vertex (simplex, column) [dimension, unused] = size (simplex); result = repmat (mp_opt_element (simplex, 1) * 0, dimension, 1); for row = 1:dimension result = mp_solver_put (result, row, 1, ... mp_opt_element (simplex, (column - 1) * dimension + row)); endfor endfunction mplapack-interop-0.5.1/inst/private/mp_interp_make_linear_pp.m0000644000230300031750000000140015274353473024067 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function pp = mp_interp_make_linear_pp (x, y) pieces = rows (x) - 1; zero = mp_interp_element (y, 1) * 0; coefficients = repmat (zero, pieces, 2); for index = 1:pieces left = mp_interp_element (x, index); right = mp_interp_element (x, index + 1); left_value = mp_interp_element (y, index); slope = (mp_interp_element (y, index + 1) - left_value) ... / (right - left); coefficients = mp_interp_put (coefficients, index, 1, slope); coefficients = mp_interp_put (coefficients, index, 2, left_value); endfor pp = struct ("form", "pp", "breaks", x, "coefs", coefficients, ... "pieces", pieces, "order", 2, "dim", 1, ... "method", "linear"); endfunction mplapack-interop-0.5.1/inst/private/mp_interp_element.m0000644000230300031750000000066415274353473022565 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_interp_element (value, row, column) if (! __mplapack_core__ ("value_is_matrix", value)) result = value; return; endif if (nargin == 2) payload = __mplapack_core__ ("matrix_linear_subscript", value, row); else payload = __mplapack_core__ ("matrix_subscript", value, row, column); endif result = mp ("0"); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/private/mp_random_dimensions.m0000644000230300031750000000372315274353473023262 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [rows_out, columns_out] = mp_random_dimensions (arguments, name) if (isempty (arguments)) rows_out = 1; columns_out = 1; return; endif if (numel (arguments) == 1) specification = arguments{1}; if (isnumeric (specification) && ! islogical (specification) && isreal (specification) && numel (specification) == 2) rows_out = mp_random_dimension (specification(1), name); columns_out = mp_random_dimension (specification(2), name); return; endif dimension = mp_random_dimension (specification, name); rows_out = dimension; columns_out = dimension; return; endif if (numel (arguments) == 2) rows_out = mp_random_dimension (arguments{1}, name); columns_out = mp_random_dimension (arguments{2}, name); return; endif error ("mplapack:rng:InvalidDimensions", ... "%s expects no dimensions, one dimension/vector, or two dimensions", name); endfunction function dimension = mp_random_dimension (value, name) if (! isnumeric (value) || islogical (value) || ! isreal (value) || ! isscalar (value)) error ("mplapack:rng:InvalidDimensions", ... "%s dimensions must be nonnegative integer scalars", name); endif if (isinteger (value)) if (is_signed_integer_type (value) && value < 0) error ("mplapack:rng:InvalidDimensions", ... "%s dimensions must be nonnegative", name); endif dimension = value; return; endif supplied = double (value); if (! isfinite (supplied) || supplied != fix (supplied) || supplied < 0 || supplied > 9007199254740992) error ("mplapack:rng:InvalidDimensions", ... "%s dimensions must be nonnegative exact integers", name); endif dimension = supplied; endfunction function result = is_signed_integer_type (value) result = isa (value, "int8") || isa (value, "int16") ... || isa (value, "int32") || isa (value, "int64"); endfunction mplapack-interop-0.5.1/inst/private/mp_quad_element.m0000644000230300031750000000062415274353473022212 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_quad_element (value, index) if (! isa (value, "mp")) error ("mplapack:quad:Internal", "quadrature element requires mp data"); endif if (numel (value) == 1) result = value; return; endif payload = __mplapack_core__ ("matrix_linear_subscript", value, index); result = mp ("0"); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/private/mp_opt_options.m0000644000230300031750000000732415274353473022130 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function options = mp_opt_options (arguments, template, dimension, method) scale = abs (template); if (scale < mp ("1")), scale = mp ("1"); endif options.tol_x = sqrt (eps (scale)); options.tol_fun = sqrt (eps (scale)); options.max_iter = max (100, 4 * double (mpbits ())); options.max_fun_evals = max (200, 200 * dimension); options.display = "off"; if (isempty (arguments)), return; endif if (numel (arguments) == 1 && isstruct (arguments{1})) supplied = arguments{1}; names = fieldnames (supplied); for index = 1:numel (names) options = mp_opt_set_option (options, names{index}, supplied.(names{index}), ... template, method); endfor else if (mod (numel (arguments), 2) != 0) error ("mplapack:optimization:InvalidOptions", ... "options must be a struct or name/value pairs"); endif for index = 1:2:numel (arguments) if (! ischar (arguments{index})) error ("mplapack:optimization:InvalidOptions", ... "option names must be text"); endif options = mp_opt_set_option (options, arguments{index}, ... arguments{index + 1}, template, method); endfor endif endfunction function options = mp_opt_set_option (options, supplied_name, value, template, method) name = lower (supplied_name); if (strcmp (name, "tolx")) options.tol_x = mp_opt_option_mp (value, template, "TolX"); elseif (strcmp (name, "tolfun")) options.tol_fun = mp_opt_option_mp (value, template, "TolFun"); elseif (strcmp (name, "maxiter")) options.max_iter = mp_opt_positive_count (value, "MaxIter"); elseif (strcmp (name, "maxfunevals")) options.max_fun_evals = mp_opt_positive_count (value, "MaxFunEvals"); elseif (strcmp (name, "display")) if (! ischar (value) || ! any (strcmp (lower (value), ... {"off", "iter", "final", "notify"}))) error ("mplapack:optimization:InvalidOptions", ... "Display must be off, iter, final, or notify"); endif options.display = lower (value); elseif (strcmp (name, "funvalcheck")) if (! islogical (value) || ! isscalar (value)) error ("mplapack:optimization:InvalidOptions", ... "FunValCheck must be a scalar logical"); endif elseif (strcmp (name, "outputfcn") || strcmp (name, "plotfcns")) error ("mplapack:optimization:Unsupported", ... "%s is not supported for MP optimization", supplied_name); else error ("mplapack:optimization:InvalidOptions", ... "unsupported %s option '%s'", method, supplied_name); endif if (options.tol_x <= 0 || options.tol_fun <= 0) error ("mplapack:optimization:InvalidOptions", ... "TolX and TolFun must be positive"); endif endfunction function result = mp_opt_option_mp (value, template, name) if (isa (value, "mp")) result = value; elseif (isnumeric (value) && isreal (value) && isscalar (value) ... && isfinite (value)) result = template * 0 + value; else error ("mplapack:optimization:InvalidOptions", ... "%s must be a positive finite scalar", name); endif if (! isreal (result) || ! isscalar (result) || ! isfinite (result) ... || result <= 0) error ("mplapack:optimization:InvalidOptions", ... "%s must be a positive finite scalar", name); endif endfunction function result = mp_opt_positive_count (value, name) if (! isnumeric (value) || ! isscalar (value) || ! isfinite (value) ... || value < 1 || value != fix (value)) error ("mplapack:optimization:InvalidOptions", ... "%s must be a positive integer", name); endif result = double (value); endfunction mplapack-interop-0.5.1/inst/private/mp_interp_put.m0000644000230300031750000000037615274353473021744 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_interp_put (value, row, column, replacement) payload = __mplapack_core__ ("matrix_subsasgn", value, row, column, replacement); result = mp ("0"); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/private/mp_solver_put.m0000644000230300031750000000037615274353473021755 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_solver_put (value, row, column, replacement) payload = __mplapack_core__ ("matrix_subsasgn", value, row, column, replacement); result = mp ("0"); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/private/mp_interp_normalize.m0000644000230300031750000000315015274353473023125 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [x_out, y_out, template] = mp_interp_normalize (x, y, name) if (isa (x, "mp")) template = mp_interp_element (x, 1); elseif (isa (y, "mp")) template = mp_interp_element (y, 1); else error ("mplapack:interp:RequiresMp", ... "%s requires an mp grid or data value", name); endif if (! isa (x, "mp")) x = template * 0 + x; endif if (! isa (y, "mp")) y = template * 0 + y; endif if (! isnumeric (x) || ! isnumeric (y) || ! isreal (x) || numel (x) < 2 || numel (y) < 2) error ("mplapack:interp:InvalidInput", ... "%s requires numeric vectors with at least two points", name); endif if (rows (x) != 1 && columns (x) != 1) error ("mplapack:interp:InvalidInput", "%s grid must be a vector", name); endif if (rows (x) == 1) x = transpose (x); endif if (rows (y) == 1 && columns (y) == numel (x)) y = transpose (y); endif if (rows (y) != numel (x)) error ("mplapack:interp:DimensionMismatch", ... "%s grid and data lengths do not match", name); endif if (columns (y) != 1) error ("mplapack:interp:MatrixDataUnsupported", ... "%s currently supports one-dimensional data vectors", name); endif if (mp_interp_element (x, 2) < mp_interp_element (x, 1)) x = flipud (x); y = flipud (y); endif for index = 1:(rows (x) - 1) if (mp_interp_element (x, index + 1) == mp_interp_element (x, index)) error ("mplapack:interp:RepeatedGrid", ... "%s grid points must be distinct", name); endif endfor x_out = x; y_out = y; endfunction mplapack-interop-0.5.1/inst/private/mp_rng_state.m0000644000230300031750000000444215274353473021537 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_rng_state (action, varargin) persistent current_state; if (isempty (current_state)) [first, second] = __mplapack_core__ ("rng_seed", uint64 (0)); current_state = mp_rng_make_state (first, second); endif switch (action) case "get" result = current_state; case "set" if (numel (varargin) != 1) error ("mplapack:rng:InvalidState", ... "rng state setter expects one state struct"); endif current_state = mp_rng_validate_state (varargin{1}); result = current_state; case "set_raw" if (numel (varargin) != 2) error ("mplapack:rng:InvalidState", ... "raw rng state setter expects two words"); endif current_state = mp_rng_make_state (varargin{1}, varargin{2}); result = current_state; otherwise error ("mplapack:rng:InvalidState", "unknown private rng action"); endswitch endfunction function state = mp_rng_make_state (first, second) first = uint64 (first); second = uint64 (second); if (first == 0 && second == 0) error ("mplapack:rng:InvalidState", ... "rng state must not contain two zero words"); endif state = struct ("algorithm", "xorshift128plus-v1", ... "version", uint64 (1), ... "state", uint64 ([first, second])); endfunction function state = mp_rng_validate_state (state) if (! isstruct (state) || ! isscalar (state) || ! isfield (state, "algorithm") || ! isfield (state, "version") || ! isfield (state, "state")) error ("mplapack:rng:InvalidState", ... "rng state must be a scalar versioned state struct"); endif if (! ischar (state.algorithm) || ! strcmp (state.algorithm, ... "xorshift128plus-v1") || ! isa (state.version, "uint64") || state.version != uint64 (1) || ! isa (state.state, "uint64") || numel (state.state) != 2) error ("mplapack:rng:InvalidState", ... "unsupported rng algorithm, version, or state representation"); endif if (state.state(1) == 0 && state.state(2) == 0) error ("mplapack:rng:InvalidState", ... "rng state must not contain two zero words"); endif state.state = reshape (state.state, 1, 2); endfunction mplapack-interop-0.5.1/inst/private/mp_solver_element.m0000644000230300031750000000066415274353473022576 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_solver_element (value, row, column) if (! __mplapack_core__ ("value_is_matrix", value)) result = value; return; endif if (nargin == 2) payload = __mplapack_core__ ("matrix_linear_subscript", value, row); else payload = __mplapack_core__ ("matrix_subscript", value, row, column); endif result = mp ("0"); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/private/mp_opt_element.m0000644000230300031750000000044315274353473022061 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_opt_element (value, index) if (numel (value) == 1) result = value; return; endif payload = __mplapack_core__ ("matrix_linear_subscript", value, index); result = mp ("0"); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/private/mp_opt_call.m0000644000230300031750000000070715274353473021346 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function value = mp_opt_call (fun, argument, shape) if (nargin == 3) argument = reshape (argument, shape(1), shape(2)); endif value = fun (argument); if (! isa (value, "mp") || ! isreal (value) || ! isscalar (value) ... || ! isfinite (value)) error ("mplapack:optimization:CallbackContract", ... "optimization callback must return one finite real mp scalar"); endif endfunction mplapack-interop-0.5.1/inst/fminsearch.m0000644000230300031750000001573315274353473017527 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [argument, value, exitflag, output] = fminsearch (fun, initial, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{x} =} fminsearch (@var{fun}, @var{x0}) ## @deftypefnx {} {[@var{x}, @var{fval}, @var{exitflag}, @var{output}] =} fminsearch (@dots{}, @var{options}) ## Minimize a real scalar MP objective with an arbitrary-precision ## Nelder-Mead simplex. ## @end deftypefn if (nargin < 2 || nargin > 3 || ! isa (fun, "function_handle")) error ("mplapack:optimization:InvalidArguments", ... "fminsearch expects a function handle, initial mp data, and options"); endif [initial, template, shape] = mp_opt_initial (initial); dimension = numel (initial); options = mp_opt_options (varargin, template, dimension, "fminsearch"); zero = mp_opt_element (initial, 1) * 0; simplex = repmat (zero, dimension, dimension + 1); for row = 1:dimension simplex = mp_solver_put (simplex, row, 1, mp_opt_element (initial, row)); endfor for vertex = 2:(dimension + 1) for row = 1:dimension simplex = mp_solver_put (simplex, row, vertex, ... mp_opt_element (initial, row)); endfor coordinate = mp_opt_element (initial, vertex - 1); if (abs (coordinate) > mp ("1")) step = mp ("0.05") * abs (coordinate); else step = mp ("0.00025"); endif simplex = mp_solver_put (simplex, vertex - 1, vertex, coordinate + step); endfor values = repmat (zero, dimension + 1, 1); evaluations = 0; for vertex = 1:(dimension + 1) values = mp_solver_put (values, vertex, 1, ... mp_opt_call (fun, mp_opt_vertex (simplex, vertex), shape)); evaluations += 1; endfor ## Standard Nelder-Mead coefficients. They are exact decimal MP values, ## not constants obtained by converting binary64 literals. alpha = mp ("1"); gamma = mp ("2"); rho = mp ("0.5"); sigma = mp ("0.5"); exitflag = 0; iterations = 0; for iteration = 1:options.max_iter iterations = iteration; order = mp_opt_order (values); best_index = order(1); worst_index = order(end); second_worst_index = order(end - 1); best = mp_opt_vertex (simplex, best_index); worst = mp_opt_vertex (simplex, worst_index); diameter = mp ("0"); for row = 1:dimension distance = abs (mp_opt_element (best, row) ... - mp_opt_element (worst, row)); if (distance > diameter), diameter = distance; endif endfor best_value = mp_opt_element (values, best_index); spread = abs (mp_opt_element (values, worst_index) - best_value); if (diameter <= options.tol_x * (mp ("1") + mp_opt_vector_scale (best)) ... && spread <= options.tol_fun * (mp ("1") + abs (best_value))) exitflag = 1; break; endif centroid = repmat (zero, dimension, 1); for ordered = 1:dimension vertex = mp_opt_vertex (simplex, order(ordered)); centroid += vertex; endfor centroid = centroid / mp (dimension); reflected = centroid + alpha * (centroid - worst); reflected_value = mp_opt_call (fun, reflected, shape); evaluations += 1; if (reflected_value < best_value) expanded = centroid + gamma * (reflected - centroid); expanded_value = mp_opt_call (fun, expanded, shape); evaluations += 1; if (expanded_value < reflected_value) simplex = mp_opt_replace_vertex (simplex, expanded, worst_index); values = mp_solver_put (values, worst_index, 1, expanded_value); else simplex = mp_opt_replace_vertex (simplex, reflected, worst_index); values = mp_solver_put (values, worst_index, 1, reflected_value); endif elseif (reflected_value < mp_opt_element (values, second_worst_index)) simplex = mp_opt_replace_vertex (simplex, reflected, worst_index); values = mp_solver_put (values, worst_index, 1, reflected_value); else if (reflected_value < mp_opt_element (values, worst_index)) contracted = centroid + rho * (reflected - centroid); else contracted = centroid + rho * (worst - centroid); endif contracted_value = mp_opt_call (fun, contracted, shape); evaluations += 1; if (contracted_value < mp_opt_element (values, worst_index)) simplex = mp_opt_replace_vertex (simplex, contracted, worst_index); values = mp_solver_put (values, worst_index, 1, contracted_value); else for ordered = 2:(dimension + 1) vertex_index = order(ordered); current = mp_opt_vertex (simplex, vertex_index); shrunk = best + sigma * (current - best); simplex = mp_opt_replace_vertex (simplex, shrunk, vertex_index); values = mp_solver_put (values, vertex_index, 1, ... mp_opt_call (fun, shrunk, shape)); evaluations += 1; endfor endif endif if (evaluations >= options.max_fun_evals) break; endif endfor order = mp_opt_order (values); argument = reshape (mp_opt_vertex (simplex, order(1)), shape(1), shape(2)); value = mp_opt_element (values, order(1)); if (exitflag == 1) message = "converged"; elseif (evaluations >= options.max_fun_evals) message = "maximum function evaluations reached"; else message = "maximum iterations reached"; endif output = struct ("iterations", iterations, "funcCount", evaluations, ... "algorithm", "MP Nelder-Mead simplex", "message", message); endfunction function [value, template, shape] = mp_opt_initial (value) if (isa (value, "mp")) if (! isreal (value) || isempty (value)) error ("mplapack:optimization:InvalidInput", ... "fminsearch initial point must be nonempty real mp data"); endif template = mp_opt_element (value, 1); elseif (isnumeric (value) && isreal (value) && ! isempty (value)) template = mp (value(1)); value = template * 0 + value; else error ("mplapack:optimization:InvalidInput", ... "fminsearch initial point must be nonempty real data"); endif shape = size (value); value = reshape (value, numel (value), 1); endfunction function order = mp_opt_order (values) count = numel (values); order = 1:count; for index = 2:count candidate = order(index); position = index - 1; while (position >= 1 ... && mp_opt_element (values, candidate) ... < mp_opt_element (values, order(position))) order(position + 1) = order(position); position -= 1; endwhile order(position + 1) = candidate; endfor endfunction function result = mp_opt_replace_vertex (simplex, vertex, column) [dimension, unused] = size (simplex); result = simplex; for row = 1:dimension result = mp_solver_put (result, row, column, mp_opt_element (vertex, row)); endfor endfunction function result = mp_opt_vector_scale (value) result = mp ("1"); for index = 1:numel (value) candidate = abs (mp_opt_element (value, index)); if (candidate > result), result = candidate; endif endfor endfunction mplapack-interop-0.5.1/inst/mkpp.m0000644000230300031750000000272515274353473016354 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function pp = mkpp (breaks, coefs, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{pp} =} mkpp (@var{breaks}, @var{coefs}) ## Construct a scalar-output MP piecewise polynomial from MP breaks and ## coefficient rows in descending powers of the local coordinate. ## @end deftypefn if (nargin < 2 || nargin > 3 || ! isa (breaks, "mp") || ! isa (coefs, "mp") || rows (breaks) != 1 && columns (breaks) != 1) error ("mplapack:interp:InvalidPP", ... "mkpp expects mp break and coefficient arrays"); endif if (rows (breaks) == 1) breaks = transpose (breaks); endif if (rows (breaks) < 2 || rows (coefs) != rows (breaks) - 1) error ("mplapack:interp:InvalidPP", ... "mkpp coefficient rows must equal the number of pieces"); endif for index = 1:(rows (breaks) - 1) if (mp_interp_element (breaks, index + 1) <= mp_interp_element (breaks, index)) error ("mplapack:interp:InvalidPP", "mkpp breaks must increase"); endif endfor if (nargin == 3) dimension = varargin{1}; if (! isnumeric (dimension) || ! isscalar (dimension) || dimension != 1) error ("mplapack:interp:InvalidPP", ... "only scalar-output pp values are currently supported"); endif endif pp = struct ("form", "pp", "breaks", breaks, "coefs", coefs, ... "pieces", rows (coefs), "order", columns (coefs), ... "dim", 1, "method", "custom"); endfunction mplapack-interop-0.5.1/inst/integral.m0000644000230300031750000000117415274353473017207 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [result, error_estimate] = integral (fun, a, b, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{q} =} integral (@var{fun}, @var{a}, @var{b}) ## @deftypefnx {} {[@var{q}, @var{err}] =} integral (@dots{}, @var{options}) ## Compute a one-dimensional integral with MPFR/MPC nodes, weights, ## transformations, and error estimates. The scalar callback contract is ## intentional; ArrayValued is rejected explicitly until a shape-preserving ## MP vector reduction is specified. ## @end deftypefn [result, error_estimate] = quadgk (fun, a, b, varargin{:}); endfunction mplapack-interop-0.5.1/inst/@mp/0000755000230300031750000000000015274353473015735 5ustar rafaelrafaelmplapack-interop-0.5.1/inst/@mp/null.m0000644000230300031750000000174215274353473017071 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{Z} =} null (@var{A}, @var{tol}) ## Return an arbitrary-precision right-null-space basis selected from native ## singular values. The tolerance is precision-sensitive. ## @seealso{svd, rank, orth} ## @end deftypefn function result = null (value, varargin) ## Compute a right null-space basis from the arbitrary-precision SVD. if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "null expects an mp matrix and optional tolerance"); endif [m,n] = size (value); [u,s,v] = svd (value); if (nargin == 2) tol = varargin{1}; elseif (min (m,n) == 0) tol = []; else tol = []; endif if (isempty (tol)), rank_value = rank (value); else, rank_value = rank (value, tol); endif rank_value = double (rank_value); if (rank_value < n) result = mp_slice (v, 1:n, rank_value+1:n); else result = zeros (n,0, "like", value); endif endfunction mplapack-interop-0.5.1/inst/@mp/vertcat.m0000644000230300031750000000125515274353473017566 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = vertcat (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{C} =} vertcat (@var{A}, @var{B}, @dots{}) ## Concatenate dense real or complex @code{mp} values vertically. ## @end deftypefn if (nargin < 1) error ("mplapack:mp:InvalidOperands", ... "mp vertical concatenation expects at least one operand"); endif payload = __mplapack_core__ ("matrix_vertcat", varargin{:}); result = varargin{1}; if (! isa (result, "mp")) for k = 2:nargin if (isa (varargin{k}, "mp")) result = varargin{k}; break; endif endfor endif result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/conv.m0000644000230300031750000000226615274353473017066 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} conv (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = conv (a, b, varargin) if (nargin != 2 || ! isa (a, "mp")), error ("mplapack:mp:InvalidInput", "conv requires an mp first vector"); endif if (! isa (b,"mp")), b = mp (b); endif if (numel (a) == 0 || numel (b) == 0), result = zeros (0,1,"like",a); return; endif template = a; if (!isreal (b)), template=b; endif result = zeros (numel(a)+numel(b)-1,1,"like",template); for i = 1:numel(a) for j = 1:numel(b) result = mp_put (result, i+j-1, 1, ... mp_element (result,i+j-1) + mp_element (a, i)*mp_element (b, j)); endfor endfor [m,n] = size(a); if (m == 1 && n != 1), result = result.'; endif endfunction mplapack-interop-0.5.1/inst/@mp/or.m0000644000230300031750000000134115274353473016532 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} or (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = or (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mp logical or expects two operands"); endif result = __mplapack_core__ ("script_logical", lhs, "or", rhs); endfunction mplapack-interop-0.5.1/inst/@mp/atan.m0000644000230300031750000000144215274353473017037 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} atan (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = atan (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "atan expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "atan"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/det.m0000644000230300031750000000250215274353473016666 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = det (value) ## -*- texinfo -*- ## @deftypefn {} {@var{d} =} det (@var{A}) ## Compute a dense real or complex arbitrary-precision determinant through ## MPLAPACK Rgetrf or Cgetrf. The determinant is formed at the stored ## operand precision from pivot parity and the U diagonal product; public ## inputs remain unchanged. With two outputs, the second result is the ## MPFR/MPC 1-norm reciprocal-condition estimate. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "det expects one mp value"); endif if (nargout > 2) error ("mplapack:mp:OutputCount", ... "mp det returns one or two outputs"); endif if (nargout == 2) if (isempty (value)) error ("mplapack:mp:OutputCount", ... "det of an empty matrix has one output"); endif [det_payload, rcond_payload] = __mplapack_core__ ("det_rcond", value); det_result = mp (0); det_result.payload_ = det_payload; rcond_result = mp (0); rcond_result.payload_ = rcond_payload; varargout{1} = det_result; varargout{2} = rcond_result; else payload = __mplapack_core__ ("det", value); result = mp (0); result.payload_ = payload; varargout{1} = result; endif endfunction mplapack-interop-0.5.1/inst/@mp/qz.m0000644000230300031750000000371015274353473016546 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = qz (a, b, varargin) ## @deftypefn {} {@var{AA} =} qz (@var{A}, @var{B}) ## @deftypefnx {} {[@var{AA}, @var{BB}, @var{Q}, @var{Z}] =} qz (@var{A}, @var{B}, @var{type}) ## Compute the arbitrary-precision generalized Schur decomposition. ## The returned orientation is Octave's Q*A*Z=AA and Q*B*Z=BB. ## A real request uses the real GGES path; the default is complex QZ. ## @end deftypefn if (nargin < 2 || nargin > 3 || ! isa (a, "mp") || ! isa (b, "mp")) error ("mplapack:mp:InvalidInput", ... "qz expects two mp matrix operands and an optional type"); endif if (nargout > 6) error ("mplapack:mp:OutputCount", "mp qz returns at most six outputs"); endif option = "complex"; if (nargin == 3) if (! ischar (varargin{1}) && ! isstring (varargin{1})) error ("mplapack:mp:InvalidOption", ... "qz option must be \"real\" or \"complex\""); endif option = char (varargin{1}); if (! strcmp (option, "real") && ! strcmp (option, "complex")) error ("mplapack:mp:InvalidOption", ... "qz option must be \"real\" or \"complex\""); endif endif [aa_payload, bb_payload, q_payload, z_payload] = ... __mplapack_core__ ("qz", a, b, option); aa = mp (0); aa.payload_ = aa_payload; bb = mp (0); bb.payload_ = bb_payload; q = mp (0); q.payload_ = q_payload; z = mp (0); z.payload_ = z_payload; if (nargout <= 1) varargout{1} = aa; return; endif varargout{1} = aa; varargout{2} = bb; if (nargout <= 2) return; endif varargout{3} = q; if (nargout <= 3) return; endif varargout{4} = z; if (nargout > 4) ## The existing arbitrary-precision generalized eigensolver supplies ## the optional right/left eigenvectors without converting the pencil. [v, lambda, w] = eig (a, b, "qz", "vector"); varargout{5} = v; if (nargout == 6) varargout{6} = w; endif endif endfunction mplapack-interop-0.5.1/inst/@mp/xor.m0000644000230300031750000000134515274353473016726 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} xor (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = xor (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mp logical xor expects two operands"); endif result = __mplapack_core__ ("script_logical", lhs, "xor", rhs); endfunction mplapack-interop-0.5.1/inst/@mp/unique.m0000644000230300031750000000250615274353473017424 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {[@var{u}, @var{ia}, @var{ic}] =} unique (@var{A}) ## Return exact unique arbitrary-precision values with documented sorted, ## stable, row, NaN, and index behavior. ## @seealso{union, intersect, ismember} ## @end deftypefn function varargout = unique (value, varargin) ## Exact unique values for current two-dimensional mp semantics. if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "unique expects an mp value"); endif stable = false; rows_mode = false; for k = 1:numel (varargin) if (ischar (varargin{k}) || isstring (varargin{k})) option = char (varargin{k}); if (strcmp (option, "stable")) stable = true; elseif (strcmp (option, "rows")) rows_mode = true; elseif (! strcmp (option, "sorted")) error ("mplapack:mp:InvalidOption", "unsupported unique option"); endif endif endfor if (rows_mode) [values, first, inverse] = mp_set_unique_rows (value, stable); else [values, first, inverse] = mp_set_unique (value, stable); [m,n] = size (value); if (m == 1 && n != 1) values = values.'; endif endif varargout{1} = values; if (nargout > 1), varargout{2} = first; endif if (nargout > 2), varargout{3} = inverse; endif endfunction mplapack-interop-0.5.1/inst/@mp/tan.m0000644000230300031750000000143615274353473016701 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} tan (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = tan (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "tan expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "tan"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/prod.m0000644000230300031750000000175015274353473017062 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} prod (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = prod (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "prod expects an mp value"); endif if (nargout > 1) error ("mplapack:mp:InvalidOutput", "prod returns one output"); endif payload = __mplapack_core__ ("script_reduce", value, "prod", varargin{:}); if (! isnumeric (payload)) result = mp (0); result.payload_ = payload; else result = payload; endif varargout{1} = result; endfunction mplapack-interop-0.5.1/inst/@mp/intersect.m0000644000230300031750000000406615274353473020121 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} intersect (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = intersect (a, b, varargin) if (nargin < 2 || ! isa (a, "mp")), error ("mplapack:mp:InvalidInput", "intersect requires mp input"); endif if (! isa (b, "mp")), b = mp (b); endif stable = mp_set_has_option (varargin, "stable"); rows_mode = mp_set_has_option (varargin, "rows"); if (rows_mode) [ma,na] = size (a); [mb,nb] = size (b); if (na != nb), error ("mplapack:mp:InvalidInput", "intersect rows require matching columns"); endif [candidate, first] = mp_set_unique_rows (a, stable); keep = false (rows (candidate), 1); locations = zeros (rows (candidate),1); for i=1:rows(candidate) for j=1:mb if (mp_rows_equal(candidate,i,b,j)), keep(i)=true; locations(i)=j; break; endif endfor endfor varargout{1} = mp_slice(candidate,find(keep),1:na); else [candidate, first] = mp_set_unique (a, stable); candidate_column = mp_column(candidate); keep = false (numel (candidate_column), 1); locations = zeros (numel(candidate_column),1); bc = mp_column(b); for i=1:numel(candidate_column) for j=1:numel(bc) if (isequaln(mp_element(candidate_column,i),mp_element(bc,j))), keep(i)=true; locations(i)=j; break; endif endfor endfor varargout{1} = mp_slice(candidate_column,find(keep),1); [ma,na] = size(a); [mb,nb] = size(b); if (ma==1 && na!=1 && mb==1 && nb!=1), varargout{1}=varargout{1}.'; endif endif if (nargout > 1) varargout{2} = first(keep); endif if (nargout > 2) varargout{3} = locations(keep); endif endfunction mplapack-interop-0.5.1/inst/@mp/isnumeric.m0000644000230300031750000000045715274353473020117 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = isnumeric (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} isnumeric (@var{value}) ## Report that an @code{mp} scalar or dense matrix is numeric. ## @end deftypefn result = (nargin == 1 && isa (value, "mp")); endfunction mplapack-interop-0.5.1/inst/@mp/sinh.m0000644000230300031750000000144215274353473017055 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} sinh (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = sinh (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "sinh expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "sinh"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/log2.m0000644000230300031750000000152015274353473016754 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} log2 (@dots{}) ## Compute the supported arbitrary-precision base-2 logarithm for one @code{mp} value. ## Real inputs use MPFR @code{log2}; complex inputs use the gmpfrxx MPC ## @code{mpfrxx::log2} compatibility wrapper. The operation follows the ## stored-precision and @code{mpbits} contract and never falls back to builtin ## binary64 arithmetic. See the user manual for supported forms, precision, ## and principal-branch behavior. ## @seealso{mp, mpbits} ## @end deftypefn function result = log2 (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "log2 expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "log2"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/Inf.m0000644000230300031750000000167615274353473016641 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} Inf (@dots{}) ## Construct dense arbitrary-precision @code{mp} data with the requested shape or special values; template forms preserve the @code{mp} precision. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = Inf (varargin) if (nargin < 2) error ("mplapack:mp:InvalidArguments", ... "Inf requires dimensions, \"like\", and an mp template"); endif [template, dimensions] = mp_parse_like_constructor (varargin, "Inf"); payload = __mplapack_core__ ("script_structure", "like", "inf", ... template, dimensions{:}); result = template; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/chol.m0000644000230300031750000000341015274353473017036 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = chol (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{R} =} chol (@var{A}) ## @deftypefnx {} {@var{R} =} chol (@var{A}, @var{uplo}) ## @deftypefnx {} {[@var{R}, @var{p}] =} chol (@var{A}, @var{uplo}) ## Factor a dense real or complex @code{mp} matrix through MPLAPACK MPFR ## @code{Rpotrf} or @code{Cpotrf}. The default and @code{"upper"} use the ## upper triangle; @code{"lower"} uses the lower triangle. For complex ## input the selected triangle defines a Hermitian matrix. Structural copies ## preserve the source precision and public values remain immutable. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "chol expects one mp value and an optional upper/lower flag"); endif if (nargout > 2) error ("mplapack:mp:OutputCount", ... "dense mp chol returns at most a factor and status"); endif option = 'upper'; if (nargin == 2) option = varargin{1}; if (! ischar (option) && ! isstring (option)) error ("mplapack:mp:InvalidOption", ... "chol option must be \"upper\" or \"lower\""); endif option = char (option); if (! strcmp (option, "upper") && ! strcmp (option, "lower")) error ("mplapack:mp:InvalidOption", ... "chol option must be \"upper\" or \"lower\""); endif endif [payload, status] = __mplapack_core__ ("chol", value, option); if (nargout <= 1 && status != 0) error ("mplapack:mp:NotPositiveDefinite", ... "chol: input matrix is not positive definite"); endif result = value; result.payload_ = payload; varargout{1} = result; if (nargout == 2) varargout{2} = status; endif endfunction mplapack-interop-0.5.1/inst/@mp/inf.m0000644000230300031750000000112515274353473016666 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} inf (@dots{}) ## Construct dense arbitrary-precision @code{mp} data with the requested shape or special values; template forms preserve the @code{mp} precision. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = inf (varargin) result = Inf (varargin{:}); endfunction mplapack-interop-0.5.1/inst/@mp/eye.m0000644000230300031750000000167615274353473016707 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} eye (@dots{}) ## Construct dense arbitrary-precision @code{mp} data with the requested shape or special values; template forms preserve the @code{mp} precision. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = eye (varargin) if (nargin < 2) error ("mplapack:mp:InvalidArguments", ... "eye requires dimensions, \"like\", and an mp template"); endif [template, dimensions] = mp_parse_like_constructor (varargin, "eye"); payload = __mplapack_core__ ("script_structure", "like", "eye", ... template, dimensions{:}); result = template; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/char.m0000644000230300031750000000156015274353473017032 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{text} =} char (@var{x}) ## Return the canonical decimal representation of scalar @code{mp} value ## @var{x}. ## ## The result contains enough digits to reconstruct the same MPFR value when ## parsed at @var{x}'s precision. It is not necessarily the shortest decimal ## representation or a precision-independent exact serialization. ## @end deftypefn function text = char (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "char expects one scalar mp value"); endif if (__mplapack_core__ ("value_is_matrix", value)) error ("mplapack:mp:MatrixConversionUnsupported", ... "char conversion for dense mp matrices is not implemented in M10"); endif text = __mplapack_core__ ("scalar_to_canonical_text", value); endfunction mplapack-interop-0.5.1/inst/@mp/kron.m0000644000230300031750000000200115274353473017055 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} kron (@var{A}, @var{B}) ## Compute a two-dimensional arbitrary-precision Kronecker product. Inputs ## are promoted to one native @code{mp} precision without binary64 fallback. ## @seealso{mp, mtimes, mpbits} ## @end deftypefn function result = kron (a, b) ## Compute a two-dimensional arbitrary-precision Kronecker product. if (nargin != 2 || ! isa (a, "mp")) error ("mplapack:mp:InvalidInput", "kron requires an mp first operand"); endif if (! isa (b, "mp")) b = mp (b); endif [ma,na] = size (a); [mb,nb] = size (b); template = a; if (! isreal (b)) template = b; endif result = zeros (ma*mb, na*nb, "like", template); for ja = 1:na for ia = 1:ma for jb = 1:nb for ib = 1:mb result = mp_put (result, (ia-1)*mb+ib, (ja-1)*nb+jb, ... mp_element (a,ia,ja) * mp_element (b,ib,jb)); endfor endfor endfor endfor endfunction mplapack-interop-0.5.1/inst/@mp/lgamma.m0000644000230300031750000000162415274353473017354 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} lgamma (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = lgamma (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "lgamma expects one real mp value"); endif if (! isreal (value)), error ("mplapack:mp:ComplexUnsupported", "lgamma is implemented for real mp values only"); endif result = mp (0); result.payload_ = __mplapack_core__ ("script_elementary", value, "lgamma"); endfunction mplapack-interop-0.5.1/inst/@mp/any.m0000644000230300031750000000137515274353473016710 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} any (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = any (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "any expects an mp value"); endif result = __mplapack_core__ ("script_any_all", value, "any", varargin{:}); endfunction mplapack-interop-0.5.1/inst/@mp/real.m0000644000230300031750000000073615274353473017044 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = real (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} real (@var{value}) ## Return the real component of an @code{mp} value at its stored precision. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "real expects one mp value"); endif payload = __mplapack_core__ ("value_real", value); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/round.m0000644000230300031750000000141515274353473017243 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} round (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = round (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "round expects one mp value"); endif result = value; result.payload_ = __mplapack_core__ ("script_round", value, "round"); endfunction mplapack-interop-0.5.1/inst/@mp/compan.m0000644000230300031750000000207515274353473017374 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} compan (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = compan (value) if (nargin != 1 || ! isa (value,"mp")), error ("mplapack:mp:InvalidInput", "compan expects an mp coefficient vector"); endif p=value(:); n=numel(p)-1; if (n < 1), result=zeros(0,0,"like",value); return; endif if (mp_element (p,1)==0), error ("mplapack:mp:InvalidInput", "compan requires a nonzero leading coefficient"); endif result=zeros(n,n,"like",value); for i=2:n, result=mp_put(result,i,i-1,1); endfor for j=1:n, result=mp_put(result,1,j,-mp_element (p,j+1)/mp_element (p,1)); endfor endfunction mplapack-interop-0.5.1/inst/@mp/rot90.m0000644000230300031750000000123115274353473017065 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = rot90 (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} rot90 (@var{value}) ## @deftypefnx {} {@var{result} =} rot90 (@var{value}, @var{k}) ## Rotate a dense two-dimensional @code{mp} value counterclockwise. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidArguments", ... "rot90 expects an mp value and an optional count"); endif payload = __mplapack_core__ ("script_structure", value, "rot90", ... varargin{:}); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/diff.m0000644000230300031750000000127115274353473017024 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = diff (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{d} =} diff (@var{A}) ## @deftypefnx {} {@var{d} =} diff (@var{A}, @var{n}) ## @deftypefnx {} {@var{d} =} diff (@var{A}, @var{n}, @var{dim}) ## Compute finite differences using native MPFR/MPC subtraction. ## @end deftypefn if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "diff expects an mp value"); endif if (nargout > 1) error ("mplapack:mp:OutputCount", "diff returns one output"); endif payload = __mplapack_core__ ("script_diff", value, varargin{:}); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/schur.m0000644000230300031750000000271415274353473017243 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = schur (value, varargin) ## @deftypefn {} {@var{S} =} schur (@var{A}) ## @deftypefnx {} {[@var{U}, @var{S}] =} schur (@var{A}, @var{type}) ## Compute an unordered arbitrary-precision Schur decomposition. The ## type is "real" (the default for real input) or "complex". The result ## satisfies S = U'*A*U; real Schur output can contain 2-by-2 blocks. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "schur expects one mp value and an optional real/complex flag"); endif if (nargout > 2) error ("mplapack:mp:OutputCount", "mp schur returns S or U,S"); endif option = "real"; if (nargin == 2) if (! ischar (varargin{1}) && ! isstring (varargin{1})) error ("mplapack:mp:InvalidOption", ... "schur option must be \"real\" or \"complex\""); endif option = char (varargin{1}); if (! strcmp (option, "real") && ! strcmp (option, "complex")) error ("mplapack:mp:InvalidOption", ... "schur option must be \"real\" or \"complex\""); endif elseif (isreal (value) == 0) option = "complex"; endif [u_payload, s_payload] = __mplapack_core__ ("schur", value, option); u = mp (0); u.payload_ = u_payload; s = mp (0); s.payload_ = s_payload; if (nargout <= 1) varargout{1} = s; else varargout{1} = u; varargout{2} = s; endif endfunction mplapack-interop-0.5.1/inst/@mp/flipud.m0000644000230300031750000000075215274353473017402 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = flipud (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} flipud (@var{value}) ## Flip a dense two-dimensional @code{mp} value from up to down. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "flipud expects one mp value"); endif payload = __mplapack_core__ ("script_structure", value, "flip", 1); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/asinh.m0000644000230300031750000000144615274353473017222 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} asinh (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = asinh (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "asinh expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "asinh"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/poly.m0000644000230300031750000000155415274353473017103 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{p} =} poly (@var{A}) ## Return the monic polynomial coefficients associated with an arbitrary- ## precision root vector or square matrix. Matrix roots use the native ## arbitrary-precision eigenvalue path and coefficients retain @code{mp} data. ## @seealso{roots, polyval, compan} ## @end deftypefn function result = poly (value) if (nargin != 1 || ! isa (value,"mp")), error ("mplapack:mp:InvalidInput", "poly expects an mp vector or square matrix"); endif [m,n]=size(value); if (m==n && m>1) roots_value=eig(value,"vector"); else roots_value=value(:); endif result=mp (1); for k=1:numel(roots_value) ## Coefficients are stored in descending powers: (z-r) = [1,-r]. result=conv(result,[1,-mp_element(roots_value,k)]); endfor result = result.'; endfunction mplapack-interop-0.5.1/inst/@mp/setxor.m0000644000230300031750000000367715274353473017454 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} setxor (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = setxor (a, b, varargin) if (nargin < 2 || ! isa (a, "mp")), error ("mplapack:mp:InvalidInput", "setxor requires mp input"); endif if (! isa (b, "mp")), b = mp (b); endif stable = mp_set_has_option (varargin, "stable"); rows_mode = mp_set_has_option (varargin, "rows"); if (rows_mode) [left,left_i]=setdiff(a,b,varargin{:}); [right,right_i]=setdiff(b,a,varargin{:}); [ml,nl]=size(left); [mr,nr]=size(right); combined=zeros(ml+mr,nl,"like",a); if(isreal(a)&&!isreal(b)),combined=zeros(ml+mr,nl,"like",b);endif for i=1:ml,for j=1:nl,combined=mp_put(combined,i,j,mp_element(left,i,j));endfor,endfor for i=1:mr,for j=1:nr,combined=mp_put(combined,ml+i,j,mp_element(right,i,j));endfor,endfor [values,first,inverse]=mp_set_unique_rows(combined,stable); varargout{1}=values; if(nargout>1),varargout{2}=left_i(first(first<=ml));endif if(nargout>2),varargout{3}=right_i(first(first>ml)-ml);endif else [left,left_i]=setdiff(a,b,varargin{:}); [right,right_i]=setdiff(b,a,varargin{:}); combined=mp_set_concat_columns(left,right); [values,first,inverse]=mp_set_unique(combined,stable); [ma,na]=size(a);[mb,nb]=size(b); if(ma==1&&na!=1&&mb==1&&nb!=1),values=values.';endif varargout{1}=values; if(nargout>1),varargout{2}=left_i(first(first<=numel(left)));endif if(nargout>2),varargout{3}=right_i(first(first>numel(left))-numel(left));endif endif endfunction mplapack-interop-0.5.1/inst/@mp/minus.m0000644000230300031750000000124515274353473017250 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = minus (lhs, rhs) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} minus (@var{lhs}, @var{rhs}) ## Subtract real scalar or dense matrix @code{mp} values with 2-D singleton ## expansion. Result precision is derived only from the operands and the ## operands remain unchanged. ## @end deftypefn if (nargin != 2) error ("mplapack:mp:InvalidOperands", ... "mp subtraction expects exactly two operands"); endif payload = __mplapack_core__ ("scalar_subtract", lhs, rhs); if (isa (lhs, "mp")) result = lhs; else result = rhs; endif result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/diag.m0000644000230300031750000000151615274353473017022 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = diag (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} diag (@var{value}) ## @deftypefnx {} {@var{result} =} diag (@var{value}, @var{k}) ## Extract or construct a dense two-dimensional @code{mp} diagonal matrix. ## The source precision and real/complex storage kind are preserved. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidArguments", ... "diag expects an mp value and an optional offset"); endif if (nargin == 1) payload = __mplapack_core__ ("script_structure", value, "diag"); else payload = __mplapack_core__ ("script_structure", value, "diag", ... varargin{1}); endif result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/uplus.m0000644000230300031750000000063315274353473017265 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = uplus (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} uplus (@var{value}) ## Return an immutable real scalar or dense matrix @code{mp} value unchanged. ## @end deftypefn if (nargin != 1) error ("mplapack:mp:InvalidOperands", ... "unary mp plus expects exactly one operand"); endif result = value; endfunction mplapack-interop-0.5.1/inst/@mp/ne.m0000644000230300031750000000134115274353473016514 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} ne (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = ne (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mp inequality expects two operands"); endif result = __mplapack_core__ ("script_compare", lhs, rhs, "ne"); endfunction mplapack-interop-0.5.1/inst/@mp/isempty.m0000644000230300031750000000071515274353473017610 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = isempty (value) ## -*- texinfo -*- ## @deftypefn {} {@var{tf} =} isempty (@var{A}) ## Return true when a dense real @code{mp} value has no elements. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "isempty expects one mp value"); endif info = __mplapack_core__ ("value_shape_info", value); result = logical (info.is_empty); endfunction mplapack-interop-0.5.1/inst/@mp/eq.m0000644000230300031750000000133715274353473016524 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} eq (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = eq (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mp equality expects two operands"); endif result = __mplapack_core__ ("script_compare", lhs, rhs, "eq"); endfunction mplapack-interop-0.5.1/inst/@mp/subsref.m0000644000230300031750000000302015274353473017557 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = subsref (value, index) ## -*- texinfo -*- ## @deftypefn {} {@var{B} =} subsref (@var{A}, @var{index}) ## Implement dense @code{mp} indexing while preserving native value semantics. ## @end deftypefn if (isempty (index)) result = value; return; endif if (strcmp (index(1).type, ".") && strcmp (index(1).subs, "payload_")) error ("mplapack:mp:PrivateAccess", ... "private access to payload_ is not permitted"); endif if (strcmp (index(1).type, "{}")) error ("mplapack:mp:IndexingUnsupported", ... "dense mp cell indexing is not supported"); endif if (strcmp (index(1).type, "()")) if (! __mplapack_core__ ("value_is_matrix", value)) error ("mplapack:mp:IndexingUnsupported", ... "scalar mp indexing is not supported"); endif subs = index(1).subs; if (numel (subs) == 1) payload = __mplapack_core__ ("matrix_linear_subscript", value, ... subs{1}); elseif (numel (subs) == 2) payload = __mplapack_core__ ("matrix_subscript", value, ... subs{1}, subs{2}); else error ("mplapack:mp:IndexingUnsupported", ... "only one- and two-dimensional indexing is supported"); endif result = mp (0); result.payload_ = payload; if (numel (index) > 1) result = subsref (result, index(2:end)); endif return; endif result = builtin ("subsref", value, index); endfunction mplapack-interop-0.5.1/inst/@mp/deconv.m0000644000230300031750000000305215274353473017371 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} deconv (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = deconv (a, b) if (nargin != 2 || ! isa (a, "mp") || ! isa (b, "mp")), error ("mplapack:mp:InvalidInput", "deconv expects two mp vectors"); endif aa = a(:); bb = b(:); if (numel(bb) == 0 || mp_element (bb, 1) == 0), error ("mplapack:mp:InvalidInput", "deconv divisor must have a nonzero leading coefficient"); endif if (numel(aa) < numel(bb)) q = zeros (1,1,"like",a); q = mp_put (q,1,1,mp(0)); r = a; else q = zeros (numel(aa)-numel(bb)+1,1,"like",a); work = zeros (numel(aa),1,"like",a); for t = 1:numel(aa), work = mp_put (work,t,1,mp_element (aa,t)); endfor for k = 1:numel(q) q = mp_put (q,k,1,mp_element (work, k) / mp_element (bb, 1)); for j = 1:numel(bb) work = mp_put (work,k+j-1,1,mp_element (work, k+j-1) - mp_element (q, k)*mp_element (bb, j)); endfor endfor r = mp_slice (work,numel(q)+1:numel(aa),1); endif [m,n] = size(a); if (m == 1 && n != 1), q=q.'; r=r.'; endif varargout{1}=q; if (nargout>1), varargout{2}=r; endif endfunction mplapack-interop-0.5.1/inst/@mp/expm.m0000644000230300031750000000362215274353473017067 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} expm (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = expm (value) ## Matrix exponential by arbitrary-precision scaling and squaring with a ## precision-adaptive Taylor series. This is distinct from element-wise ## exp and avoids a fixed-degree approximant at high MPFR precision. if (nargin != 1 || ! isa (value, "mp")), error ("mplapack:mp:InvalidInput", "expm expects one mp matrix"); endif [m,n] = size (value); if (m != n), error ("mplapack:mp:InvalidInput", "expm expects a square matrix"); endif if (m == 0), result = value; return; endif I = eye (m, n, "like", value); A = value; half = mp ("0.5"); scale_count = 0; while (norm (A, 1) > half) A = A * half; scale_count = scale_count + 1; endwhile result = I; term = I; max_terms = 2 * mpdigits () + 32; for k = 1:max_terms ## k is an exactly representable loop counter, not a numerical result. term = (term * A) * (mp (1) / mp (double (k))); result = result + term; series_scale = norm (result, 1); if (series_scale < mp (1)), series_scale = mp (1); endif series_tol = mp (max (m,n)) * eps (series_scale); if (norm (term, 1) <= series_tol), break; endif endfor if (k == max_terms && norm (term, 1) > series_tol) error ("mplapack:mp:ConvergenceFailure", ... "expm Taylor series did not converge at source precision"); endif for k = 1:scale_count result = result * result; endfor endfunction mplapack-interop-0.5.1/inst/@mp/loglog.m0000644000230300031750000000142215274353473017375 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} loglog (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = loglog (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("loglog", args{:}); else [varargout{1:nargout}] = builtin ("loglog", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/not.m0000644000230300031750000000135015274353473016712 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} not (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = not (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "not expects one mp value"); endif result = __mplapack_core__ ("script_logical", value, "not"); endfunction mplapack-interop-0.5.1/inst/@mp/angle.m0000644000230300031750000000070315274353473017201 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = angle (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} angle (@var{value}) ## Return the MPFR/MPC argument of an @code{mp} value. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "angle expects one mp value"); endif result = mp (0); result.payload_ = __mplapack_core__ ("script_unary", value, "angle"); endfunction mplapack-interop-0.5.1/inst/@mp/subsasgn.m0000644000230300031750000000252215274353473017741 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = subsasgn (value, index, rhs) ## -*- texinfo -*- ## @deftypefn {} {@var{B} =} subsasgn (@var{A}, @var{index}, @var{rhs}) ## Perform supported in-bounds indexed assignment on a copied @code{mp} value. ## A real lhs promotes to complex when the rhs is complex. ## @end deftypefn if (isempty (index)) result = value; return; endif if (strcmp (index(1).type, "{}")) error ("mplapack:mp:Immutable", ... "cell-style assignment is not supported for mp values"); endif if (strcmp (index(1).type, "()")) if (numel (index) != 1) error ("mplapack:mp:AssignmentUnsupported", ... "chained indexed assignment is not supported"); endif subs = index(1).subs; if (numel (subs) == 1) payload = __mplapack_core__ ("matrix_linear_subsasgn", value, ... subs{1}, rhs); elseif (numel (subs) == 2) payload = __mplapack_core__ ("matrix_subsasgn", value, ... subs{1}, subs{2}, rhs); else error ("mplapack:mp:IndexingUnsupported", ... "only one- and two-dimensional assignment is supported"); endif result = value; result.payload_ = payload; return; endif result = builtin ("subsasgn", value, index, rhs); endfunction mplapack-interop-0.5.1/inst/@mp/and.m0000644000230300031750000000134515274353473016660 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} and (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = and (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mp logical and expects two operands"); endif result = __mplapack_core__ ("script_logical", lhs, "and", rhs); endfunction mplapack-interop-0.5.1/inst/@mp/cos.m0000644000230300031750000000143615274353473016703 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} cos (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = cos (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "cos expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "cos"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/ndims.m0000644000230300031750000000056415274353473017232 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function count = ndims (value) ## -*- texinfo -*- ## @deftypefn {} {@var{n} =} ndims (@var{A}) ## Return two for every supported dense matrix @code{mp} value. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "ndims expects one mp value"); endif count = 2; endfunction mplapack-interop-0.5.1/inst/@mp/erfc.m0000644000230300031750000000161215274353473017032 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} erfc (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = erfc (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "erfc expects one real mp value"); endif if (! isreal (value)), error ("mplapack:mp:ComplexUnsupported", "erfc is implemented for real mp values only"); endif result = mp (0); result.payload_ = __mplapack_core__ ("script_elementary", value, "erfc"); endfunction mplapack-interop-0.5.1/inst/@mp/rows.m0000644000230300031750000000067015274353473017110 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function count = rows (value) ## -*- texinfo -*- ## @deftypefn {} {@var{n} =} rows (@var{A}) ## Return the number of rows in a dense real @code{mp} value. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "rows expects one mp value"); endif info = __mplapack_core__ ("value_shape_info", value); count = double (info.rows); endfunction mplapack-interop-0.5.1/inst/@mp/meshc.m0000644000230300031750000000141615274353473017214 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} meshc (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = meshc (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("meshc", args{:}); else [varargout{1:nargout}] = builtin ("meshc", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/cond.m0000644000230300031750000000336415274353473017044 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = cond (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{c} =} cond (@var{A}) ## @deftypefnx {} {@var{c} =} cond (@var{A}, @var{p}) ## Compute a dense arbitrary-precision condition number. The default and ## p=2 paths use Rgesvd/Cgesvd; p=1 and p=Inf use Rgecon/Cgecon; and the ## "fro" spelling uses the singular values at the stored operation ## precision. Results are real arbitrary-precision scalars. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "cond expects one mp value and an optional norm selector"); endif if (nargout > 1) error ("mplapack:mp:OutputCount", "mp cond returns one output"); endif option = "two"; if (nargin == 2) request = varargin{1}; if (ischar (request) || isstring (request)) request = char (request); if (strcmp (request, "fro")) option = "frobenius"; else error ("mplapack:mp:InvalidOption", ... "cond string option must be \"fro\""); endif elseif (isnumeric (request) && ! islogical (request) && isreal (request) && isscalar (request)) if (request == 1) option = "one"; elseif (request == 2) option = "two"; elseif (isinf (request) && request > 0) option = "infinity"; else error ("mplapack:mp:InvalidOption", ... "cond norm must be 1, 2, Inf, or \"fro\""); endif else error ("mplapack:mp:InvalidOption", ... "cond norm must be 1, 2, Inf, or \"fro\""); endif endif payload = __mplapack_core__ ("cond", value, option); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/rref.m0000644000230300031750000000527115274353473017056 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = rref (value, varargin) ## @deftypefn {} {@var{R} =} rref (@var{A}) ## @deftypefnx {} {[@var{R},@var{k}] =} rref (@var{A}, @var{tol}) ## Arbitrary-precision Gauss-Jordan reduction with scaled pivot selection. if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "rref expects an mp matrix and optional tolerance"); endif [m,n] = size (value); R = value; if (nargin == 2) tol = varargin{1}; if (isa (tol, "mp")) if (! isreal (tol) || ! isscalar (tol) || tol < 0) error ("mplapack:mp:InvalidTolerance", ... "rref tolerance must be a nonnegative real scalar"); endif elseif (! isnumeric (tol) || islogical (tol) || ! isreal (tol) || ! isscalar (tol) || tol < 0) error ("mplapack:mp:InvalidTolerance", ... "rref tolerance must be a nonnegative real scalar"); else tol = mp (tol); endif else ## Use a scale-aware unit roundoff derived from the source value. eps() ## is evaluated by MPFR at p_op; no host binary64 epsilon participates. scale = mp (0); for j = 1:n for i = 1:m candidate = abs (mp_element (value,i,j)); if (candidate > scale) scale = candidate; endif endfor endfor if (scale == 0) tol = mp (0); else tol = mp (max (m,n)) * scale * eps (scale); endif endif pivot_columns = []; row = 1; for column = 1:n if (row > m) break; endif pivot = row; best = abs (mp_element (R,row,column)); for candidate = row+1:m candidate_value = abs (mp_element (R,candidate,column)); if (candidate_value > best) best = candidate_value; pivot = candidate; endif endfor if (best <= tol) continue; endif if (pivot != row) for j = 1:n temporary = mp_element (R,row,j); debug_value = mp_element (R,pivot,j); R = mp_put (R,row,j,debug_value); R = mp_put (R,pivot,j,temporary); endfor endif pivot_value = mp_element (R,row,column); for j = 1:n current_value = mp_element (R,row,j); R = mp_put (R,row,j,current_value / pivot_value); endfor for i = 1:m if (i != row) factor = mp_element (R,i,column); if (factor != 0) for j = 1:n current_value = mp_element (R,i,j); R = mp_put (R,i,j,current_value - factor * mp_element (R,row,j)); endfor endif endif endfor pivot_columns(end+1) = column; row = row + 1; endfor varargout{1} = R; if (nargout > 1) varargout{2} = pivot_columns; endif endfunction mplapack-interop-0.5.1/inst/@mp/eps.m0000644000230300031750000000137415274353473016707 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} eps (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = eps (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "eps expects one mp value"); endif result = value; result.payload_ = __mplapack_core__ ("script_eps", value); endfunction mplapack-interop-0.5.1/inst/@mp/fix.m0000644000230300031750000000140515274353473016701 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} fix (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = fix (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "fix expects one mp value"); endif result = value; result.payload_ = __mplapack_core__ ("script_round", value, "fix"); endfunction mplapack-interop-0.5.1/inst/@mp/plot3.m0000644000230300031750000000106315274353473017154 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{h} =} plot3 (@dots{}) ## Plot three-dimensional @code{mp} data through Octave's graphics API. ## Only final visualization data is converted to builtin @code{double}; no ## numerical operation uses this graphics conversion. ## @seealso{plot, mp} ## @end deftypefn function varargout = plot3 (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("plot3", args{:}); else [varargout{1:nargout}] = builtin ("plot3", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/ceil.m0000644000230300031750000000141115274353473017024 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} ceil (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = ceil (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "ceil expects one mp value"); endif result = value; result.payload_ = __mplapack_core__ ("script_round", value, "ceil"); endfunction mplapack-interop-0.5.1/inst/@mp/polyder.m0000644000230300031750000000463415274353473017600 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} polyder (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = polyder (value, varargin) if (nargin < 1 || nargin > 2 || ! isa (value,"mp")) error ("mplapack:mp:InvalidInput", "polyder expects one or two mp coefficient vectors"); endif [m,nc] = size (value); if (m != 1 && nc != 1) error ("mplapack:mp:InvalidInput", "polyder expects a coefficient vector"); endif if (nargin == 2) other = varargin{1}; if (! isa (other, "mp")), other = mp (other); endif [om,on] = size (other); if (om != 1 && on != 1) error ("mplapack:mp:InvalidInput", "polyder expects a coefficient vector"); endif if (nargout <= 1) varargout{1} = polyder (conv (value, other)); return; endif ## [q,d] = polyder (b,a) is the derivative of b/a. ## Work in columns so a row/column mix cannot trigger implicit ## broadcasting in the element-wise subtraction. value_derivative = polyder (value); other_derivative = polyder (other); value_column = mp_column (value); other_column = mp_column (other); derivative_value_column = mp_column (value_derivative); derivative_other_column = mp_column (other_derivative); left = conv (derivative_value_column, other_column); right = conv (value_column, derivative_other_column); numerator = left - right; denominator = conv (other_column, other_column); ## Match Octave's normalized quotient derivative representation. leading = mp_element (denominator, 1); result = (numerator / leading).'; varargout{1} = result; varargout{2} = (denominator / leading).'; return; endif n = numel(value); if (n <= 1) result=zeros(1,1,"like",value); result=mp_put(result,1,1,mp(0)); varargout{1} = result; return; endif result=zeros(n-1,1,"like",value); for k=1:n-1, result=mp_put(result,k,1,mp_element (value,k)*(n-k)); endfor if (m==1 && nc!=1), result=result.'; endif varargout{1} = result; endfunction mplapack-interop-0.5.1/inst/@mp/stairs.m0000644000230300031750000000142215274353473017417 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} stairs (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = stairs (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("stairs", args{:}); else [varargout{1:nargout}] = builtin ("stairs", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/transpose.m0000644000230300031750000000100015274353473020120 0ustar rafaelrafaelfunction result = transpose (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} transpose (@var{value}) ## Return the precision-preserving non-conjugating transpose of a real ## scalar or dense matrix @code{mp} value. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "transpose expects one mp value"); endif payload = __mplapack_core__ ("matrix_transpose", value); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/size.m0000644000230300031750000000243015274353473017064 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = size (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{dims} =} size (@var{A}) ## Return the two-dimensional shape of a dense real @code{mp} value. ## @end deftypefn if (! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "size expects an mp value"); endif if (numel (varargin) > 1) error ("mplapack:mp:InvalidInput", "size accepts at most one dimension"); endif info = __mplapack_core__ ("value_shape_info", value); dimensions = [double(info.rows), double(info.columns)]; if (numel (varargin) == 1) dimension = varargin{1}; if (! isnumeric (dimension) || ! isreal (dimension) || ! isscalar (dimension) || ! isfinite (dimension) || dimension != fix (dimension) || dimension < 1) error ("mplapack:mp:InvalidDimension", ... "size dimension must be a positive integer scalar"); endif if (dimension <= 2) varargout{1} = dimensions(dimension); else varargout{1} = 1; endif return; endif if (nargout <= 1) varargout{1} = dimensions; else for index = 1:nargout if (index <= 2) varargout{index} = dimensions(index); else varargout{index} = 1; endif endfor endif endfunction mplapack-interop-0.5.1/inst/@mp/surf.m0000644000230300031750000000141215274353473017070 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} surf (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = surf (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("surf", args{:}); else [varargout{1:nargout}] = builtin ("surf", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/polyval.m0000644000230300031750000000256515274353473017611 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{y} =} polyval (@var{p}, @var{x}) ## Evaluate an arbitrary-precision polynomial by native Horner arithmetic. ## Coefficients and arguments retain the documented operation precision. ## @seealso{poly, roots, polyvalm} ## @end deftypefn function result = polyval (coefficients, x, varargin) ## Horner evaluation of an arbitrary-precision coefficient vector. if (nargin < 2 || ! isa (coefficients, "mp")), error ("mplapack:mp:InvalidInput", "polyval requires an mp coefficient vector"); endif if (nargin > 3), error ("mplapack:mp:InvalidArguments", "unsupported polyval arguments"); endif if (numel (coefficients) == 0), result = mp (0); return; endif if (! isa (x, "mp")), x = mp (x); endif [m,n] = size (x); if (m == 1 && n == 1) result = mp_element (coefficients, 1); for k = 2:numel (coefficients) result = result*x + mp_element (coefficients, k); endfor return; endif template = x; if (! isreal (coefficients)), template = coefficients; endif result = zeros (m,n,"like",template); for j = 1:n for i = 1:m xi = mp_element (x,i,j); value = mp_element (coefficients, 1); for k = 2:numel (coefficients) value = value*xi + mp_element (coefficients, k); endfor result = mp_put (result,i,j,value); endfor endfor endfunction mplapack-interop-0.5.1/inst/@mp/NaN.m0000644000230300031750000000167615274353473016601 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} NaN (@dots{}) ## Construct dense arbitrary-precision @code{mp} data with the requested shape or special values; template forms preserve the @code{mp} precision. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = NaN (varargin) if (nargin < 2) error ("mplapack:mp:InvalidArguments", ... "NaN requires dimensions, \"like\", and an mp template"); endif [template, dimensions] = mp_parse_like_constructor (varargin, "NaN"); payload = __mplapack_core__ ("script_structure", "like", "nan", ... template, dimensions{:}); result = template; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/qr.m0000644000230300031750000000506615274353473016544 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = qr (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{R} =} qr (@var{A}) ## @deftypefnx {} {[@var{Q}, @var{R}] =} qr (@var{A}) ## @deftypefnx {} {@var{R} =} qr (@var{A}, "econ") ## @deftypefnx {} {[@var{Q}, @var{R}] =} qr (@var{A}, "econ") ## Compute dense MPFR QR for real or complex input. One output is R and two outputs are Q,R; ## three outputs request column-pivoted QR with a matrix or vector ## permutation output. The numeric 0 option is a deprecated economy ## compatibility form. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "qr expects one mp value and an optional econ flag"); endif if (nargout > 3) error ("mplapack:mp:OutputCount", ... "dense mp qr returns at most Q, R, and a permutation"); endif mode = "full"; permutation = "matrix"; if (nargin == 2) option = varargin{1}; if (ischar (option) || isstring (option)) option = char (option); if (strcmp (option, "econ")) mode = "econ"; elseif (strcmp (option, "matrix")) permutation = "matrix"; elseif (strcmp (option, "vector")) permutation = "vector"; else error ("mplapack:mp:InvalidOption", ... "qr option must be \"econ\", \"matrix\", or \"vector\""); endif elseif (isnumeric (option) && ! islogical (option) && isreal (option) && isscalar (option) && option == 0) mode = "econ"; permutation = "vector"; else error ("mplapack:mp:InvalidOption", ... "qr option must be \"econ\", \"matrix\", \"vector\", or deprecated numeric 0"); endif endif if (nargout <= 2) if (nargout <= 1) payload = __mplapack_core__ ("qr", value, mode, "r"); result = value; result.payload_ = payload; varargout{1} = result; else [q_payload, r_payload] = __mplapack_core__ ("qr", value, mode, "qr"); q_result = value; q_result.payload_ = q_payload; r_result = value; r_result.payload_ = r_payload; varargout{1} = q_result; varargout{2} = r_result; endif elseif (nargout == 3) [q_payload, r_payload, permutation_payload] = __mplapack_core__ ( "qr_pivoted", value, mode, permutation); q_result = value; q_result.payload_ = q_payload; r_result = value; r_result.payload_ = r_payload; varargout{1} = q_result; varargout{2} = r_result; varargout{3} = permutation_payload; endif endfunction mplapack-interop-0.5.1/inst/@mp/zeros.m0000644000230300031750000000116115274353473017254 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = zeros (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} zeros (@var{dims}, "like", @var{A}) ## Construct a zero @code{mp} array using the precision and storage kind of ## @var{A}. This method deliberately supports the explicit @code{"like"} ## form only. ## @end deftypefn [template, dimensions] = mp_parse_like_constructor (varargin, "zeros"); payload = __mplapack_core__ ("script_structure", "like", "zeros", ... template, dimensions{:}); result = template; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/le.m0000644000230300031750000000135115274353473016513 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} le (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = le (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mp less-than-or-equal expects two operands"); endif result = __mplapack_core__ ("script_compare", lhs, rhs, "le"); endfunction mplapack-interop-0.5.1/inst/@mp/fliplr.m0000644000230300031750000000075515274353473017412 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = fliplr (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} fliplr (@var{value}) ## Flip a dense two-dimensional @code{mp} value from left to right. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "fliplr expects one mp value"); endif payload = __mplapack_core__ ("script_structure", value, "flip", 2); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/gammaln.m0000644000230300031750000000163115274353473017530 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} gammaln (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = gammaln (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "gammaln expects one real mp value"); endif if (! isreal (value)), error ("mplapack:mp:ComplexUnsupported", "gammaln is implemented for real mp values only"); endif result = mp (0); result.payload_ = __mplapack_core__ ("script_elementary", value, "gammaln"); endfunction mplapack-interop-0.5.1/inst/@mp/log10.m0000644000230300031750000000144615274353473017042 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} log10 (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = log10 (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "log10 expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "log10"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/ismember.m0000644000230300031750000000313415274353473017717 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} ismember (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = ismember (a, b, varargin) if (nargin < 2 || ! isa (a, "mp")), error ("mplapack:mp:InvalidInput", "ismember requires an mp first operand"); endif if (! isa (b, "mp")), b = mp (b); endif rows_mode = mp_set_has_option (varargin, "rows"); if (rows_mode) [ma,na]=size(a); [mb,nb]=size(b); if (na != nb), error ("mplapack:mp:InvalidInput", "ismember rows require matching columns"); endif tf=false(ma,1); location=zeros(ma,1); for i=1:ma for j=1:mb if (mp_rows_equal(a,i,b,j)), tf(i)=true; location(i)=j; break; endif endfor endfor else tf = false (numel (a), 1); location = zeros (numel (a), 1); af = mp_column (a); bf = mp_column (b); for i = 1:numel (af) for j = 1:numel (bf) if (isequal (mp_element (af,i), mp_element (bf,j))) tf(i) = true; location(i) = j; break; endif endfor endfor [m,n] = size (a); if (m == 1 && n != 1), tf = tf.'; location = location.'; endif endif varargout{1} = tf; if (nargout > 1), varargout{2} = location; endif endfunction mplapack-interop-0.5.1/inst/@mp/sumsq.m0000644000230300031750000000175515274353473017273 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} sumsq (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = sumsq (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "sumsq expects an mp value"); endif if (nargout > 1) error ("mplapack:mp:InvalidOutput", "sumsq returns one output"); endif payload = __mplapack_core__ ("script_reduce", value, "sumsq", varargin{:}); if (! isnumeric (payload)) result = mp (0); result.payload_ = payload; else result = payload; endif varargout{1} = result; endfunction mplapack-interop-0.5.1/inst/@mp/cbrt.m0000644000230300031750000000144215274353473017046 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} cbrt (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = cbrt (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "cbrt expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "cbrt"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/orth.m0000644000230300031750000000160415274353473017070 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{Q} =} orth (@var{A}, @var{tol}) ## Return an arbitrary-precision orthonormal basis for the range of @var{A}, ## using native SVD values and a precision-sensitive tolerance. ## @seealso{svd, rank, null} ## @end deftypefn function result = orth (value, varargin) ## Return an arbitrary-precision orthonormal basis for the range of A. if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "orth expects an mp matrix and optional tolerance"); endif [m,n] = size (value); [u,s,v] = svd (value, "econ"); if (nargin == 2) tol = varargin{1}; elseif (min (m,n) == 0) tol = []; else tol = []; endif if (isempty (tol)), rank_value = rank (value); else, rank_value = rank (value, tol); endif result = mp_slice (u, 1:m, 1:double (rank_value)); endfunction mplapack-interop-0.5.1/inst/@mp/nan.m0000644000230300031750000000112515274353473016666 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} nan (@dots{}) ## Construct dense arbitrary-precision @code{mp} data with the requested shape or special values; template forms preserve the @code{mp} precision. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = nan (varargin) result = NaN (varargin{:}); endfunction mplapack-interop-0.5.1/inst/@mp/exp.m0000644000230300031750000000143615274353473016713 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} exp (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = exp (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "exp expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "exp"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/erf.m0000644000230300031750000000160515274353473016671 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} erf (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = erf (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "erf expects one real mp value"); endif if (! isreal (value)), error ("mplapack:mp:ComplexUnsupported", "erf is implemented for real mp values only"); endif result = mp (0); result.payload_ = __mplapack_core__ ("script_elementary", value, "erf"); endfunction mplapack-interop-0.5.1/inst/@mp/uminus.m0000644000230300031750000000100615274353473017430 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = uminus (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} uminus (@var{value}) ## Negate an immutable real scalar or dense matrix @code{mp} value at its ## stored precision. ## @end deftypefn if (nargin != 1) error ("mplapack:mp:InvalidOperands", ... "unary mp minus expects exactly one operand"); endif payload = __mplapack_core__ ("scalar_negate", value); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/isinf.m0000644000230300031750000000066315274353473017230 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = isinf (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} isinf (@var{value}) ## Return a builtin logical mask for MPFR/MPC infinite values. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "isinf expects one mp value"); endif result = __mplapack_core__ ("script_predicate", value, "isinf"); endfunction mplapack-interop-0.5.1/inst/@mp/min.m0000644000230300031750000000232115274353473016674 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} min (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = min (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "min expects an mp value as the first operand"); endif if (nargout > 2) error ("mplapack:mp:InvalidOutput", "min returns at most two outputs"); endif if (nargout > 1) [payload, indices] = __mplapack_core__ ("script_extremum", value, "min", "value_index", varargin{:}); else payload = __mplapack_core__ ("script_extremum", value, "min", "value", varargin{:}); endif if (! isnumeric (payload)) result = mp (0); result.payload_ = payload; else result = payload; endif varargout{1} = result; if (nargout > 1) varargout{2} = indices; endif endfunction mplapack-interop-0.5.1/inst/@mp/cumprod.m0000644000230300031750000000176715274353473017577 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} cumprod (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = cumprod (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "cumprod expects an mp value"); endif if (nargout > 1) error ("mplapack:mp:InvalidOutput", "cumprod returns one output"); endif payload = __mplapack_core__ ("script_reduce", value, "cumprod", varargin{:}); if (! isnumeric (payload)) result = mp (0); result.payload_ = payload; else result = payload; endif varargout{1} = result; endfunction mplapack-interop-0.5.1/inst/@mp/private/0000755000230300031750000000000015274353473017407 5ustar rafaelrafaelmplapack-interop-0.5.1/inst/@mp/private/mp_set_has_option.m0000644000230300031750000000050415274353473023276 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_set_has_option (arguments, option) result = false; for k = 1:numel (arguments) if ((ischar (arguments{k}) || isstring (arguments{k})) ... && strcmp (char (arguments{k}), option)) result = true; return; endif endfor endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_column.m0000644000230300031750000000052515274353473021560 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_column (value) ## Reshape through the native core; this also handles scalar mp values, ## for which the old-style class colon indexer is intentionally limited. result = mp (0); result.payload_ = __mplapack_core__ ("matrix_reshape", value, numel (value), 1); endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_binary_utility.m0000644000230300031750000000065415274353473023335 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_binary_utility (lhs, rhs, operation) if (isa (lhs, "mp")) result = lhs; elseif (isa (rhs, "mp")) result = rhs; else error ("mplapack:mp:InvalidOperands", ... "%s requires at least one mp operand", operation); endif payload = __mplapack_core__ ("script_binary_utility", lhs, rhs, operation); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_put.m0000644000230300031750000000036515274353473021075 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_put (value, row, column, replacement) payload = __mplapack_core__ ("matrix_subsasgn", value, row, column, replacement); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_element.m0000644000230300031750000000065315274353473021716 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_element (value, row, column) if (! __mplapack_core__ ("value_is_matrix", value)) result = value; return; endif if (nargin == 2) payload = __mplapack_core__ ("matrix_linear_subscript", value, row); else payload = __mplapack_core__ ("matrix_subscript", value, row, column); endif result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_parse_like_constructor.m0000644000230300031750000000115315274353473025044 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [template, dimensions] = mp_parse_like_constructor (arguments, kind) marker = 0; for k = 1:numel (arguments) if (ischar (arguments{k}) && strcmp (arguments{k}, "like")) marker = k; break; endif endfor if (marker == 0 || marker != numel (arguments) - 1 || marker == 1 || ! isa (arguments{marker + 1}, "mp")) error ("mplapack:mp:InvalidArguments", ... "%s requires dimensions followed by \"like\" and an mp template", kind); endif template = arguments{marker + 1}; dimensions = arguments(1:marker - 1); endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_set_concat_columns.m0000644000230300031750000000070015274353473024140 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_set_concat_columns (a, b) template = a; if (isreal (a) && ! isreal (b)), template = b; endif result = zeros (numel (a) + numel (b), 1, "like", template); ac = mp_column (a); bc = mp_column (b); for k = 1:numel (ac), result = mp_put (result,k,1,mp_element (ac,k)); endfor for k = 1:numel (bc), result = mp_put (result,numel (ac)+k,1,mp_element (bc,k)); endfor endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_slice.m0000644000230300031750000000034215274353473021357 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_slice (value, rows, columns) payload = __mplapack_core__ ("matrix_subscript", value, rows, columns); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_order_less.m0000644000230300031750000000115415274353473022423 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_order_less (lhs, rhs) ## Exact total order used by set operations. Real values use MPFR order; ## complex values follow Octave's magnitude-then-phase ordering. lhs_nan = isnan (lhs); rhs_nan = isnan (rhs); if (lhs_nan || rhs_nan) result = ! lhs_nan && rhs_nan; return; endif if (isreal (lhs) && isreal (rhs)) result = lhs < rhs; return; endif lhs_abs = abs (lhs); rhs_abs = abs (rhs); if (! isequal (lhs_abs, rhs_abs)) result = lhs_abs < rhs_abs; else result = angle (lhs) < angle (rhs); endif endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_rows_equal.m0000644000230300031750000000062315274353473022443 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_rows_equal (a, row_a, b, row_b) [~, columns_a] = size (a); [~, columns_b] = size (b); if (columns_a != columns_b), result = false; return; endif result = true; for column = 1:columns_a if (! isequal (mp_element (a,row_a,column), mp_element (b,row_b,column))) result = false; return; endif endfor endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_set_unique.m0000644000230300031750000000230715274353473022444 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [values, first, inverse] = mp_set_unique (value, stable) flat = mp_column (value); count = numel (flat); values = zeros (count, 1, "like", value); first = zeros (count, 1); inverse = zeros (count, 1); unique_count = 0; for k = 1:count found = 0; for j = 1:unique_count if (isequal (mp_element (flat,k), mp_element (values,j))) found = j; break; endif endfor if (found == 0) unique_count = unique_count + 1; values = mp_put (values,unique_count,1,mp_element (flat,k)); first(unique_count) = k; found = unique_count; endif inverse(k) = found; endfor if (unique_count == 0) values = zeros (0,1,"like",value); first = zeros (0,1); else values = mp_slice (values, 1:unique_count, 1); first = first(1:unique_count); endif if (! stable && unique_count > 1) [values, order] = sort (values); old_first = first; first = old_first(order); for k = 1:count for j = 1:unique_count if (isequal (mp_element (flat,k), mp_element (values,j))) inverse(k) = j; break; endif endfor endfor endif endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_graphics_args.m0000644000230300031750000000057015274353473023077 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function args = mp_graphics_args (varargin) ## Convert only mp data at the final graphics boundary. Handles, strings, ## property values, and all other graphics arguments are kept unchanged. args = varargin; for k = 1:numel (args) if (isa (args{k}, "mp")) args{k} = double (args{k}); endif endfor endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_set_unique_rows.m0000644000230300031750000000415715274353473023523 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [values, first, inverse] = mp_set_unique_rows (value, stable) [row_count, column_count] = size (value); values = zeros (row_count, column_count, "like", value); first = zeros (row_count, 1); inverse = zeros (row_count, 1); unique_count = 0; for row = 1:row_count found = 0; for candidate = 1:unique_count if (mp_rows_equal (value,row,values,candidate)) found = candidate; break; endif endfor if (found == 0) unique_count = unique_count + 1; for column = 1:column_count values = mp_put (values,unique_count,column,mp_element (value,row,column)); endfor first(unique_count) = row; found = unique_count; endif inverse(row) = found; endfor values = mp_slice (values,1:unique_count,1:column_count); first = first(1:unique_count); if (! stable && unique_count > 1) order = 1:unique_count; for i = 1:unique_count-1 selected = i; for j = i+1:unique_count if (mp_row_less (values,order(j),values,order(selected))) selected = j; endif endfor if (selected != i) temporary = order(i); order(i) = order(selected); order(selected) = temporary; endif endfor sorted = zeros (unique_count,column_count,"like",value); old_first = first; for i = 1:unique_count for column = 1:column_count sorted = mp_put (sorted,i,column,mp_element (values,order(i),column)); endfor first(i) = old_first(order(i)); endfor values = sorted; for row = 1:row_count for candidate = 1:unique_count if (mp_rows_equal (value,row,values,candidate)) inverse(row) = candidate; break; endif endfor endfor endif endfunction function result = mp_row_less (lhs, row_lhs, rhs, row_rhs) [~, columns] = size (lhs); for column = 1:columns left = mp_element (lhs,row_lhs,column); right = mp_element (rhs,row_rhs,column); if (isequal (left,right)), continue; endif result = mp_order_less (left,right); return; endfor result = false; endfunction mplapack-interop-0.5.1/inst/@mp/private/mp_statistic_result.m0000644000230300031750000000033215274353473023664 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mp_statistic_result (payload) if (isnumeric (payload)) result = payload; else result = mp (0); result.payload_ = payload; endif endfunction mplapack-interop-0.5.1/inst/@mp/times.m0000644000230300031750000000127215274353473017236 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = times (lhs, rhs) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} times (@var{lhs}, @var{rhs}) ## Multiply real scalar or dense matrix operands with @code{.*}, including ## 2-D singleton expansion. Matrix multiplication @code{*} remains the ## separate MPLAPACK Rgemm operation. ## @end deftypefn if (nargin != 2) error ("mplapack:mp:InvalidOperands", ... "mp element-wise multiplication expects exactly two operands"); endif payload = __mplapack_core__ ("scalar_multiply", lhs, rhs); if (isa (lhs, "mp")) result = lhs; else result = rhs; endif result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/inv.m0000644000230300031750000000143215274353473016707 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = inv (value) ## -*- texinfo -*- ## @deftypefn {} {@var{B} =} inv (@var{A}) ## Compute the dense real or complex arbitrary-precision inverse through ## MPLAPACK Rgetrf/Rgetri or Cgetrf/Cgetri. Workspace is queried at the ## operation precision and the public input remains immutable. Singular ## matrices and nonsquare matrices are reported explicitly. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "inv expects one mp value"); endif if (nargout > 1) error ("mplapack:mp:OutputCount", ... "mp inv returns one output"); endif payload = __mplapack_core__ ("inv", value); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/expm1.m0000644000230300031750000000144615274353473017152 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} expm1 (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = expm1 (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "expm1 expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "expm1"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/logspace.m0000644000230300031750000000151315274353473017710 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = logspace (first, last, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} logspace (@var{first}, @var{last}) ## @deftypefnx {} {@var{result} =} logspace (@var{first}, @var{last}, @var{n}) ## Construct a real native MPFR logarithmic row vector. ## @end deftypefn if (nargin < 2 || nargin > 3) error ("mplapack:mp:InvalidArguments", ... "logspace expects two endpoints and an optional count"); endif if (isa (first, "mp")) template = first; elseif (isa (last, "mp")) template = last; else error ("mplapack:mp:InvalidOperands", ... "logspace requires an mp endpoint"); endif payload = __mplapack_core__ ("script_logspace", first, last, varargin{:}); result = template; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/rem.m0000644000230300031750000000131415274353473016675 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} rem (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = rem (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "rem expects two operands"); endif result = mp_binary_utility (lhs, rhs, "rem"); endfunction mplapack-interop-0.5.1/inst/@mp/linspace.m0000644000230300031750000000152315274353473017712 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = linspace (first, last, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} linspace (@var{first}, @var{last}) ## @deftypefnx {} {@var{result} =} linspace (@var{first}, @var{last}, @var{n}) ## Construct a native MPFR/MPC row vector with exact endpoints. ## @end deftypefn if (nargin < 2 || nargin > 3) error ("mplapack:mp:InvalidArguments", ... "linspace expects two endpoints and an optional count"); endif if (isa (first, "mp")) template = first; elseif (isa (last, "mp")) template = last; else error ("mplapack:mp:InvalidOperands", ... "linspace requires an mp endpoint"); endif payload = __mplapack_core__ ("script_linspace", first, last, varargin{:}); result = template; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/atanh.m0000644000230300031750000000144615274353473017213 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} atanh (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = atanh (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "atanh expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "atanh"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/sign.m0000644000230300031750000000077215274353473017061 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = sign (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} sign (@var{value}) ## Return the native MPFR/MPC sign of an @code{mp} value. ## Complex nonzero values return @code{x ./ abs (x)}. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "sign expects one mp value"); endif result = mp (0); result.payload_ = __mplapack_core__ ("script_unary", value, "sign"); endfunction mplapack-interop-0.5.1/inst/@mp/polyvalm.m0000644000230300031750000000222115274353473017753 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} polyvalm (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = polyvalm (coefficients, value) if (nargin != 2 || ! isa (coefficients, "mp") || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "polyvalm expects mp coefficients and an mp square matrix"); endif [m,n] = size (value); if (m != n), error ("mplapack:mp:InvalidInput", "polyvalm expects a square matrix"); endif if (numel (coefficients) == 0), result = zeros (m,n,"like",value); return; endif result = mp_element (coefficients, 1) * eye (m,n,"like",value); for k = 2:numel (coefficients) result = result*value + mp_element (coefficients, k)*eye (m,n,"like",value); endfor endfunction mplapack-interop-0.5.1/inst/@mp/all.m0000644000230300031750000000137515274353473016671 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} all (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = all (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "all expects an mp value"); endif result = __mplapack_core__ ("script_any_all", value, "all", varargin{:}); endfunction mplapack-interop-0.5.1/inst/@mp/hypot.m0000644000230300031750000000132415274353473017256 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} hypot (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = hypot (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "hypot expects two operands"); endif result = mp_binary_utility (lhs, rhs, "hypot"); endfunction mplapack-interop-0.5.1/inst/@mp/plot.m0000644000230300031750000000106615274353473017074 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{h} =} plot (@dots{}) ## Plot @code{mp} data through Octave's graphics API. Only the final ## visualization data is explicitly converted to builtin @code{double}; ## numerical calculations must be completed before this boundary. ## @seealso{plot3, mp} ## @end deftypefn function varargout = plot (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("plot", args{:}); else [varargout{1:nargout}] = builtin ("plot", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/mod.m0000644000230300031750000000131415274353473016671 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mod (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = mod (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mod expects two operands"); endif result = mp_binary_utility (lhs, rhs, "mod"); endfunction mplapack-interop-0.5.1/inst/@mp/pinv.m0000644000230300031750000000267715274353473017103 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = pinv (value, varargin) ## @deftypefn {} {@var{X} =} pinv (@var{A}) ## @deftypefnx {} {@var{X} =} pinv (@var{A}, @var{tol}) ## Compute the Moore-Penrose inverse with the arbitrary-precision SVD. ## The default cutoff is derived from the source precision and matrix scale. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "pinv expects an mp matrix and optional tolerance"); endif [m,n] = size (value); [u,s,v] = svd (value, "econ"); k = min (m,n); if (k == 0) result = zeros (n,m, "like", value); return; endif if (nargin == 2) tol = varargin{1}; if (isa (tol, "mp")) threshold = tol; elseif (isnumeric (tol) && isreal (tol) && isscalar (tol) && tol >= 0) threshold = mp (tol); else error ("mplapack:mp:InvalidTolerance", "pinv tolerance must be nonnegative"); endif else threshold = []; endif if (isempty (threshold)) keep = rank (value); else keep = rank (value, threshold); endif if (keep == 0) result = zeros (n,m, "like", value); return; endif keep = double (keep); if (keep == 1) result = mp_slice (v, 1:n, 1) * inv (mp_element (s, 1, 1)) ... * mp_slice (u, 1:m, 1)'; else result = mp_slice (v, 1:n, 1:keep) * inv (mp_slice (s, 1:keep, 1:keep)) ... * mp_slice (u, 1:m, 1:keep)'; endif endfunction mplapack-interop-0.5.1/inst/@mp/tanh.m0000644000230300031750000000144215274353473017046 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} tanh (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = tanh (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "tanh expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "tanh"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/conj.m0000644000230300031750000000074615274353473017053 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = conj (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} conj (@var{value}) ## Return the complex conjugate of an @code{mp} value at its stored ## precision. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "conj expects one mp value"); endif payload = __mplapack_core__ ("value_conj", value); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/var.m0000644000230300031750000000176315274353473016712 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} var (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = var (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "var expects an mp value"); endif if (nargout > 2) error ("mplapack:mp:InvalidOutput", "var returns at most two outputs"); endif [payload, mean_payload] = __mplapack_core__ ("script_statistics", value, "var", varargin{:}); varargout{1} = mp_statistic_result (payload); if (nargout > 1) varargout{2} = mp_statistic_result (mean_payload); endif endfunction mplapack-interop-0.5.1/inst/@mp/cosh.m0000644000230300031750000000144215274353473017050 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} cosh (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = cosh (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "cosh expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "cosh"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/saveobj.m0000644000230300031750000000156715274353473017555 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{state} =} saveobj (@var{value}) ## Convert an @code{mp} value to the versioned exact save/load schema without ## binary64 conversion or native-pointer serialization. ## @seealso{loadobj, mp} ## @end deftypefn function state = saveobj (value) ## Serialize @mp values as an explicit, portable schema. The native bridge ## emits canonical MPFR/MPC text and never converts through binary64. if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "saveobj expects one mp value"); endif state = value; ## Keep the original class marker so Octave's legacy serializer restores an ## mp object. The native payload is replaced by a plain struct; the bridge ## lazily decodes that struct after load. state.payload_ = __mplapack_core__ ("serialize", value); endfunction mplapack-interop-0.5.1/inst/@mp/properties.m0000644000230300031750000000137615274353473020316 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} properties (@dots{}) ## Inspect the public @code{mp} value metadata and stored precision. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = properties (value) ## The native payload is an implementation detail and is not a public ## property of an mp value. if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "properties expects one mp value"); endif result = cell (0, 1); endfunction mplapack-interop-0.5.1/inst/@mp/rcond.m0000644000230300031750000000126715274353473017226 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = rcond (value) ## -*- texinfo -*- ## @deftypefn {} {@var{r} =} rcond (@var{A}) ## Compute the dense arbitrary-precision 1-norm reciprocal condition ## estimate through MPLAPACK Rgecon or Cgecon. The result is a real ## arbitrary-precision scalar and the input remains unchanged. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "rcond expects one mp value"); endif if (nargout > 1) error ("mplapack:mp:OutputCount", "mp rcond returns one output"); endif payload = __mplapack_core__ ("rcond", value); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/surfc.m0000644000230300031750000000141615274353473017237 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} surfc (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = surfc (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("surfc", args{:}); else [varargout{1:nargout}] = builtin ("surfc", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/mtimes.m0000644000230300031750000000160215274353473017410 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mtimes (lhs, rhs) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mtimes (@var{lhs}, @var{rhs}) ## Multiply supported @code{mp} scalars and dense matrices. Real-only ## matrix multiplication uses the native MPFR MPLAPACK reference ## @code{Rgemm} path. A complex participant uses the native MPC MPLAPACK ## @code{Cgemm} path, with scalar scaling remaining native MPC arithmetic. ## Real or complex double operands may be mixed with an @code{mp} operand ## and are converted directly from their binary64 components at the ## operation precision. ## @end deftypefn if (nargin != 2) error ("mplapack:mp:InvalidOperands", ... "mp multiplication expects exactly two operands"); endif payload = __mplapack_core__ ("mtimes", lhs, rhs); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/hess.m0000644000230300031750000000155115274353473017057 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = hess (value) ## @deftypefn {} {@var{H} =} hess (@var{A}) ## @deftypefnx {} {[@var{P}, @var{H}] =} hess (@var{A}) ## Compute the arbitrary-precision Hessenberg decomposition using ## MPLAPACK GEHRD/ORGHR or GEHRD/UNGHR. The two-output form satisfies ## P*H*P' = A (with conjugate transpose for complex values). ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "hess expects one mp value"); endif if (nargout > 2) error ("mplapack:mp:OutputCount", "mp hess returns H or P,H"); endif [p_payload, h_payload] = __mplapack_core__ ("hess", value); p = mp (0); p.payload_ = p_payload; h = mp (0); h.payload_ = h_payload; if (nargout <= 1) varargout{1} = h; else varargout{1} = p; varargout{2} = h; endif endfunction mplapack-interop-0.5.1/inst/@mp/length.m0000644000230300031750000000064515274353473017401 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function count = length (value) ## -*- texinfo -*- ## @deftypefn {} {@var{n} =} length (@var{A}) ## Return the larger matrix dimension of a dense @code{mp} value. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "length expects one mp value"); endif dimensions = size (value); count = max (dimensions); endfunction mplapack-interop-0.5.1/inst/@mp/semilogy.m0000644000230300031750000000143215274353473017743 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} semilogy (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = semilogy (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("semilogy", args{:}); else [varargout{1:nargout}] = builtin ("semilogy", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/horzcat.m0000644000230300031750000000126115274353473017565 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = horzcat (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{C} =} horzcat (@var{A}, @var{B}, @dots{}) ## Concatenate dense real or complex @code{mp} values horizontally. ## @end deftypefn if (nargin < 1) error ("mplapack:mp:InvalidOperands", ... "mp horizontal concatenation expects at least one operand"); endif payload = __mplapack_core__ ("matrix_horzcat", varargin{:}); result = varargin{1}; if (! isa (result, "mp")) for k = 2:nargin if (isa (varargin{k}, "mp")) result = varargin{k}; break; endif endfor endif result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/arg.m0000644000230300031750000000041415274353473016663 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = arg (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} arg (@var{value}) ## Alias for the arbitrary-precision @code{angle} operation. ## @end deftypefn result = angle (value); endfunction mplapack-interop-0.5.1/inst/@mp/end.m0000644000230300031750000000155115274353473016663 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = end (value, index, number_of_indices) ## -*- texinfo -*- ## @deftypefn {} {@var{n} =} end (@var{A}, @var{k}, @var{nidx}) ## Provide @code{end} values for supported one- and two-dimensional indexing. ## @end deftypefn if (nargin != 3 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "end expects an mp value and indexing metadata"); endif info = __mplapack_core__ ("value_shape_info", value); if (number_of_indices == 1) result = double (info.numel); elseif (number_of_indices == 2 && index == 1) result = double (info.rows); elseif (number_of_indices == 2 && index == 2) result = double (info.columns); else error ("mplapack:mp:IndexingUnsupported", ... "only one- and two-dimensional end indexing is supported"); endif endfunction mplapack-interop-0.5.1/inst/@mp/ones.m0000644000230300031750000000170315274353473017060 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} ones (@dots{}) ## Construct dense arbitrary-precision @code{mp} data with the requested shape or special values; template forms preserve the @code{mp} precision. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = ones (varargin) if (nargin < 2) error ("mplapack:mp:InvalidArguments", ... "ones requires dimensions, \"like\", and an mp template"); endif [template, dimensions] = mp_parse_like_constructor (varargin, "ones"); payload = __mplapack_core__ ("script_structure", "like", "ones", ... template, dimensions{:}); result = template; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/disp.m0000644000230300031750000000125115274353473017051 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function disp (value) ## -*- texinfo -*- ## @deftypefn {} {} disp (@var{A}) ## Display a dense real @code{mp} value without reducing it to binary64. ## @end deftypefn ## Display canonical multiprecision text. Octave's binary64 format setting ## does not reduce or otherwise change this representation. if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "disp expects one mp value"); endif if (__mplapack_core__ ("value_is_matrix", value)) fprintf ("%s\n", __mplapack_core__ ("matrix_display_text", value)); return; endif fprintf ("%s\n", char (value)); endfunction mplapack-interop-0.5.1/inst/@mp/balance.m0000644000230300031750000000216315274353473017502 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = balance (value, varargin) ## @deftypefn {} {@var{AA} =} balance (@var{A}) ## Balance a square arbitrary-precision matrix through MPLAPACK GEBAL. ## The optional "noperm"/"noscal" choices select scale-only or ## permutation-only balancing. The public one-output form is provided; ## generalized pair balancing remains deliberately unsupported until a ## joint Ward-style MPFR/MPC path is available. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "balance expects one mp value and an optional option"); endif if (nargout > 1) error ("mplapack:mp:OutputCount", ... "mp balance currently returns the balanced matrix only"); endif option = ""; if (nargin == 2) if (! ischar (varargin{1}) && ! isstring (varargin{1})) error ("mplapack:mp:InvalidOption", "balance option must be text"); endif option = char (varargin{1}); endif payload = __mplapack_core__ ("balance", value, option); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/contour3.m0000644000230300031750000000143215274353473017667 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} contour3 (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = contour3 (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("contour3", args{:}); else [varargout{1:nargout}] = builtin ("contour3", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/stem.m0000644000230300031750000000141215274353473017061 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} stem (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = stem (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("stem", args{:}); else [varargout{1:nargout}] = builtin ("stem", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/median.m0000644000230300031750000000161615274353473017354 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} median (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = median (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "median expects an mp value"); endif if (nargout > 1) error ("mplapack:mp:InvalidOutput", "median returns one output"); endif payload = __mplapack_core__ ("script_statistics", value, "median", varargin{:}); result = mp_statistic_result (payload); endfunction mplapack-interop-0.5.1/inst/@mp/max.m0000644000230300031750000000232115274353473016676 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} max (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = max (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "max expects an mp value as the first operand"); endif if (nargout > 2) error ("mplapack:mp:InvalidOutput", "max returns at most two outputs"); endif if (nargout > 1) [payload, indices] = __mplapack_core__ ("script_extremum", value, "max", "value_index", varargin{:}); else payload = __mplapack_core__ ("script_extremum", value, "max", "value", varargin{:}); endif if (! isnumeric (payload)) result = mp (0); result.payload_ = payload; else result = payload; endif varargout{1} = result; if (nargout > 1) varargout{2} = indices; endif endfunction mplapack-interop-0.5.1/inst/@mp/ge.m0000644000230300031750000000135415274353473016511 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} ge (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = ge (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mp greater-than-or-equal expects two operands"); endif result = __mplapack_core__ ("script_compare", lhs, rhs, "ge"); endfunction mplapack-interop-0.5.1/inst/@mp/ctranspose.m0000644000230300031750000000077115274353473020301 0ustar rafaelrafaelfunction result = ctranspose (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} ctranspose (@var{value}) ## Return the precision-preserving conjugate transpose of a scalar or dense ## matrix @code{mp} value. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "ctranspose expects one mp value"); endif payload = __mplapack_core__ ("matrix_ctranspose", value); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/polyint.m0000644000230300031750000000217115274353473017612 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} polyint (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = polyint (value, varargin) if (nargin < 1 || nargin > 2 || ! isa (value,"mp")), error ("mplapack:mp:InvalidInput", "polyint expects an mp coefficient vector and optional constant"); endif if (nargin==2), constant=varargin{1}; if (!isa(constant,"mp")), constant=mp(constant); endif; else, constant=mp(0); endif result=zeros(numel(value)+1,1,"like",value); for k=1:numel(value) result=mp_put(result,k,1,mp_element (value,k)/(numel(value)-k+1)); endfor result=mp_put(result,numel(value)+1,1,constant); [m,n]=size(value); if (m==1 && n!=1), result=result.'; endif endfunction mplapack-interop-0.5.1/inst/@mp/mesh.m0000644000230300031750000000141215274353473017045 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mesh (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = mesh (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("mesh", args{:}); else [varargout{1:nargout}] = builtin ("mesh", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/bounds.m0000644000230300031750000000202015274353473017377 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} bounds (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = bounds (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "bounds expects an mp value"); endif if (nargout > 2) error ("mplapack:mp:InvalidOutput", "bounds returns at most two outputs"); endif [lower_payload, upper_payload] = __mplapack_core__ ("script_statistics", value, "bounds", varargin{:}); varargout{1} = mp_statistic_result (lower_payload); if (nargout > 1) varargout{2} = mp_statistic_result (upper_payload); endif endfunction mplapack-interop-0.5.1/inst/@mp/reshape.m0000644000230300031750000000201015274353473017533 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = reshape (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} reshape (@var{value}, @var{m}, @var{n}) ## @deftypefnx {} {@var{result} =} reshape (@var{value}, [@var{m} @var{n}]) ## Reshape a real scalar or dense matrix @code{mp} value while preserving ## its column-major element order and stored precision. One @code{[]} may ## be used for an inferred dimension. ## @end deftypefn if (nargin != 2 && nargin != 3) error ("mplapack:mp:InvalidArguments", ... "reshape expects a value and one or two dimensions"); endif if (! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "reshape expects an mp value"); endif if (numel (varargin) == 1) payload = __mplapack_core__ ("matrix_reshape", value, varargin{1}); else payload = __mplapack_core__ ("matrix_reshape", value, varargin{1}, ... varargin{2}); endif result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/isequaln.m0000644000230300031750000000125215274353473017734 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = isequaln (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} isequaln (@varargin{}) ## Compare @code{mp} values by exact stored native value and shape, treating ## corresponding NaNs as equal. ## @end deftypefn if (nargin <= 1) result = true; return; endif for k = 2:nargin if (! isa (varargin{k-1}, "mp") || ! isa (varargin{k}, "mp")) result = false; return; endif if (! __mplapack_core__ ("value_equal", varargin{1}, varargin{k}, ... "isequaln")) result = false; return; endif endfor result = true; endfunction mplapack-interop-0.5.1/inst/@mp/lt.m0000644000230300031750000000134015274353473016530 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} lt (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = lt (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mp less-than expects two operands"); endif result = __mplapack_core__ ("script_compare", lhs, rhs, "lt"); endfunction mplapack-interop-0.5.1/inst/@mp/sqrtm.m0000644000230300031750000000345515274353473017270 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} sqrtm (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = sqrtm (value) ## Principal matrix square root via a complex Schur form and triangular ## recurrence. All matrix arithmetic remains in mp storage. if (nargin != 1 || ! isa (value, "mp")), error ("mplapack:mp:InvalidInput", "sqrtm expects one mp matrix"); endif [m,n] = size (value); if (m != n), error ("mplapack:mp:InvalidInput", "sqrtm expects a square matrix"); endif if (m == 0) result = value; if (nargout > 1), varargout{2} = mp (0); endif varargout{1} = result; return; endif [U,T] = schur (value, "complex"); R = zeros (m,n, "like", T); for i = 1:m R = mp_put (R,i,i,sqrt (mp_element (T, i, i))); endfor for j = 2:n for i = j-1:-1:1 correction = mp_element (T, i, j); for k = i+1:j-1 correction = correction - mp_element (R, i, k)*mp_element (R, k, j); endfor denominator = mp_element (R, i, i) + mp_element (R, j, j); if (denominator == 0) error ("mplapack:mp:ConvergenceFailure", ... "sqrtm triangular recurrence encountered a singular branch"); endif R = mp_put (R,i,j,correction / denominator); endfor endfor result = U * R * U'; if (nargout > 1) varargout{2} = norm (result*result-value, "fro"); endif varargout{1} = result; endfunction mplapack-interop-0.5.1/inst/@mp/eig.m0000644000230300031750000001340615274353473016663 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = eig (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{lambda} =} eig (@var{A}) ## @deftypefnx {} {[@var{V}, @var{D}] =} eig (@var{A}) ## @deftypefnx {} {[@var{V}, @var{D}, @var{W}] =} eig (@var{A}, @var{B}) ## @deftypefnx {} {[@var{V}, @var{d}] =} eig (@var{A}, "vector") ## Compute dense arbitrary-precision standard and generalized eigenproblems ## through the corresponding MPLAPACK MPFR/MPC drivers. A generalized ## problem accepts the Octave-compatible "chol" and "qz" algorithm options; ## an exactly symmetric/Hermitian positive-definite pair selects the ## Cholesky-definite path by default and otherwise uses the QZ path. ## @end deftypefn if (nargin < 1 || nargin > 4 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "eig expects an mp value and at most three options/operands"); endif if (nargout > 3) error ("mplapack:mp:OutputCount", ... "mp eig returns at most three outputs"); endif is_generalized = (nargin >= 2 && isa (varargin{1}, "mp")); mode = "matrix"; if (is_generalized) other = varargin{1}; algorithm = "auto"; algorithm_seen = false; mode_seen = false; for k = 2:numel (varargin) option = varargin{k}; if (! ischar (option) && ! isstring (option)) error ("mplapack:mp:InvalidOption", ... "generalized eig option must be \"chol\", \"qz\", \"matrix\", or \"vector\""); endif option = char (option); if (strcmp (option, "chol") || strcmp (option, "qz")) if (algorithm_seen) error ("mplapack:mp:InvalidOption", ... "generalized eig algorithm options are mutually exclusive"); endif algorithm = option; algorithm_seen = true; elseif (strcmp (option, "matrix") || strcmp (option, "vector")) if (mode_seen) error ("mplapack:mp:InvalidOption", ... "generalized eig output options may be specified only once"); endif mode = option; mode_seen = true; else error ("mplapack:mp:InvalidOption", ... "generalized eig option must be \"chol\", \"qz\", \"matrix\", or \"vector\""); endif endfor if (nargout <= 1) if (strcmp (mode, "matrix") && mode_seen) output_mode = "diagonal"; else output_mode = "values"; endif [payload] = __mplapack_core__ ("geig", value, other, output_mode, algorithm); result = mp (0); result.payload_ = payload; varargout{1} = result; elseif (nargout == 3) if (strcmp (mode, "vector")) output_mode = "left-vector"; else output_mode = "left"; endif [v_payload, d_payload, w_payload] = __mplapack_core__ ( "geig", value, other, output_mode, algorithm); v_result = mp (0); v_result.payload_ = v_payload; d_result = mp (0); d_result.payload_ = d_payload; w_result = mp (0); w_result.payload_ = w_payload; varargout{1} = v_result; varargout{2} = d_result; varargout{3} = w_result; else if (strcmp (mode, "vector")) output_mode = "vector"; else output_mode = "matrix"; endif [v_payload, d_payload] = __mplapack_core__ ( "geig", value, other, output_mode, algorithm); v_result = mp (0); v_result.payload_ = v_payload; d_result = mp (0); d_result.payload_ = d_payload; varargout{1} = v_result; varargout{2} = d_result; endif return; endif balance_mode = "auto"; mode_seen = false; balance_seen = false; for k = 1:numel (varargin) option = varargin{k}; if (! ischar (option) && ! isstring (option)) error ("mplapack:mp:InvalidOption", ... "eig option must be \"matrix\", \"vector\", \"balance\", or \"nobalance\""); endif option = char (option); if (strcmp (option, "matrix") || strcmp (option, "vector")) if (mode_seen) error ("mplapack:mp:InvalidOption", ... "eig output options may be specified only once"); endif mode = option; mode_seen = true; elseif (strcmp (option, "balance") || strcmp (option, "nobalance")) if (balance_seen) error ("mplapack:mp:InvalidOption", ... "eig balance options may be specified only once"); endif balance_mode = option; balance_seen = true; else error ("mplapack:mp:InvalidOption", ... "eig option must be \"matrix\", \"vector\", \"balance\", or \"nobalance\""); endif endfor if (nargout <= 1) if (strcmp (mode, "matrix") && mode_seen) output_mode = "diagonal"; else output_mode = "values"; endif [payload] = __mplapack_core__ ("eig", value, output_mode, balance_mode); result = mp (0); result.payload_ = payload; varargout{1} = result; elseif (nargout == 3) if (strcmp (mode, "vector")) output_mode = "left-vector"; else output_mode = "left"; endif [v_payload, d_payload, w_payload] = __mplapack_core__ ( "eig", value, output_mode, balance_mode); v_result = mp (0); v_result.payload_ = v_payload; d_result = mp (0); d_result.payload_ = d_payload; w_result = mp (0); w_result.payload_ = w_payload; varargout{1} = v_result; varargout{2} = d_result; varargout{3} = w_result; else if (strcmp (mode, "vector")) output_mode = "vector"; else output_mode = "matrix"; endif [v_payload, d_payload] = __mplapack_core__ ( "eig", value, output_mode, balance_mode); v_result = mp (0); v_result.payload_ = v_payload; d_result = mp (0); d_result.payload_ = d_payload; varargout{1} = v_result; varargout{2} = d_result; endif endfunction mplapack-interop-0.5.1/inst/@mp/asin.m0000644000230300031750000000144215274353473017046 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} asin (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = asin (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "asin expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "asin"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/triu.m0000644000230300031750000000137515274353473017104 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = triu (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} triu (@var{value}) ## @deftypefnx {} {@var{result} =} triu (@var{value}, @var{k}) ## Return the upper triangular part of a dense @code{mp} matrix. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidArguments", ... "triu expects an mp value and an optional offset"); endif if (nargin == 1) payload = __mplapack_core__ ("script_structure", value, "triu"); else payload = __mplapack_core__ ("script_structure", value, "triu", ... varargin{1}); endif result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/logm.m0000644000230300031750000000403615274353473017054 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} logm (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = logm (value) ## Principal matrix logarithm using inverse scaling by repeated matrix ## square roots followed by the Mercator series. The square roots and ## series terms are arbitrary-precision matrix operations. if (nargin != 1 || ! isa (value, "mp")), error ("mplapack:mp:InvalidInput", "logm expects one mp matrix"); endif [m,n] = size (value); if (m != n), error ("mplapack:mp:InvalidInput", "logm expects a square matrix"); endif if (m == 0), result = value; varargout{1} = result; return; endif [U,T] = schur (value, "complex"); I = eye (m,n,"like",T); Y = T; scale_count = 0; while (norm (Y-I, 1) > mp ("0.25")) Y = sqrtm (Y); scale_count = scale_count + 1; if (scale_count > 64) error ("mplapack:mp:ConvergenceFailure", "logm inverse scaling did not converge"); endif endwhile X = Y-I; term = X; L = X; max_terms = 2 * mpdigits () + 32; for k = 2:max_terms term = term * X; ## k is an exactly representable loop counter, not a numerical result. signed_term = term / mp (double (k)); if (mod (k,2) == 0), L = L - signed_term; else L = L + signed_term; endif series_scale = norm (L, 1); if (series_scale < mp (1)), series_scale = mp (1); endif series_tol = mp (max (m,n)) * eps (series_scale); if (norm (signed_term, 1) <= series_tol), break; endif endfor factor = mp (2)^scale_count; result = U * (factor*L) * U'; if (nargout > 1), varargout{2} = norm (expm (result)-value, "fro"); endif varargout{1} = result; endfunction mplapack-interop-0.5.1/inst/@mp/atan2.m0000644000230300031750000000131415274353473017117 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} atan2 (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = atan2 (y, x) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "atan2 expects two operands"); endif result = mp_binary_utility (y, x, "atan2"); endfunction mplapack-interop-0.5.1/inst/@mp/signbit.m0000644000230300031750000000135515274353473017556 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} signbit (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = signbit (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "signbit expects one mp value"); endif result = __mplapack_core__ ("script_signbit", value); endfunction mplapack-interop-0.5.1/inst/@mp/std.m0000644000230300031750000000176315274353473016714 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} std (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = std (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "std expects an mp value"); endif if (nargout > 2) error ("mplapack:mp:InvalidOutput", "std returns at most two outputs"); endif [payload, mean_payload] = __mplapack_core__ ("script_statistics", value, "std", varargin{:}); varargout{1} = mp_statistic_result (payload); if (nargout > 1) varargout{2} = mp_statistic_result (mean_payload); endif endfunction mplapack-interop-0.5.1/inst/@mp/double.m0000644000230300031750000000136315274353473017370 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{value} =} double (@var{x}) ## Explicitly convert @code{mp} value @var{x} to IEEE-754 binary64. ## ## Conversion uses round-to-nearest with ties to even. Precision may be lost. ## Matrix shape is preserved and each matrix element is converted directly ## from its native MPFR value. ## @end deftypefn function value = double (input) if (nargin != 1 || ! isa (input, "mp")) error ("mplapack:mp:InvalidInput", ... "double expects one mp value"); endif if (__mplapack_core__ ("value_is_matrix", input)) value = __mplapack_core__ ("matrix_to_double", input); return; endif value = __mplapack_core__ ("scalar_to_double", input); endfunction mplapack-interop-0.5.1/inst/@mp/sqrt.m0000644000230300031750000000144215274353473017105 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} sqrt (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = sqrt (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "sqrt expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "sqrt"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/log.m0000644000230300031750000000143615274353473016700 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} log (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = log (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "log expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "log"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/isequal.m0000644000230300031750000000126115274353473017556 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = isequal (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} isequal (@varargin{}) ## Compare @code{mp} values by exact stored native value and shape. ## NaN values are not equal, as in builtin Octave. ## @end deftypefn if (nargin <= 1) result = true; return; endif for k = 2:nargin if (! isa (varargin{k-1}, "mp") || ! isa (varargin{k}, "mp")) result = false; return; endif if (! __mplapack_core__ ("value_equal", varargin{1}, varargin{k}, ... "isequal")) result = false; return; endif endfor result = true; endfunction mplapack-interop-0.5.1/inst/@mp/setdiff.m0000644000230300031750000000345415274353473017545 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} setdiff (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = setdiff (a, b, varargin) if (nargin < 2 || ! isa (a, "mp")), error ("mplapack:mp:InvalidInput", "setdiff requires mp input"); endif if (! isa (b, "mp")), b = mp (b); endif stable = mp_set_has_option (varargin, "stable"); rows_mode = mp_set_has_option (varargin, "rows"); if (rows_mode) [ma,na] = size(a); [mb,nb] = size(b); if (na != nb), error ("mplapack:mp:InvalidInput", "setdiff rows require matching columns"); endif [candidate, first] = mp_set_unique_rows(a,stable); keep=true(rows(candidate),1); for i=1:rows(candidate) for j=1:mb if (mp_rows_equal(candidate,i,b,j)), keep(i)=false; break; endif endfor endfor varargout{1}=mp_slice(candidate,find(keep),1:na); else [candidate, first] = mp_set_unique (a, stable); candidate_column=mp_column(candidate); bc=mp_column(b); keep=true(numel(candidate_column),1); for i=1:numel(candidate_column) for j=1:numel(bc) if (isequaln(mp_element(candidate_column,i),mp_element(bc,j))), keep(i)=false; break; endif endfor endfor varargout{1}=mp_slice(candidate_column,find(keep),1); [ma,na]=size(a); if (ma==1 && na!=1), varargout{1}=varargout{1}.'; endif endif if (nargout > 1), varargout{2}=first(keep); endif endfunction mplapack-interop-0.5.1/inst/@mp/gt.m0000644000230300031750000000134315274353473016526 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} gt (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = gt (lhs, rhs) if (nargin != 2) error ("mplapack:mp:InvalidOperands", "mp greater-than expects two operands"); endif result = __mplapack_core__ ("script_compare", lhs, rhs, "gt"); endfunction mplapack-interop-0.5.1/inst/@mp/svd.m0000644000230300031750000000404615274353473016713 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = svd (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{s} =} svd (@var{A}) ## @deftypefnx {} {[@var{U}, @var{S}, @var{V}] =} svd (@var{A}) ## @deftypefnx {} {[@var{U}, @var{S}, @var{V}] =} svd (@var{A}, "econ") ## Compute dense arbitrary-precision real or complex SVD through MPLAPACK ## @code{Rgesvd} or @code{Cgesvd}. The numeric zero option is the ## deprecated economy compatibility form. Singular values are real @code{mp} ## values for both real and complex inputs. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "svd expects one mp value and an optional econ flag"); endif if (nargout == 2 || nargout > 3) error ("mplapack:mp:OutputCount", ... "dense mp svd returns one output or U, S, and V"); endif mode = "full"; if (nargin == 2) option = varargin{1}; if (ischar (option) || isstring (option)) option = char (option); if (strcmp (option, "econ")) mode = "econ"; else error ("mplapack:mp:InvalidOption", ... "svd option must be \"econ\" or deprecated numeric 0"); endif elseif (isnumeric (option) && ! islogical (option) && isreal (option) && isscalar (option) && option == 0) mode = "econ"; else error ("mplapack:mp:InvalidOption", ... "svd option must be \"econ\" or deprecated numeric 0"); endif endif if (nargout <= 1) payload = __mplapack_core__ ("svd", value, mode, "values"); result = mp (0); result.payload_ = payload; varargout{1} = result; else [u_payload, s_payload, v_payload] = __mplapack_core__ ( "svd", value, mode, "factors"); u_result = value; u_result.payload_ = u_payload; s_result = mp (0); s_result.payload_ = s_payload; v_result = value; v_result.payload_ = v_payload; varargout{1} = u_result; varargout{2} = s_result; varargout{3} = v_result; endif endfunction mplapack-interop-0.5.1/inst/@mp/floor.m0000644000230300031750000000141515274353473017235 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} floor (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = floor (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "floor expects one mp value"); endif result = value; result.payload_ = __mplapack_core__ ("script_round", value, "floor"); endfunction mplapack-interop-0.5.1/inst/@mp/logical.m0000644000230300031750000000136615274353473017533 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} logical (@dots{}) ## Apply the native arbitrary-precision @code{mp} predicate or logical operation without converting numerical data through builtin @code{double}. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = logical (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "logical expects one mp value"); endif result = ! __mplapack_core__ ("script_logical", value, "not"); endfunction mplapack-interop-0.5.1/inst/@mp/sum.m0000644000230300031750000000174315274353473016724 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} sum (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = sum (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "sum expects an mp value"); endif if (nargout > 1) error ("mplapack:mp:InvalidOutput", "sum returns one output"); endif payload = __mplapack_core__ ("script_reduce", value, "sum", varargin{:}); if (! isnumeric (payload)) result = mp (0); result.payload_ = payload; else result = payload; endif varargout{1} = result; endfunction mplapack-interop-0.5.1/inst/@mp/norm.m0000644000230300031750000000242715274353473017073 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = norm (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{y} =} norm (@var{x}) ## @deftypefnx {} {@var{y} =} norm (@var{x}, @var{p}) ## Compute arbitrary-precision vector and dense matrix norms through the ## MPFR/MPC MPLAPACK backend. Vectors support 0, 1, 2, Inf, -Inf, fro, and ## positive finite p values; matrices support 1, 2, Inf, and fro. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "norm expects one mp value and an optional p or fro flag"); endif if (nargin == 1) request = 2; else request = varargin{1}; if ((ischar (request) || isstring (request)) && ! strcmp (char (request), "fro")) error ("mplapack:mp:InvalidOption", ... "norm string option must be \"fro\""); endif if (! ischar (request) && ! isstring (request) && (! isnumeric (request) || islogical (request) || ! isreal (request) || ! isscalar (request))) error ("mplapack:mp:InvalidOption", ... "norm p must be a real scalar or \"fro\""); endif endif payload = __mplapack_core__ ("norm", value, request); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/acosh.m0000644000230300031750000000144615274353473017215 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} acosh (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = acosh (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "acosh expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "acosh"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/flip.m0000644000230300031750000000123315274353473017044 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = flip (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} flip (@var{value}) ## @deftypefnx {} {@var{result} =} flip (@var{value}, @var{dim}) ## Flip a dense two-dimensional @code{mp} value along one dimension. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidArguments", ... "flip expects an mp value and an optional dimension"); endif payload = __mplapack_core__ ("script_structure", value, "flip", ... varargin{:}); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/range.m0000644000230300031750000000161115274353473017206 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} range (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = range (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "range expects an mp value"); endif if (nargout > 1) error ("mplapack:mp:InvalidOutput", "range returns one output"); endif payload = __mplapack_core__ ("script_statistics", value, "range", varargin{:}); result = mp_statistic_result (payload); endfunction mplapack-interop-0.5.1/inst/@mp/roots.m0000644000230300031750000000160515274353473017263 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} roots (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = roots (value) if (nargin != 1 || ! isa (value,"mp")), error ("mplapack:mp:InvalidInput", "roots expects an mp coefficient vector"); endif p=value(:); while (numel(p)>1 && mp_element (p,1)==0), p=mp_slice (p,2:numel(p),1); endwhile if (numel(p)<=1), result=zeros(0,1,"like",value); return; endif result=eig(compan(p),"vector"); endfunction mplapack-interop-0.5.1/inst/@mp/mp.m0000644000230300031750000001102415274353473016525 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function obj = mp (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{x} =} mp (@var{value}) ## Construct an arbitrary-precision real or complex scalar or dense matrix. ## ## @var{value} may be scalar decimal text, a real or complex @code{double} ## scalar or matrix, a two-dimensional cell matrix of scalar decimal text, ## or an existing @code{mp}. Text is parsed directly at the current project ## precision. @code{double} input preserves each already-rounded IEEE ## binary64 value exactly when transferring it to MPFR. ## ## The legacy user-class representation is used because Octave 11.1 invokes ## @code{saveobj} for this form. Normal values contain only a native ## MPFR/MPC payload; the save hook replaces that payload by the versioned ## exact serialization struct before Octave writes the object. ## @end deftypefn if (nargin == 2) if (! ischar (varargin{1}) || ! ischar (varargin{2}) || isempty (varargin{1}) || isempty (varargin{2}) || rows (varargin{1}) != 1 || rows (varargin{2}) != 1) error ("mplapack:mp:InvalidInput", ... "mp expects exactly one scalar input"); endif payload = __mplapack_core__ ("scalar_create_complex_text", ... varargin{1}, varargin{2}); obj = class (struct ("payload_", payload), "mp"); return; endif if (nargin != 1) error ("mplapack:mp:InvalidInput", ... "mp expects exactly one scalar input"); endif value = varargin{1}; if (isa (value, "mp")) obj = value; return; endif if (ischar (value)) if (isempty (value)) error ("mplapack:mp:InvalidInput", ... "mp scalar text must not be empty"); endif if (rows (value) != 1) error ("mplapack:mp:MatrixUnsupported", ... "text arrays are not implemented before M07"); endif if (value(1) == '(') payload = __mplapack_core__ ("scalar_create_complex_text_single", value); else payload = __mplapack_core__ ("scalar_create_text", value); endif obj = class (struct ("payload_", payload), "mp"); return; endif if (isa (value, "double")) if (! isreal (value)) if (ndims (value) != 2) error ("mplapack:mp:MatrixUnsupported", ... "only two-dimensional mp matrices are supported"); endif if (numel (value) == 1) payload = __mplapack_core__ ("scalar_create_complex_double", value); else payload = __mplapack_core__ ("matrix_create_complex_double", value); endif obj = class (struct ("payload_", payload), "mp"); return; endif if (ndims (value) != 2) error ("mplapack:mp:MatrixUnsupported", ... "only two-dimensional mp matrices are supported"); endif if (numel (value) == 1) payload = __mplapack_core__ ("scalar_create_double", value); else payload = __mplapack_core__ ("matrix_create_double", value); endif obj = class (struct ("payload_", payload), "mp"); return; endif if (iscell (value)) if (ndims (value) != 2) error ("mplapack:mp:MatrixUnsupported", ... "only two-dimensional mp matrices are supported"); endif if (numel (value) == 1) element = value{1}; if (! ischar (element) || isempty (element) || rows (element) != 1) error ("mplapack:mp:InvalidInput", ... "a 1x1 cell constructor requires one nonempty text row"); endif if (element(1) == '(') payload = __mplapack_core__ ("scalar_create_complex_text_single", element); else payload = __mplapack_core__ ("scalar_create_text", element); endif else is_complex_text = false; for index = 1:numel (value) element = value{index}; if (ischar (element) && ! isempty (element) && rows (element) == 1 && element(1) == '(') is_complex_text = true; break; endif endfor if (is_complex_text) payload = __mplapack_core__ ("matrix_create_complex_text_cell", value); else payload = __mplapack_core__ ("matrix_create_text_cell", value); endif endif obj = class (struct ("payload_", payload), "mp"); return; endif if (isnumeric (value) && (! isreal (value))) error ("mplapack:mp:InvalidInput", ... "unsupported complex input type"); endif error ("mplapack:mp:InvalidInput", ... ["mp input must be decimal text, a real double scalar/matrix, ", ... "a text cell matrix, or mp"]); endfunction mplapack-interop-0.5.1/inst/@mp/semilogx.m0000644000230300031750000000143215274353473017742 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} semilogx (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = semilogx (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("semilogx", args{:}); else [varargout{1:nargout}] = builtin ("semilogx", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/find.m0000644000230300031750000000210715274353473017033 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} find (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = find (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "find expects an mp value"); endif if (nargout > 3) error ("mplapack:mp:OutputCount", "find returns at most three outputs"); endif outputs = cell (1, max (1, nargout)); [outputs{:}] = __mplapack_core__ ("script_find", value, nargout, varargin{:}); if (nargout >= 3) selected = value; selected.payload_ = outputs{3}; outputs{3} = selected; endif for index = 1:nargout varargout{index} = outputs{index}; endfor endfunction mplapack-interop-0.5.1/inst/@mp/cumsum.m0000644000230300031750000000176215274353473017432 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} cumsum (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = cumsum (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "cumsum expects an mp value"); endif if (nargout > 1) error ("mplapack:mp:InvalidOutput", "cumsum returns one output"); endif payload = __mplapack_core__ ("script_reduce", value, "cumsum", varargin{:}); if (! isnumeric (payload)) result = mp (0); result.payload_ = payload; else result = payload; endif varargout{1} = result; endfunction mplapack-interop-0.5.1/inst/@mp/rank.m0000644000230300031750000000252515274353473017052 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = rank (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{r} =} rank (@var{A}) ## @deftypefnx {} {@var{r} =} rank (@var{A}, @var{tol}) ## Compute the numerical rank of a dense arbitrary-precision real or complex ## matrix from MPFR/MPC singular values. The default tolerance is ## max(size(A))*sigma_max*Rlamch_mpfr("E") at the operation precision. ## The structural rank result is returned as an ordinary Octave scalar. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "rank expects one mp value and an optional real tolerance"); endif if (nargout > 1) error ("mplapack:mp:OutputCount", "mp rank returns one output"); endif if (nargin == 1) result = __mplapack_core__ ("rank", value); else tol = varargin{1}; if (isa (tol, "mp")) if (! isreal (tol) || ! isscalar (tol)) error ("mplapack:mp:InvalidOption", ... "rank tolerance must be a real scalar"); endif elseif (! isnumeric (tol) || islogical (tol) || ! isreal (tol) || ! isscalar (tol)) error ("mplapack:mp:InvalidOption", ... "rank tolerance must be a real scalar"); endif result = __mplapack_core__ ("rank", value, tol); endif endfunction mplapack-interop-0.5.1/inst/@mp/tril.m0000644000230300031750000000137515274353473017073 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = tril (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} tril (@var{value}) ## @deftypefnx {} {@var{result} =} tril (@var{value}, @var{k}) ## Return the lower triangular part of a dense @code{mp} matrix. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidArguments", ... "tril expects an mp value and an optional offset"); endif if (nargin == 1) payload = __mplapack_core__ ("script_structure", value, "tril"); else payload = __mplapack_core__ ("script_structure", value, "tril", ... varargin{1}); endif result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/scatter.m0000644000230300031750000000142615274353473017563 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} scatter (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = scatter (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("scatter", args{:}); else [varargout{1:nargout}] = builtin ("scatter", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/mean.m0000644000230300031750000000160415274353473017034 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mean (@dots{}) ## Compute the dense arbitrary-precision reduction or statistic with native MPFR/MPC values and the documented dimension and NaN rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = mean (value, varargin) if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "mean expects an mp value"); endif if (nargout > 1) error ("mplapack:mp:InvalidOutput", "mean returns one output"); endif payload = __mplapack_core__ ("script_statistics", value, "mean", varargin{:}); result = mp_statistic_result (payload); endfunction mplapack-interop-0.5.1/inst/@mp/scatter3.m0000644000230300031750000000143215274353473017643 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} scatter3 (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = scatter3 (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("scatter3", args{:}); else [varargout{1:nargout}] = builtin ("scatter3", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/sin.m0000644000230300031750000000143615274353473016710 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} sin (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = sin (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "sin expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "sin"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/rdivide.m0000644000230300031750000000142315274353473017541 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = rdivide (lhs, rhs) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} rdivide (@var{lhs}, @var{rhs}) ## Divide real scalar or dense matrix operands element by element with ## @code{./} and 2-D singleton expansion. Division by zero and special ## values follow MPFR round-to-nearest semantics. Matrix right division ## with @code{/} is provided separately by @code{mrdivide}. ## @end deftypefn if (nargin != 2) error ("mplapack:mp:InvalidOperands", ... "mp element-wise division expects exactly two operands"); endif payload = __mplapack_core__ ("scalar_divide", lhs, rhs); if (isa (lhs, "mp")) result = lhs; else result = rhs; endif result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/log1p.m0000644000230300031750000000144615274353473017142 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} log1p (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = log1p (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "log1p expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "log1p"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/mrdivide.m0000644000230300031750000000232415274353473017717 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mrdivide (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{C} =} mrdivide (@var{A}, @var{B}) ## Solve the dense right-division problem @code{A / B} using the ## conjugate-transpose identity @code{(B' \ A')'}. Scalar denominators ## use the native element-wise division path. Square singular systems use ## the rank-revealing minimum-norm path, matching Octave's right division. ## @end deftypefn if (nargin != 2) error ("mplapack:mp:InvalidOperands", ... "mp right division expects exactly two operands"); endif if (isscalar (varargin{2})) result = rdivide (varargin{1}, varargin{2}); return; endif lhs_transposed = ctranspose (varargin{2}); rhs_transposed = ctranspose (varargin{1}); try result = ctranspose (mldivide (lhs_transposed, rhs_transposed)); catch exception if (! strcmp (exception.identifier, "mplapack:mp:SingularMatrix")) rethrow (exception); endif payload = __mplapack_core__ ("mldivide_rank", lhs_transposed, ... rhs_transposed); result = mp (0); result.payload_ = payload; result = ctranspose (result); end_try_catch endfunction mplapack-interop-0.5.1/inst/@mp/cat.m0000644000230300031750000000206615274353473016666 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = cat (dimension, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} cat (@var{dimension}, @var{A}, @var{B}, @dots{}) ## Concatenate dense two-dimensional @code{mp} values along dimension 1 or 2. ## @end deftypefn if (nargin < 2 || ! isnumeric (dimension) || ! isreal (dimension) || ! isscalar (dimension) || dimension != fix (dimension) || (dimension != 1 && dimension != 2)) error ("mplapack:mp:InvalidDimension", ... "cat supports only dimensions 1 and 2"); endif template = []; for k = 1:numel (varargin) if (isa (varargin{k}, "mp")) template = varargin{k}; break; endif endfor if (isempty (template)) error ("mplapack:mp:InvalidOperands", ... "cat requires at least one mp operand"); endif if (dimension == 1) payload = __mplapack_core__ ("matrix_vertcat", varargin{:}); else payload = __mplapack_core__ ("matrix_horzcat", varargin{:}); endif result = template; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/numel.m0000644000230300031750000000113115274353473017227 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function count = numel (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{n} =} numel (@var{A}) ## Return the number of stored elements in a dense real @code{mp} value. ## @end deftypefn if (! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "numel expects an mp value"); endif if (! isempty (varargin)) error ("mplapack:mp:IndexingUnsupported", ... "dense mp matrix indexing is not implemented in M07"); endif info = __mplapack_core__ ("value_shape_info", value); count = double (info.numel); endfunction mplapack-interop-0.5.1/inst/@mp/mpower.m0000644000230300031750000000116615274353473017430 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mpower (lhs, rhs) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mpower (@var{lhs}, @var{rhs}) ## Compute scalar power or integer powers of square dense @code{mp} ## matrices. Matrix powers use exponentiation by squaring and the native ## MPFR/MPC matrix multiplication and inverse paths. ## @end deftypefn if (nargin != 2) error ("mplapack:mp:InvalidOperands", ... "mp matrix power expects exactly two operands"); endif payload = __mplapack_core__ ("mpower", lhs, rhs); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/power.m0000644000230300031750000000117615274353473017254 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = power (lhs, rhs) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} power (@var{lhs}, @var{rhs}) ## Compute element-wise power for dense arbitrary-precision real or complex ## @code{mp} values, including mixed builtin scalar and matrix operands. ## Domain crossings promote to MPC at the operation precision. ## @end deftypefn if (nargin != 2) error ("mplapack:mp:InvalidOperands", ... "mp power expects exactly two operands"); endif payload = __mplapack_core__ ("power", lhs, rhs); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/acos.m0000644000230300031750000000144215274353473017041 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} acos (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = acos (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "acos expects one mp value"); endif payload = __mplapack_core__ ("script_elementary", value, "acos"); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/colon.m0000644000230300031750000000155515274353473017233 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = colon (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} colon (@var{a}, @var{b}) ## @deftypefnx {} {@var{result} =} colon (@var{a}, @var{s}, @var{b}) ## Construct a real arbitrary-precision range without a binary64 loop. ## @end deftypefn if (nargin != 2 && nargin != 3) error ("mplapack:mp:InvalidArguments", ... "colon expects two endpoints or an endpoint, step, and endpoint"); endif template = []; for k = 1:nargin if (isa (varargin{k}, "mp")) template = varargin{k}; break; endif endfor if (isempty (template)) error ("mplapack:mp:InvalidOperands", ... "colon requires an mp endpoint or step"); endif payload = __mplapack_core__ ("script_range", varargin{:}); result = template; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/plus.m0000644000230300031750000000130115274353473017071 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = plus (lhs, rhs) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} plus (@var{lhs}, @var{rhs}) ## Add real scalar or dense matrix @code{mp} values, with 2-D singleton ## expansion. Mixed real @code{double} operands are converted directly at ## the operation precision; the current default precision is not used. ## @end deftypefn if (nargin != 2) error ("mplapack:mp:InvalidOperands", ... "mp addition expects exactly two operands"); endif payload = __mplapack_core__ ("scalar_add", lhs, rhs); if (isa (lhs, "mp")) result = lhs; else result = rhs; endif result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/repmat.m0000644000230300031750000000136415274353473017407 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = repmat (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} repmat (@var{value}, @var{m}, @var{n}) ## @deftypefnx {} {@var{result} =} repmat (@var{value}, [@var{m} @var{n}]) ## Repeat a dense two-dimensional @code{mp} value while preserving its ## native precision and storage kind. ## @end deftypefn if (nargin < 2 || nargin > 3 || ! isa (value, "mp")) error ("mplapack:mp:InvalidArguments", ... "repmat expects an mp value and one or two repetition dimensions"); endif payload = __mplapack_core__ ("script_structure", value, "repmat", ... varargin{:}); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/lu.m0000644000230300031750000000445615274353473016544 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = lu (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{Y} =} lu (@var{A}) ## @deftypefnx {} {[@var{L}, @var{U}] =} lu (@var{A}) ## @deftypefnx {} {[@var{L}, @var{U}, @var{P}] =} lu (@var{A}) ## @deftypefnx {} {[@var{L}, @var{U}, @var{p}] =} lu (@var{A}, "vector") ## Compute dense MPFR LU through MPLAPACK @code{Rgetrf} or complex ## @code{Cgetrf}. One output is the packed LAPACK factor. Two outputs ## absorb row permutation into L so that A = L*U; three outputs return P so ## that P*A = L*U. The @code{"vector"} option returns the final 1-based ## row permutation vector. Real and complex dense matrices share these ## packed, two-output, matrix-permutation, and vector-permutation forms. ## @end deftypefn if (nargin < 1 || nargin > 2 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", ... "lu expects one mp value and an optional vector flag"); endif if (nargout > 3) error ("mplapack:mp:OutputCount", ... "dense mp lu returns at most three outputs"); endif vector_option = false; if (nargin == 2) option = varargin{1}; if (! ischar (option) && ! isstring (option)) error ("mplapack:mp:InvalidOption", ... "lu option must be \"vector\""); endif option = char (option); if (! strcmp (option, "vector")) error ("mplapack:mp:InvalidOption", ... "lu option must be \"vector\""); endif vector_option = true; endif if (nargout <= 1) payload = __mplapack_core__ ("lu", value, "packed"); result = value; result.payload_ = payload; varargout{1} = result; elseif (nargout == 2) [l_payload, u_payload] = __mplapack_core__ ("lu", value, "two"); l_result = value; l_result.payload_ = l_payload; u_result = value; u_result.payload_ = u_payload; varargout{1} = l_result; varargout{2} = u_result; else mode = "matrix"; if (vector_option) mode = "vector"; endif [l_payload, u_payload, permutation] = __mplapack_core__ ( "lu", value, mode); l_result = value; l_result.payload_ = l_payload; u_result = value; u_result.payload_ = u_payload; varargout{1} = l_result; varargout{2} = u_result; varargout{3} = permutation; endif endfunction mplapack-interop-0.5.1/inst/@mp/waterfall.m0000644000230300031750000000143615274353473020100 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} waterfall (@dots{}) ## Convert final @code{mp} visualization data at the graphics boundary and call the corresponding Octave graphics routine. Numerical work remains in arbitrary precision until this boundary. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = waterfall (varargin) args = mp_graphics_args (varargin{:}); if (nargout == 0) builtin ("waterfall", args{:}); else [varargout{1:nargout}] = builtin ("waterfall", args{:}); endif endfunction mplapack-interop-0.5.1/inst/@mp/mldivide.m0000644000230300031750000000130715274353473017711 0ustar rafaelrafaelfunction result = mldivide (lhs, rhs) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} mldivide (@var{lhs}, @var{rhs}) ## Solve dense @code{mp} systems with MPLAPACK. Real square systems use ## @code{Rgesv}; complex square systems use @code{Cgesv}; rectangular real ## systems use the rank-revealing @code{Rgelss} driver. Scalar left ## division uses native MPFR or MPC arithmetic. Sparse systems are not ## implemented. ## @end deftypefn if (nargin != 2) error ("mplapack:mp:InvalidOperands", ... "mp left division expects exactly two operands"); endif payload = __mplapack_core__ ("mldivide", lhs, rhs); result = mp (0); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/loadobj.m0000644000230300031750000000224215274353473017525 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{value} =} loadobj (@var{state}) ## Restore an @code{mp} value from the versioned exact serialization schema, ## including its stored precision and real/complex payload kind. ## @seealso{saveobj, mp, mpbits} ## @end deftypefn function value = loadobj (state) ## Reconstruct a saved @mp value at its recorded precision. The ambient ## default is restored even when native reconstruction raises an error. if (nargin != 1 || ! isa (state, "mp")) error ("mplapack:SerializationError", ... "loadobj expects one serialized mp value"); endif payload_state = builtin ("subsref", state, substruct (".", "payload_")); if (! isstruct (payload_state) || ! isfield (payload_state, "precision_bits")) error ("mplapack:SerializationError", ... "serialized mp value has no precision_bits field"); endif saved_precision = mpbits (); unwind_protect mpbits (payload_state.precision_bits); value = state; value.payload_ = __mplapack_core__ ("deserialize", payload_state); unwind_protect_cleanup mpbits (saved_precision); end_unwind_protect endfunction mplapack-interop-0.5.1/inst/@mp/abs.m0000644000230300031750000000102115274353473016652 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = abs (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} abs (@var{value}) ## Return the MPFR absolute value or MPC magnitude of an @code{mp} value. ## The result is real @code{mp} storage at the source precision. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "abs expects one mp value"); endif result = mp (0); result.payload_ = __mplapack_core__ ("script_unary", value, "abs"); endfunction mplapack-interop-0.5.1/inst/@mp/isnan.m0000644000230300031750000000065615274353473017232 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = isnan (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} isnan (@var{value}) ## Return a builtin logical mask for MPFR/MPC NaN values. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "isnan expects one mp value"); endif result = __mplapack_core__ ("script_predicate", value, "isnan"); endfunction mplapack-interop-0.5.1/inst/@mp/columns.m0000644000230300031750000000070715274353473017577 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function count = columns (value) ## -*- texinfo -*- ## @deftypefn {} {@var{n} =} columns (@var{A}) ## Return the number of columns in a dense real @code{mp} value. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "columns expects one mp value"); endif info = __mplapack_core__ ("value_shape_info", value); count = double (info.columns); endfunction mplapack-interop-0.5.1/inst/@mp/sort.m0000644000230300031750000000174415274353473017110 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function varargout = sort (value, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{s} =} sort (@var{A}) ## @deftypefnx {} {@var{s} =} sort (@var{A}, @var{dim}) ## @deftypefnx {} {@var{s} =} sort (@var{A}, @var{direction}) ## @deftypefnx {} {[@var{s}, @var{idx}] =} sort (@dots{}) ## Sort a two-dimensional real or complex @code{mp} matrix using native ## MPFR/MPC comparisons. Complex values are ordered by magnitude and then ## phase, matching Octave's complex sort ordering. ## @end deftypefn if (nargin < 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "sort expects an mp value"); endif if (nargout > 2) error ("mplapack:mp:OutputCount", "sort returns at most two outputs"); endif [payload, indices] = __mplapack_core__ ("script_sort", value, varargin{:}); result = value; result.payload_ = payload; varargout{1} = result; if (nargout > 1) varargout{2} = indices; endif endfunction mplapack-interop-0.5.1/inst/@mp/isfinite.m0000644000230300031750000000067515274353473017735 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = isfinite (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} isfinite (@var{value}) ## Return a builtin logical mask for finite MPFR/MPC values. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "isfinite expects one mp value"); endif result = __mplapack_core__ ("script_predicate", value, "isfinite"); endfunction mplapack-interop-0.5.1/inst/@mp/union.m0000644000230300031750000000353115274353473017245 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} union (@dots{}) ## Perform the supported dense arbitrary-precision polynomial or set operation with package-owned @code{mp} values and documented conditioning/ordering rules. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function varargout = union (a, b, varargin) if (nargin < 2 || ! isa (a, "mp")) error ("mplapack:mp:InvalidInput", "union requires an mp first operand"); endif if (! isa (b, "mp")), b = mp (b); endif stable = mp_set_has_option (varargin, "stable"); rows_mode = mp_set_has_option (varargin, "rows"); if (rows_mode) [ma,na] = size (a); [mb,nb] = size (b); if (na != nb), error ("mplapack:mp:InvalidInput", "union rows require matching columns"); endif combined = zeros (ma+mb,na,"like",a); if (isreal (a) && !isreal (b)), combined=zeros(ma+mb,na,"like",b); endif for i=1:ma, for j=1:na, combined=mp_put(combined,i,j,mp_element(a,i,j)); endfor, endfor for i=1:mb, for j=1:nb, combined=mp_put(combined,ma+i,j,mp_element(b,i,j)); endfor, endfor [values, first, inverse] = mp_set_unique_rows (combined, stable); na_index = ma; else combined = mp_set_concat_columns (a,b); [values, first, inverse] = mp_set_unique (combined, stable); na_index = numel (a); endif [ma,na] = size (a); [mb,nb] = size (b); if (! rows_mode && ma == 1 && na != 1 && mb == 1 && nb != 1) values = values.'; endif varargout{1} = values; if (nargout > 1) varargout{2} = first(first <= na_index); endif if (nargout > 2) varargout{3} = first(first > na_index) - na_index; endif endfunction mplapack-interop-0.5.1/inst/@mp/imag.m0000644000230300031750000000075015274353473017032 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = imag (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} imag (@var{value}) ## Return the imaginary component of an @code{mp} value at its stored ## precision. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "imag expects one mp value"); endif payload = __mplapack_core__ ("value_imag", value); result = value; result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/@mp/isreal.m0000644000230300031750000000065315274353473017376 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = isreal (value) ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} isreal (@var{value}) ## Return whether an @code{mp} value has a real native payload. ## @end deftypefn if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "isreal expects one mp value"); endif result = __mplapack_core__ ("value_is_real", value); endfunction mplapack-interop-0.5.1/inst/@mp/gamma.m0000644000230300031750000000161715274353473017202 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} gamma (@dots{}) ## Compute the supported arbitrary-precision result for the supplied @code{mp} inputs using the documented native backend or package-owned algorithm. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits} ## @end deftypefn function result = gamma (value) if (nargin != 1 || ! isa (value, "mp")) error ("mplapack:mp:InvalidInput", "gamma expects one real mp value"); endif if (! isreal (value)), error ("mplapack:mp:ComplexUnsupported", "gamma is implemented for real mp values only"); endif result = mp (0); result.payload_ = __mplapack_core__ ("script_elementary", value, "gamma"); endfunction mplapack-interop-0.5.1/inst/ppder.m0000644000230300031750000000237015274353473016513 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} ppder (@dots{}) ## Differentiate or integrate a supported arbitrary-precision piecewise-polynomial form. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits, mpdigits} ## @end deftypefn function result = ppder (pp) if (! isstruct (pp) || ! isscalar (pp) || ! isfield (pp, "form") || ! strcmp (pp.form, "pp") || pp.order < 1) error ("mplapack:interp:InvalidPP", "ppder expects an pp struct"); endif old_order = pp.order; new_order = max (1, old_order - 1); zero = mp_interp_element (pp.coefs, 1, 1) * 0; coefficients = repmat (zero, pp.pieces, new_order); if (old_order > 1) for piece = 1:pp.pieces for column = 1:(old_order - 1) factor = old_order - column; coefficients = mp_interp_put (coefficients, piece, column, ... mp_interp_element (pp.coefs, piece, column) * factor); endfor endfor endif result = pp; result.coefs = coefficients; result.order = new_order; endfunction mplapack-interop-0.5.1/inst/ppval.m0000644000230300031750000000353015274353473016522 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = ppval (pp, query) ## -*- texinfo -*- ## @deftypefn {} {@var{y} =} ppval (@var{pp}, @var{x}) ## Evaluate a scalar-output MP piecewise polynomial using MPFR/MPC Horner ## arithmetic. Extrapolation uses the first or last piece. ## @end deftypefn if (! isstruct (pp) || ! isscalar (pp) || ! isfield (pp, "form") || ! strcmp (pp.form, "pp") || ! isfield (pp, "breaks") || ! isfield (pp, "coefs") || ! isa (pp.breaks, "mp") || ! isa (pp.coefs, "mp")) error ("mplapack:interp:InvalidPP", ... "ppval expects an MPLAPACK scalar piecewise polynomial"); endif if (! isnumeric (query)) error ("mplapack:interp:InvalidQuery", "ppval query must be numeric"); endif break_template = mp_interp_element (pp.breaks, 1); if (! isa (query, "mp")) query = break_template * 0 + query; endif zero = mp_interp_element (pp.coefs, 1, columns (pp.coefs)) * 0; result = repmat (zero, rows (query), columns (query)); for column = 1:columns (query) for row = 1:rows (query) point = mp_interp_element (query, row, column); piece = mp_interp_piece (pp.breaks, point); origin = mp_interp_element (pp.breaks, piece); value = mp_interp_element (pp.coefs, piece, 1); for coefficient = 2:columns (pp.coefs) value = value * (point - origin) ... + mp_interp_element (pp.coefs, piece, coefficient); endfor result = mp_interp_put (result, row, column, value); endfor endfor endfunction function piece = mp_interp_piece (breaks, point) count = rows (breaks); piece = count - 1; if (point <= mp_interp_element (breaks, 1)) piece = 1; return; endif for index = 1:(count - 1) if (point <= mp_interp_element (breaks, index + 1)) piece = index; return; endif endfor endfunction mplapack-interop-0.5.1/inst/mprand.m0000644000230300031750000000140315274353473016656 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = mprand (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{r} =} mprand () ## @deftypefnx {} {@var{r} =} mprand (@var{n}) ## @deftypefnx {} {@var{r} =} mprand (@var{m}, @var{n}) ## Generate deterministic uniform arbitrary-precision values on [0,1). ## The current @code{mpbits} default selects the output precision. ## @end deftypefn [rows_out, columns_out] = mp_random_dimensions (varargin, "mprand"); state = mp_rng_state ("get"); [payload, first, second] = __mplapack_core__ ( "rng_uniform", rows_out, columns_out, state.state(1), state.state(2)); state.state = uint64 ([first, second]); mp_rng_state ("set", state); result = mp ("0"); result.payload_ = payload; endfunction mplapack-interop-0.5.1/inst/mpbits.m0000644000230300031750000000134715274353473016702 0ustar rafaelrafael## -*- texinfo -*- ## @deftypefn {} {@var{bits} =} mpbits () ## @deftypefnx {} {@var{bits} =} mpbits (@var{n}) ## Return or set the default precision, in bits, for subsequently created ## @code{mp} values. ## ## The initial default is 512 bits. Setting the default does not alter or ## re-round existing values. With an output, the setter returns the resulting ## current default. ## @end deftypefn function value = mpbits (varargin) if (nargin > 1) error ("mplapack:mpbits:InvalidPrecision", ... "mpbits accepts zero or one precision argument"); endif if (nargin == 0) value = __mplapack_core__ ("precision_get_bits"); else value = __mplapack_core__ ("precision_set_bits", varargin{1}); endif endfunction mplapack-interop-0.5.1/inst/spline.m0000644000230300031750000000130615274353473016671 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause ## -*- texinfo -*- ## @deftypefn {} {@var{result} =} spline (@dots{}) ## Construct a piecewise-polynomial interpolant from arbitrary-precision data. ## The operation follows the stored-precision and @code{mpbits} contract; ## it does not silently fall back to builtin binary64 arithmetic. See the ## user manual for supported forms, real/complex behavior, and limitations. ## @seealso{mp, mpbits, mpdigits} ## @end deftypefn function pp = spline (x, y) if (nargin != 2) error ("mplapack:interp:InvalidArguments", "spline expects x and y"); endif [x, y, template] = mp_interp_normalize (x, y, "spline"); pp = mp_interp_make_pp (x, y, "spline"); endfunction mplapack-interop-0.5.1/inst/interp1.m0000644000230300031750000001115715274353473016766 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = interp1 (x, y, query, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{yi} =} interp1 (@var{x}, @var{y}, @var{xi}) ## @deftypefnx {} {@var{yi} =} interp1 (@dots{}, @var{method}) ## @deftypefnx {} {@var{yi} =} interp1 (@dots{}, @var{method}, @var{extrap}) ## Interpolate one-dimensional MP data without converting the grid or query ## points to binary64. Supported methods are nearest, previous, next, ## linear, pchip, and spline. ## @end deftypefn if (nargin < 3 || nargin > 5) error ("mplapack:interp:InvalidArguments", ... "interp1 expects x, y, query, and optional method/extrapolation"); endif [x, y, template] = mp_interp_normalize (x, y, "interp1"); method = "linear"; extrapolate = false; extrapolation = []; pp_request = false; if (ischar (query)) if (nargin != 4 || ! ischar (varargin{1}) || ! strcmp (lower (varargin{1}), "pp")) error ("mplapack:interp:InvalidArguments", ... "interp1 pp form is interp1(x,y,method,\"pp\")"); endif method = lower (query); pp_request = true; endif if (pp_request) supported_pp = {"linear", "pchip", "spline"}; if (! any (strcmp (method, supported_pp))) error ("mplapack:interp:InvalidMethod", ... "this interp1 method has no pp form"); endif if (strcmp (method, "linear")) result = mp_interp_make_linear_pp (x, y); else result = mp_interp_make_pp (x, y, method); endif return; endif if (nargin >= 4) option = varargin{1}; if (! ischar (option)) extrapolation = option; extrapolate = true; else method = lower (option); if (strcmp (method, "extrap")) method = "linear"; extrapolate = true; endif endif endif if (nargin == 5) extrapolation = varargin{2}; if (ischar (extrapolation) && strcmp (lower (extrapolation), "extrap")) extrapolation = []; endif extrapolate = true; endif if (strcmp (method, "pp")) if (nargin != 4) error ("mplapack:interp:InvalidArguments", ... "interp1 pp form accepts the method without extrapolation"); endif if (nargout != 1) error ("mplapack:interp:InvalidOutput", "interp1 pp form returns one pp output"); endif result = mp_interp_make_pp (x, y, "spline"); return; endif supported = {"nearest", "previous", "next", "linear", "pchip", "spline"}; if (! any (strcmp (method, supported))) error ("mplapack:interp:InvalidMethod", "unsupported interp1 method"); endif if (strcmp (method, "pchip") || strcmp (method, "spline")) pp = mp_interp_make_pp (x, y, method); endif if (! isa (query, "mp")) query = template * 0 + query; endif output_zero = mp_interp_element (y, 1) * 0; result = repmat (output_zero, rows (query), columns (query)); last_piece = rows (x) - 1; for column = 1:columns (query) for row = 1:rows (query) point = mp_interp_element (query, row, column); outside = point < mp_interp_element (x, 1) ... || point > mp_interp_element (x, rows (x)); if (outside && ! extrapolate) value = output_zero + NaN; elseif (outside && extrapolate && ! isempty (extrapolation)) if (isa (extrapolation, "mp")) value = extrapolation; else value = output_zero + extrapolation; endif elseif (strcmp (method, "pchip") || strcmp (method, "spline")) value = ppval (pp, point); else piece = mp_interp_piece_for_interp (x, point); left = mp_interp_element (x, piece); right = mp_interp_element (x, piece + 1); left_value = mp_interp_element (y, piece); right_value = mp_interp_element (y, piece + 1); if (strcmp (method, "linear")) value = left_value + (point - left) ... * (right_value - left_value) / (right - left); elseif (strcmp (method, "nearest")) if (abs (point - left) < abs (right - point)) value = left_value; else value = right_value; endif elseif (strcmp (method, "previous")) value = left_value; else value = right_value; endif endif result = mp_interp_put (result, row, column, value); endfor endfor endfunction function piece = mp_interp_piece_for_interp (grid, point) piece = rows (grid) - 1; if (point <= mp_interp_element (grid, 1)) piece = 1; return; endif for index = 1:(rows (grid) - 1) if (point <= mp_interp_element (grid, index + 1)) piece = index; return; endif endfor endfunction mplapack-interop-0.5.1/inst/fminbnd.m0000644000230300031750000000763715274353473017031 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [argument, value, exitflag, output] = fminbnd (fun, lower, upper, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{x} =} fminbnd (@var{fun}, @var{a}, @var{b}) ## @deftypefnx {} {[@var{x}, @var{fval}, @var{exitflag}, @var{output}] =} fminbnd (@dots{}, @var{options}) ## Minimize a real scalar MP objective on an MP bounded interval. ## @end deftypefn if (nargin < 3 || nargin > 4 || ! isa (fun, "function_handle")) error ("mplapack:optimization:InvalidArguments", ... "fminbnd expects a function handle, lower bound, upper bound, and options"); endif [lower, upper, template] = mp_opt_bounds (lower, upper); if (lower > upper) temporary = lower; lower = upper; upper = temporary; endif options = mp_opt_options (varargin, template, 1, "fminbnd"); if (lower == upper) argument = lower; value = mp_opt_call (fun, argument); exitflag = 1; output = mp_opt_output (0, 1, "bounded interval is a point", ... "MP golden-section bounded search"); return; endif golden = (sqrt (mp ("5")) - mp ("1")) / mp ("2"); first = upper - golden * (upper - lower); second = lower + golden * (upper - lower); first_value = mp_opt_call (fun, first); second_value = mp_opt_call (fun, second); evaluations = 2; iterations = 0; exitflag = 0; for iteration = 1:options.max_iter iterations = iteration; center = (first + second) / mp ("2"); ## A small objective-value difference does not imply a small distance ## from the minimizer (the two samples can straddle a flat minimum). ## Require the MP coordinate bracket to satisfy TolX; TolFun remains part ## of the common option contract and is used by fminsearch. if (abs (upper - lower) <= options.tol_x * (mp ("1") + abs (center))) exitflag = 1; break; endif if (first_value <= second_value) upper = second; second = first; second_value = first_value; first = upper - golden * (upper - lower); first_value = mp_opt_call (fun, first); else lower = first; first = second; first_value = second_value; second = lower + golden * (upper - lower); second_value = mp_opt_call (fun, second); endif evaluations += 1; endfor if (first_value <= second_value) argument = first; value = first_value; else argument = second; value = second_value; endif if (exitflag == 1) message = "converged"; else message = "maximum iterations reached"; endif output = mp_opt_output (iterations, evaluations, message, ... "MP golden-section bounded search"); endfunction function [lower, upper, template] = mp_opt_bounds (lower, upper) if (isa (lower, "mp")) if (! isreal (lower) || ! isscalar (lower) || ! isfinite (lower)) error ("mplapack:optimization:InvalidBounds", ... "fminbnd bounds must be finite real mp scalars"); endif elseif (isnumeric (lower) && isreal (lower) && isscalar (lower) ... && isfinite (lower)) lower = mp (lower); else error ("mplapack:optimization:InvalidBounds", ... "fminbnd bounds must be finite real scalars"); endif template = lower; if (isa (upper, "mp")) if (! isreal (upper) || ! isscalar (upper) || ! isfinite (upper)) error ("mplapack:optimization:InvalidBounds", ... "fminbnd bounds must be finite real mp scalars"); endif elseif (isnumeric (upper) && isreal (upper) && isscalar (upper) ... && isfinite (upper)) upper = template * 0 + upper; else error ("mplapack:optimization:InvalidBounds", ... "fminbnd bounds must be finite real scalars"); endif endfunction function output = mp_opt_output (iterations, evaluations, message, algorithm) output = struct ("iterations", iterations, "funcCount", evaluations, ... "algorithm", algorithm, "message", message); endfunction mplapack-interop-0.5.1/inst/mpdigits.m0000644000230300031750000000147715274353473017230 0ustar rafaelrafael## -*- texinfo -*- ## @deftypefn {} {@var{digits} =} mpdigits () ## @deftypefnx {} {@var{digits} =} mpdigits (@var{n}) ## Return or set the default precision in complete base-10 significant digits. ## ## @code{mpdigits (@var{n})} selects ## @code{ceil (@var{n} * log2 (10))} bits for subsequently created ## @code{mp} values, with no hidden guard bits. Existing values are unchanged. ## With an output, the setter returns the resulting guaranteed digit count. ## @end deftypefn function value = mpdigits (varargin) if (nargin > 1) error ("mplapack:mpdigits:InvalidPrecision", ... "mpdigits accepts zero or one precision argument"); endif if (nargin == 0) value = __mplapack_core__ ("precision_get_digits"); else value = __mplapack_core__ ("precision_set_digits", varargin{1}); endif endfunction mplapack-interop-0.5.1/inst/mplapack_version.m0000644000230300031750000000160315274353473020734 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function info = mplapack_version () ## -*- texinfo -*- ## @deftypefn {} {@var{info} =} mplapack_version () ## Report the loaded Octave, MPLAPACK, and MPFR backend versions. ## This diagnostic does not perform numerical conversion or change the ## current arbitrary-precision default. @seealso{mp, mpbits} ## @end deftypefn if (nargin != 0) print_usage (); endif info = __mplapack_core__ ("version"); if (nargout == 0) printf ("Octave: %s\n", info.octave); printf ("MPLAPACK: %s\n", info.mplapack); printf ("Backend: %s\n", info.backend); printf ("MPFR: %s\n", info.mpfr); printf ("Probe: %s\n", info.probe_routine); printf ("Probe value: %.17g\n", info.probe_value); if (info.probe_ok) printf ("Probe result: PASS\n"); else printf ("Probe result: FAIL\n"); endif endif endfunction mplapack-interop-0.5.1/inst/interp2.m0000644000230300031750000002142615274353473016767 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function result = interp2 (varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{zi} =} interp2 (@var{x}, @var{y}, @var{z}, @var{xi}, @var{yi}) ## @deftypefnx {} {@var{zi} =} interp2 (@dots{}, @var{method}) ## @deftypefnx {} {@var{zi} =} interp2 (@dots{}, @var{method}, @var{extrap}) ## Evaluate a two-dimensional MP grid without converting coordinates or ## queries to binary64. nearest, linear, pchip, and spline are supported. ## @end deftypefn if (nargin != 3 && (nargin < 5 || nargin > 7)) error ("mplapack:interp:InvalidArguments", ... "interp2 expects z,xi,yi or x,y,z,xi,yi and options"); endif if (nargin == 3) z = varargin{1}; xi = varargin{2}; yi = varargin{3}; if (isa (z, "mp")) template = mp_interp_element (z, 1, 1); elseif (isa (xi, "mp")) template = mp_interp_element (xi, 1); elseif (isa (yi, "mp")) template = mp_interp_element (yi, 1); else error ("mplapack:interp:RequiresMp", "interp2 requires an mp input"); endif z = mp_interp2_promote (z, template); coordinate_template = real (template); x = coordinate_template * 0 + (1:columns (z)); y = transpose (coordinate_template * 0 + (1:rows (z))); options = {}; else x = varargin{1}; y = varargin{2}; z = varargin{3}; xi = varargin{4}; yi = varargin{5}; template = mp_interp2_find_template ({x, y, z, xi, yi}); coordinate_template = real (template); x = mp_interp2_promote (x, coordinate_template); y = mp_interp2_promote (y, coordinate_template); z = mp_interp2_promote (z, template); options = varargin(6:end); endif if (nargin == 3) template = mp_interp_element (z, 1, 1); xi = mp_interp2_promote (xi, template); yi = mp_interp2_promote (yi, template); endif if (! isa (xi, "mp")), xi = template * 0 + xi; endif if (! isa (yi, "mp")), yi = template * 0 + yi; endif if (rows (z) == 0 || columns (z) == 0) error ("mplapack:interp:InvalidInput", "interp2 data must be nonempty"); endif [x, y, z] = mp_interp2_axes (x, y, z, coordinate_template); method = "linear"; extrapolate = false; extrapolation = []; if (numel (options) >= 1) if (! ischar (options{1})) extrapolation = options{1}; extrapolate = true; else method = lower (options{1}); endif endif if (numel (options) == 2) extrapolation = options{2}; if (ischar (extrapolation) && strcmp (lower (extrapolation), "extrap")) extrapolation = []; endif extrapolate = true; endif if (! any (strcmp (method, {"nearest", "linear", "pchip", "spline"}))) error ("mplapack:interp:InvalidMethod", "unsupported interp2 method"); endif if (numel (xi) != numel (yi) && numel (xi) != 1 && numel (yi) != 1) error ("mplapack:interp:DimensionMismatch", ... "interp2 query grids must have matching shapes"); endif output_rows = max (rows (xi), rows (yi)); output_columns = max (columns (xi), columns (yi)); if (numel (xi) == 1 && numel (yi) > 1) output_rows = rows (yi); output_columns = columns (yi); elseif (numel (yi) == 1 && numel (xi) > 1) output_rows = rows (xi); output_columns = columns (xi); endif zero = mp_interp_element (z, 1, 1) * 0; result = repmat (zero, output_rows, output_columns); for column = 1:output_columns for row = 1:output_rows qx = mp_interp2_query (xi, row, column); qy = mp_interp2_query (yi, row, column); outside = qx < mp_interp_element (x, 1) ... || qx > mp_interp_element (x, rows (x)) ... || qy < mp_interp_element (y, 1) ... || qy > mp_interp_element (y, rows (y)); if (outside && ! extrapolate) value = zero + NaN; elseif (outside && extrapolate && ! isempty (extrapolation)) if (isa (extrapolation, "mp")) value = extrapolation; else value = zero + extrapolation; endif elseif (strcmp (method, "nearest")) ix = mp_interp2_nearest_axis (x, qx); iy = mp_interp2_nearest_axis (y, qy); value = mp_interp_element (z, iy, ix); elseif (strcmp (method, "linear")) value = mp_interp2_linear_value (x, y, z, qx, qy); else value = mp_interp2_tensor_value (x, y, z, qx, qy, method); endif result = mp_interp_put (result, row, column, value); endfor endfor endfunction function template = mp_interp2_find_template (values) template = []; for index = 1:numel (values) if (isa (values{index}, "mp")) template = mp_interp_element (values{index}, 1); return; endif endfor error ("mplapack:interp:RequiresMp", "interp2 requires an mp grid or data value"); endfunction function result = mp_interp2_promote (value, template) if (isa (value, "mp")) result = value; else result = template * 0 + value; endif endfunction function [x_out, y_out, z_out] = mp_interp2_axes (x, y, z, template) rows_z = rows (z); columns_z = columns (z); if (rows (x) == 1 || columns (x) == 1) if (numel (x) != columns_z) error ("mplapack:interp:DimensionMismatch", "x axis length does not match z"); endif if (rows (x) == 1), x_out = transpose (x); else, x_out = x; endif elseif (rows (x) == rows_z && columns (x) == columns_z) x_out = repmat (template * 0, columns_z, 1); for column = 1:columns_z x_out = mp_interp_put (x_out, column, 1, mp_interp_element (x, 1, column)); endfor else error ("mplapack:interp:DimensionMismatch", "x grid shape does not match z"); endif if (rows (y) == 1 || columns (y) == 1) if (numel (y) != rows_z) error ("mplapack:interp:DimensionMismatch", "y axis length does not match z"); endif if (rows (y) == 1), y_out = transpose (y); else, y_out = y; endif elseif (rows (y) == rows_z && columns (y) == columns_z) y_out = repmat (template * 0, rows_z, 1); for row = 1:rows_z y_out = mp_interp_put (y_out, row, 1, mp_interp_element (y, row, 1)); endfor else error ("mplapack:interp:DimensionMismatch", "y grid shape does not match z"); endif for index = 1:(rows (x_out) - 1) if (mp_interp_element (x_out, index + 1) == mp_interp_element (x_out, index)) error ("mplapack:interp:RepeatedGrid", "x grid points must be distinct"); endif endfor for index = 1:(rows (y_out) - 1) if (mp_interp_element (y_out, index + 1) == mp_interp_element (y_out, index)) error ("mplapack:interp:RepeatedGrid", "y grid points must be distinct"); endif endfor if (mp_interp_element (x_out, 2) < mp_interp_element (x_out, 1)) x_out = flipud (x_out); z = fliplr (z); endif if (mp_interp_element (y_out, 2) < mp_interp_element (y_out, 1)) y_out = flipud (y_out); z = flipud (z); endif z_out = z; endfunction function point = mp_interp2_query (value, row, column) if (numel (value) == 1) point = mp_interp_element (value, 1); else point = mp_interp_element (value, row, column); endif endfunction function index = mp_interp2_nearest_axis (axis, point) index = 1; best = abs (point - mp_interp_element (axis, 1)); for candidate = 2:numel (axis) distance = abs (point - mp_interp_element (axis, candidate)); if (distance < best) index = candidate; best = distance; endif endfor endfunction function value = mp_interp2_linear_value (x, y, z, qx, qy) ix = mp_interp2_piece (x, qx); iy = mp_interp2_piece (y, qy); x0 = mp_interp_element (x, ix); x1 = mp_interp_element (x, ix + 1); y0 = mp_interp_element (y, iy); y1 = mp_interp_element (y, iy + 1); tx = (qx - x0) / (x1 - x0); ty = (qy - y0) / (y1 - y0); z00 = mp_interp_element (z, iy, ix); z01 = mp_interp_element (z, iy, ix + 1); z10 = mp_interp_element (z, iy + 1, ix); z11 = mp_interp_element (z, iy + 1, ix + 1); value = (1 - ty) * ((1 - tx) * z00 + tx * z01) ... + ty * ((1 - tx) * z10 + tx * z11); endfunction function value = mp_interp2_tensor_value (x, y, z, qx, qy, method) intermediate = repmat (mp_interp_element (z, 1, 1) * 0, rows (y), 1); for row = 1:rows (y) row_values = repmat (mp_interp_element (z, 1, 1) * 0, rows (x), 1); for column = 1:rows (x) row_values = mp_interp_put (row_values, column, 1, ... mp_interp_element (z, row, column)); endfor row_pp = mp_interp_make_pp (x, row_values, method); intermediate = mp_interp_put (intermediate, row, 1, ppval (row_pp, qx)); endfor result_pp = mp_interp_make_pp (y, intermediate, method); value = ppval (result_pp, qy); endfunction function piece = mp_interp2_piece (axis, point) piece = numel (axis) - 1; if (point <= mp_interp_element (axis, 1)), piece = 1; return; endif for index = 1:(numel (axis) - 1) if (point <= mp_interp_element (axis, index + 1)) piece = index; return; endif endfor endfunction mplapack-interop-0.5.1/inst/quadgk.m0000644000230300031750000000614615274353473016662 0ustar rafaelrafael## SPDX-License-Identifier: BSD-2-Clause function [result, error_estimate] = quadgk (fun, a, b, varargin) ## -*- texinfo -*- ## @deftypefn {} {@var{q} =} quadgk (@var{fun}, @var{a}, @var{b}) ## @deftypefnx {} {[@var{q}, @var{err}] =} quadgk (@dots{}, @var{options}) ## Adaptive arbitrary-precision one-dimensional quadrature. This ## implementation uses MPFR/MPC tanh-sinh quadrature, a robust ## double-exponential method compatible with endpoint singularities. ## @end deftypefn if (nargin < 3 || ! isa (fun, "function_handle")) error ("mplapack:quad:InvalidArguments", ... "quadgk expects a function handle and two endpoints"); endif [a, b, template] = mp_quad_endpoints (a, b); options = mp_quad_options (varargin, template); if (! isempty (options.waypoints) && (isinf (a) || isinf (b))) error ("mplapack:quad:Unsupported", ... "Waypoints with an infinite endpoint are not supported"); endif if (a == b) result = template * 0; error_estimate = template * 0; return; endif points = {a}; if (! isempty (options.waypoints)) for index = 1:numel (options.waypoints) point = options.waypoints{index}; if (point > a && point < b), points{end + 1} = point; endif endfor endif points{end + 1} = b; points = mp_quad_sort_points (points); result = []; error_estimate = []; for index = 1:(numel (points) - 1) [piece, piece_error] = mp_quad_tanh_sinh (fun, points{index}, ... points{index + 1}, options); if (isempty (result)) result = piece; error_estimate = piece_error; else result += piece; error_estimate += piece_error; endif endfor endfunction function [left, right, template] = mp_quad_endpoints (a, b) if (isa (a, "mp")) if (! isreal (a) || ! isscalar (a)), error ("mplapack:quad:InvalidInterval", ... "endpoints must be real scalars"); endif left = a; elseif (isnumeric (a) && isreal (a) && isscalar (a)) left = mp (a); else error ("mplapack:quad:InvalidInterval", "endpoints must be real scalars"); endif template = left; if (isa (b, "mp")) if (! isreal (b) || ! isscalar (b)), error ("mplapack:quad:InvalidInterval", ... "endpoints must be real scalars"); endif right = b; elseif (isnumeric (b) && isreal (b) && isscalar (b)) right = template * 0 + b; else error ("mplapack:quad:InvalidInterval", "endpoints must be real scalars"); endif if (isnan (left) || isnan (right)) error ("mplapack:quad:InvalidInterval", "endpoints must not be NaN"); endif endfunction function points = mp_quad_sort_points (points) ## Insertion sort keeps waypoint ordering in MP comparisons rather than ## converting the grid to builtin doubles. for index = 2:numel (points) candidate = points{index}; position = index - 1; while (position >= 1 && points{position} > candidate) points{position + 1} = points{position}; position -= 1; endwhile points{position + 1} = candidate; endfor endfunction mplapack-interop-0.5.1/docs/0000755000230300031750000000000015274353473015174 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/matrix-multiplication.md0000644000230300031750000000537115274353473022063 0ustar rafaelrafael# Scope M08 implements dense real `mp` multiplication through the installed MPLAPACK MPFR reference `Rgemm` routine. Scalar `mtimes` and matrix/scalar scaling use the native MPFR scalar path. M09 adds `mldivide` through `Rgesv`. # MPLAPACK precision boundary The MPLAPACK MPFR backend follows the uniform-precision calling contract provided by `MplapackMpfrPrecisionScope` in the installed `mplapack_mpfr_precision.h` header. One invocation has one precision `p`: the current-thread MPFR default and every participating `REAL` object are `p` bits. Mixed-precision arrays are never passed to MPLAPACK. The upstream contract implementation used for M08 is commit `1cf03d1a1aa2afecde5f1840fbe9663ecfc31e57`. The caller, rather than MPLAPACK, selects the operation precision. # Operation precision and promotion For two `mp` operands, `p = max(lhs precision, rhs precision)`. Existing matrices are immutable, so operation-owned column-major copies are promoted to `p` before entering the precision scope. Promotion uses direct MPFR copying and preserves the stored value exactly. A raw real double matrix, when accepted as a mixed operand, is converted directly from its incoming binary64 values at the other `mp` operand's precision. The project construction default is not used to select `p`. The temporary scope restores the caller's current-thread default after success and errors. # Rgemm call Nondegenerate matrix products use `Rgemm("N", "N", m, n, k, alpha, A, lda, B, ldb, beta, C, ldc)` with exact MPFR `alpha = 1` and `beta = 0`. M07's contiguous column-major `mpfr_class` storage is passed directly as `REAL *`; there is no packing or transpose. Dimensions and leading dimensions use checked MPLAPACK integer conversions. Before the call, a native contract checker verifies the TLS precision, matrix storage precisions, and `alpha`/`beta` precision. It only accepts a match and never repairs a mismatch. # Shapes and ownership Dimension compatibility is checked before allocation. Empty products are handled without unsafe zero-size backend calls and retain `p` metadata. A `1x1` result is normalized to the existing scalar payload; all other results are one native dense matrix payload. Result storage is independent of both inputs, and public inputs remain unchanged. # Scalar scaling `mp` scalar/matrix scaling is native MPFR element scaling at `max(matrix precision, scalar precision)`. Scaling by a real double uses the matrix precision and direct binary64-to-MPFR conversion. No double or text arithmetic fallback is used. # Non-goals M08 does not implement matrix indexing, element-wise matrix operators, matrix conversion/formatting, transpose-aware GEMM, complex matrices, sparse matrices. The optimized/threaded MPFR backend is not a dependency of this path. mplapack-interop-0.5.1/docs/todo/0000755000230300031750000000000015274353473016141 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/todo/T14-fminunc.md0000644000230300031750000000255715274353473020501 0ustar rafaelrafael# T14 TODO — `fminunc` ## Scope Unconstrained arbitrary-precision `fminunc` for scalar real MP objectives. ## Why deferred T14 closes bounded golden-section and Nelder-Mead optimization. It does not freeze gradient/Jacobian options, finite-difference steps, trust-region or line-search behavior, termination metadata, or complex-objective semantics. ## Current evidence `fminbnd` and `fminsearch` pass quadratic, Rosenbrock, badly scaled, and high-precision objective tests. `fminunc` is rejected by the firewall rather than delegated to builtin binary64 optimization. ## Required dependency/algorithm An MPFR/MPC gradient/Jacobian path with p-aware finite differences and a reviewed trust-region or line-search algorithm; user callbacks must receive and return native MP values. ## Public API target Octave-compatible real `fminunc` with documented options, gradients, Jacobian/output metadata, and explicit complex policy. ## Precision requirements Coordinates, objective/gradient values, steps, norms, tolerances, and stopping tests use one selected MPFR/MPC precision without binary64 fallback. ## Test requirements Convex/nonconvex/scaled problems, analytic and finite-difference gradients, termination/options, failure cases, 1024/2048-bit canaries, ambient scope, and sanitizers. ## Re-entry milestone Future optimization milestone after T14; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T03-polyfit-polyeig.md0000644000230300031750000000233115274353473022162 0ustar rafaelrafael# T03 TODO — `polyfit` and `polyeig` ## Scope Arbitrary-precision polynomial fitting and polynomial eigenvalue problems. ## Why deferred Neither Octave's weighted/optional-output `polyfit` contract nor the polyeig coefficient layout and conditioning policy was frozen in T03. ## Current evidence `polyval`, `polyvalm`, `roots`, `poly`, convolution, calculus helpers, and `compan` pass the T03 wall. The deferred calls are rejected rather than using binary64 fitting or eigensolvers. ## Required dependency/algorithm MPFR/MPC QR/SVD least-squares fitting with scaling and covariance outputs; for `polyeig`, a reviewed companion-linearization algorithm with explicit singular/infinite-eigenvalue semantics. ## Public API target Octave-compatible `polyfit` and `polyeig` for dense MP data. ## Precision requirements Coefficient scaling, residuals, rank decisions, eigenvalues, and optional outputs must remain at one selected MPFR/MPC precision. ## Test requirements Exact/noisy fits, rank-deficient Vandermonde systems, complex coefficients, multiple polynomial degrees, infinite eigenvalues, 1024/2048-bit canaries, and sanitizer coverage. ## Re-entry milestone Future polynomial milestone after T03; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T12-complex-nonlinear-solvers.md0000644000230300031750000000232615274353473024157 0ustar rafaelrafael# T12 TODO — complex nonlinear callbacks ## Scope Complex `fzero`/`fsolve` callback and solver semantics for `mp`/MPC values. ## Why deferred T12 intentionally closes only real scalar/root and real-system contracts. Octave's complex `fzero` restrictions, complex `fsolve` Jacobian layout, and convergence policy were not guessed. ## Current evidence Real MP callbacks, Newton/backtracking, finite-difference Jacobians, and precision-aware tolerances pass. Complex callback results are rejected by an explicit boundary. ## Required dependency/algorithm Native MPC residual/Jacobian arithmetic, complex finite differences or user Jacobians, and a reviewed complex convergence/line-search policy. ## Public API target Octave-compatible complex nonlinear solves with native MPC callbacks and explicit output metadata. ## Precision requirements Residuals, Jacobians, steps, stopping tests, and callbacks use one operation precision; no binary64 fallback is permitted. ## Test requirements Complex roots/systems, user Jacobians, singular Jacobians, branch-sensitive callbacks, high precision, ambient scope, rejection, and sanitizers. ## Re-entry milestone Future nonlinear-solvers milestone after T12; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T08-volume-graphics-after-ND.md0000644000230300031750000000233015274353473023535 0ustar rafaelrafael# T08 TODO — volume graphics after N-D storage ## Scope `slice`, `isosurface`, and related volume/N-D graphics APIs. ## Why deferred The public `mp` contract is currently dense and two-dimensional. Implementing volume graphics before defining N-D storage would create an inconsistent shape and conversion boundary. ## Current evidence `plot3`, `scatter3`, `mesh`, `surf`, `contour3`, `meshc`, `surfc`, and `waterfall` pass with final-boundary conversion. Volume forms are firewall- rejected and no numerical data path converts through binary64. ## Required dependency/algorithm First establish N-D MPFR/MPC storage and indexing; then define an explicit final visualization conversion for each volume API. ## Public API target Octave-compatible volume graphics using MP data with conversion confined to the final graphics boundary. ## Precision requirements All field construction remains MPFR/MPC; only values consumed by the host graphics routine may become builtin doubles. ## Test requirements N-D shapes, slices/isosurfaces, handles and property forwarding, range-loss behavior, high precision, firewall, and sanitizers. ## Re-entry milestone After N-D storage and graphics boundary milestones; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T08-meshgrid.md0000644000230300031750000000224315274353473020637 0ustar rafaelrafael# T08 TODO — `meshgrid` boundary audit ## Scope An MP-aware `meshgrid` wrapper for two-dimensional coordinate grids. ## Why deferred T08 closes the graphics-call boundary for vector and matrix data but does not add a public MP `meshgrid` method or freeze its N-D output forms. ## Current evidence The 3-D graphics wrappers pass vector/matrix fixtures and convert only at the final graphics call. `meshgrid` with MP arguments remains outside that surface and must not silently construct through binary64. ## Required dependency/algorithm Native MPFR/MPC repetition and shape construction using the existing dense column-major storage; no backend LAPACK dependency is needed. ## Public API target Two-dimensional real/complex `meshgrid` outputs with Octave-compatible input forms and precision propagation. ## Precision requirements Coordinates and repeated outputs retain the selected MPFR/MPC precision. ## Test requirements Vector/scalar forms, descending and complex coordinates, output shapes, precision, graphics composition, and firewall/sanitizer coverage. ## Re-entry milestone Future graphics/structure milestone after N-D policy review; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T06-special-functions.md0000644000230300031750000000664415274353473022472 0ustar rafaelrafael# T06 TODO — remaining special-function families This document is the re-entry record for every deferred `TODO-T06-*` entry in `docs/special-functions-backend-matrix.md`. ## Common fields - **Scope:** expose the named Octave special-function family for dense MP values. - **Why deferred:** a backend primitive alone does not establish Octave argument order, normalization, tails, output count, domains, branches, or complex behavior. - **Current evidence:** T05 `gamma`, `gammaln`, `lgamma`, `erf`, and `erfc` are closed; all other listed families remain firewall-rejected and have no binary64 fallback. - **Required dependency/algorithm:** use the frozen gmpfrxx/MPFR primitive where its semantics match, or add a reviewed arbitrary-precision algorithm; raw double implementations are forbidden. - **Public API target:** Octave-compatible wrapper with explicit real/complex and domain semantics for each family. - **Precision requirements:** one-operation/one-precision MPFR/MPC scope, p-aware stopping/error estimates, and 1024/2048-bit canaries where useful. - **Test requirements:** signature/output count, domains, poles, NaN/Inf, signed zero, branch cuts, high precision, ambient scope, and sanitizers. - **Re-entry milestone:** a future special-functions milestone after T06; none is part of T00–T14. ## Family-specific contracts ### `psi` — `TODO-T06-PSI` Map Octave's `psi` signatures to the native `digamma` wrapper, including integer/order forms if exposed by Octave, real poles, complex policy, and output precision. ### `polygamma` — `TODO-T06-POLYGAMMA` Select a reviewed arbitrary-precision recurrence/asymptotic or backend dependency for arbitrary order and validate poles and complex arguments. ### `beta` — `TODO-T06-BETA` Define public domain/pole behavior and cancellation-safe native evaluation for the available `mpfr_beta` primitive. ### `betaln` — `TODO-T06-BETALN` Use precision-matched log-gamma identities with tests for cancellation, negative arguments, poles, and Octave output conventions. ### `gammainc` — `TODO-T06-GAMMAINC` Map `gamma_inc` to normalized lower/upper incomplete gamma semantics and Octave's `tail` option; do not equate names without these tests. ### `betainc` — `TODO-T06-BETAINC` Choose and validate a native arbitrary-precision incomplete-beta algorithm, including complement and endpoint stability. ### `erfinv`/`erfcinv` — `TODO-T06-INV-ERF` Add a reviewed inverse-error algorithm with endpoint, signed-domain, and complex-domain policy tests. ### `erfcx` — `TODO-T06-ERFCX` Add a region-partitioned scaled-error algorithm stable in both tails. ### `expint` — `TODO-T06-EXPINT` Map MPFR `eint` to Octave's argument, branch, and domain semantics. ### `zeta` — `TODO-T06-ZETA` Define a public Octave mapping and real/complex domain contract for `zeta` and `zeta_ui`. ### Bessel J/Y — `TODO-T06-BESSEL-J`, `TODO-T06-BESSEL-Y` Extend the available order-0/order-1 primitives or select a reviewed general-order arbitrary-precision algorithm. ### Bessel I/K — `TODO-T06-BESSEL-I`, `TODO-T06-BESSEL-K` Provide and validate arbitrary-precision modified-Bessel algorithms; no binary64 bridge is acceptable. ### Hankel — `TODO-T06-HANKEL` Define general J/Y composition and complex branch-cut behavior. ### Airy — `TODO-T06-AIRY` Define whether Ai-only backend support is sufficient; otherwise implement the full Octave output/Bi contract at arbitrary precision. mplapack-interop-0.5.1/docs/todo/T11-ND-interpolation.md0000644000230300031750000000252115274353473022214 0ustar rafaelrafael# T11 TODO — N-D interpolation ## Scope `interp3`, `interpn`, and general N-D grid/query interpolation. ## Why deferred The current public `mp` contract is dense and two-dimensional. N-D interpolation needs an explicit N-D storage, indexing, mesh-grid, singleton expansion, and query-shape contract before it can be implemented safely. ## Current evidence T11 `interp2` passes vector and mesh-style grids, descending axes, complex values, extrapolation, and MP queries. N-D calls are firewall-rejected and do not fall through to builtin binary64 interpolation. ## Required dependency/algorithm N-D MPFR/MPC storage and shape operations, plus tensor-product or simplex interpolation with native p-aware extrapolation and error behavior. ## Public API target Octave-compatible `interp3`/`interpn` forms, grid orientations, query shapes, methods, extrapolation, and output precision. ## Precision requirements All grid coordinates, queries, weights, coefficients, and results use one operation precision with ambient-precision restoration. ## Test requirements Vector/matrix/N-D grids, descending/repeated axes, nearest/linear/pchip/spline where supported, real/complex values, extrapolation, shape errors, 1024/2048-bit canaries, and sanitizers. ## Re-entry milestone Future N-D storage/interpolation milestone after T11; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T02-funm.md0000644000230300031750000000224515274353473017776 0ustar rafaelrafael# T02 TODO — `funm` ## Scope General matrix function `funm(A, f)` for arbitrary-precision `mp` matrices. ## Why deferred The T02 matrix-function core closes `expm`, `logm`, and `sqrtm`; it does not define callback precision, scalar-to-complex promotion, branch handling, or failure behavior for a user-supplied function. ## Current evidence The Schur backend and triangular recurrences used by T02 pass real/complex precision tests. `funm` is not exposed and is blocked by the firewall. ## Required dependency/algorithm A reviewed Schur/Parlett or blocked-Schur algorithm with MPFR/MPC callback evaluation and a documented treatment of repeated eigenvalues. ## Public API target Octave-compatible `funm` with MP scalar callback inputs and MP/MPC output. ## Precision requirements All Schur, recurrence, callback, stopping, and residual calculations use the selected operation precision; no builtin binary64 callback is permitted. ## Test requirements Diagonal, repeated, defective, real-to-complex, branch-sensitive, high- precision, ambient-scope, rejection, and sanitizer tests. ## Re-entry milestone Future matrix-functions milestone after T02; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T00-schur-optional-ordering.md0000644000230300031750000000234515274353473023606 0ustar rafaelrafael# T00 TODO — optional Schur/QZ ordering helpers ## Scope Optional eigenvalue ordering and selector-callback forms for `schur`/`qz`. ## Why deferred The closed T00 surface validates decomposition and reconstruction, but did not freeze Octave's selector syntax, callback invocation, reordering failure semantics, or generalized-pair ordering contract. ## Current evidence Real and complex `hess`, `balance`, `schur`, and `qz` reconstruction passed at the accepted precision canaries. The compatibility firewall rejects the unimplemented optional forms. ## Required dependency/algorithm MPLAPACK Schur reordering drivers or a reviewed arbitrary-precision selector and swap algorithm, with MPFR/MPC-aware separation tests. ## Public API target Octave-compatible ordered `schur`/`qz` outputs and selector forms without binary64 conversion. ## Precision requirements One operation/one MPFR or MPC precision, ambient-scope restoration, and 1024/2048-bit ordering canaries. ## Test requirements Separated real and complex eigenvalue fixtures, repeated/clustered values, selector callbacks, reconstruction, failure status, and sanitizer coverage. ## Re-entry milestone Future T-series milestone after the dense T00 core; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T10-matrix-valued-pp.md0000644000230300031750000000231015274353473022220 0ustar rafaelrafael# T10 TODO — matrix-valued piecewise polynomials ## Scope Matrix-valued `y`/coefficient outputs for `interp1`, `pchip`, `spline`, and the PP helper family. ## Why deferred T10 deliberately freezes scalar-output PP layout and does not define the coefficient ordering, output shape, or complex matrix-valued callback contract. ## Current evidence Scalar-output `interp1`, `pchip`, `spline`, `ppval`, `mkpp`, `unmkpp`, `ppder`, and `ppint` pass with MPFR/MPC values. Matrix-valued PP forms remain firewall-rejected. ## Required dependency/algorithm Extend the native PP schema and Horner engine with explicit multidimensional shape metadata; no conversion to double is allowed. ## Public API target Octave-compatible matrix-valued PP construction, evaluation, differentiation, and integration. ## Precision requirements Every coefficient and result retains the selected MPFR/MPC precision and ambient precision is restored after callbacks/operations. ## Test requirements Vector-, matrix-, and complex-valued data, all methods, extrapolation, PP round-trip, derivative/integral shape, 1024/2048-bit cases, and sanitizers. ## Re-entry milestone Future interpolation milestone after T10; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T04-ismembertol.md0000644000230300031750000000216515274353473021356 0ustar rafaelrafael# T04 TODO — `ismembertol` ## Scope Tolerance-based set membership for real and complex arbitrary-precision values. ## Why deferred The exact T04 set contract does not define Octave's `ByRows`, `OutputAllIndices`, absolute/relative tolerance, NaN, signed-zero, or complex-distance policy. ## Current evidence `unique`, `union`, `intersect`, `setdiff`, `setxor`, and `ismember` pass exact real/complex edge cases. `ismembertol` is explicitly rejected. ## Required dependency/algorithm Native MPFR/MPC distance and bucket/search logic with an overflow-safe, precision-aware tolerance comparison; no double hash key. ## Public API target Octave-compatible `ismembertol` forms, including row and index outputs. ## Precision requirements Tolerance and all distance comparisons use the selected operation precision, with stored precision preserved and ambient precision restored. ## Test requirements Absolute/relative tolerance boundaries, rows, duplicates, NaN/Inf, signed-zero, complex distance, high precision, and sanitizer tests. ## Re-entry milestone Future exact-set extension milestone after T04; not part of T00–T14. mplapack-interop-0.5.1/docs/todo/T13-array-valued-quadrature.md0000644000230300031750000000230015274353473023572 0ustar rafaelrafael# T13 TODO — array-valued quadrature ## Scope `integral`/`quadgk` with `ArrayValued` callbacks and shape-preserving outputs. ## Why deferred T13 closes scalar MP callbacks only. It does not define vector/matrix accumulation, output shape validation, mixed real/complex arrays, or componentwise error estimates. ## Current evidence Finite, infinite, waypoint, endpoint-singular, complex scalar integrals and MP tolerances pass. `ArrayValued` is explicitly rejected; it is not routed to Octave's binary64 quadrature. ## Required dependency/algorithm Shape-aware native MPFR/MPC tanh-sinh accumulation with per-component or norm-based error control and a documented callback contract. ## Public API target Octave-compatible array-valued callbacks with stable output shape and arbitrary-precision results. ## Precision requirements Nodes, weights, callback values, accumulators, tolerances, and error estimates remain at one selected MPFR/MPC precision. ## Test requirements Vector/matrix real and complex callbacks, shape mismatch, waypoints, infinite/endpoints, cancellation, 1024/2048-bit canaries, and sanitizers. ## Re-entry milestone Future quadrature milestone after T13; not part of T00–T14. mplapack-interop-0.5.1/docs/rank-deficient-solve.md0000644000230300031750000000353415274353473021534 0ustar rafaelrafael# Dense MPFR rank-deficient rectangular solve M16 extends rectangular dense real `mp` left division to rank-deficient systems. For `A` of size `m x n` and `B` of size `m x nrhs`, `A \ B` returns an `n x nrhs` minimum-norm least-squares solution. This includes the full-column-rank overdetermined case (`m >= n`) and full-row-rank or rank-deficient underdetermined cases (`m < n`). The public rectangular path uses the installed MPLAPACK MPFR `Rgelss` driver. `Rgelsy` was audited but rejected because its pinned MPFR path misclassified an exact rank-one fixture at 512 bits; `Rgelsd` passed but adds unneeded divide-and-conquer and integer-workspace complexity. `Rgelss` provides SVD-based rank determination and the minimum-norm solution. Before each call, the binding derives `p_op` from the operands, copies `A` and a `max(m,n) x nrhs` padded `B` into operation-owned storage, and creates `RCOND`, singular values, and `WORK` at `p_op`. A `MplapackMpfrPrecisionScope(p_op)` surrounds both the workspace query and the actual call. No mixed-precision MPLAPACK invocation is issued and public inputs are never overwritten. The default rank threshold is `Rlamch_mpfr("E")` at `p_op`, not a binary64 constant or the ambient `mpbits()` setting. For `m != n`, rank deficiency is supported and the reported rank remains an internal diagnostic. `info > 0` is a deterministic convergence error and `info < 0` is an internal argument error. Square systems continue to use M09 `Rgesv`, including their existing singular behavior; scalar division is unchanged. The effective numerical rank can change with `p_op`. A direction below the machine epsilon at one operand precision can be resolved at a higher precision. Rank tolerance is not a public argument in M16. Rank-revealing public APIs, singular values, condition estimates, complex and sparse systems remain future work. mplapack-interop-0.5.1/docs/lu.md0000644000230300031750000000375215274353473016145 0ustar rafaelrafael# Dense real LU factorization M21 adds dense real arbitrary-precision LU factorization through the installed MPLAPACK MPFR `Rgetrf` routine. `Rgetrf` uses partial row pivoting; it overwrites an operation-owned copy, so the public `mp` input is never modified. The supported forms are: ```octave Y = lu (A) [L, U] = lu (A) [L, U, P] = lu (A) [L, U, p] = lu (A, "vector") ``` `A` may be square, tall, or wide. LU uses the stored precision of `A`; the current `mpbits()` default is not consulted for an existing value. Every returned `mp` factor has the same precision as `A`, and the operation restores the caller's current precision after success or failure. The one-output form returns the packed LAPACK factorization with the same shape as `A`: the upper trapezoid contains `U`, the strict lower trapezoid contains the multipliers of unit-diagonal `L`, and the row permutation is not encoded in the result. The two-output form absorbs the row permutation into the returned L-like factor, so its defining relation is: ```text A = L * U ``` The two-output `L` therefore need not be triangular when pivoting occurs. For the canonical three-output form: ```text P * A = L * U ``` where `P` is a builtin double row-permutation matrix. For the vector form, `p` is a builtin double **column** vector of 1-based row indices and: ```text A (p, :) = L * U ``` For `m x n` input and `k = min (m,n)`, canonical three-output factors have shapes `L: m x k`, `U: k x n`, and `P: m x m`. Singular matrices are still factorized: a positive `Rgetrf` `INFO` is retained internally and does not turn `lu` into a solve-style error. A zero diagonal in `U` means the factors do not define an inverse, not that factor extraction failed. M21's original scope was dense real values. Sparse/UMFPACK threshold and Q/R outputs, `luupdate`, rank, condition estimation, and triangular-solve optimizations remain outside M21. N01 separately adds public dense real and complex `det` and `inv` through the corresponding GETRF/GETRI paths. mplapack-interop-0.5.1/docs/binary-redistribution-licenses.md0000644000230300031750000000364615274353473023662 0ustar rafaelrafael# Binary redistribution license inventory D01R1 records source and runtime license facts for future binary work. This is not legal advice and does not perform the package-specific legal review owned by B01–B05/PPA milestones. | Component | Source/license fact | Planned handling | |---|---|---| | `mplapack-interop` | BSD 2-Clause (`COPYING`, `LICENSE`) | Include license and notices in every artifact | | MPLAPACK | 2-clause BSD-style terms plus original LAPACK/BLAS notices | Include `COPYING` and all required upstream notices | | gmpfrxx_mkII | BSD 2-Clause | Include exact source/license correspondence | | GMP | dual GPL-2+ or LGPL-3+ terms stated by the release headers | Final bundling review and corresponding notices required | | MPFR | LGPL-3+ terms stated by the release headers | Final bundling review and corresponding notices required | | MPC | LGPL-3+ terms stated by the release headers | Final bundling review and corresponding notices required | | libstdc++/libgcc or libc++ | toolchain/platform runtime terms | B-target toolchain review; do not assume one universal closure | | Octave/system C libraries | host/platform dependencies | Do not bundle Octave or base system C libraries in this package | ## Corresponding source Each binary manifest points to the exact corresponding source release by: ```text component name version repository URL commit/tag source archive filename archive SHA256 ``` The package artifact contains the project licenses and dependency notices that the final B-target review approves. A future binary release must not replace these with a generic “built from source” statement. ## Bundle boundary The architecture permits package-local bundling of the MPLAPACK MPFR runtime, MPC/MPFR/GMP runtime closure, and any gmpfrxx provider that is actually required. The final target milestone decides exact files and license text. It does not permit global installation or an unrecorded system fallback. mplapack-interop-0.5.1/docs/svd-verification.md0000644000230300031750000001470015274353473020774 0ustar rafaelrafael# Verified SVD baselines This document describes the finite-arithmetic verification layer used by the SVT example suite. It defines what the result means and what it does not mean. The code is under `examples/svd_tiers/private/`; no verifier is installed as a public package function. ## Boundary and precision roles The checker receives the actual `mp` target and the actual factors returned by the public `svd` call. It does not invoke `svd` to manufacture a reference factorization. A separate high-precision reference is useful for diagnostics, but reference agreement is not a certificate. Inputs, factors, interval endpoints, and replay snapshots stay in MPFR/MPC arithmetic. Exact widening is used only to evaluate a stored result at the declared evaluation precision. No value is converted to binary64 on a mathematical or acceptance path. `double` conversion is reserved for optional presentation plots. The private interval layer checks its supported contract before operating: ```text 64 <= q <= 4096 finite MPFR/MPC point data valid matrix dimensions and compatible shapes domain/range preconditions for every elementary operation ``` Invalid data fails closed. A failed sufficient inequality is classified as `INCONCLUSIVE`, not as proof that the input is singular or that no factor exists. ## V1A: all singular values For an economy factorization ```text A = U*S*V' ``` the implementation forms interval enclosures for the target, the two Gram defects, and the reconstruction defect. The method ID is `svt_polar_weyl_v1`. A conservative factor perturbation radius `epsilon` is then applied to each diagonal singular value: ```text max(0, s_j - epsilon) <= sigma_j(A) <= s_j + epsilon ``` The calculation binds the enclosure to the same `A`, `U`, `S`, and `V` that were measured. It checks finite data, economy shapes, diagonal/nonnegative/ descending `S`, and valid Gram defects before making the inclusion claim. The singular-value target is resolved only when the lower endpoint is positive. For a positive value, the width is compared relatively. A zero or unresolved component uses the declared scale-aware absolute rule instead. A certified interval may be broad; `CERTIFIED` and `meets_accuracy_target` are separate. ## V1B: cluster projectors For a declared cluster of positive singular indices, the checker applies a signed dilation argument. It considers both `+sigma` and `-sigma` and, for a rectangular target, the structural zero eigenvalues of the dilation. It does not divide by an internal cluster gap. Thus a repeated target group is valid when the external signed-dilation separation is sufficient. The method ID is `svt_dilation_projector_v1`. It returns separate left/right projector radii and the certified external lower gap. A permutation or a common orthogonal rotation inside a repeated group leaves the claim valid. A rotation that mixes a target group with an exterior value must not receive a certified result. The full-space square branch is explicit: when the selected cluster exhausts the dilation complement, the complementary bound is the zero interval rather than an artificial division by zero. ## V2: compatible factor boxes The method ID is `svt_dilation_factor_boxes_v1`. For positive, separated, simple singular pairs it combines a factorization residual with the signed dilation separation to produce conservative entrywise rectangles around the left and right vectors. The implementation reports a common phase/sign choice for a pair, because `u_j` and `v_j` may be changed together without changing `u_j*s_j*v_j'`. Changing only one side's phase is treated as incompatible. An exactly repeated singular value does not receive an individual-vector certificate and is reported as `UNSUPPORTED_MULTIPLICITY`; its cluster remains covered by V1B. The boxes are norm-derived sufficient bounds, not the full componentwise algorithm from the motivating literature. ## V3: inverse and spectral norm bound The method ID is `svt_neumann_inverse_v1`. For a square target `A` and a public solve output `X`, the checker forms an outward enclosure of ```text R = I - A*X ``` and requires a certified norm upper bound `r < 1`. It also obtains a certified upper bound for a norm of `X`. The Neumann argument then yields a finite inverse-norm upper bound and the positive lower bound ```text sigma_min(A) >= (1-r) / ||X||_upper ``` The exact norm constants and matrix-bound operations are implemented in the private interval layer and are included in the certificate JSON. A zero or poor approximate inverse cannot pass. Rectangular inverse requests return `UNSUPPORTED_RECTANGULAR` because this baseline does not prove a pseudoinverse claim. ## Exact replay and artifact binding `svt_serialize_mp_array` writes every finite MPFR/MPC entry as exact signed dyadic data with shape, precision, real/imaginary components, and a canonical byte digest. `svt_dyadic_decode` reconstructs the value without decimal round-tripping. `svt_replay_snapshots` checks the digest and reproduces the stored target/factor records independently of the profile runner. The required output files are versioned as `svt-v1`. Certificates contain the method ID, status, preconditions, interval fields, target/factor identity, and `paper_algorithm_reproduction=false`. The writer also emits display TSVs and an environment record, but display decimals are not proof endpoints. Coverage is checked independently by `svt_check_coverage`: every expected `(case_id, mode, native, work_bits)` key must occur exactly once, and the row count must equal the manifest calculation. Empty, missing, and duplicate rows are rejection tests. ## Adversarial controls The self-tests cover malformed shapes, negative or unordered singular values, non-orthogonal factors, invalid cluster indices, external-gap collapse, single-sided phase corruption, repeated factors, singular targets, poor inverses, rectangular inverse requests, invalid interval domains, and exact dyadic round trips. These controls exercise rejection paths; they do not weaken the positive gate. ## Claim boundary The verifier establishes only the finite inequalities represented by its implemented baselines for the represented point matrix and factors. It does not port all algorithms from Rump--Lange, Rump--Ogita, or Rump, does not claim interval-input robustness beyond the point enclosures implemented here, and does not certify an unresolved singular value as zero. See `docs/codex/svt/VERIFICATION.md` for the normative formulas and `docs/codex/svt/SOURCES.md` for source attribution. mplapack-interop-0.5.1/docs/precision-semantics.md0000644000230300031750000001644115274353473021503 0ustar rafaelrafael# Precision semantics This document is normative. Implementations must obey it unless a later milestone changes the contract with rationale, explicit tests, and migration notes when user-visible behavior changes. ## Decimal string input ```octave x = mp("0.1"); ``` The decimal text `0.1` is parsed directly at the target MPFR precision. It does not first pass through IEEE binary64. The result is therefore a high-precision approximation to the mathematical decimal value 1/10. ## Double input ```octave x = mp(0.1); ``` The Octave literal is already an IEEE binary64 value before `mp` receives it. Conversion to MPFR must preserve the numerical value of that binary64 input. It must not pretend to be equivalent to `mp("0.1")`. Tests must demonstrate this distinction. ## Canonical precision unit Bits are the canonical internal precision unit. The primary API is `mpbits()` and `mpbits(n)`; `mpdigits()` is a convenience API. M03 initially established the project-owned state at 128 bits. M04 changes the fresh-session initial default to 512 bits and exposes that same state through `mpbits` and `mpdigits`; there is no second setting. Constructors read the current value from the internal precision component and pass it explicitly to each new native scalar or uniform-precision dense matrix. Normal construction does not use MPFR's mutable process-global default. M03 scalar construction uses explicit MPFR round-to-nearest (`MPFR_RNDN`) for both decimal parsing and conversion of an incoming binary64 value. It does not inherit a caller-modified MPFR process default rounding mode. ## Decimal-digit conversion `mpdigits(n)` requests at least `n` complete base-10 significant digits for subsequently constructed values and maps directly to: ```text bits = ceil(n * log2(10)) ``` M04 adds no hidden guard bits. The conversion is certified with directed MPFR interval bounds, so it cannot silently truncate or return one bit too few. `mpdigits()` reports: ```text digits = floor(bits * log10(2)) ``` This is the number of complete decimal digits guaranteed by the current representational precision; it is not an accuracy claim for an arbitrary algorithm. The public getters and successful setters return `uint64` values. ## Default state lifetime The default is process-local and session-local, not thread-local. It is stored in the native precision component with data-race-safe atomic access. A change persists across ordinary `clear` and `pkg unload`/`pkg load` in the same Octave process because the native module remains resident. It is neither written to disk nor inherited by another Octave process; every fresh process starts at 512 bits. `mpbits(n)` and `mpdigits(n)` validate and convert the complete request before committing the new state. Failed setters leave the previous value unchanged. Floating inputs are accepted only in their contiguous exact-integer range; Octave integer scalar types allow larger exact requests up to the MPFR range. The project does not call `mpfr_set_default_prec` to represent its state. Instead, successful `mpbits(n)` and `mpdigits(n)` setters synchronize the calling thread's gmpfrxx/MPFR default through its public setter. This default is an execution context for MPLAPACK MPFR calls, not storage for an existing value. M08 and M09 temporarily enter `MplapackMpfrPrecisionScope` at the operand-derived operation precision and restore the caller's default on every exit. Explicit-precision construction remains independent of later default changes, and no process-wide precision mutation is used. ## Existing objects Changing the default precision affects subsequently created `mp` values only. It must not silently mutate existing values: ```octave mpbits(128); a = mp("0.1"); mpbits(512); b = mp("0.1"); ``` Here `a` retains its original precision and `b` uses the new default. M07 applies the same invariant to matrices. One matrix has one immutable precision, every element is explicitly initialized at that precision, and later default changes do not alter matrix metadata or element values. M10 applies the same invariant to read-only indexing and conversion. Matrix elements and slices are copied at the source matrix precision, while `double(A)` is an explicit MPFR-to-binary64 conversion and `disp(A)` uses the source values directly. Neither operation uses the current default to choose an extracted precision or display precision. M11 applies the invariant to dense element-wise `+`, `-`, `.*`, and `./`, as well as unary signs. Binary `mp` operands use the maximum stored operand precision; a mixed binary64 operand uses the `mp` operand precision. Each destination element is explicitly allocated at that operation precision and computed with direct MPFR round-to-nearest arithmetic. Two-dimensional singleton expansion does not materialize expanded operands, and neither the project default nor the current-thread MPFR default participates in result precision selection or changes during these operations. M12 applies the same invariant to structural operations. `transpose`, `ctranspose`, and `reshape` copy existing MPFR values at the source object's precision and preserve the column-major linear order for reshape. They do not perform numerical rounding, use the current-thread MPFR default, or change the project default. M13 applies the invariant to concatenation. For `[A, B, ...]` and `[A; B; ...]`, the result precision is the maximum stored precision of every participating `mp` operand, including empty matrices; real double operands do not increase it. Each source value is copied directly into one uniformly precise destination, preserving the represented lower-precision value without reconstructing lost information. Concatenation does not use the current default, MPFR TLS default, or a precision scope. M14 applies the invariant to indexed assignment. For an `mp` lhs and `mp` RHS, the copied result precision is the maximum of their stored precisions; a builtin double RHS leaves lhs precision unchanged. Assignment never narrows a matrix, and a higher-precision RHS widens the complete uniformly precise copy. Values are transferred directly with MPFR operations, without text or double round trips. The current project/default precision is not used. ## Explicit scalar conversion `char(x)` formats the immutable value using `x`'s stored precision. The canonical decimal is guaranteed to reconstruct the same MPFR value when read at that precision with `MPFR_RNDN`; it is not a precision-independent exact serialization. Changing the current default cannot change existing text. `double(x)` is an explicit, potentially lossy conversion of the stored value to IEEE binary64 using `MPFR_RNDN`. It never converts through decimal text. The presence of this explicit method does not authorize implicit binary64 fallback in arithmetic or generic numeric functions. ## Mixed precision M06 establishes the scalar `mp`/`mp` operation rule: ```text result precision = max(lhs precision, rhs precision) ``` For scalar `mp`/`double` arithmetic, result precision is the stored `mp` precision. The binary64 operand is converted directly at that precision, so the current project default never participates in arithmetic result selection. All M06 operations explicitly use `MPFR_RNDN`. A later milestone may change these rules only for a strong documented reason, with explicit tests and migration notes for any user-visible change. mplapack-interop-0.5.1/docs/codex/0000755000230300031750000000000015274353473016276 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/codex/svt/0000755000230300031750000000000015274353473017112 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/codex/svt/cases.json0000644000230300031750000002754115274353473021114 0ustar rafaelrafael{ "schema": "svt-case-manifest-v1", "prepared": "2026-09-10", "notes": [ "Parameters are suite selections, not claimed published experiment outcomes.", "Only below-guard DD rows intentionally materialize a rounded recipe.", "Measured SVD row counts exclude references, inverse solves, verification jobs and shape tests." ], "profiles": { "smoke": { "work_bits": [ 128, 256 ], "native": true, "modes": [ "values", "econ" ], "cases": [ { "id": "S1-NRO-TWO", "tier": "S", "family": "nro_block", "parameters": { "m": 4, "mode": "two", "b": 12 } }, { "id": "S1-NRO-THREE", "tier": "S", "family": "nro_block", "parameters": { "m": 4, "mode": "three", "b": 12 } }, { "id": "S1-NRO-GRADED", "tier": "S", "family": "nro_block", "parameters": { "m": 4, "mode": "graded", "g": 4 } }, { "id": "S2-JS", "tier": "S", "family": "jacobi_stirling", "parameters": { "n": 8, "z": 1 } }, { "id": "S3-LAH", "tier": "S", "family": "lah", "parameters": { "n": 8 } }, { "id": "S4-DD-SYM", "tier": "S", "family": "dd_path", "parameters": { "n": 8, "b": 32, "rho_num": 1, "rho_den": 1, "allow_below_guard": true } }, { "id": "S4-DD-NONSYM", "tier": "S", "family": "dd_path", "parameters": { "n": 8, "b": 32, "rho_num": 1, "rho_den": 2, "allow_below_guard": true } }, { "id": "A1-PASCAL-LOWER", "tier": "A", "family": "pascal", "parameters": { "n": 8, "representation": "lower" } }, { "id": "A1-PASCAL-SYM", "tier": "A", "family": "pascal", "parameters": { "n": 8, "representation": "symmetric" } }, { "id": "A2-VAND", "tier": "A", "family": "vandermonde", "parameters": { "n": 8, "node_den_bits": 4 } }, { "id": "A3-BDI-RAW", "tier": "A", "family": "bidiagonal", "parameters": { "n": 8, "a": 4, "representation": "raw" } }, { "id": "A3-BDI-MIXED", "tier": "A", "family": "bidiagonal", "parameters": { "n": 8, "a": 4, "representation": "mixed" } }, { "id": "A4-LAU-TALL", "tier": "A", "family": "lauchli", "parameters": { "n": 4, "b": 20, "representation": "tall" } }, { "id": "A4-LAU-WIDE", "tier": "A", "family": "lauchli", "parameters": { "n": 4, "b": 20, "representation": "wide" } }, { "id": "A5-GEO", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 8, "mode": "geometric", "a": 4 } }, { "id": "A5-CLOSE", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 8, "mode": "close", "b": 32 } }, { "id": "A5-REPEAT", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 8, "mode": "repeat" } }, { "id": "A5-RANK4", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 8, "mode": "rank4" } }, { "id": "A5-RANK5", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 8, "mode": "rank5", "b": 32 } }, { "id": "A6-NRO-COMPANION", "tier": "A", "family": "nro_companion", "parameters": { "n": 8, "nu": 16 } } ], "expected_svd_rows": 120, "reference_bits": [ 512, 640 ], "evaluation_bits": 768 }, "demo": { "work_bits": [ 128, 256, 512 ], "native": true, "modes": [ "values", "econ" ], "cases": [ { "id": "S1-NRO-TWO", "tier": "S", "family": "nro_block", "parameters": { "m": 16, "mode": "two", "b": 40 } }, { "id": "S1-NRO-THREE", "tier": "S", "family": "nro_block", "parameters": { "m": 16, "mode": "three", "b": 40 } }, { "id": "S1-NRO-GRADED", "tier": "S", "family": "nro_block", "parameters": { "m": 16, "mode": "graded", "g": 3 } }, { "id": "S2-JS", "tier": "S", "family": "jacobi_stirling", "parameters": { "n": 16, "z": 1 } }, { "id": "S3-LAH", "tier": "S", "family": "lah", "parameters": { "n": 20 } }, { "id": "S4-DD-SYM", "tier": "S", "family": "dd_path", "parameters": { "n": 24, "b": 160, "rho_num": 1, "rho_den": 1, "allow_below_guard": true } }, { "id": "S4-DD-NONSYM", "tier": "S", "family": "dd_path", "parameters": { "n": 24, "b": 160, "rho_num": 1, "rho_den": 2, "allow_below_guard": true } }, { "id": "A1-PASCAL-LOWER", "tier": "A", "family": "pascal", "parameters": { "n": 24, "representation": "lower" } }, { "id": "A1-PASCAL-SYM", "tier": "A", "family": "pascal", "parameters": { "n": 24, "representation": "symmetric" } }, { "id": "A2-VAND", "tier": "A", "family": "vandermonde", "parameters": { "n": 16, "node_den_bits": 5 } }, { "id": "A3-BDI-RAW", "tier": "A", "family": "bidiagonal", "parameters": { "n": 16, "a": 8, "representation": "raw" } }, { "id": "A3-BDI-MIXED", "tier": "A", "family": "bidiagonal", "parameters": { "n": 16, "a": 8, "representation": "mixed" } }, { "id": "A4-LAU-TALL", "tier": "A", "family": "lauchli", "parameters": { "n": 8, "b": 100, "representation": "tall" } }, { "id": "A4-LAU-WIDE", "tier": "A", "family": "lauchli", "parameters": { "n": 8, "b": 100, "representation": "wide" } }, { "id": "A5-GEO", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 16, "mode": "geometric", "a": 8 } }, { "id": "A5-CLOSE", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 8, "mode": "close", "b": 100 } }, { "id": "A5-REPEAT", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 8, "mode": "repeat" } }, { "id": "A5-RANK4", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 8, "mode": "rank4" } }, { "id": "A5-RANK5", "tier": "A", "family": "hadamard_spectrum", "parameters": { "n": 8, "mode": "rank5", "b": 100 } }, { "id": "A6-NRO-COMPANION", "tier": "A", "family": "nro_companion", "parameters": { "n": 16, "nu": 256 } }, { "id": "A4-LAU-COMPLEX", "tier": "A", "family": "lauchli", "parameters": { "n": 8, "b": 100, "representation": "tall", "quarter_turn_phases": true } }, { "id": "S1-NRO-SCALE-UP", "tier": "S", "family": "nro_block", "parameters": { "m": 16, "mode": "two", "b": 40, "scale_bits": 600 } }, { "id": "S1-NRO-SCALE-DOWN", "tier": "S", "family": "nro_block", "parameters": { "m": 16, "mode": "two", "b": 40, "scale_bits": -600 } } ], "expected_svd_rows": 184, "reference_bits": [ 768, 896 ], "evaluation_bits": 1024 }, "stress": { "work_bits": [ 256, 512, 1024 ], "native": true, "modes": [ "values", "econ" ], "cases": [ { "id": "ST-NRO", "tier": "S", "family": "nro_block", "parameters": { "m": 16, "mode": "two", "b": 300 } }, { "id": "ST-JS", "tier": "S", "family": "jacobi_stirling", "parameters": { "n": 32, "z": 1 } }, { "id": "ST-LAH", "tier": "S", "family": "lah", "parameters": { "n": 32 } }, { "id": "ST-DD", "tier": "S", "family": "dd_path", "parameters": { "n": 32, "b": 600, "rho_num": 1, "rho_den": 2, "allow_below_guard": true } }, { "id": "ST-VAND", "tier": "A", "family": "vandermonde", "parameters": { "n": 32, "node_den_bits": 6 } }, { "id": "ST-BDI", "tier": "A", "family": "bidiagonal", "parameters": { "n": 32, "a": 8, "representation": "mixed" } }, { "id": "ST-COMPANION", "tier": "A", "family": "nro_companion", "parameters": { "n": 32, "nu": 256 } } ], "expected_svd_rows": 56, "reference_bits": [ 1536, 1664 ], "evaluation_bits": 2048, "opt_in": true } } } mplapack-interop-0.5.1/docs/codex/svt/MILESTONES.md0000644000230300031750000002705615274353473021130 0ustar rafaelrafael# SVT00--SVT19: implementation milestones One milestone at a time. Before advancing, run its gate and write `svtXX-report.md` at the repository root. Each report records branch, starting and validated code state, changed paths, actual command lines, environment/module resolution, observed metrics, PASS/FAIL/BLOCKED, and limitations. Do not report a future commit hash or claim execution from a preparation script. A scientific or arithmetic-contract failure blocks dependent claims. Independent S/A work can proceed when only a V prerequisite is unavailable, but the full task cannot be PASS. No routine confirmation is required after a passed gate. ## SVT00 -- local audit and non-destructive integration map Read AGENTS.md, local instructions, earlier NEIG/SVD docs, implemented examples, SVD/eig/solve tests, precision semantics, package builder, manual sources, example QA, and actual loaded modules. Probe public real/complex economy/full/one-output SVD. Audit the scalar RN/sqrt/range contract and exact widening from local source. Create a reuse/path map for existing constructors and metrics. Allocate three unoccupied example numbers. Record missing capabilities without adding APIs. Gate: focused existing tests pass; executable/module paths and public API contracts are documented; reuse plan preserves old behavior. A missing Octave/backend is BLOCKED, not PASS. An unproven scalar contract is a V-specific blocker. ## SVT01 -- facade, manifest, precision, and output safety Implement validated entry points, tier/profile dispatch skeleton, precision cleanup, exact widening, and no-overwrite output-directory handling. Parse/validate the normative manifest or generate an equivalent internal manifest with an equality test. No all-case result may be marked complete before every case exists. Gate: invalid options, injected errors, ambient precision below/above input, alias preservation, filters, new-directory safety, and path restoration tests pass. Verify smoke=20 cases/120 rows and demo=23 cases/184 rows before adding solvers. ## SVT02 -- exact construction utilities and identity metadata Implement Sylvester H/G, exact power-of-two/scaling helpers, integer recurrence support, ceil-log2 guards, known projectors, and input/model identity metadata. Use dense MP matrices, not matrices of scalar wrapper cells. Gate: exact orthogonality, signed phase identity, common-denominator construction bounds, below-guard rejection, and sufficient-precision equality tests pass. No native floating construction of a supposedly exact irrational/rational fixture. ## SVT03 -- measured runner and provisional reference/metric engine Connect one-output and economy solves, frozen-input references, model references, MP reevaluation, errors, residuals, orthogonality, timings and statuses. Use a few small synthetic fixtures before enabling the literature families. References are explicitly `consistent_reference` until certified later. Gate: dimension/type/order/finite checks, complex V rather than VT conventions, zero-reference handling, below-resolution classification, residual perturbation and timing separation tests pass. No hidden double norm/comparison path. ## SVT04 -- Tier S1: three NRO block variants Implement two-, three-, and graded-level block matrices, stable analytic spectra, reciprocal pairing, exact inverse construction checks, and native equality checks. Run all S1 smoke/demo precisions and modes. Preserve repeated groups. Gate: exact model/native identity where promised; analytic forward gates and common residual gates pass at highest precision; all actual measured rows recorded. No forced low-precision failure. Test that the unstable subtraction formula is not used for the small reference singular values. ## SVT05 -- Tier S2: Jacobi--Stirling Implement z=1 recurrence, indexing, exactness budget and leading 5-by-5 fixture. Run smoke/demo; record exact input vs any native rounding without inferring spectral preservation from integer-looking values. Gate: constructor/unit-triangular checks and provisional high-precision accuracy gates pass; source attribution does not claim a structured HRA solver was ported. ## SVT06 -- Tier S3: Lah Implement unsigned Lah recurrence and fixtures; add integer budget and native input accounting. Run smoke/demo; preserve the unit diagonal/rank proof. Gate: recurrence and closed-form checks on small exact integers, high-precision accuracy, residuals, and precise input identity tests pass. ## SVT07 -- Tier S4: symmetric/nonsymmetric DD pair Implement the two paths, stable symmetric reference, exact minimum tau, nonsymmetric reference, and deliberate tau loss in native and 128-bit demo construction. Prove/test rank n-1 of the tau=0 represented matrix by leading minors/row sums. Gate: exact-model high-precision targets pass; rounded-input rows are neither silently skipped nor judged against tau as if their input still contained it. Do not label the nonsymmetric minimum singular value tau. ## SVT08 -- Tier A1: Pascal pair Implement exact lower/symmetric Pascal and prove/test P=Q*Q'. Run both versions with references and input metadata. Check the cross-family squared-spectrum identity at sufficient precision, without introducing a general normal-equations SVD path. Gate: exact fixtures, symmetry, positivity/rank proofs, provisional accuracy and existing regressions pass. Correct the source wording: the Pascal paper is not claimed to contain the exact SVD table used by this suite. ## SVT09 -- Tier A2/A3: Vandermonde and graded bidiagonal pair Implement dyadic nodes and powers, raw/mixed bidiagonal matrices and exactness proofs. Run required sizes and modes. Keep specialized bidiagonal comparator availability informational; do not install or bind a new driver. Gate: exactness guards, raw/mixed model spectrum agreement, high-precision recovery, and type/precision tests pass. No generic dense HRA guarantee is invented. ## SVT10 -- Tier A4/A5: reuse/extend Lauchli and Hadamard controls Reuse proven existing code where practical. Add tall/wide Lauchli, geometric, close/repeated, rank-four/rank-five cases and exact projectors. Add the explicitly named normal-equations negative control outside the reference/timed path. Gate: all cases meet provisional high-precision targets; repeated-column rotation leaves group tests unchanged; ideal rank is not forced on rounded native inputs. Full/economy shape and extra structural null-direction tests pass. ## SVT11 -- Tier A6: bounded-integer NRO companion-like family Implement the deterministic k/nu construction, Horner certificate, entry bound and published equation-(82) fixture/inverse. Run the small and hard cases. Gate: exact unimodularity proof checks and exact inverse fixture pass; native input is unchanged; provisional spectrum/residual gates pass. A merely small approximate determinant is not accepted as the determinant proof. ## SVT12 -- private outward arithmetic, proof audit, exact serialization Implement V0.1--V0.3 and V4 from VERIFICATION.md. Bind audited correctly rounded primitives to conservative outward endpoint/rectangle operations and matrix/norm bounds. Implement exact dyadic encoding/decoding and replay inputs. Gate: every arithmetic precondition has a checked code path; rational corner and cancellation tests pass; invalid-domain/range tests fail closed; exact endpoint serialization round-trips. Complete a written proof-to-code audit. No ordinary GEMM plus final epsilon inflation, external interval dependency, or new rounding API. ## SVT13 -- V1 all-singular-value enclosures and certified references Implement the polar/Weyl checker without computing polar factors. It must consume actual stored approximate factors and target input. Add broad/narrow status handling. Certify the reference solves and replace provisional final error claims by valid bounds from those enclosures. Keep numerical consistency data for comparison. Gate: known-spectrum tests are enclosed, malformed factors fail closed, all required highest-precision S/A spectrum certificates meet their width targets. Recheck every S/A recovery target with certified references. Do not omit a hard family. ## SVT14 -- V1 cluster projectors Implement signed dilation separation with all complementary +/- values and structural zeros, and raw-factor projector radii. Do not divide by an internal cluster gap. Handle the empty-complement full-space branch explicitly. Gate: close/repeated Hadamard and tall/wide Lauchli group certificates meet targets; rotation/permutation tests pass; an exterior-gap collapse is INCONCLUSIVE. Known exact projectors corroborate the rigorous bounds. ## SVT15 -- V2 compatible simple-factor boxes Implement positive simple-singular-value boxes and common-phase semantics. Return unsupported individual identification at multiplicity while preserving V1 results. Add real/complex rectangular tests and nontrivial geometric/graded NRO tests. Gate: required simple-factor radius targets pass; common phase invariance holds; single-sided phase corruption is detected; no unique repeated-vector claim. Reports explicitly state that these are conservative norm-derived entrywise boxes, not a full implementation of the Rump--Ogita componentwise algorithm. ## SVT16 -- V3 norms, inverse residual, and sigma_min bound Implement norm intervals and Neumann inverse verification using public solve outputs. Record inverse work precision separately. Use verified norm bounds for X. Add good/bad inverse and singular/rectangular negative controls. Gate: all required invertible cases certify r<1 and positive sigma_min lower bound; the published exact inverse fixture agrees; no singular/bad input gets false PASS. A failed sufficient condition is not labeled proof of singularity. ## SVT17 -- complex/range controls and complete measurement output Enable all 23 demo cases, including phased tall Lauchli and NRO scales +/-600. Run every smoke/demo row and V job. Write versioned TSV/JSON/report/environment artifacts, canonical hashes, full target/factor snapshots, and checker replay. Add optional plots with only presentation-boundary conversions. Gate: exactly 120 smoke and 184 demo measured SVD rows; references/V jobs counted separately; all fixed numerical/certificate targets pass; wrong/missing rows fail coverage. Headless plot=false is tested. No overwritten prior artifacts. ## SVT18 -- examples, documentation, and regression integration Add the three allocated top-level examples. Each has a small reproducible default and clear pointers to full demo output. Integrate tests into the existing runner; do not replace or bypass prior NEIG/SVD coverage. Update the authoritative manual source and regenerate derived Markdown using the actual local tools. Gate: focused tests, existing relevant regressions, document generation checks, and all documentation examples pass. Source ledger correctly distinguishes paper formulas, suite adaptations, HRA interpretation, and implemented verifier baselines. ## SVT19 -- isolated package QA and final evidence Build using the existing source-package process. Inspect archive contents for examples/helpers/tests/docs. Run from an extracted source/example tree with an isolated installed package, not accidentally through checkout paths. Show `which` evidence. Do not overwrite production installations or publish. Gate: clean-package smoke, demo and all mandatory V checks pass; existing tests and examples remain green; no unauthorized API/backend/dependency changes. Complete 20-milestone table, row counts, numerical results, source identities, actual commands, and NOT_RUN list (stress/OS/graphics as applicable). Final `results.ok` must agree with process exit status and reported coverage. No missing execution labeled PASS. mplapack-interop-0.5.1/docs/codex/svt/SOURCES.md0000644000230300031750000003564315274353473020572 0ustar rafaelrafael# SVT source ledger and attribution limits Checked during preparation on 2026-09-10. This ledger distinguishes publisher metadata/abstracts, inspected mathematical content, and original suite derivations. DOIs below were matched to title, authors, and publication metadata through primary publisher or author-institution records. No book is required or cited, so there is no unverified ISBN dependency. Official software documentation has no paper DOI. No licensed article PDFs, third-party numerical source, or font files are bundled. The prepared examples use independently written mathematical constructions. Their particular dimensions, powers of two, and acceptance targets are suite choices, not claimed reproductions of published numerical tables. The selected Tier V baselines are **not ports of the three paper algorithms**. Full derivations of these narrower baselines are in VERIFICATION.md. ## [NRO11] Integer matrices with controlled singular-value distributions Tetsuo Nishi, Siegfried M. Rump, and Shin'ichi Oishi. **On the generation of very ill-conditioned integer matrices.** *Nonlinear Theory and Its Applications, IEICE* **2**(2), 226--245 (2011). DOI: **10.1587/nolta.2.226**. Primary records: ```text https://www.jstage.jst.go.jp/article/nolta/2/2/2_2_226/_article https://www.jstage.jst.go.jp/article/nolta/2/2/2_2_226/_pdf/-char/en ``` Checked: matching publisher metadata; public article text in Sections 4 and 5. The displayed matrix/inverse in equation (82) was also checked in a page image. The other construction formulas were read from the article text; this is not a claim that every equation/table in the paper was visually inspected. Section 5 supplies the block family `[I,B;0,I]`. Its stable singular-value formula in CASES.md follows by orthogonal reduction to 2-by-2 blocks; choosing B=H*diag(w) is this suite's deterministic specialization. Section 4 supplies the bounded-integer companion-like construction using Horner coefficients. CASES.md specifies the chosen alternating k sequence and reproduces a small exact identity from (82) for a construction check, not an entire published experiment. No claim is made that arbitrary prescribed real spectra can all be realized by bounded integer matrices. Integer inputs are exact only within their stated significand/range bounds. ## [JS14] Jacobi--Stirling Jorge Delgado and Juan Manuel Peña. **Fast and accurate algorithms for Jacobi--Stirling matrices.** *Applied Mathematics and Computation* **236**, 253--259 (2014). DOI: **10.1016/j.amc.2014.03.047**. ```text https://www.sciencedirect.com/science/article/abs/pii/S0096300314004093 https://doi.org/10.1016/j.amc.2014.03.047 ``` Checked: publisher title/DOI/abstract and the bibliographic record reproduced in primary follow-up articles by the same research group. The volume is 236, not 235. The paper explicitly addresses singular values and inverses to high relative accuracy. The suite uses the integer second-kind recurrence at z=1, not copied algorithm code. Its numerical reference is independently certified by the SVT checker; no unimplemented structured factor algorithm is advertised as an oracle. Terminology caution: triangular matrices have zero minors. Use totally nonnegative for nonnegative minors, or explain the article's convention; do not claim every minor is strictly positive. ## [LAH19] Lah matrices in the Laguerre paper Jorge Delgado, Héctor Orera, and Juan Manuel Peña. **Accurate computations with Laguerre matrices.** *Numerical Linear Algebra with Applications* **26**(1), e2217 (2019). DOI: **10.1002/nla.2217**. ```text https://onlinelibrary.wiley.com/doi/10.1002/nla.2217 ``` Checked: publisher authors/title/DOI, volume/issue/article number, and summary. The first-online date is 2018-10-05; the issue/citation year is 2019. The summary explicitly includes Lah bidiagonal factorizations and high-relative-accuracy singular values. CASES.md uses the exact integer Lah recurrence/closed form. This preparation does not claim a full transcription of the paper's algorithm. ## [DD11] Diagonally dominant representations Froilán M. Dopico and Plamen Koev. **Perturbation theory for the LDU factorization and accurate computations for diagonally dominant matrices.** *Numerische Mathematik* **119**, 337--371 (2011). DOI: **10.1007/s00211-011-0382-3**. ```text https://link.springer.com/article/10.1007/s00211-011-0382-3 ``` Checked: publisher metadata and abstract. Its accurate-factorization theory is about carefully represented diagonally dominant data. It is not a guarantee for arbitrary dense `svd(A)` after losing the small DD part during materialization. The symmetric shifted path and biased nonsymmetric path are suite-derived members of this class. Only the symmetric member has the stated elementary singular-value formula. A constant row sum is an eigenvalue statement, not a singular-value oracle. ## [PAS13] Pascal Pedro Alonso, Jorge Delgado, Rafael Gallego, and Juan Manuel Peña. **Conditioning and accurate computations with Pascal matrices.** *Journal of Computational and Applied Mathematics* **252**, 21--26 (2013). DOI: **10.1016/j.cam.2011.12.007**. ```text https://doi.org/10.1016/j.cam.2011.12.007 ``` Checked: publisher record and available text/summary. The DOI contains 2011 but this is a 2013 journal issue. The paper's explicitly described applications include eigenvalues, inverses, and systems. Do not pretend it supplies a reproduced SVD benchmark table. SVD use here also relies on the TN framework [TN05] and on the suite's independent exact binomial construction/certified reference. ## [TN05] High relative accuracy from totally nonnegative factors Plamen Koev. **Accurate Eigenvalues and SVDs of Totally Nonnegative Matrices.** *SIAM Journal on Matrix Analysis and Applications* **27**(1), 1--23 (2005). DOI: **10.1137/S0895479803438225**. ```text https://epubs.siam.org/doi/10.1137/S0895479803438225 ``` Checked: publisher title/author/DOI, issue metadata, and abstract. Use the 2005 issue year, not a later webpage/online timestamp. The accuracy statement is conditional on accurately supplied bidiagonal-factor data. The suite chooses dyadic Vandermonde nodes and includes Pascal/combinatorial families, but does not claim dense reconstruction plus generic SVD inherits the structured guarantee. TNTool is neither bundled nor a required runtime dependency. ## [RL23] Tier V1 target: all singular pairs and clusters Siegfried M. Rump and Marko Lange. **Fast computation of error bounds for all eigenpairs of a Hermitian and all singular pairs of a rectangular matrix with emphasis on eigen- and singular value clusters.** *Journal of Computational and Applied Mathematics* **434**, 115332 (2023). DOI: **10.1016/j.cam.2023.115332**. ```text https://www.sciencedirect.com/science/article/pii/S0377042723002765 https://tore.tuhh.de/entities/publication/3757f148-23ee-4e71-a0cb-3a661c4dfef8 ``` Checked: publisher/author-institution title, authors, volume, article number, DOI and abstract. The paper addresses singular vectors/subspaces and individual values, including clusters/multiplicities and interval inputs. Its complete algorithm was not transcribed in this preparation. SVT supplies the narrower, explicitly derived polar/Weyl value inclusion and signed-dilation projector bound for point matrices. It does not claim the paper's interval-input coverage, operation counts, sharpness, or full algorithm reproduction. ## [RO24] Tier V2 target: compatible factor enclosures Siegfried M. Rump and Takeshi Ogita. **Verified Error Bounds for Matrix Decompositions.** *SIAM Journal on Matrix Analysis and Applications* **45**(4), 2155--2183 (2024). DOI: **10.1137/24M165096X**. ```text https://epubs.siam.org/doi/10.1137/24M165096X https://tore.tuhh.de/entities/publication/1dabce2f-756a-45e2-9864-be6f35145a89 ``` Checked: matching publisher and author-institution metadata and abstract. First online 2024-11-11. The paper addresses rigorous entrywise factor bounds and uses accurate dot products and preconditioning. Its full methods have not been transcribed here. SVT V2 instead provides conservative norm-derived entrywise boxes in the positive, simple, separated setting, with a common phase for each left/right vector pair. Repeated individual vectors are deliberately unsupported; V1 handles their subspaces. This is a baseline for the same class of output claim, not the RO24 algorithm or its claimed accuracy/performance. ## [R11] Tier V3 target: spectral and inverse norms Siegfried M. Rump. **Verified bounds for singular values, in particular for the spectral norm of a matrix and its inverse.** *BIT Numerical Mathematics* **51**(2), 367--384 (2011). DOI: **10.1007/s10543-010-0294-0**. ```text https://link.springer.com/article/10.1007/s10543-010-0294-0 https://tore.tuhh.de/entities/publication/20883cce-df79-4410-b84a-328eee23797c ``` Checked: publisher title/author/DOI/volume/pages and abstract. The first-online date is 2010-11-11; the issue date is June 2011. The paper presents several norm verification approaches. SVT's elementary approximate-inverse/Neumann certificate is derived in VERIFICATION.md; it is not advertised as a port of all those methods. ## [WED72] Background for subspace perturbation Per-Åke Wedin. **Perturbation bounds in connection with singular value decomposition.** *BIT* **12**, 99--111 (1972). DOI: **10.1007/BF01932678**. ```text https://link.springer.com/article/10.1007/BF01932678 ``` Checked: publisher author/title/DOI/volume/pages/year. Supports the distinction between individual vectors and separated subspaces. The constants and signed- dilation proof used by SVT are stated independently in VERIFICATION.md; no implicit appeal to an untranscribed theorem is needed for their finite-arithmetic checker. ## [LAU61] Historical provenance and current matrix convention Peter Läuchli. **Jordan-Elimination und Ausgleichung nach kleinsten Quadraten.** *Numerische Mathematik* **3**, 226--240 (1961). DOI: **10.1007/BF01386022**. ```text https://link.springer.com/article/10.1007/BF01386022 https://math.nist.gov/MatrixMarket/deli/Lauchli/information.html ``` The DOI/title/author/pages were matched in the preceding SVD source ledger and primary bibliographic references; the current NIST definition confirms the modern matrix convention. The analytic spectrum in CASES.md follows directly from `L'*L=11'+mu^2*I`. The powers of two and the complex/tall/wide controls are suite choices, not historical experiments reproduced from the 1961 article. ## [MPFR] Correct rounding, interpreted with a local binding audit GNU MPFR manual, version 4.2.2 as displayed during preparation, floating-point numbers and rounding modes. ```text https://www.mpfr.org/mpfr-current/mpfr.html ``` Checked: correctly rounded operations behave as if computed exactly and then rounded; represented inputs are treated as exact; nearest rounding has the stated half-ulp error bound. This establishes an MPFR primitive contract, not proof that a particular `mp` binding selects that mode. SVT00/SVT12 must inspect local source and test ranges/precision. Never infer a library-wide contract from sample results. ## [LAPACK-LASQ1] Bidiagonal relative-accuracy comparator Netlib LAPACK, DLASQ1 documentation. ```text https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html ``` Checked: high relative accuracy in the absence of denormalization, underflow, and overflow. Bidiagonal-array input is not equivalent to a dense SVD API. No new LASQ1 binding is requested. An already available comparator may be logged only with its arithmetic range and limitations. ## [REPO] Earlier public API snapshot and mandatory local re-audit ```text https://github.com/nakatamaho/octave-mplapack https://raw.githubusercontent.com/nakatamaho/octave-mplapack/main/docs/svd.md https://raw.githubusercontent.com/nakatamaho/octave-mplapack/main/inst/@mp/svd.m https://raw.githubusercontent.com/nakatamaho/octave-mplapack/main/docs/precision-semantics.md ``` The provided earlier SVD specification/source ledger described these interfaces. Attempts to refresh the repository during this revision failed. Consequently this bundle does NOT claim to have verified the current public or local source. SVT00 must record the actual checkout, supported methods, native module paths, rounding modes, precision ownership, test commands, manual source, and package QA process. ## Source-to-implementation map | Spec area | Source or direct derivation | Required qualification | |---|---|---| | S1/A6 integer generators | NRO11 Sections 5/4; exact identities | Deterministic suite parameter choices | | S2 integer recurrence | JS14 family; exact recurrence checks | No invented structured oracle | | S3 integer recurrence | LAH19 family; exact closed-form check | Issue year 2019, online 2018 | | S4 DD path pair | DD11 class; direct construction | Only symmetric version has analytic singular values | | A1 Pascal | PAS13 + TN05; binomial identity | Do not invent PAS13 SVD tables | | A2 Vandermonde | TN05; dyadic node specialization | Guard significand budget for powers | | A3 bidiagonal pair | LAPACK-LASQ1; orthogonal invariance | No transfer of an HRA guarantee to a dense solve | | A4 Lauchli | LAU61/NIST; direct Gram identity | Normal equations are a negative control | | A5 known spectrum | Orthogonal invariance, exact dyadic construction | Original fixtures, not named published tests | | V1/V2/V3 targets | RL23 / RO24 / R11 | Baselines, not full paper reproductions | | Certified primitive arithmetic | MPFR + explicit outward-padding proof | Source audit, range checks, no final-only padding | | Exact endpoint persistence | Dyadic encoding derivation | Decimal display is not an outward certificate | ## SVT implementation ledger The executable suite is an independently written adaptation of the families and claim classes above. The selected matrix dimensions, dyadic scalings, complex phases, global-scale controls, reference precisions, acceptance targets, and exact replay representation are suite choices. They are not reproduced published tables or a claim that the source papers' structured solvers have been ported. The implemented Tier V baselines are deliberately narrower than the motivating papers: `svt_polar_weyl_v1` encloses singular values from the actual stored factors; `svt_dilation_projector_v1` encloses separated positive cluster projectors; `svt_dilation_factor_boxes_v1` gives conservative compatible norm-derived boxes for simple pairs; and `svt_neumann_inverse_v1` verifies a public solve output through an outward residual and a Neumann bound. These methods do not claim interval-input coverage, full componentwise algorithms, or the performance guarantees of the cited work. The certificate implementation uses only the existing public `mp`, `mpbits`, dense arithmetic, `svd`, and solve operations. MPFR/MPC values remain at one operation precision; exact dyadic serialization is used for replay, while binary64 conversion is limited to optional presentation plots. The verifier is example-local and no public API, backend, rounding setter, dependency, or installed header was added for SVT. mplapack-interop-0.5.1/docs/codex/svt/CASES.md0000644000230300031750000003460215274353473020277 0ustar rafaelrafael# SVT matrix definitions, exactness, and references All indices in formulas below are mathematical indices, explicitly zero- or one-based. Translate to Octave without changing the convention. Case sizes and parameters are in `cases.json`. Do not substitute gallery defaults. Formula variants and chosen parameters are suite adaptations unless an equation number from a paper is explicitly identified. ## C0. Shared Hadamard mixing For a power of two n construct Sylvester H by H1=[1] and H(2n)=[H,H;H,-H]. Let G be H with rows cyclically shifted downward once. Then H*H'=G*G'=n*I exactly. Define mix(B) = H*B*G'/n. This is two-sided orthogonal equivalence, NOT an eigenvalue similarity. Avoid forming sqrt(n) in the input constructor. For diagonal d>=0 the singular values are d. Known projectors of an index group J are P_U = H(:,J)*H(:,J)'/n; P_V = G(:,J)*G(:,J)'/n. These are exact dyadics when the significand bound covers the integer sums. Do not require individual bases of a repeated group to match H or G columns. Quarter-turn diagonal phases D_L,D_R preserve singular values and transform projectors by D*P*D'. Global scale 2^s multiplies singular values by 2^s. An exactness proof needs a common power-of-two denominator and an absolute bound on all integer partial sums. Equality between two floating calculations is a useful regression check, not a replacement for this proof. ## S1. NRO block matrices: two, three, and graded levels Primary source [NRO11], Section 5. Use m a power of four in the required profiles. Let w_j be nonnegative powers of two or zero and B=H_m*diag(w). Define A = [I_m, B; zeros(m), I_m]. All entries are 0, 1, or signed powers of two. All required native inputs are exactly representable, including the scaled controls within their exponent range. The inverse is exactly [I,-B;0,I], and det(A)=1. These are constructor invariants, not permission to replace an SVD or a tested inverse solve by the formula. Since (H_m/sqrt(m)) is orthogonal, beta_j=sqrt(m)*w_j are the singular values of B. Each beta generates two singular values of A: a_j = (sqrt(beta_j^2+4)+beta_j)/2; b_j = 2/(sqrt(beta_j^2+4)+beta_j). Use the second formula for the small value, never cancellation of square roots. For beta=0, a=b=1 exactly. The singular values must be sorted together only in the reference array. Reference projectors are optional except in focused tests. Proof: apply left/right block orthogonal factors from a B SVD and a permutation; the problem becomes independent [[1,beta],[0,1]] blocks. Their singular values are a and 1/a. This stable reference formula is an algebraic consequence of the paper's block construction, not a transcription of a published test parameter. Required variants: - two-level: w_j=2^b for all j; - three-level: first m/2 weights 2^b, remaining weights zero; - graded: w_j=2^(g*(j-1)), j=1..m. Smoke: m=4,b=12,g=4. Demo: m=16,b=40,g=3. Thus the two-level demo is 32-by-32, has entries only 0,1,+/-2^40, beta=2^42 and condition approximately 2^84. Do not demand native failure. The three-level case has true unit singular values as well as reciprocal extreme groups; multiplicities are intended. Test A*inverse_formula=I exactly at sufficient precision, full rank by proof, reciprocal pairing, and no input conversion error in native. Add the b=0 small case. Do not assert that any arbitrary specified spectrum can be realized by bounded integer entries: the paper's freedom is constrained. ## S2. Jacobi--Stirling second-kind matrix Primary source [JS14]. Fix z=1. For mathematical i,j=0..n-1 define J(i,j)=JS_i^j(1), with J(0,0)=1, J(i,0)=0 for i>0, J(0,j)=0 for j>0, and J(i,j) = J(i-1,j-1) + j*(j+1)*J(i-1,j), 1<=j<=i. Upper-triangular entries are zero. The leading 5-by-5 fixture is 1 0 0 0 0 0 1 0 0 0 0 2 1 0 0 0 4 8 1 0 0 8 52 20 1 The matrix is unit lower triangular and det=1. Do not discard the leading 1-by-1 block without changing the case ID. The literature sometimes calls matrices with all nonnegative minors "totally positive"; this suite uses "totally nonnegative" for triangular matrices with structural zero minors. Do not assert strict positivity of every minor of this triangular matrix. Use additions/multiplications on MP integers. A conservative exactness budget is p_min = 3 + sum(ceil_log2(1+r*(r+1)), r=1..n-1). Here ceil_log2 is computed on exact small integer arguments by comparisons, not a rounded logarithm at a power-of-two boundary. A row-sum/product bound controls all positive intermediates. Prove the bound and verify equality with a wider construction. Test n=1 and small known rows. Smoke n=8; demo n=16. Reference: high-precision SVD, then V1-certified intervals for the actual exact matrix. A structured HRA comparator may corroborate but is not required. Do not claim the generic dense driver implements the paper's bidiagonal-factor method. ## S3. Unsigned Lah matrix Primary source [LAH19]. For i,j=1..n, L(i,j) = binomial(i-1,j-1) * i! / j! for j<=i, else 0. Generate by L(1,1)=1 and L(i,j)=L(i-1,j-1)+(i+j-1)*L(i-1,j), with out-of-range entries zero. Do not evaluate factorials in binary64. The first four rows are [1], [2,1], [6,6,1], [24,36,12,1]. Unit lower triangular, det=1. A conservative budget is `p_min=3+sum(ceil_log2(2*i),i=2..n)`; a maximum-entry recurrence gives the proof. Smoke n=8; demo n=20. Do not infer exact construction merely because values have no printed fraction. A rounded lower-triangular matrix may remain exactly full rank while its small singular values change. Its unit diagonal does establish full rank; it does not establish spectral accuracy. Reference and HRA attribution rules are as for S2. ## S4. Diagonally dominant path pair Relevant class theory: [DD11]. The selected path formulas are suite adaptations. For tau=2^-b and rho>0 dyadic define the n-by-n tridiagonal A: A(1,1)=1+tau; A(1,2)=-1; A(i,i-1)=-rho; A(i,i)=1+rho+tau; A(i,i+1)=-1 (2<=i=1, p>=b+2 suffices for exact input. Smoke n=8,b=32; demo n=24,b=160. The p=128 demo is intentionally below the guard: it solves the explicitly labeled rounded tau=0 input. Native tau loss is also intentional. Build and compare the exact high-precision model separately. For rho=1, A is SPD and its ascending singular values are tau + 4*sin(k*pi/(2*n))^2, k=0..n-1. Set k=0 to exactly tau. Generate pi/trigonometric quantities in MP, not native. The positive-term form avoids cancellation in 2-2*cos. These numerical sine values are analytic-reference evaluations, not certified transcendental intervals; certify the spectrum independently with V1. The exact minimum tau is a strong special check. For rho=1/2, do NOT assert sigma_min=tau. A*ones=tau*ones determines an eigenvalue, not a singular value. Use high-precision SVD plus a certified reference. For tau=0 the leading j-by-j principal determinants, j0 strict row diagonal dominance proves nonsingularity. A density or triangularity shortcut must not replace svd. ## A1. Pascal pair Relevant source [PAS13], plus [TN05] for SVD use of the nonnegative factor data. For 1<=i,j<=n: Q(i,j)=binomial(i-1,j-1) if j<=i, otherwise 0; P(i,j)=binomial(i+j-2,i-1). Generate binomial values through Pascal addition, not native nchoosek/factorial. Prove and test P=Q*Q' exactly at sufficient precision. Both det=1. Q is unit lower triangular and P is symmetric positive definite. Budget p_min=n+2 for Q, 2*n+2 for P is conservative. Smoke n=8; demo n=24. The Pascal paper explicitly demonstrates eigenvalues, inverses and systems; the SVD fixture here also relies on the general TN SVD framework. Do not call the SVD run a numerical table reproduced from the Pascal paper. Numerical cross-check: sorted singular values of P equal the squares of those of Q mathematically. Compare with sufficient precision or enclosing arithmetic. This exact cross-family identity does not authorize forming A'*A as a generic SVD oracle. V1 remains the certification path. ## A2. Dyadic Vandermonde Relevant source [TN05]. For positive increasing nodes x_i=i/2^d with n<2^d, V(i,j)=x_i^(j-1), 1<=i,j<=n. Build successive powers in work MP arithmetic. Sufficient exactness budget: `p_min=2+(n-1)*ceil_log2(n)`. Common dyadic denominators and integer powers give this bound. Smoke n=8,d=4; demo n=16,d=5. Verify distinct nodes and determinant product positivity algebraically; do not impose a determinant-based accuracy gate. Native rounding may change entries; do not assert a rank without proof. Reference: consistent high precision followed by V1 certification. A TN algorithm fed exact/accurate factor parameters is a different computation from dense svd(V). ## A3. Graded bidiagonal and mixed partner For a>=1 define B(i,i)=2^(-a*(i-1)); B(i,i+1)=2^(-a*(i-1)-1), i=2, set k_i=(-1)^(i-1), i=1..n-1, and k_n=1. Let a_1=k_1; a_i=k_i-nu*k_(i-1), 2<=i<=n. The first row of C is [a_1,...,a_n]. For i=2..n set C(i,i-1)=1, C(i,i)=-nu; all other entries are zero. This is a deterministic selection within the paper's construction, not a reproduction of every sign/parameter choice in its generator. All entries satisfy abs(C(i,j))<=nu+1. The input uses only small integers. The Horner recurrence h=a_1; h=h*nu+a_i for i=2..n ends at k_n=1, hence det(C)=(-1)^(n-1). Check intermediate h=k_i, not a floating near-zero determinant. Smoke n=8,nu=16; demo n=16,nu=256. These native inputs are exactly representable. A sufficient input/construction budget is ceil_log2(nu+1)+3. Full rank follows exactly. Reproduce the separate published equation-(82) 4-by-4 fixture and inverse: C = [1 -6 7 -9; 1 -5 0 0; 0 1 -5 0; 0 0 1 -5]; X = [125 -124 130 -225; 25 -25 26 -45; 5 -5 5 -9; 1 -1 1 -2]. Test C*X=X*C=I exactly. Do not require its rounded printed singular values from the paper as an oracle. Main references use high-precision SVD and V1-certified intervals. The explicit inverse fixture also tests V3 against a provable inverse. ## Controls and common exactness checks Complex demo: multiply the tall Lauchli case by D_L on the left and D_R' on the right, diagonal entries cycling [1,i,-1,-i]. Construct real/imaginary integer parts through the audited public complex API. Singular values are unchanged. Transform known projectors with the same phases and preserve conjugate-transpose semantics. Scaling demo: multiply NRO two-level by 2^600 and by 2^-600, separately. Model and native matrices remain representable; metrics are evaluated in MP to avoid native squaring overflow/underflow. Verify exact unscaled recovery by inverse power-of-two scaling. Time the actual requested matrix, not an unscaled surrogate. Stress choices in the manifest are additional experiments, not guaranteed targets. Construct exact bit budgets before enabling them. Reject inconsistent settings. Reference maxima are fixed; do not silently double until a desired result appears. For each constructor test n at its lower supported boundary, dimensions, analytic rank where available, exactness across two sufficient precisions, alias preservation, precision cleanup on error, and a deliberately insufficient-precision request. Do not impose performance thresholds or assert that all ill-conditioned fixtures must exhibit the same failure mode. mplapack-interop-0.5.1/docs/codex/svt/PREPARATION.md0000644000230300031750000001057615274353473021231 0ustar rafaelrafael# Preparation evidence and limitations Prepared on 2026-09-10. These are checks of mathematical definitions and bundle consistency, not tests of an octave-mplapack implementation. No Octave executable was available. Attempts to refresh the public target repository failed. The actual local API, MPFR rounding-mode use, native module selection, implementation results, and clean-package QA are deliberately left to the mandatory SVT milestones. ## Executed preparation command From the bundle root, the preparation run was equivalent to: ```sh python3 docs/codex/svt/preparation/check_math.py \ --output docs/codex/svt/preparation/check-results.json ``` The checked-in output records that actual run. A rerun must not overwrite it. Run without `--output` to print results, or choose a new output filename. The script uses Python's standard library only and refuses to replace an existing output file. It is not required at runtime by the eventual Octave suite. ## Exact checks that passed The script checked the following with integers and fractions: - Sylvester orthogonality at orders 1,2,4,8,16,32; the 32-by-32 NRO demo's explicit inverse identity and exact representability of every input entry in binary64. - Jacobi--Stirling leading rows; Lah recurrence versus the integer closed form; Pascal's P=Q*Q' identity at orders 8,16,20,24,32. - The published NRO equation-(82) matrix/inverse identity in both product orders; the deterministic companion-like generator's entry bound, Horner invariant, and exact determinant at orders 2,3,8,16,32 with the tested integer parameters. - Symmetric and biased DD tau=0 matrices: all row sums zero, every proper leading principal determinant equal to one, full determinant zero. Adding 2^-160 to their diagonals is lost in binary64 and in toy 128-bit RN, but retained at 256. - The Hadamard-mixed geometric demo's exact dyadic entries need at most 121 significant binary digits; the specification's conservative guard is 126. - Every manifest bit guard and row count, including explicit below-guard DD rows. Selected largest integer-entry bit lengths: | Order | Jacobi--Stirling | Lah | Symmetric Pascal | |---:|---:|---:|---:| | 8 | 16 | 18 | 12 | | 16 | 52 | 49 | 28 | | 20 | 74 | 67 | 36 | | 24 | 98 | 86 | 43 | | 32 | 150 | 126 | 59 | These are maximum entry bit lengths, not condition numbers, required solve precisions, or sufficient proofs for every intermediate. The specification uses separate conservative intermediate bounds. Profile consistency checks: | Profile | Cases | Work bits | Measured SVD calls including native | |---|---:|---|---:| | smoke | 20 | 128,256 | 120 | | demo | 23 | 128,256,512 | 184 | | stress, opt-in | 7 | 256,512,1024 | 56 | Reference solves, shape tests, inverse solves, and V jobs are excluded from these counts. Only the two DD demo cases at 128 bits and the DD stress case at 256/512 bits are intentionally below their exact-model construction guard. ## Rounding-algebra checks A small exact Fraction implementation of normalized binary RN (unbounded exponent, ties to even) corroborated the primitive outward enclosure at 5,184 signed-rational and square-root test points, including deliberately small toy precisions. For square roots, comparison was performed by squaring rational endpoints exactly. This sampling is not a proof of a universal rounding theorem and does not audit the target library. The proof is explicitly given in VERIFICATION.md and the executor must separately establish that the real scalar binding satisfies its hypotheses. Toy q=8/16 tests intentionally go below the verifier's supported q>=64; they are extra algebra checks, not expanded production scope. ## Unexecuted and unclaimed No actual Octave/MPLAPACK SVD, matrix solve, scalar-binding audit, interval checker, certificate replay, numerical acceptance target, plotting backend, or isolated package test was executed here. The Tier V algorithms specified in this bundle have proofs and implementation requirements, but are not an already-built library. The preparation data must never be copied into an implementation report as evidence that SVT00--SVT19 passed. Publisher/author-institution records establish the cited bibliographic metadata and claim limits. The bundle does not claim to port the complete Rump--Lange, Rump--Ogita, or Rump algorithms. See SOURCES.md for exact DOI matches and access scope, and VERIFICATION.md for the actual narrower certificate methods. mplapack-interop-0.5.1/docs/codex/svt/VERIFICATION.md0000644000230300031750000004511415274353473021323 0ustar rafaelrafael# SVT verification baselines: contracts, proofs, and adversarial tests ## V0. What is and is not being implemented The three Tier V papers motivate three targets: all singular values and clusters [RL23], compatible factor enclosures [RO24], and matrix/inverse norms [R11]. This file specifies original, conservative baselines for those targets, with complete proof obligations. It does **not** reproduce those papers' full algorithms, entrywise sharpness, operation counts, interval-data support, or all edge cases. Use `paper_algorithm_reproduction=false` in reports and artifacts. Approximate values/factors come from the existing public SVD. Verification uses separate outward arithmetic. No result is certified merely by precision doubling, a small nonrigorous norm, an assumed residual bound, or high-relative-accuracy theory for another input representation. First implementation scope: finite point real/complex dense matrices with m,n>=1; economy SVD with k=min(m,n); finite nonnegative descending approximate singular values. Complex intervals are rectangles in real/imaginary parts. Positive clusters are supported; exact mathematical rank supplied by a constructor is separate metadata. Zero-dimensional SVD inputs return UNSUPPORTED_EMPTY (interval helper arrays may still be empty). Generic interval-input families and generic null-space dimension certification are outside this baseline. Never advertise those as implemented. ## V0.1 Audited scalar contract For every real scalar operation used by the verifier, establish from local source: r = RN_q(x op y), op in {+, -, *, /}, or r = RN_q(sqrt(x)), with correctly rounded round-to-nearest at recorded q bits, exact interpretation of represented inputs, and no hidden binary64 path. Comparisons, sign, and abs of a finite scalar must be exact. Verify scalar extraction retains precision. q>=64. No compiled rounding-mode API or process-wide hardware rounding change is needed. MPFR's correctly rounded operation guarantee is the underlying source [MPFR]. The package's use of that guarantee must still be audited locally. The certifier has a bounded arithmetic domain, not an unchecked exponent claim. For this task require q<=4096, finite primitive results either zero or between 2^-8192 and 2^8192 in magnitude, and a backend range supporting at least 2^-32768 through 2^32768 without subnormalization. Check exact powers and reciprocal identities at startup, inspect range/subnormalization behavior, and record the contract. Do not change the user's MPFR exponent range. Detect NaN, infinity, unexpected zero, zero padding radius, and out-of-contract results; return an explicit failure status, never a certificate. This range covers all required fixtures and their proof calculations, but must be checked at runtime. ## V0.2 A rigorous enclosure from an RN operation Let u=2^-q, computed exactly in MP, and let r be the nonzero result of one audited RN primitive on exact represented scalar operands. Form t = 8*u*abs(r) # exact power-of-two scaling lo = RN_q(r-t) hi = RN_q(r+t). The multiplication by 8u is an exponent shift and must be exact in range. The subtractions/additions forming endpoints are performed at q, with no later cast. Return [lo,hi]. This is NOT a heuristic "add a few epsilons to the final answer". It encloses each individual primitive before interval propagation. Proof under the stated contract: if z is the exact primitive result, abs(z-r) <= u/(1-u)*abs(r) <= 2*u*abs(r). Rounding either endpoint contributes at most `u*(1+8*u)*abs(r) <= 2*u*abs(r)`. Consequently lo<=r-6u|r|<=z and hi>=r+6u|r|>=z. q>=64 is more than sufficient for these inequalities. Audit endpoint range and exact scaling rather than assuming them. When r=0, return [0,0] ONLY after proving exact zero from the operands: addition x=-y; subtraction x=y; multiplication one operand zero; division zero numerator and nonzero denominator; sqrt input zero. Otherwise an unexpected zero is a range/contract failure. Never give a nonzero unknown result a [0,0] interval. A stored finite scalar itself becomes the point interval [x,x] without padding. This proof is specific to the real scalar primitives and the stated range. Do not apply it directly to a complex multiply, norm, dot product, or matrix product whose internal rounding path was not modeled. ## V0.3 Endpoint operations and verified norms Implement private structs with lower/upper real mp arrays at known q. Support point, add, subtract, multiply, divide when zero is excluded, square, sqrt for a nonnegative domain, conjugation, transpose, and matrix product. For multiplication and division combine all endpoint candidates with outward primitive enclosures. For square of an interval crossing zero, the lower bound is exactly zero, not the lower endpoint squared. Division across zero is INCONCLUSIVE/invalid domain, not an infinite interval fed into later claims. Explicitly handle empty arrays. For complex arithmetic use real rectangular formulas and individually enclosed real operations. Conjugating a rectangle negates/reverses its imaginary endpoints. Matrix multiply is an explicitly enclosed sum of products. A standard MP GEMM followed by a final padding operation is forbidden in the proof path. For a real/complex interval residual R enclosing an exact matrix, bound ||R||F by an outward sum of squared upper bounds on abs of its real and imaginary components, followed by an outward square root. This is also an upper bound on ||R||2. Never use an ordinary computed norm as a certified upper bound. For a point matrix X a lower bound on ||X||2 is the maximum of certified lower bounds on the Euclidean norms of its columns (or rows). An upper bound is its verified Frobenius norm. Tighter certified bounds may be obtained through V1, but ordinary svd(X) without verification cannot supply them. All subsequent mathematical upper/lower bounds in this file are evaluated with these enclosing operations. Branch on lower/upper endpoints in the safe direction. For example, a separation test uses Delta_lower > 2*epsilon_upper, not rounded midpoints. Intersect with known nonnegativity only where justified mathematically. Do not clip negative singular values returned by the approximate solver. ## V1a. All singular values via polar correction and Weyl Inputs: exact represented A, U, V, and diagonal S=diag(s), with m-by-n A, k=min(m,n), U:m-by-k, V:n-by-k. s is nonnegative and descending. Widen these exact represented values to q before taking point intervals. Do not recompute the SVD inside the checker. Record and serialize their identities. Compute certified upper bounds gU >= ||U'*U-I||F gV >= ||V'*V-I||F r >= ||A-U*S*V'||F. Require gU<1 and gV<1. Otherwise return INCONCLUSIVE with the failed conditions. Define upper bounds dU = gU/(1+sqrt(1-gU)) dV = gV/(1+sqrt(1-gV)) vN = sqrt(1+gV) epsilon = r + s(1)*(dU*vN+dV). All quantities here denote enclosing upper evaluations, not bare RN formulas. The all-zero s case is valid; do not divide by s(1). **Proof.** The thin polar factors Q_U=U(U'*U)^(-1/2), Q_V analogously, exist and have orthonormal columns. They are proof objects, not matrices the implementation needs to compute. If lambda is an eigenvalue of U'*U then lambda>=1-gU>0 and abs(sqrt(lambda)-1)=abs(lambda-1)/(sqrt(lambda)+1). Summing squares yields ||U-Q_U||F<=dU. Similarly ||V-Q_V||F<=dV and ||V||2<=vN. With A0=Q_U*S*Q_V', U*S*V'-A0 = (U-Q_U)*S*V' + Q_U*S*(V-Q_V)', so ||A-A0||F<=epsilon. A0 has exactly the k singular values s. Weyl's singular value inequality gives abs(sigma_i(A)-s_i)<=epsilon for every ordered i. Return outward intervals lower_i=max(0, lower(s_i-epsilon)); upper_i=upper(s_i+epsilon). This encloses every singular value, including clustered or zero ones; no matching heuristic or simple-root assumption is needed. It does not prove that an interval containing zero represents an exact zero. Distinguish valid broad intervals from resolved positive lower bounds and useful relative widths. Method ID: `svt_polar_weyl_v1`. ## V1b. Positive singular-cluster projector bounds Use the same A0 and epsilon. Let J select a positive cluster among the approximate s values. Internal equality is permitted. In the Hermitian dilation H(A0)=[0,A0;A0',0], the target set is BOTH +s_j and -s_j for j in J. Its complement includes both signs of every other s and |m-n| structural zero eigenvalues. Zero s outside J also count as zeros. Compute a rigorous lower bound Delta on separation between the target and complement spectra. Do not omit negative or structural zero values. If the complement is empty in the full square case, the true and polar projectors are the full identity. Set b_sub=0 in that trivial-space branch, but still add the raw-factor polar-correction terms below; do not return zero error for nonorthogonal raw columns. Require every V1a lower endpoint in J to be strictly positive, and, when a complement exists, Delta>2*epsilon. Otherwise return INCONCLUSIVE for the subspace claim while preserving V1a's valid value intervals. For rJ=|J| define b_sub = 2*sqrt(rJ)*epsilon/(Delta-epsilon). **Proof.** The dilation perturbation has spectral norm <=epsilon. The gap condition identifies a true invariant subspace of the same dimension 2*rJ, separated from its complement by at least Delta-epsilon relative to the A0 target values. The residual in an orthonormal target basis has Frobenius norm <=sqrt(2*rJ)*epsilon. In the exact complementary eigenbasis, the Sylvester equation divides each entry by an eigenvalue separation >=Delta-epsilon. Thus the Frobenius sine-of-angle bound is <=sqrt(2*rJ)*epsilon/(Delta-epsilon). Equal-dimensional orthogonal projectors differ in Frobenius norm by sqrt(2) times that sine norm. The signed cluster projector is blockdiag(P_U,P_V), giving the stated b_sub for each block. This proof includes multiplicity inside the cluster, not a zero outer gap. Bounds for the projectors formed from the RAW returned columns, rather than the uncomputed polar columns, are bU = b_sub + (sqrt(1+gU)+1)*dU; bV = b_sub + (sqrt(1+gV)+1)*dV. This follows by expanding U_J*U_J'-Q_UJ*Q_UJ' and bounding the factors. Return bU and bV as upper bounds to the corresponding uniquely identified true cluster projectors. Do not silently normalize/reorthogonalize U/V before measuring them. Known dyadic model projectors provide strong independent tests for the close and repeated Hadamard group and the Lauchli small group. Rotating a repeated pair by an exact orthogonal matrix must not invalidate the group claim. A wrong column outside the group must be detected by tests. Method ID: `svt_dilation_projector_v1`. ## V2. Entrywise boxes for compatible simple SVD factors This baseline supports positive, simple, separated singular values. It does NOT supply a unique basis at multiplicity, full rectangular null-space bases, or the sharp entrywise bounds/complexity of [RO24]. Reports must state this limitation. For each positive s_i, define Delta_i as the separation of +s_i from every other eigenvalue of H(A0): all +s_j with j!=i, all -s_j including -s_i, and structural zeros. Require Delta_i>2*epsilon and the certified sigma_i lower bound positive. Define z_i = 2*epsilon/(Delta_i-epsilon); radius_U_i = dU + z_i; radius_V_i = dV + z_i. Return componentwise boxes centered on the RAW columns U(:,i), V(:,i), using the respective column radius for each real component. In the complex case use that radius on both real and imaginary components; the enclosing rectangle is allowed to be conservative. Singular-value boxes are those from V1a. Off-diagonal S entries are exactly zero in the certified factorization. **Proof of compatibility.** The normalized dilation eigenvector of A0 is `y0=[Q_U(:,i);Q_V(:,i)]/sqrt(2)`. Its residual for H(A) has norm <=epsilon. Spectral separation bounds the sine of its angle to the true one-dimensional eigenspace by epsilon/(Delta_i-epsilon). There exists a single phase making vector distance <=sqrt(2)*epsilon/(Delta_i-epsilon). Rescaling either block by sqrt(2) gives z_i. Adding polar correction gives the radii above. The same phase applies to BOTH true u_i and true v_i, so the pair still satisfies A*v_i=sigma_i*u_i and A'*u_i=sigma_i*v_i. This proves existence of a compatible SVD inside the boxes; it does not independently choose unrelated phases for left and right vectors. For all positive simple singular values certified simultaneously, the true columns can be chosen orthonormal and the phases preserve the factorization. For a multiple/unsupported index return `UNSUPPORTED_MULTIPLICITY` for individual factor identification and retain any V1 cluster certificate. Do not claim the SVD itself fails to exist. Do not use known exact factors in the checker; they are independent test data only. Mandatory small factor test: A=Q_L*diag(3,1)*Q_R' with Q_L=[1,0;0,1;0,0] and Q_R=I_2, plus a quarter-turn complex diagonal phase variant. Add the nontrivial Hadamard geometric case. Apply arbitrary common +/- signs or unit complex phases to each returned U/V pair and require validity to persist. Changing only V's phase must increase the residual and must not yield an incorrectly tight certificate. Method ID: `svt_dilation_factor_boxes_v1`. ## V3. Spectral norm, inverse norm, and nonsingularity For a point A, V1a provides an interval for ||A||2 via its largest singular value. The direct verified column-lower/Frobenius-upper bounds are a separate conservative route. Do not confuse a norm interval with a bound on every factor entry. For square A and an approximate inverse X (computed through existing public solve `A \ I` at recorded work precision), compute R=I-A*X, with r>=||R||F>=||R||2 verified. Require r<1. This proves A and X are nonsingular because A*X=I-R is nonsingular. Obtain verified xlo<=||X||2<=xhi, with xhi>0. Then xlo/(1+r) <= ||inverse(A)||2 <= xhi/(1-r). **Proof.** inverse(A)=X*(I-R)^(-1) and ||(I-R)^(-1)||2<=1/(1-r). Conversely X=inverse(A)*(I-R), whose norm is <=||inverse(A)||2*(1+r). Thus a positive lower bound on sigma_min(A) is (1-r)/xhi. When xlo>0, an upper bound is `(1+r)/xlo`; otherwise return no finite upper bound from this route. Use outward evaluations in both directions. Do not use an ordinary approximation of ||X||2 in a claimed bound. No test based on det(A) or a small ordinary residual may replace r<1. If r>=1, report INCONCLUSIVE, not "singular". For rectangular A this inverse method is UNSUPPORTED; do not substitute a pseudoinverse argument without a new proof. Known inverse formulas for NRO are checks, not a substitute for the main solve. The exact equation-(82) inverse is a useful independent small positive test. A singular input cannot satisfy this sufficient condition when the arithmetic is correct. That negative test is mandatory. Method ID: `svt_neumann_inverse_v1`. ## V4. Exact certificate serialization The numerical certificate targets exact represented binary values. A decimal string that round-trips at q is not necessarily an outward decimal real endpoint. Use a canonical exact encoding: {"sign": -1|0|1, "mantissa_hex": "...", "exponent2": integer} value = sign * integer(mantissa_hex,16) * 2^exponent2. Zero has sign=0, mantissa_hex="0", exponent2=0. Nonzero mantissas are positive odd integers, leading hex zeroes omitted; use lower-case hex. Complex entries contain separate exact real/imaginary encodings. Include original storage bits, shape, column/row traversal order, method version, and canonical-byte hash. Implement extraction from public MP operations only. One possible exact procedure: find e such that 2^e<=abs(x)<2^(e+1) by bounded binary search on integer exponents; scale exactly into [1,2); extract q binary digits by comparison with 1, exact subtraction, and doubling; assert no remainder after the known significand length; trim trailing zero bits and adjust exponent e-q+1; group bits into hex using only small native integers. The range contract bounds the exponent search. No private payload, decimal widening, or double-valued mantissa is allowed. Decode by repeated exact multiply-by-16 and add-small-digit at enough precision, then exact binary scaling. Reject insufficient target precision rather than round a certificate endpoint silently. Round-trip test real, complex, signed zero, values below 2^-1074, and q up to the declared evaluation precision. Scalar value identity, not display identity, is the acceptance criterion. Human-readable decimal fields are optional companions labeled approximate displays. Reloaded exact certificate targets must be used for a checker replay test. Never trust an input hash without also binding shape/precision/method metadata. ## V5. Required adversarial tests and proof audit Each proof operation must be covered by unit tests and source review. Numerical sampling is a bug detector; the proof above is what justifies enclosure. 1. Scalar endpoints: signs, cancellation, zero, division by 3, perfect/nonperfect square roots, tiny representable results, and invalid/range cases at q=64,128,256. For bounded rational tests compare by exact cross multiplication at a provably sufficient integer/dyadic precision, not merely another floating approximation. For sqrt compare squared endpoints exactly against the positive rational target. 2. Interval corner tests: all multiplication sign combinations; intervals crossing zero; excluded-zero division; complex conjugation; complex matrix residuals. Independently constructed rational/dyadic matrix examples must be enclosed. 3. V1: exact identity/zero/simple diagonal, dense known spectra, tall/wide economy, negative/nonfinite/missorted input rejection, bad Gram matrices, deliberately perturbed factors. A wide valid interval is not the same as an invalid result. 4. V1 cluster: exact repeat, close pair, permutations, internal rotations, and an exterior-gap collapse. The gap condition must fail closed when uncertainty reaches a complementary value. Never reject internal equality alone. 5. V2: compatible common phases, wrong single-sided phase, exact multiplicity, insufficient gap, tall full-column-rank real/complex cases. Use interval comparisons to show known exact factors admit the common phase/basis required by the theorem. 6. V3: exact NRO inverse, computed good inverse, poor inverse such as zero X, singular rank-four input, and explicit rectangular rejection. No false nonsingularity. 7. Exact serialization and replay; default/path restoration after injected failures; immutable inputs; all proof comparisons in MP/enclosing arithmetic. A developer-review checklist must restate every precondition and identify the code that enforces it. A failed arithmetic-contract audit blocks certificate claims. No report may replace a missing proof/implementation with "MPFR is accurate enough". mplapack-interop-0.5.1/docs/codex/svt/preparation/0000755000230300031750000000000015274353473021436 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/codex/svt/preparation/check_math.py0000644000230300031750000002560115274353473024102 0ustar rafaelrafael#!/usr/bin/env python3 """Exact preparation checks, not an Octave implementation or acceptance run. Uses only Python's standard library. Integer/Fraction identities are exact. Toy correctly-rounded binary arithmetic checks corroborate, but do not replace, the proof or the required source audit of the actual MPFR binding. """ from __future__ import annotations import argparse import json import math from fractions import Fraction as F from pathlib import Path from typing import Any Matrix = list[list[Any]] def pow2(e: int) -> F: return F(2**e) if e >= 0 else F(1, 2**(-e)) def ceil_log2(n: int) -> int: if n < 1: raise ValueError("Positive integer required") return (n - 1).bit_length() def transpose(a: Matrix) -> Matrix: return [list(x) for x in zip(*a)] def mm(a: Matrix, b: Matrix) -> Matrix: bt = transpose(b) return [[sum(x * y for x, y in zip(row, col)) for col in bt] for row in a] def identity(n: int) -> Matrix: return [[int(i == j) for j in range(n)] for i in range(n)] def hadamard(n: int) -> Matrix: if n < 1 or n & (n - 1): raise ValueError("Power-of-two size required") h = [[1]] while len(h) < n: h = [r + r for r in h] + [r + [-v for v in r] for r in h] return h def js(n: int) -> Matrix: a = [[0] * n for _ in range(n)] a[0][0] = 1 for i in range(1, n): for j in range(1, i + 1): a[i][j] = a[i - 1][j - 1] + j * (j + 1) * a[i - 1][j] return a def lah(n: int) -> Matrix: a = [[0] * n for _ in range(n)] a[0][0] = 1 for i in range(2, n + 1): for j in range(1, i + 1): left = a[i - 2][j - 2] if j > 1 else 0 same = a[i - 2][j - 1] a[i - 1][j - 1] = left + (i + j - 1) * same return a def det_exact(a: Matrix) -> F: b = [[F(x) for x in row] for row in a] d = F(1) n = len(b) for k in range(n): pivot = next((i for i in range(k, n) if b[i][k]), None) if pivot is None: return F(0) if pivot != k: b[k], b[pivot] = b[pivot], b[k] d = -d value = b[k][k] d *= value for i in range(k + 1, n): t = b[i][k] / value for j in range(k + 1, n): b[i][j] -= t * b[k][j] b[i][k] = F(0) return d def min_bits(x: F) -> int: """Significand bits needed for an exact finite dyadic value.""" x = F(x) if not x: return 0 den = x.denominator if den & (den - 1): raise ValueError("Value is not dyadic") m = abs(x.numerator) while not m & 1: m >>= 1 return m.bit_length() def floor_log2(x: F) -> int: if x <= 0: raise ValueError("Positive value required") e = x.numerator.bit_length() - x.denominator.bit_length() return e - 1 if x < pow2(e) else e def rn(x: F, bits: int) -> F: """Unbounded-exponent normalized binary RN, ties to even.""" if not x: return F(0) sign = 1 if x > 0 else -1 x = abs(x) scale = pow2(floor_log2(x) - bits + 1) y = x / scale k, rem = divmod(y.numerator, y.denominator) if 2 * rem > y.denominator or (2 * rem == y.denominator and k & 1): k += 1 return sign * k * scale def sqrt_rn(x: F, bits: int) -> F: if x < 0: raise ValueError("Nonnegative value required") if not x: return F(0) scale = pow2(floor_log2(x) // 2 - bits + 1) y = x / (scale * scale) k = math.isqrt(y.numerator // y.denominator) midpoint_squared = F((2 * k + 1)**2, 4) if y > midpoint_squared or (y == midpoint_squared and k & 1): k += 1 return k * scale def padded(r: F, bits: int) -> tuple[F, F]: if not r: return F(0), F(0) t = 8 * pow2(-bits) * abs(r) assert rn(t, bits) == t return rn(r - t, bits), rn(r + t, bits) def case_budget(case: dict[str, Any]) -> int: p = case["parameters"] family = case["family"] n = p.get("n", p.get("m")) if family == "nro_block": return 2 if family == "jacobi_stirling": return 3 + sum(ceil_log2(1 + r * (r + 1)) for r in range(1, n)) if family == "lah": return 3 + sum(ceil_log2(2 * i) for i in range(2, n + 1)) if family == "dd_path": return p["b"] + 2 if family == "pascal": return n + 2 if p["representation"] == "lower" else 2 * n + 2 if family == "vandermonde": return 2 + (n - 1) * ceil_log2(n) if family == "bidiagonal": return p["a"] * (n - 1) + 4 if family == "lauchli": return 2 if family == "hadamard_spectrum": if p["mode"] == "geometric": return p["a"] * (n - 1) + ceil_log2(n) + 2 return p.get("b", 4) + ceil_log2(n) + 5 if family == "nro_companion": return ceil_log2(p["nu"] + 1) + 3 raise ValueError(f"Unknown family: {family}") def run() -> dict[str, Any]: manifest_path = Path(__file__).resolve().parents[1] / "cases.json" manifest = json.loads(manifest_path.read_text()) counts, budgets = {}, [] for name, profile in manifest["profiles"].items(): cases = profile["cases"] assert len({c["id"] for c in cases}) == len(cases) count = len(cases) * (len(profile["work_bits"]) + int(profile["native"])) * len(profile["modes"]) assert count == profile["expected_svd_rows"] counts[name] = {"cases": len(cases), "svd_rows": count} for c in cases: guard = case_budget(c) below = [p for p in profile["work_bits"] if p < guard] assert not below or c["family"] == "dd_path", (name, c["id"], guard) assert profile["work_bits"][-1] >= guard budgets.append({"profile": name, "case": c["id"], "guard": guard, "intentional_below_guard_bits": below}) for n in [1, 2, 4, 8, 16, 32]: h = hadamard(n) assert mm(h, transpose(h)) == [[n * x for x in row] for row in identity(n)] h = hadamard(16) b = [[(2**40) * v for v in row] for row in h] a = [identity(16)[i] + b[i] for i in range(16)] + [[0] * 16 + identity(16)[i] for i in range(16)] inv = [identity(16)[i] + [-v for v in b[i]] for i in range(16)] + [[0] * 16 + identity(16)[i] for i in range(16)] assert mm(a, inv) == identity(32) == mm(inv, a) assert all(F.from_float(float(x)) == x for row in a for x in row) assert js(5) == [[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 2, 1, 0, 0], [0, 4, 8, 1, 0], [0, 8, 52, 20, 1]] integer_bits = [] for n in [8, 16, 20, 24, 32]: j, l = js(n), lah(n) for i in range(1, n + 1): for k in range(1, i + 1): assert l[i - 1][k - 1] == math.comb(i - 1, k - 1) * math.factorial(i) // math.factorial(k) q = [[math.comb(i, k) if k <= i else 0 for k in range(n)] for i in range(n)] p = [[math.comb(i + k, i) for k in range(n)] for i in range(n)] assert mm(q, transpose(q)) == p integer_bits.append({"n": n, "js_max_integer_bits": max(x.bit_length() for row in j for x in row), "lah_max_integer_bits": max(x.bit_length() for row in l for x in row), "pascal_symmetric_max_integer_bits": max(x.bit_length() for row in p for x in row)}) published_c = [[1, -6, 7, -9], [1, -5, 0, 0], [0, 1, -5, 0], [0, 0, 1, -5]] published_x = [[125, -124, 130, -225], [25, -25, 26, -45], [5, -5, 5, -9], [1, -1, 1, -2]] assert mm(published_c, published_x) == identity(4) == mm(published_x, published_c) for n, nu in [(2, 2), (3, 3), (8, 16), (16, 256), (32, 256)]: k = [(-1)**i for i in range(n - 1)] + [1] first = [k[0]] + [k[i] - nu * k[i - 1] for i in range(1, n)] c = [first] + [[int(j == i - 1) - nu * int(j == i) for j in range(n)] for i in range(1, n)] horner = first[0] for t in first[1:]: horner = nu * horner + t assert horner == 1 assert max(abs(x) for row in c for x in row) <= nu + 1 assert det_exact(c) == (-1)**(n - 1) for rho in [F(1), F(1, 2)]: n = 8 d = [[F(0)] * n for _ in range(n)] d[0][0] = 1 d[0][1] = -1 for i in range(1, n - 1): d[i][i - 1], d[i][i], d[i][i + 1] = -rho, 1 + rho, -1 d[-1][-2], d[-1][-1] = -rho, rho assert all(sum(row) == 0 for row in d) assert det_exact(d) == 0 assert all(det_exact([row[:k] for row in d[:k]]) == 1 for k in range(1, n)) for i in range(n): shifted = d[i][i] + pow2(-160) assert F.from_float(float(shifted)) == d[i][i] assert rn(shifted, 128) == d[i][i] assert rn(shifted, 256) == shifted # Exact dyadic significand requirement in the dense geometric demo. n, step = 16, 8 h = hadamard(n) g = h[-1:] + h[:-1] hdiag = [[F(v) * pow2(-step * j) for j, v in enumerate(row)] for row in h] mixed = [[x / n for x in row] for row in mm(hdiag, transpose(g))] max_mixed_bits = max(min_bits(x) for row in mixed for x in row) assert max_mixed_bits <= step * (n - 1) + ceil_log2(n) + 2 <= 128 arithmetic_checks = 0 for bits in [8, 16, 64, 128]: for a0 in range(1, 13): for b0 in range(1, 10): for e in [-100, -7, 0, 53]: value = F(a0, b0) * pow2(e) for z in [value, -value]: lo, hi = padded(rn(z, bits), bits) assert lo <= z <= hi arithmetic_checks += 1 r = sqrt_rn(value, bits) lo, hi = padded(r, bits) assert 0 <= lo and lo * lo <= value <= hi * hi arithmetic_checks += 1 return {"status": "PASS", "scope": "Exact Python mathematical preparation checks only", "octave_executed": False, "backend_rounding_contract_audited": False, "paper_algorithm_reproduction": False, "profile_counts": counts, "guard_checks": budgets, "integer_bit_lengths": integer_bits, "nro_native_input_exact": True, "published_inverse_identity_exact": True, "dd_tau_loss_and_rank_checks": True, "geometric_demo_actual_significand_bits": max_mixed_bits, "toy_rn_enclosure_checks": arithmetic_checks, "notes": ["Rational/integer identities are exact.", "Toy RN checks corroborate the algebra; the general proof remains in VERIFICATION.md.", "No tests here demonstrate actual Octave execution or library rounding behavior."]} def main() -> None: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--output", type=Path, help="Optional new JSON output path; existing files are not replaced") args = parser.parse_args() result = run() text = json.dumps(result, indent=2) + "\n" if args.output: with args.output.open("x", encoding="utf-8") as f: f.write(text) else: print(text, end="") if __name__ == "__main__": main() mplapack-interop-0.5.1/docs/codex/svt/preparation/check-results.json0000644000230300031750000001751715274353473025120 0ustar rafaelrafael{ "status": "PASS", "scope": "Exact Python mathematical preparation checks only", "octave_executed": false, "backend_rounding_contract_audited": false, "paper_algorithm_reproduction": false, "profile_counts": { "smoke": { "cases": 20, "svd_rows": 120 }, "demo": { "cases": 23, "svd_rows": 184 }, "stress": { "cases": 7, "svd_rows": 56 } }, "guard_checks": [ { "profile": "smoke", "case": "S1-NRO-TWO", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "S1-NRO-THREE", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "S1-NRO-GRADED", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "S2-JS", "guard": 34, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "S3-LAH", "guard": 27, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "S4-DD-SYM", "guard": 34, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "S4-DD-NONSYM", "guard": 34, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A1-PASCAL-LOWER", "guard": 10, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A1-PASCAL-SYM", "guard": 18, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A2-VAND", "guard": 23, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A3-BDI-RAW", "guard": 32, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A3-BDI-MIXED", "guard": 32, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A4-LAU-TALL", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A4-LAU-WIDE", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A5-GEO", "guard": 33, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A5-CLOSE", "guard": 40, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A5-REPEAT", "guard": 12, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A5-RANK4", "guard": 12, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A5-RANK5", "guard": 40, "intentional_below_guard_bits": [] }, { "profile": "smoke", "case": "A6-NRO-COMPANION", "guard": 8, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "S1-NRO-TWO", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "S1-NRO-THREE", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "S1-NRO-GRADED", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "S2-JS", "guard": 95, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "S3-LAH", "guard": 91, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "S4-DD-SYM", "guard": 162, "intentional_below_guard_bits": [ 128 ] }, { "profile": "demo", "case": "S4-DD-NONSYM", "guard": 162, "intentional_below_guard_bits": [ 128 ] }, { "profile": "demo", "case": "A1-PASCAL-LOWER", "guard": 26, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A1-PASCAL-SYM", "guard": 50, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A2-VAND", "guard": 62, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A3-BDI-RAW", "guard": 124, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A3-BDI-MIXED", "guard": 124, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A4-LAU-TALL", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A4-LAU-WIDE", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A5-GEO", "guard": 126, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A5-CLOSE", "guard": 108, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A5-REPEAT", "guard": 12, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A5-RANK4", "guard": 12, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A5-RANK5", "guard": 108, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A6-NRO-COMPANION", "guard": 12, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "A4-LAU-COMPLEX", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "S1-NRO-SCALE-UP", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "demo", "case": "S1-NRO-SCALE-DOWN", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "stress", "case": "ST-NRO", "guard": 2, "intentional_below_guard_bits": [] }, { "profile": "stress", "case": "ST-JS", "guard": 248, "intentional_below_guard_bits": [] }, { "profile": "stress", "case": "ST-LAH", "guard": 163, "intentional_below_guard_bits": [] }, { "profile": "stress", "case": "ST-DD", "guard": 602, "intentional_below_guard_bits": [ 256, 512 ] }, { "profile": "stress", "case": "ST-VAND", "guard": 157, "intentional_below_guard_bits": [] }, { "profile": "stress", "case": "ST-BDI", "guard": 252, "intentional_below_guard_bits": [] }, { "profile": "stress", "case": "ST-COMPANION", "guard": 12, "intentional_below_guard_bits": [] } ], "integer_bit_lengths": [ { "n": 8, "js_max_integer_bits": 16, "lah_max_integer_bits": 18, "pascal_symmetric_max_integer_bits": 12 }, { "n": 16, "js_max_integer_bits": 52, "lah_max_integer_bits": 49, "pascal_symmetric_max_integer_bits": 28 }, { "n": 20, "js_max_integer_bits": 74, "lah_max_integer_bits": 67, "pascal_symmetric_max_integer_bits": 36 }, { "n": 24, "js_max_integer_bits": 98, "lah_max_integer_bits": 86, "pascal_symmetric_max_integer_bits": 43 }, { "n": 32, "js_max_integer_bits": 150, "lah_max_integer_bits": 126, "pascal_symmetric_max_integer_bits": 59 } ], "nro_native_input_exact": true, "published_inverse_identity_exact": true, "dd_tau_loss_and_rank_checks": true, "geometric_demo_actual_significand_bits": 121, "toy_rn_enclosure_checks": 5184, "notes": [ "Rational/integer identities are exact.", "Toy RN checks corroborate the algebra; the general proof remains in VERIFICATION.md.", "No tests here demonstrate actual Octave execution or library rounding behavior." ] } mplapack-interop-0.5.1/docs/codex/NEIGT-GOAL.md0000644000230300031750000001020615274353473020205 0ustar rafaelrafael# NEIGT execution prompt Open Codex at the `octave-mplapack` repository root, select the user's Luna model with xhigh reasoning, and paste the following. It references every companion in this bundle; do not supply the entry document alone. ```text /goal Implement docs/codex/NEIGT-LUNA-XHIGH.md and all referenced neigt companion specifications, cases.json, and verification-jobs.json for the mplapack-interop Octave package. Read AGENTS.md and all applicable local instructions first. Execute NEIGT00 through NEIGT25 sequentially, run each gate, and write neigtXX-report.md before advancing. Continue automatically after PASS; on a genuine blocker stop dependent work, preserve evidence, and provide a minimal reproducer. Do not stop at a plan. Implement every requested Tier S/A matrix and every V-S/V-A verification target. S1 must implement the specified Ozaki--Ogita Theorem-1 error-free triple-product generator, including its actual generation precision, paired-block rule, requested-versus-realized standard forms, and independent exactness checks; do not replace it with a generic similarity generator. Preserve working NEIG/SVD/SVT/NEIGV examples, reuse compatible tested helpers, and never assume earlier specifications were implemented. Use only the existing public mp arithmetic/eig/svd/qr/solve interfaces. Do not modify dependency headers, MPLAPACK, MPFR/MPC, src, installed mp methods, compiler semantics, or public precision/rounding/interval/generalized-eig/Schur APIs. Tier V must contain actual outward-safe arithmetic and proof checkers, not heuristic residuals, precision agreement, empty adapters, or optional external dependencies. Audit the scalar rounding/range contract and implement the complete conservative methods specified in CERTIFICATES.md, labeling them as baselines rather than full reproductions of the cited paper algorithms. Require counted all-spectrum coverage; nontrivial repeated/defective/merged invariant-subspace certificates; verified pseudospectrum points and positive-area cells; compatible eigenfactor boxes; genuine triangular Schur factors for separated simple cases and explicitly block Schur for the defective case; finite generalized-pencil verification using a proved solve reduction even when eig(A,B) is absent; and positive normalized Perron pairs including the nontrivial left stationary vector. Never claim a true Jordan block is diagonalizable, infer exact multiplicity from a disk count, or confuse an invariant-basis certificate with a spectrally isolated cluster. Keep generation models, frozen solver inputs, work precision, raw solver outputs, auxiliary candidates, and certificate targets separate and exactly identified. Use MP bijective minimum-bottleneck matching, correct complex left-vector conventions, and exact widening for diagnostics. Do not substitute known roots or higher-precision solves into measured outputs. Candidate-only QR, contour solves, and bounded graph Newton refinement are allowed only as specified and must be separately recorded. Run all 120 smoke and 168 demo measured eig rows, all 26 verification jobs for each profile, fixed usefulness/accuracy gates, exact serialization/replay and adversarial tests, existing relevant regressions, and isolated clean-package QA. Stress is opt-in; report it and any plotting as NOT_RUN unless executed. Do not force native failures, require balancing improvement, weaken thresholds, change parameters after seeing results, silently widen work inputs, use an MP-to-binary64 numerical fallback, overwrite unrelated files/results/reports, or push/merge/tag/publish. Missing mandatory code or an unproved arithmetic contract is BLOCKED, not a successful unsupported case. Finish with the actual changed paths, exact commands, measured S/A/V results, all 26 milestone statuses, counted coverage, replayable certificates, source attribution, and honest limitations. Unexecuted tests are never PASS. ``` The main specification, not a shortened paraphrase, defines the task. A filtered example run has its own scope_ok; only complete mandatory coverage can claim the all-tier task passed. The installation helper copies instructions, not code that has already passed these implementation gates. mplapack-interop-0.5.1/docs/codex/neigt/0000755000230300031750000000000015274353473017404 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/codex/neigt/ARITHMETIC.md0000644000230300031750000001651715274353473021371 0ustar rafaelrafael# The proof arithmetic and exact serialization contract ## 1. Reuse or implement, but do not assume Reuse the existing SVT private interval/rectangle layer only after auditing its proof, actual code, tests, shape conventions, precision, range and serialization. The presence of an SVT specification is not an implementation. If absent, implement this self-contained layer under the example tree. No new installed interval API. Proof primitives are **real scalar** +,-,*,/,sqrt in correctly rounded RN_q, q>=64; exact abs/sign/comparison, known stored input precision, and no hidden double evaluation. Confirm the source path to MPFR and its rounding argument. Runtime probes supplement but do not establish this source-level contract [MPFR]. Complex proofs are rectangles made from these real scalar primitives; do not assume a whole MPC multiply, GEMM, norm or dot product has one final rounding. Bounded verifier domain: q<=4096, nonzero ordinary primitive results in [2^-8192,2^8192] in magnitude, and an unchanged backend range supporting at least [2^-32768,2^32768] without subnormalization. Exact padding/scaling intermediates may occupy the wider backend range. Audit this and test exact powers/reciprocal identities; do not modify global MPFR exponent limits. Detect NaN, infinity, unexpected zero, zero padding or range violations and fail closed. The OO generator at 53 bits is a separate RN computation with its own audit. Do not apply a q>=64 verifier assumption to that generator without acknowledging the different role. Every certificate runs at the stated q>=64. ## 2. Enclose one RN primitive rigorously For a nonzero rounded primitive r=RN_q(z), u=2^-q, set ```text t=8*u*abs(r) # exact power-of-two scaling in range lo=RN_q(r-t) hi=RN_q(r+t) ``` The exact z is contained: |z-r|<=u/(1-u)|r|<=2u|r|. Each rounded endpoint moves by at most u*(1+8u)|r|<=2u|r|, leaving at least 6u|r| of outward margin. This is a per-primitive proof, **not** heuristic final-answer padding. For r=0 allow [0,0] only with an exact-zero witness from operands: x=-y for +, x=y for -, an operand zero for *, zero numerator/nonzero denominator for /, or zero argument for sqrt. Otherwise return a range/contract failure. Point values become [x,x] without rounding. Exact binary scaling must itself be audited. For nonnegative sqrt bounds, intersect with nonnegativity only by its proved domain. An interval crossing a negative square-root domain or zero denominator is not silently repaired. Distinguish invalid input from an inconclusive proof domain. ## 3. Interval and rectangle operations Endpoint addition/subtraction; min/max of all four endpoint products/quotients; zero-excluding division; square with lower=0 when crossing zero; monotone square root; real/imaginary complex rectangles; conjugation negates and reverses the imaginary endpoints. Evaluate every endpoint primitive outward as above. Matrices: explicit enclosed sums of enclosed products, conjugating transpose, block extraction/assembly, Kronecker product, and left/right point multiplication. Empty helper arrays are allowed with correct shapes; eigenproblem n=0 is outside scope. Do not certify a matrix product by padding an ordinary GEMM once. For complex rectangles, bound modulus by outward sqrt(re^2+im^2), or use the more conservative upper bound max|re|+max|im|. Lower bounds may use distance of the rectangle to the origin. Never use center modulus as an enclosing endpoint. Verified upper matrix infinity norm: maximum of outward row sums of upper moduli. Verified upper Frobenius norm: outward sum of squared upper real/imaginary magnitudes, then outward sqrt. It bounds the spectral norm. Distinguish matrix infinity norm from entrywise max norm and vectorized infinity norm everywhere. For exact point columns, verified lower Euclidean norms give spectral-norm lower bounds. Ordinary `norm`/`svd` output is never itself a rigorous norm bound. All theorem inequalities use enclosing endpoints in the safe direction. Examples: `upper(e)<1`, `upper(c+e*t+g*t*t)upper(radius_i+radius_j)`. ## 4. Inverse and linear-image enclosures For a square point or interval X and point inverse candidate R, if `e=upper(||I-R*X||inf)<1`, every X in the enclosure is nonsingular, as is R. Use the identity X^(-1)=(I-E)^(-1)*R, E=I-RX. A conservative entrywise inverse enclosure is centered on R, with each complex entry allowed modulus at most ```text theta = e*upper(||R||inf)/(1-e). ``` A tighter per-entry Neumann-sum enclosure is optional, with a proved tail. For a right-hand side F, `||X^(-1)F||inf <= ||R F||inf/(1-e)` often avoids unnecessary interval widening. Use the latter in the all-spectrum and pencil checkers. Never certify nonsingularity from a nonzero approximate determinant. ## 5. Exact dyadic values, copying, and serialization Represent exact binary values by ```json {"sign": 1, "mantissa_hex": "1f", "exponent2": -12} ``` meaning sign*integer(mantissa_hex,16)*2^exponent2. A nonzero mantissa is positive, odd, lowercase and without leading zeros. Zero is sign=0,mantissa_hex="0",exponent2=0. Complex values have separate real/imaginary encodings. Include shape, column-major traversal, stored precision, method version and a canonical byte hash. Public-operation extraction: locate exponent by bounded exact comparisons with powers of two; scale into [1,2); extract the known p significand bits by comparison, exact subtraction and doubling; require zero remainder after p bits; remove trailing zero bits and group into hexadecimal. Native integers are used only for bounded indices, bit counts and hex digits, not for a large mantissa. Do not export a large mantissa through binary64 or use private object payloads. Decode with sufficient precision via repeated multiply-by-16/add-digit and exact binary scaling. Reject an insufficient destination precision. Decimal display strings, even if same-precision round-tripping, are not outward real endpoints. Signed-zero sign is not mathematically significant but its policy must be documented. Certificate records bind all inputs, candidates and interval endpoints to exact content. Save a JSON witness; reload in a fresh session and rerun the checker. Do not trust a stored status, root list or bound without recomputing predicates. Tampering with a target, radius, hash, shape, precision or method ID must be caught. A supplied larger valid bound may pass validity while failing the quality gate. ## 6. Tests and proof-to-code map Test signs, cancellation, exact zeros, division by 3, perfect/nonperfect roots, 2^-1500, q=64/128/256, range/NaN/infinity errors, complex conjugation and all multiplication sign combinations. Check rational cases by exact cross multiplication at a proved sufficient precision, not merely a second rounded calculation. For square roots compare squared rational endpoints with the exact argument. Test interval matrix products against independent exact small dyadic computations, all relevant induced norms, and full preservation of precision/path/input aliases. Report separate evidence for the proof and the tests. Random or exhaustive finite samples detect bugs; they do not establish a floating-point theorem by themselves. Every checker report identifies the code enforcing each assumption and its source-level RN contract. An unknown primitive or a whole unmodeled matrix operation on a proof path is a blocker, not permission to write CERTIFIED. mplapack-interop-0.5.1/docs/codex/neigt/CERTIFICATES.md0000644000230300031750000004733615274353473021610 0ustar rafaelrafael# V-S / V-A: complete conservative verification baselines ## 0. Scope, method identity, and proof inputs These are original conservative implementations of the requested verification **targets**. They are not full implementations of [R22], [R01], [F21], [RO24], [M14], or [M21]. Use the method IDs below and `paper_algorithm_reproduction=false`. In particular the explicit Kronecker graph checker can be much more expensive than the cubic algorithms in the papers. It is restricted to the small jobs in the manifest, not a performance comparison. A checker consumes exact represented target data (or a proved enclosure of one fixed target), finite approximate candidates, a query and a precision contract. It must not consume trusted exact roots, multiplicities, eigenvectors, or a "known correct" status from a matrix constructor. Those are independent tests. All arithmetic in a proof predicate is outward arithmetic from ARITHMETIC.md. Norm notation: ||.||inf is induced matrix infinity norm, |Z|max is maximum entry modulus, and vectorization uses column-major order. Norms/inequalities in formulas below mean rigorous upper/lower evaluations, not ordinary rounded quantities. ## 1. V-S1: counted all-spectrum inclusion Method: `neigt_similarity_gershgorin_v1`. Inputs: target A, point candidate basis X, point inverse candidate R, point central matrix T. Usually X is returned V, T is returned D; a separately logged QR/Schur candidate is also allowed. No inverse is trusted without the residual test. Compute enclosing E=I-RX and F=AX-XT. Let ```text e >= ||E||inf c >= ||R F||inf require e < 1 eta = upper(c/(1-e)). ``` **Proof.** RX=I-E is nonsingular, so R and X are nonsingular. `C=X^(-1) A X=T+(I-E)^(-1) R F`, hence ||C-T||inf<=eta. Thus all eigenvalues of A are in the n disks ```text center_i = T(i,i) radius_i = upper(sum_{j!=i} abs(T(i,j)) + eta). ``` Keep the stronger row-norm perturbation bound eta here; do not accidentally claim an elementwise eta bound gives a row bound eta rather than n*eta. Build an overlap **supergraph**: omit an edge only after proving `lower(abs(center_i-center_j)) > upper(radius_i+radius_j)`. Otherwise include the edge. Each connected component is a union of disks and is certifiably separated from all other components. It contains exactly as many roots, counting algebraic multiplicity, as its number of indexed disks. Counting proof: for C(t)=diag(T)+t*(C-diag(T)), 0<=t<=1, every Gershgorin disk stays inside its indexed outer disk. No eigenvalue can pass between the separated outer components. At t=0 the roots are the indexed centers. This proves exact component counts and coverage of all n roots, including multiplicities. Singleton components enclose one simple eigenvalue. A k-component does NOT prove k equal roots, semisimplicity or defect. Duplicate candidate centers merge rather than furnishing duplicate certificates for the same root. Broad full-spectrum coverage is valid but may fail the usefulness gate. For an interval enclosure of a fixed A, take the supremum bounds over that rectangle; the same proof holds uniformly. Store target provenance explicitly. Tests: exact diagonal, repeated diagonal, real complex-pair block, upper Jordan, permuted candidates, X singular, R=0, wrong T, deliberately duplicated candidate roots, touching disks, conservative overlap from uncertain distance, all n counts. No nonrigorous condition estimate substitutes for e<1. ## 2. Shared certified similarity enclosure For later checkers obtain a rectangular enclosure of the fixed C=X^(-1) A X by the preceding residual formula: C lies in T plus a complex entrywise modulus uncertainty <=eta. Rectangles [-eta,eta]+i[-eta,eta] are conservative. Real inputs remain real intervals. A directly enclosed inverse times A times X is also allowed, with its own proof. Never use bare `X\(A*X)` as an exact C in a certificate. ## 3. V-S2: a verified invariant graph Method: `neigt_riccati_graph_v1`. Partition a certified C enclosure after k candidate columns, h=n-k: ```text C = [C11 C12; C21 C22], 1<=k=1, ```text abs(lambda(M)-c0)^j <= ||(M-c0*I)^j||inf. ``` Enclose the matrix power and choose an exact dyadic radius rho with `rho^j >= upper_norm`. Use j=block_dimension in the required defective jobs. No transcendental root is needed: exponent search on powers of two gives a rigorous, possibly factor-two conservative radius. This is a containing disk, not proof all roots equal c0. Apply it to D2 blocks as useful as well. The query center c0 is not assumed to be an eigenvalue; a wrong center simply produces a poor region. Region separation still must be proved. ### 3.2 Orthogonal-projector error bounds Let X1=X(:,1:k), X2=X(:,k+1:n), ```text g1 >= ||X1'*X1-I||F; require g1<1 alo <= sqrt(1-g1), strictly positive b >= ||X2||2 * sqrt(h*k)*t. ``` If b=1, the existence certificate may still hold; prepare a better candidate for this projector claim. Proof: `(I-P_X1)*Y1=(I-P_X1)*(X2*Z)` and sigma_min(Y1)>=alo-b; apply the pseudoinverse to an orthonormal basis of range(Y1). For equal-dimensional spaces, projector norm equals the sine norm; Frobenius is <=sqrt(2*k) times that norm. This is a geometric range bound, not a Hermitian eigenvalue-gap theorem applied to a nonnormal matrix. Tests: semisimple repeat, true Jordan cluster with separated complement, nearby clusters merged, wrong selected dimension, zero outer separation, bad transpose in a complex K, nonzero C12 quadratic term, wrong radius and singular R_s. The nilpotent power bound must be checked independently on exact small blocks. ## 4. V-S3: pseudospectrum points and cells via verified SVD Methods: `neigt_svd_pseudospectrum_point_v1`, `neigt_svd_pseudospectrum_cell_v1`. Use the closed complex-perturbation 2-norm definition: ```text z belongs to sigma_eps(A) iff sigma_min(z*I-A) <= eps, eps>0. ``` Freeze B=zI-A as an exact matrix expression. If zI-A is not exactly representable at candidate precision, retain the expression enclosure and do not silently replace its certificate target by its rounded candidate. The proof residual must enclose the exact difference, either by exact higher-precision construction with a bit guard or by interval expression evaluation from exact z,A. Reuse the audited SVT polar/Weyl verifier, or implement this required baseline: for returned SVD candidates U,s,V of the rounded approximation to B, verify ```text gU >= ||U'*U-I||F < 1; gV >= ||V'*V-I||F < 1 r >= ||B-U*diag(s)*V'||F s is finite, nonnegative and descending fU = gU/(1+sqrt(1-gU)); fV=gV/(1+sqrt(1-gV)) delta = r+s(1)*(fU*sqrt(1+gV)+fV). ``` Polar factors Q_U,Q_V have ||U-Q_U||F<=fU and ||V-Q_V||F<=fV, and `B0=Q_U*diag(s)*Q_V'` has exactly s as singular values. The displayed delta bounds ||B-B0||2. Weyl's singular-value inequality therefore gives `lower=max(0,lower(s(end)-delta))`, `upper=upper(s(end)+delta)`. No Gram matrix B'*B is used as an eig oracle. The Gram matrices of candidate U/V are proof data, not normal-equations SVD. If upper<=eps -> CERTIFIED_INSIDE; if lower>eps -> CERTIFIED_OUTSIDE; otherwise INCONCLUSIVE. Do not force a boundary point to one side by a tolerance. For a closed cell centered at z0 with every point within a certified distance d, 1-Lipschitz continuity of sigma_min(zI-A) gives [max(0,lower-d),upper+d]. Classify the whole cell using the same predicates. A rectangle with halfwidths hx,hy may conservatively use d=hx+hy. A finite grid is not a boundary certificate. Mandatory checks include an inside point at an exactly known simple/Jordan root, an outside point selected beyond a verified norm bound, an inside and outside cell, Grcar point probes, and an intentionally straddling scalar interval sent to the classification helper. Store all B/candidate/proof identities. Underlying SVD preparation calls are counted separately from core eig timings. ## 5. V-A1: compatible eigenfactors and Schur/block-Schur boxes Methods: `neigt_eigenfactor_boxes_v1`, `neigt_interval_qr_schur_v1`, `neigt_interval_qr_block_schur_v1`. ### 5.1 Compatible full simple eigenfactorization For each simple isolated root use the graph checker with k=1 and an appropriately permuted point candidate basis. Obtain a column enclosure for a true e_i and a scalar enclosure for lambda_i. Require n mutually disjoint certified eigenvalue regions, so the actual e_i are linearly independent and are compatible columns of one E satisfying A E=E Lambda. Assemble interval E and Lambda. Verify nonsingularity uniformly over E's enclosure using an inverse candidate and the Neumann test. Enclose its inverse, then define W=(E^(-1))'. This proves simultaneous existence of ```text A*E=E*Lambda; W'*A=Lambda*W'; W'*E=I. ``` The right vectors have the graph's gauge, not automatically unit norm. The left factor uses dual normalization. These are not automatically boxes about the original independently normalized W returned by eig. Report exact centers/gauges and optionally transform its approximate columns before comparing. Independent signs/phases must not break the proof. Duplicated or non-isolated roots cannot satisfy the all-simple factor contract. Return individual-vector non-identifiability as a domain reason and retain any cluster certificate. ### 5.2 Genuine Schur factors on the separated simple case Evaluate **exact mathematical Gram--Schmidt/QR through interval arithmetic** on the verified E box in its fixed column order. Each step encloses the exact projection sums, residual column and positive Euclidean normalization. Every normalization norm must have a strictly positive lower bound. Complex inner products conjugate their first argument. Norm squares are computed from sums of real^2+imag^2, not a possibly nonreal interval self-inner-product guessed real. For the actual compatible E, this exact procedure defines E=Q R with Q unitary and R upper triangular with positive real diagonal. Thus `T=R*Lambda*R^(-1)=Q'*A*Q` is upper triangular and A=Q*T*Q'. Return interval Q,T. Lower-triangular entries of the true T are zero **by this algebraic proof**; it is not numerical clipping of a returned Schur factor. Use the direct interval Q'*A*Q to bound the allowed upper entries and intersect only the analytically forced lower zeros. Optional interval RLambdaR^-1 is a cross-check, not mandatory duplicate work. This certifies an actual Schur decomposition, not merely a small triangular residual. Interval dependency can make the procedure inconclusive; the required small separated examples must nevertheless pass their width gates. ### 5.3 Defective cluster: only block Schur is claimed From one certified graph let H=[Y1,X2], which is nonsingular since H=X*[I,0;Z,I]. Enclose exact QR of H as above. Its first k columns span the certified invariant subspace. Therefore T=Q'*A*Q has a zero lower-left (n-k)-by-k block, although its leading k-by-k block need not be triangular or diagonal. Return CERTIFIED_BLOCK_SCHUR. No full eigenbasis is asserted for the defective block. This is mandatory alongside, not a replacement for, the true simple-case Schur certificate. Tests: real/complex 4x4 simple factors; coherent phases; wrong one-sided left normalization; permuted eigenpairs; a 4x4 J2(1)+[4,8] block-Schur case; a repeated root refusing individual factor identification; interval QR norm reaching zero. ## 6. V-A2: finite generalized pencils without an API assumption Method: `neigt_verified_finite_pencil_v1`. Target exact A,B with B nonsingular. Compute point candidates R_B for inverse B and C0=B\A by public solves; these are auxiliary calculations, not a claimed exact reduction. Verify ```text eB >= ||I-R_B*B||inf < 1 fB >= ||R_B*(A-B*C0)||inf etaB=upper(fB/(1-eB)). ``` Then C=B^(-1)A lies within entrywise modulus etaB of C0. This proves B nonsingular and the pencil regular with n finite roots. Feed this proved enclosure to V-S1 and V-S2. Their uniform predicates apply to this one exact C. All resulting claims bind the **original A,B**, not just the rounded C0. Approximate eig(C0,mode) is a portable candidate source; label it `solve_reduction_finite_pencil`, not a generalized QZ implementation. If audited public eig(A,B) exists, it may supply an additional comparator/candidate. Its absence does not skip these required jobs. No explicit production inverse or new public binding is needed. Generalized right/left residuals are A V-B V D and W'*A-D W'*B. If a left column w_C for C is mapped to the pencil, w=B^(-*)w_C, through a public solve and a verified enclosure for proof use. The compatible dual normalization is W'*B*V=I, not W'*V=I. Keep solve and eig timings separate. Subspace graph Y1,M satisfies A Y1=B Y1 M. Certify a simple real pencil, a complex pencil, and a defective selected cluster. Reuse the factor enclosure when the query requests vectors; do not claim full defective diagonalization. If B is singular or cannot be proved nonsingular, this method returns UNSUPPORTED_DOMAIN (proved singular input) or INCONCLUSIVE (failed sufficient test). It does not certify infinite roots or treat failure as proof of singularity. Test a known singular B and a poor R_B as separate negative cases. ## 7. V-A3: Perron root and normalized vector Methods: `neigt_collatz_wielandt_v1`, `neigt_positive_pair_contraction_v1`. Require a point real nonnegative A. Prove irreducibility using the graph of strictly positive entries, or a strongly connected certified-positive subgraph for enclosing data. Mandatory matrices are strictly positive. A mere observed eigenvalue of largest modulus is not the structural proof. For a point positive trial vector v, interval-evaluate all ratios (Av)_i/v_i. Collatz--Wielandt gives ```text min_i lower((Av)_i/v_i) <= rho(A) <= max_i upper((Av)_i/v_i). ``` That certifies the root, not its vector. For the latter, independently verify the normalized nonlinear eigenpair equations with real unknown y=(x,lambda): ```text F(y) = [A*x-lambda*x; sum(x)-1] J(y) = [A-lambda*I, -x; ones(1,n), 0]. ``` A center y0 comes from a logged eig candidate, real positive candidate preparation, and normalization; raw eig outputs stay untouched. Form a point inverse candidate R for J(y0). For an exact dyadic radius t>0 and real box Y=y0+[-t,t]^(n+1), compute ```text c >= ||R*F(y0)||inf e >= ||I-R*J(Y)||inf require upper(c+e*t)0 for every i. ``` **Proof.** The map y -> y-RF(y) maps the box into itself and is a contraction by the real mean-value theorem and the displayed Jacobian bound. e<1 establishes R nonsingular (at any fixed J in the box). Its unique fixed point solves F=0, has positive x and unit sum. Irreducible nonnegativity therefore identifies this positive eigenpair as the Perron pair. Intersect the lambda interval with the independent Collatz--Wielandt interval; an empty intersection signals an error. A bounded deterministic radius schedule may start above 2*c with a tiny positive floor and try four doubled dyadic radii. Log each attempt and failed predicate; do not silently alter A, the candidate precision, or the acceptance width. A good root bound with a failed vector contraction is not CERTIFIED_PERRON_PAIR. Run on P, P', PERRON_POS and its transpose. P' produces the nontrivial stationary column pi. The model identity P*1=1 may be used as an independently checked exact matrix property, but rounded native P cannot inherit it. For general positive similarity matrices use the checker, not forced rho=3/2. The second eigenvalue/spectral gap is not certified by a Perron-only method. For that additional check, use V-S1 on the same matrix and count the remaining roots. Bound moduli of disks outward and keep overlapping/ambiguous gap claims INCONCLUSIVE rather than claiming mixing-time accuracy. Negative tests: reducible matrix with two Perron vectors, a negative entry, positive-root claim with a nonpositive vector box, wrong normalization, R=0, Jacobian uncertainty crossing singularity, and a native-rounded model that is not exactly stochastic. None may get an unjustified positive-pair certificate. ## 8. Proof witnesses, replay and failure semantics Each output includes exact target/candidate IDs, all numerical bounds and radii, mathematical domain, rounding/range contract ID, method/version, dimensions, root counts/separation groups where relevant, certificate status and usefulness. A replay recomputes every predicate; no stored PASS is trusted. Meaningful failure is mandatory. INCONCLUSIVE means the sufficient conditions were not proved, not that the mathematical answer is false. UNSUPPORTED_DOMAIN is confined to explicit exclusions. Missing code, an unknown rounding primitive, a missing mandatory case or an unexpected exception is ERROR/BLOCKED and prevents task completion. Counts, subspace existence and individual factor identification are separate claims; never promote a weaker one to a stronger status. mplapack-interop-0.5.1/docs/codex/neigt/cases.json0000644000230300031750000002605315274353473021403 0ustar rafaelrafael{ "schema": "neigt-cases-v1", "version": "1.0", "prepared": "2026-09-10", "standard_modes": [ "nobalance", "balance" ], "outputs": 3, "rules": { "freeze_generation_model": true, "round_model_once_per_component": true, "require_exact_model_at_highest_smoke_demo_precision": true, "permit_lower_precision_rounded_models": true, "classify_any_native_underflow": true, "stress_is_opt_in": true, "lower_guard_rounding_note": "Do not falsely call a rounded work input exact. Stress SIM_SIMPLE, WILKINSON and MARKOV may be rounded at the lower work bits." }, "profiles": { "smoke": { "cases": [ { "id": "OO53_REAL", "tier": "S", "parameters": { "n": 8, "generation_bits": 53, "standard_form": "real" } }, { "id": "OO53_PAIR", "tier": "S", "parameters": { "n": 8, "generation_bits": 53, "standard_form": "pair" } }, { "id": "OO128_CLOSE", "tier": "S", "parameters": { "n": 8, "generation_bits": 128, "standard_form": "close" } }, { "id": "SIM_SIMPLE", "tier": "S", "parameters": { "n": 8, "gap_exponent": 24, "regime": "simple", "kmax": 1 } }, { "id": "SIM_REPEAT", "tier": "S", "parameters": { "n": 8, "regime": "semisimple", "kmax": 1 } }, { "id": "SIM_JORDAN", "tier": "S", "parameters": { "n": 8, "regime": "jordan", "kmax": 2 } }, { "id": "SIM_TWO_JORDAN", "tier": "S", "parameters": { "n": 8, "gap_exponent": 12, "regime": "two_jordan", "kmax": 2 } }, { "id": "TOEPLITZ", "tier": "S", "parameters": { "n": 16, "b": 4, "representation": "original" } }, { "id": "TOEPLITZ_SYM", "tier": "S", "parameters": { "n": 16, "b": 4, "representation": "explicitly_symmetric" } }, { "id": "FORSYTHE", "tier": "S", "parameters": { "n": 8, "a": 4, "representation": "original", "kmax": 1 } }, { "id": "FORSYTHE_SCALED", "tier": "S", "parameters": { "n": 8, "a": 4, "representation": "explicitly_scaled", "kmax": 1 } }, { "id": "FORSYTHE_ZERO", "tier": "S", "parameters": { "n": 8, "a": 4, "representation": "zero_limit", "kmax": 8 } }, { "id": "HAD_BIDIAG", "tier": "A", "parameters": { "n": 8, "s": 16 } }, { "id": "FRANK0", "tier": "A", "parameters": { "n": 8, "orientation": 0 } }, { "id": "FRANK1", "tier": "A", "parameters": { "n": 8, "orientation": 1 } }, { "id": "WILKINSON", "tier": "A", "parameters": { "n": 10 } }, { "id": "GRCAR", "tier": "A", "parameters": { "n": 12, "upper_bandwidth": 3 } }, { "id": "MKS", "tier": "A", "parameters": { "n": 12, "m": 3, "delta": "1/8", "ell": 4, "kmax": 4 } }, { "id": "MARKOV", "tier": "A", "parameters": { "n": 8, "epsilon_exponent": 24, "representation": "stochastic" } }, { "id": "PERRON_POS", "tier": "A", "parameters": { "n": 8, "epsilon_exponent": 24, "representation": "positive_similarity", "scale": "3/2" } } ], "native_baseline": true, "work_bits": [ 128, 256 ], "reference_bits": [ 512, 640 ], "evaluation_bits": 768, "expected_case_count": 20, "expected_measured_eig_rows": 120, "required_verification_profile": "smoke" }, "demo": { "cases": [ { "id": "OO53_REAL", "tier": "S", "parameters": { "n": 16, "generation_bits": 53, "standard_form": "real" } }, { "id": "OO53_PAIR", "tier": "S", "parameters": { "n": 16, "generation_bits": 53, "standard_form": "pair" } }, { "id": "OO128_CLOSE", "tier": "S", "parameters": { "n": 16, "generation_bits": 128, "standard_form": "close" } }, { "id": "SIM_SIMPLE", "tier": "S", "parameters": { "n": 16, "gap_exponent": 80, "regime": "simple", "kmax": 1 } }, { "id": "SIM_REPEAT", "tier": "S", "parameters": { "n": 16, "regime": "semisimple", "kmax": 1 } }, { "id": "SIM_JORDAN", "tier": "S", "parameters": { "n": 16, "regime": "jordan", "kmax": 2 } }, { "id": "SIM_TWO_JORDAN", "tier": "S", "parameters": { "n": 16, "gap_exponent": 40, "regime": "two_jordan", "kmax": 2 } }, { "id": "TOEPLITZ", "tier": "S", "parameters": { "n": 32, "b": 4, "representation": "original" } }, { "id": "TOEPLITZ_SYM", "tier": "S", "parameters": { "n": 32, "b": 4, "representation": "explicitly_symmetric" } }, { "id": "FORSYTHE", "tier": "S", "parameters": { "n": 16, "a": 12, "representation": "original", "kmax": 1 } }, { "id": "FORSYTHE_SCALED", "tier": "S", "parameters": { "n": 16, "a": 12, "representation": "explicitly_scaled", "kmax": 1 } }, { "id": "FORSYTHE_ZERO", "tier": "S", "parameters": { "n": 16, "a": 12, "representation": "zero_limit", "kmax": 16 } }, { "id": "HAD_BIDIAG", "tier": "A", "parameters": { "n": 16, "s": 128 } }, { "id": "FRANK0", "tier": "A", "parameters": { "n": 24, "orientation": 0 } }, { "id": "FRANK1", "tier": "A", "parameters": { "n": 24, "orientation": 1 } }, { "id": "WILKINSON", "tier": "A", "parameters": { "n": 20 } }, { "id": "GRCAR", "tier": "A", "parameters": { "n": 24, "upper_bandwidth": 3 } }, { "id": "MKS", "tier": "A", "parameters": { "n": 32, "m": 3, "delta": "1/8", "ell": 11, "kmax": 11 } }, { "id": "MARKOV", "tier": "A", "parameters": { "n": 16, "epsilon_exponent": 80, "representation": "stochastic" } }, { "id": "PERRON_POS", "tier": "A", "parameters": { "n": 16, "epsilon_exponent": 80, "representation": "positive_similarity", "scale": "3/2" } }, { "id": "HAD_COMPLEX", "tier": "A", "parameters": { "n": 16, "s": 128, "phases": "quarter_turn_repeated" } } ], "native_baseline": true, "work_bits": [ 128, 256, 512 ], "reference_bits": [ 768, 896 ], "evaluation_bits": 1024, "expected_case_count": 21, "expected_measured_eig_rows": 168, "required_verification_profile": "demo" }, "stress": { "cases": [ { "id": "OO53_REAL", "tier": "S", "parameters": { "n": 32, "generation_bits": 53, "standard_form": "real" } }, { "id": "SIM_SIMPLE", "tier": "S", "parameters": { "n": 32, "gap_exponent": 300, "regime": "simple", "kmax": 1 } }, { "id": "TOEPLITZ", "tier": "S", "parameters": { "n": 64, "b": 4, "representation": "original" } }, { "id": "FORSYTHE", "tier": "S", "parameters": { "n": 32, "a": 40, "representation": "original", "kmax": 1 } }, { "id": "FRANK0", "tier": "A", "parameters": { "n": 48, "orientation": 0 } }, { "id": "WILKINSON", "tier": "A", "parameters": { "n": 40 } }, { "id": "MKS", "tier": "A", "parameters": { "n": 64, "m": 5, "delta": "1/8", "ell": 13, "kmax": 13 } }, { "id": "MARKOV", "tier": "A", "parameters": { "n": 32, "epsilon_exponent": 300, "representation": "stochastic" } } ], "native_baseline": true, "work_bits": [ 256, 512, 1024 ], "reference_bits": [ 1536, 1664 ], "evaluation_bits": 2048, "expected_case_count": 8, "expected_measured_eig_rows": 64, "required_verification_profile": null } } } mplapack-interop-0.5.1/docs/codex/neigt/verification-jobs.json0000644000230300031750000006257415274353473023732 0ustar rafaelrafael{ "schema": "neigt-verification-jobs-v1", "version": "1.0", "rules": { "all_jobs_mandatory": true, "checkers_cannot_trust_generator_roots": true, "auxiliary_solves_counted_separately": true, "no_stress_schedule": true, "candidate_newton_steps_max": 4, "contour_node_counts": [ 16, 32, 64 ], "completion_strategies_max": 2, "radius_trials_max": 8 }, "profiles": { "smoke": { "source_bits": 256, "reference_bits": [ 512, 640 ], "evaluation_bits": 768, "expected_job_count": 26, "jobs": [ { "id": "VS1-01", "tier": "V-S", "kind": "all_spectrum", "core_case": "OO53_REAL", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 256, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-02", "tier": "V-S", "kind": "all_spectrum", "core_case": "OO53_PAIR", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 256, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-03", "tier": "V-S", "kind": "all_spectrum", "core_case": "OO128_CLOSE", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 256, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-04", "tier": "V-S", "kind": "all_spectrum", "core_case": "TOEPLITZ", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 256, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-05", "tier": "V-S", "kind": "all_spectrum", "core_case": "HAD_BIDIAG", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 256, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-06", "tier": "V-S", "kind": "all_spectrum", "core_case": "FRANK0", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 256, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-07", "tier": "V-S", "kind": "all_spectrum", "core_case": "WILKINSON", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 256, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-08", "tier": "V-S", "kind": "all_spectrum", "core_case": "GRCAR", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 256, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS2-01", "tier": "V-S", "kind": "cluster_graph", "fixture": { "n": 6, "regime": "semisimple", "query_center": "1", "query_radius": "1/4" }, "cluster_dimension": 2, "candidate_source": "computed_subspace_bounded_schedule", "expected": "CERTIFIED_CLUSTER", "projector_required": true, "full_space_triviality_allowed": false, "centered_power_bound_required": false }, { "id": "VS2-02", "tier": "V-S", "kind": "cluster_graph", "fixture": { "n": 6, "regime": "jordan", "query_center": "1", "query_radius": "1/4" }, "cluster_dimension": 2, "candidate_source": "computed_subspace_bounded_schedule", "expected": "CERTIFIED_CLUSTER", "projector_required": true, "full_space_triviality_allowed": false, "centered_power_bound_required": true }, { "id": "VS2-03", "tier": "V-S", "kind": "cluster_graph", "fixture": { "n": 8, "regime": "two_jordan", "gap_exponent": 12, "query_center": "1+2^-13", "query_radius": "1/4" }, "cluster_dimension": 4, "candidate_source": "computed_subspace_bounded_schedule", "expected": "CERTIFIED_CLUSTER", "projector_required": true, "full_space_triviality_allowed": false, "centered_power_bound_required": true }, { "id": "VS2-04", "tier": "V-S", "kind": "cluster_graph", "fixture": { "n": 6, "regime": "mks_zero", "m": 3, "delta": "1/8", "query_center": "0", "query_radius": "1/8" }, "cluster_dimension": 4, "candidate_source": "computed_subspace_bounded_schedule", "expected": "CERTIFIED_CLUSTER", "projector_required": true, "full_space_triviality_allowed": false, "centered_power_bound_required": true }, { "id": "VS3-01", "tier": "V-S", "kind": "pseudospectrum_point", "fixture": { "family": "exact_similarity", "n": 4, "regime": "jordan" }, "center": { "real": "1", "imag": "0" }, "epsilon": "2^-12", "expected": "CERTIFIED_INSIDE", "target": "exact_expression_zI_minus_A", "candidate_source": "svd_at_highest_work_bits" }, { "id": "VS3-02", "tier": "V-S", "kind": "pseudospectrum_point", "fixture": { "family": "grcar", "n": 8, "upper_bandwidth": 3 }, "center": { "real": "16", "imag": "16" }, "epsilon": "2^-8", "expected": "CERTIFIED_OUTSIDE", "target": "exact_expression_zI_minus_A", "candidate_source": "svd_at_highest_work_bits" }, { "id": "VS3-03", "tier": "V-S", "kind": "pseudospectrum_cell", "fixture": { "family": "exact_similarity", "n": 4, "regime": "jordan" }, "center": { "real": "1", "imag": "0" }, "epsilon": "2^-12", "expected": "CERTIFIED_INSIDE", "target": "exact_expression_zI_minus_A", "candidate_source": "svd_at_highest_work_bits", "halfwidths": { "real": "2^-16", "imag": "2^-16" } }, { "id": "VS3-04", "tier": "V-S", "kind": "pseudospectrum_cell", "fixture": { "family": "grcar", "n": 8, "upper_bandwidth": 3 }, "center": { "real": "16", "imag": "16" }, "epsilon": "2^-8", "expected": "CERTIFIED_OUTSIDE", "target": "exact_expression_zI_minus_A", "candidate_source": "svd_at_highest_work_bits", "halfwidths": { "real": "1/8", "imag": "1/8" } }, { "id": "VA1-01", "tier": "V-A", "kind": "factor_boxes", "fixture": { "n": 4, "regime": "real_simple" }, "required_claims": [ "CERTIFIED_EIGENFACTORS", "CERTIFIED_SCHUR_TRIANGULAR" ], "leading_invariant_dimension": null, "candidate_source": "computed_eigen_or_cluster_data" }, { "id": "VA1-02", "tier": "V-A", "kind": "factor_boxes", "fixture": { "n": 4, "regime": "complex_simple" }, "required_claims": [ "CERTIFIED_EIGENFACTORS", "CERTIFIED_SCHUR_TRIANGULAR" ], "leading_invariant_dimension": null, "candidate_source": "computed_eigen_or_cluster_data" }, { "id": "VA1-03", "tier": "V-A", "kind": "factor_boxes", "fixture": { "n": 4, "regime": "defective_block" }, "required_claims": [ "CERTIFIED_CLUSTER", "CERTIFIED_BLOCK_SCHUR" ], "leading_invariant_dimension": 2, "candidate_source": "computed_eigen_or_cluster_data" }, { "id": "VA2-01", "tier": "V-A", "kind": "finite_pencil", "fixture": { "n": 6, "regime": "real_simple", "B_recipe": "I+N_with_coherent_phase_if_complex" }, "candidate_source": "verified_solve_reduction", "public_generalized_eig_required": false, "required_claims": [ "CERTIFIED_ALL_FINITE" ], "leading_cluster_dimension": null }, { "id": "VA2-02", "tier": "V-A", "kind": "finite_pencil", "fixture": { "n": 6, "regime": "complex_simple", "B_recipe": "I+N_with_coherent_phase_if_complex" }, "candidate_source": "verified_solve_reduction", "public_generalized_eig_required": false, "required_claims": [ "CERTIFIED_ALL_FINITE" ], "leading_cluster_dimension": null }, { "id": "VA2-03", "tier": "V-A", "kind": "finite_pencil", "fixture": { "n": 6, "regime": "defective_cluster", "B_recipe": "I+N_with_coherent_phase_if_complex" }, "candidate_source": "verified_solve_reduction", "public_generalized_eig_required": false, "cluster_radius_target_exponent": -16, "required_claims": [ "CERTIFIED_ALL_FINITE", "CERTIFIED_CLUSTER" ], "leading_cluster_dimension": 2 }, { "id": "VA3-01", "tier": "V-A", "kind": "perron_pair", "fixture": { "n": 8, "epsilon_exponent": 24, "representation": "stochastic", "transpose": false, "scale": "1" }, "required_claims": [ "CERTIFIED_PERRON_ROOT", "CERTIFIED_PERRON_PAIR" ], "normalization": "sum(x)=1", "strict_component_positivity_required": true, "candidate_source": "computed_normalized_positive_pair" }, { "id": "VA3-02", "tier": "V-A", "kind": "perron_pair", "fixture": { "n": 8, "epsilon_exponent": 24, "representation": "stochastic", "transpose": true, "scale": "1" }, "required_claims": [ "CERTIFIED_PERRON_ROOT", "CERTIFIED_PERRON_PAIR" ], "normalization": "sum(x)=1", "strict_component_positivity_required": true, "candidate_source": "computed_normalized_positive_pair" }, { "id": "VA3-03", "tier": "V-A", "kind": "perron_pair", "fixture": { "n": 8, "epsilon_exponent": 24, "representation": "positive_similarity", "transpose": false, "scale": "3/2" }, "required_claims": [ "CERTIFIED_PERRON_ROOT", "CERTIFIED_PERRON_PAIR" ], "normalization": "sum(x)=1", "strict_component_positivity_required": true, "candidate_source": "computed_normalized_positive_pair" }, { "id": "VA3-04", "tier": "V-A", "kind": "perron_pair", "fixture": { "n": 8, "epsilon_exponent": 24, "representation": "positive_similarity", "transpose": true, "scale": "3/2" }, "required_claims": [ "CERTIFIED_PERRON_ROOT", "CERTIFIED_PERRON_PAIR" ], "normalization": "sum(x)=1", "strict_component_positivity_required": true, "candidate_source": "computed_normalized_positive_pair" } ] }, "demo": { "source_bits": 512, "reference_bits": [ 768, 896 ], "evaluation_bits": 1024, "expected_job_count": 26, "jobs": [ { "id": "VS1-01", "tier": "V-S", "kind": "all_spectrum", "core_case": "OO53_REAL", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 512, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-02", "tier": "V-S", "kind": "all_spectrum", "core_case": "OO53_PAIR", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 512, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-03", "tier": "V-S", "kind": "all_spectrum", "core_case": "OO128_CLOSE", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 512, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-04", "tier": "V-S", "kind": "all_spectrum", "core_case": "TOEPLITZ", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 512, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-05", "tier": "V-S", "kind": "all_spectrum", "core_case": "HAD_BIDIAG", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 512, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-06", "tier": "V-S", "kind": "all_spectrum", "core_case": "FRANK0", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 512, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-07", "tier": "V-S", "kind": "all_spectrum", "core_case": "WILKINSON", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 512, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS1-08", "tier": "V-S", "kind": "all_spectrum", "core_case": "GRCAR", "input_source": "highest_work_frozen_input", "candidate_source": "raw_highest_work_nobalance_V_D", "source_bits": 512, "expected": "CERTIFIED_ALL", "require_singletons": true }, { "id": "VS2-01", "tier": "V-S", "kind": "cluster_graph", "fixture": { "n": 6, "regime": "semisimple", "query_center": "1", "query_radius": "1/4" }, "cluster_dimension": 2, "candidate_source": "computed_subspace_bounded_schedule", "expected": "CERTIFIED_CLUSTER", "projector_required": true, "full_space_triviality_allowed": false, "centered_power_bound_required": false }, { "id": "VS2-02", "tier": "V-S", "kind": "cluster_graph", "fixture": { "n": 6, "regime": "jordan", "query_center": "1", "query_radius": "1/4" }, "cluster_dimension": 2, "candidate_source": "computed_subspace_bounded_schedule", "expected": "CERTIFIED_CLUSTER", "projector_required": true, "full_space_triviality_allowed": false, "centered_power_bound_required": true }, { "id": "VS2-03", "tier": "V-S", "kind": "cluster_graph", "fixture": { "n": 8, "regime": "two_jordan", "gap_exponent": 40, "query_center": "1+2^-41", "query_radius": "1/4" }, "cluster_dimension": 4, "candidate_source": "computed_subspace_bounded_schedule", "expected": "CERTIFIED_CLUSTER", "projector_required": true, "full_space_triviality_allowed": false, "centered_power_bound_required": true }, { "id": "VS2-04", "tier": "V-S", "kind": "cluster_graph", "fixture": { "n": 6, "regime": "mks_zero", "m": 3, "delta": "1/8", "query_center": "0", "query_radius": "1/8" }, "cluster_dimension": 4, "candidate_source": "computed_subspace_bounded_schedule", "expected": "CERTIFIED_CLUSTER", "projector_required": true, "full_space_triviality_allowed": false, "centered_power_bound_required": true }, { "id": "VS3-01", "tier": "V-S", "kind": "pseudospectrum_point", "fixture": { "family": "exact_similarity", "n": 4, "regime": "jordan" }, "center": { "real": "1", "imag": "0" }, "epsilon": "2^-12", "expected": "CERTIFIED_INSIDE", "target": "exact_expression_zI_minus_A", "candidate_source": "svd_at_highest_work_bits" }, { "id": "VS3-02", "tier": "V-S", "kind": "pseudospectrum_point", "fixture": { "family": "grcar", "n": 8, "upper_bandwidth": 3 }, "center": { "real": "16", "imag": "16" }, "epsilon": "2^-8", "expected": "CERTIFIED_OUTSIDE", "target": "exact_expression_zI_minus_A", "candidate_source": "svd_at_highest_work_bits" }, { "id": "VS3-03", "tier": "V-S", "kind": "pseudospectrum_cell", "fixture": { "family": "exact_similarity", "n": 4, "regime": "jordan" }, "center": { "real": "1", "imag": "0" }, "epsilon": "2^-12", "expected": "CERTIFIED_INSIDE", "target": "exact_expression_zI_minus_A", "candidate_source": "svd_at_highest_work_bits", "halfwidths": { "real": "2^-16", "imag": "2^-16" } }, { "id": "VS3-04", "tier": "V-S", "kind": "pseudospectrum_cell", "fixture": { "family": "grcar", "n": 8, "upper_bandwidth": 3 }, "center": { "real": "16", "imag": "16" }, "epsilon": "2^-8", "expected": "CERTIFIED_OUTSIDE", "target": "exact_expression_zI_minus_A", "candidate_source": "svd_at_highest_work_bits", "halfwidths": { "real": "1/8", "imag": "1/8" } }, { "id": "VA1-01", "tier": "V-A", "kind": "factor_boxes", "fixture": { "n": 4, "regime": "real_simple" }, "required_claims": [ "CERTIFIED_EIGENFACTORS", "CERTIFIED_SCHUR_TRIANGULAR" ], "leading_invariant_dimension": null, "candidate_source": "computed_eigen_or_cluster_data" }, { "id": "VA1-02", "tier": "V-A", "kind": "factor_boxes", "fixture": { "n": 4, "regime": "complex_simple" }, "required_claims": [ "CERTIFIED_EIGENFACTORS", "CERTIFIED_SCHUR_TRIANGULAR" ], "leading_invariant_dimension": null, "candidate_source": "computed_eigen_or_cluster_data" }, { "id": "VA1-03", "tier": "V-A", "kind": "factor_boxes", "fixture": { "n": 4, "regime": "defective_block" }, "required_claims": [ "CERTIFIED_CLUSTER", "CERTIFIED_BLOCK_SCHUR" ], "leading_invariant_dimension": 2, "candidate_source": "computed_eigen_or_cluster_data" }, { "id": "VA2-01", "tier": "V-A", "kind": "finite_pencil", "fixture": { "n": 6, "regime": "real_simple", "B_recipe": "I+N_with_coherent_phase_if_complex" }, "candidate_source": "verified_solve_reduction", "public_generalized_eig_required": false, "required_claims": [ "CERTIFIED_ALL_FINITE" ], "leading_cluster_dimension": null }, { "id": "VA2-02", "tier": "V-A", "kind": "finite_pencil", "fixture": { "n": 6, "regime": "complex_simple", "B_recipe": "I+N_with_coherent_phase_if_complex" }, "candidate_source": "verified_solve_reduction", "public_generalized_eig_required": false, "required_claims": [ "CERTIFIED_ALL_FINITE" ], "leading_cluster_dimension": null }, { "id": "VA2-03", "tier": "V-A", "kind": "finite_pencil", "fixture": { "n": 6, "regime": "defective_cluster", "B_recipe": "I+N_with_coherent_phase_if_complex" }, "candidate_source": "verified_solve_reduction", "public_generalized_eig_required": false, "cluster_radius_target_exponent": -16, "required_claims": [ "CERTIFIED_ALL_FINITE", "CERTIFIED_CLUSTER" ], "leading_cluster_dimension": 2 }, { "id": "VA3-01", "tier": "V-A", "kind": "perron_pair", "fixture": { "n": 8, "epsilon_exponent": 40, "representation": "stochastic", "transpose": false, "scale": "1" }, "required_claims": [ "CERTIFIED_PERRON_ROOT", "CERTIFIED_PERRON_PAIR" ], "normalization": "sum(x)=1", "strict_component_positivity_required": true, "candidate_source": "computed_normalized_positive_pair" }, { "id": "VA3-02", "tier": "V-A", "kind": "perron_pair", "fixture": { "n": 8, "epsilon_exponent": 40, "representation": "stochastic", "transpose": true, "scale": "1" }, "required_claims": [ "CERTIFIED_PERRON_ROOT", "CERTIFIED_PERRON_PAIR" ], "normalization": "sum(x)=1", "strict_component_positivity_required": true, "candidate_source": "computed_normalized_positive_pair" }, { "id": "VA3-03", "tier": "V-A", "kind": "perron_pair", "fixture": { "n": 8, "epsilon_exponent": 40, "representation": "positive_similarity", "transpose": false, "scale": "3/2" }, "required_claims": [ "CERTIFIED_PERRON_ROOT", "CERTIFIED_PERRON_PAIR" ], "normalization": "sum(x)=1", "strict_component_positivity_required": true, "candidate_source": "computed_normalized_positive_pair" }, { "id": "VA3-04", "tier": "V-A", "kind": "perron_pair", "fixture": { "n": 8, "epsilon_exponent": 40, "representation": "positive_similarity", "transpose": true, "scale": "3/2" }, "required_claims": [ "CERTIFIED_PERRON_ROOT", "CERTIFIED_PERRON_PAIR" ], "normalization": "sum(x)=1", "strict_component_positivity_required": true, "candidate_source": "computed_normalized_positive_pair" } ] } } } mplapack-interop-0.5.1/docs/codex/neigt/MILESTONES.md0000644000230300031750000003750615274353473021423 0ustar rafaelrafael# NEIGT00--NEIGT25: sequential implementation and evidence One active milestone at a time. Preserve separable commits/changes and write its root-level `neigtXX-report.md` after running its gate. Continue after PASS without routine confirmation. Never claim a later gate passed because a previous report or a Markdown specification exists. An implementation defect produces a minimal reproducer; dependent milestones stop, independent safe work may be reported. For each report record task/version, branch, starting and tested commit/dirty state, paths changed, module resolution, commands, exit statuses, measured results, coverage, proof obligations enforced, PASS/FAIL/BLOCKED, and limitations. Do not rewrite earlier reports to hide failures. If a report already exists, preserve it and use a dated/suffixed attempt with an index linking the history. ## NEIGT00 — repository, sources and real API audit Read all applicable repository instructions, prior NEIG/SVD/SVT/NEIGV code and reports, manifest/source package tools, documentation sources and numerical APIs. Audit actual real/complex eig outputs and balance options, scalar precision/RN contracts, QR, solves and SVD. Record actual module paths; separate a source-tree wrapper from an installed-package test. Generalized eig and public Schur are optional candidate/comparison paths, not prerequisites. Check all source ledger DOIs against the provided metadata; access failures are recorded, not invented. **Gate:** local essentials and existing focused tests pass; scope and exact reuse plan recorded; no unauthorized dependency/API changes. Missing Octave/package or unknown required rounding behavior is BLOCKED, never PASS. ## NEIGT01 — integration skeleton and manifest coverage Add the additive facade, strict options, profile dispatch and selftest skeleton. Allocate four different next-free example numbers and reconcile actual test paths. Parse the two JSON manifests without lossy numeric conversion; dyadic parameters are strings/exponents. Validate 20/21/8 cases and 120/168/64 row counts, and 26 V jobs for each mandatory profile. A not-yet-implemented tier is NOT_IMPLEMENTED, not silently skipped under `all`. **Gate:** option/error/state/path/coverage tests pass; filtered scope_ok is distinct from all-tier ok; existing entry points and reports remain intact. ## NEIGT02 — exact construction, freezing and widening Implement deterministic Sylvester Hadamard, N, integer unit-triangular X/Y, exact dyadic models, bit-length guards, immutable frozen inputs and exact widening. Record generation/model/work roles separately. Implement independent exact-product checks with sufficient guard precision, including bounds on intermediate partial sums rather than only final entries. Native is a once-rounded model. **Gate:** X*Y=Y*X=I, Hadamard orthogonality, real/complex widening value identity, 2^-1500 retention, below-guard classification, aliases and exception restoration. No decimal round-trip widening or silently higher-precision work inputs. ## NEIGT03 — matching, metrics and reference engine Implement MP minimum-bottleneck matching with exhaustive small checks and the duplicate/missing-root traps. Add right/left residuals with correct conjugation, condition status, ordinary cluster QR/projector diagnostics and reference roles. Never mutate eig outputs. Log references and candidate work separately. **Gate:** synthetic complex/real triples and deliberate wrong left conjugation are detected; MP-only tiny distances and exhaustive assignments pass; zero-root relative error and defective simple-root condition are not misreported. ## NEIGT04 — actual Ozaki--Ogita generator Implement GENERATOR-OO.md completely, including phi/psi/ufp ratios, theorem predicate, alpha/sigma, two-step rounding, paired real blocks and both exact triple-product checks. Fix generation precision independently of eig precision. Implement the 53-bit generator with audited public MP or native scalar RN as specified; using native generation here is not an MP eig fallback. **Gate:** all six smoke/demo generator fixtures have exact product checks, requested/realized differences and frozen hashes. OO128_CLOSE realizes exactly the 2^-80 first-pair gap while removing the 2^-120 requested increment. Both balance-mode highest-work forward gates pass. Never swap in a generic generator. ## NEIGT05 — exact simple, repeated, defective and merged clusters Implement all four SIM regimes through the same exact similarity. Test algebraic multiplicities and representative nilpotent powers using guarded integer/dyadic arithmetic. Separate success semantics by regime. Build independent model subspace checks without allowing those bases into positive certificate candidate paths. **Gate:** all SIM ordinary smoke/demo gates pass; an exact Jordan block is not reported as diagonalizable; semisimple multiplicity is not labeled defect. ## NEIGT06 — Toeplitz and symmetric control Implement the original and directly constructed symmetric matrices, stable MP sine/cosine references, closed-form left/right vectors and analytic conditions. Verify A*D=D*B by exact scaling. Test n=2 and several orders before full profiles. **Gate:** spectrum, condition and original-coordinate residual gates pass in both modes; condition(A), condition(D) and individual eigenvalue conditions remain separate. No mandatory balancing-improvement claim. ## NEIGT07 — Forsythe extension and zero limit Reuse the existing definition if compatible. Add nonzero original/scaled and zero limit in the same family. Test odd/even circle references in unit tests, exact r/epsilon and the diagonal-similarity identity. Constructor-only stress conversion must identify epsilon underflow at n=32,a=40 as a changed native model. **Gate:** nonzero circle gates and zero-limit defective gate pass; no nonexistent full eigenbasis is demanded; repeated circles are matched bijectively. ## NEIGT08 — reuse Hadamard and Frank without semantic drift Connect HAD_BIDIAG, both explicit Frank orientations and the independent Hermite-Jacobi reference. Check small characteristic recurrences and reflected transpose identity. Retain existing examples and their commands. Prepare, but do not yet require, the complex Hadamard wrapper for NEIGT22. **Gate:** existing regressions plus new matching/precision/condition gates pass. Gallery may be a comparator, not copied implementation or unexamined oracle. ## NEIGT09 — Wilkinson and polynomial backward error Implement exact guarded coefficient recurrence, small coefficient fixtures and Horner zero checks at sufficient guard precision. Native is a single rounding of the exact model. Implement rootwise complex coefficientwise backward error under the explicit non-monic perturbation convention in CASES.md. **Gate:** coefficient/source spectrum invariants and smoke/demo gates pass; model/frozen input errors and polynomial/matrix backward errors are separate. Do not call ordinary eig a companion-QR implementation from the cited paper. ## NEIGT10 — Grcar and MKS model 1 Reuse Grcar integers. Implement MKS's nilpotent shift plus rank-one matrix and reduced polynomial, exact determinant identity tests and rational polynomial gcd. Retain exact zero multiplicity separately from numerical zero disks. Use an independently solved smaller companion for nonzero reference roots. **Gate:** zero/nonzero decomposition, exact small determinant checks, square-free mandatory reduced polynomials, both-mode ordinary gates pass. The nonzero roots must not be confused with rounding-induced apparent roots near zero. ## NEIGT11 — stochastic and positive Perron models Implement the two lazy cyclic blocks, nonuniform teleportation vector, positive stochastic model and nonunitary positive similarity. Derive and test the spectrum, nontrivial stationary solve, exact row sums and positivity at model precision. Preserve the difference between rounded native and exact stochastic matrices. **Gate:** known spectrum, stationary equations, model gap and standard ordinary gates pass. Do not substitute r for the stationary vector or call every small-gap matrix strongly nonnormal without measured evidence. ## NEIGT12 — complete ordinary profiles and preliminary reporting Run all core smoke/demo rows, including the complex demo control. Implement raw hash binding, numerical reference status, environment and provisional reports. No `all` PASS is allowed while mandatory verification is not implemented. A `numerics_only_complete` field may honestly record successful S/A coverage. **Gate:** 120 smoke and 168 demo rows present; every fixed numerical/generation gate passes; missing/failed rows cannot disappear from a summary. ## NEIGT13 — audited outward arithmetic and exact serialization Implement ARITHMETIC.md or reuse an equivalent actually audited SVT implementation through a tested example-local facade. Confirm real RN primitive/range semantics from source, not only numerical probes. Implement rectangles, explicit interval products/norms, verified inverse residual, exact dyadic encoding/decoding and proof-witness schema. No global rounding setter or installed interval API. **Gate:** exact rational corner/adversarial tests, complex conjugation, range and zero-witness tests, serialization round-trip and restart replay pass. Document every assumption and its source/code enforcement. Unproved arithmetic is BLOCKED. ## NEIGT14 — V-S1 all-spectrum counts Implement verified similarity residual, Gershgorin disks, overlap supergraph and homotopy counting. Distinguish valid broad coverage from singleton usefulness. Never count approximate eigenvalues without proving the basis nonsingular. **Gate:** VS1-01..08 pass on raw highest-work nobalance candidates; all n roots are covered exactly once, first OO close pair remains separated, all negative counting and inverse tests pass. Higher-precision rescue data cannot replace those jobs. ## NEIGT15 — bounded candidate preparation and invariant graph Implement selected-cluster candidate QR, contour solves, bounded candidate Newton correction and alternative complement strategy. Implement the Riccati graph contraction with the nonconjugating Kronecker transpose and quadratic bound. Measure every auxiliary operation separately; roots/model basis are not trusted. **Gate:** exact synthetic graph checks and computed SIM_REPEAT/SIM_JORDAN jobs prove nontrivial invariant bases; deliberately wrong complex transpose, singular preconditioner and failed contraction do not produce certificates. ## NEIGT16 — cluster identification, nilpotent power and projectors Complete exact root counting/separation of M and D2, centered-power spectral disks and raw-basis orthogonal-projector bound. Finish merged two-Jordan and MKS-zero jobs with computed candidates, not generator columns. **Gate:** all VS2-01..04 pass their widths/projectors, including merged-group physical-spread allowance; graph existence alone is not claimed as an isolated cluster. Invalid separation and full-space triviality traps pass. ## NEIGT17 — V-S3 verified pseudospectrum points and cells Reuse the actual audited SVT polar/Weyl checker or implement the included bounded baseline. Bind exact expression zI-A, candidate SVD and proof residual. Add closed point classification and the 1-Lipschitz cell extension. **Gate:** VS3-01..04 achieve their prescribed inside/outside states, positive-area cells are genuinely covered, straddling and boundary cases remain inconclusive when warranted. A grid does not become a global boundary proof. ## NEIGT18 — V-A1 compatible eigenfactor boxes Run k=1 graph proofs for all simple roots, assemble compatible E and Lambda, verify interval E nonsingularity and enclose dual W=(E^-1)'. Record gauges and simultaneous-existence proof rather than independently normalized columns. **Gate:** real/complex VA1 simple eigenfactor portions pass; wrong phases, permutations and repeated-root individual claims do not yield false factors. ## NEIGT19 — V-A1 true Schur and defective block Schur Implement interval evaluation of exact QR with strictly positive normalization bounds. Simple E yields genuine triangular Schur T; defective Y1 completion yields only block-upper-triangular T. Lower zeros need an algebraic invariance proof. **Gate:** complete VA1-01..03 pass, including true complex-coordinate Schur and nontrivial defective block Schur. No scalar triangular/diagonal label for an unreduced defective block, and no normalizing interval across zero. ## NEIGT20 — V-A2 finite generalized pencils Implement proved B nonsingularity and the reduction enclosure for B^-1 A, then feed the rectangle into the same spectrum/graph checkers. Map left vectors back and evaluate original-pencil residuals. Direct generalized eig is optional only. For the defective job, counted graph blocks and the proved regular finite pencil provide all-root coverage without requiring a full eigenvector basis. **Gate:** VA2-01..03 pass, with original A/B hashes, all finite root counts and nontrivial defective subspace. Singular B and bad inverse tests fail closed. No missing public eig(A,B) excuse for skipping the verified reduction. ## NEIGT21 — V-A3 Perron root and vector Implement positive-graph irreducibility, Collatz--Wielandt and normalized positive pair contraction. Process original/transposed stochastic and positive-similarity matrices. A root-only interval does not satisfy the vector requirement. **Gate:** VA3-01..04 pass widths, positivity and normalization; negative entries, reducibility, nonpositive boxes and bad Jacobian inverses cannot be certified. Perron-only evidence is not used to certify the second eigenvalue. ## NEIGT22 — all tiers integrated and proof audit Run all core rows and all 26 V jobs per profile in one invocation. Include the complex Hadamard control, frozen-native exploratory certificates and all negative proof tests. Review every certificate function against its theorem/preconditions, recording code locations, not merely a green test count. **Gate:** complete S/A/V coverage, strict scope_ok/ok semantics, no missing precondition, no hidden native fallback. Stress remains opt-in/NOT_RUN. ## NEIGT23 — output, independent replay and presentation Finalize TSV, exact serialized inputs/certificates, schema/version/hash binding, new-directory-only output, restart replay and report formatting. Replay must not call eig or reconstruct a different ideal matrix. Optional plotting must convert only at the display boundary, using MP log10 of positive error before double. **Gate:** round-trip/replay/tampering/output-conflict tests pass; plot=false is headless; graphics failure cannot invalidate numerical state or proof metadata. Test plots only when an actual backend is available and report NOT_RUN otherwise. ## NEIGT24 — tests, documentation and source-package integration Integrate four numbered examples and focused tests into actual existing runners. Update authoritative manual sources and regenerate derived docs with repository commands. Preserve all old numerical/regression paths. Build source package and inspect contents for helper directories, manifests, tests and required docs. **Gate:** existing relevant NEIG/SVT regressions, new tests, documentation example runner, format/tree/doc checks and source-package content checks pass. No API or backend inventory changes apart from documented example listings. ## NEIGT25 — isolated clean-package QA and final report Use an owned temporary install prefix and extracted source/example tree. Show `which` evidence that neither mp nor helpers resolve from the developer checkout by accident. Run complete smoke/demo and all verification jobs there; preserve failure logs. Do not overwrite a production prefix or publish a release. **Gate:** all required clean-package tests pass, exactly 26 milestone statuses are reported with actual tested revisions, and final task ok agrees with coverage and proof results. Include measured table, commands, changed paths, certificates and honest limitations. Unexecuted environments/tests are NOT_RUN, never PASS. mplapack-interop-0.5.1/docs/codex/neigt/ACCEPTANCE.md0000644000230300031750000003130015274353473021311 0ustar rafaelrafael# Acceptance targets and status policy These are predeclared engineering gates, not claimed Octave observations or universal backward-error theorems. The preparation checks do not establish them. A missed mandatory target is FAIL/BLOCKED with evidence, not authorization to change a fixture, lower a threshold, or rename an inconclusive job as successful. ## 1. Coverage and counts `cases.json` is the ordinary measured-solve manifest. Without a filter: | Profile | Cases | Work precisions including native | Balance modes | Measured three-output eig calls | |---|---:|---|---:|---:| | smoke | 20 | native64, 128, 256 | 2 | 120 | | demo | 21 | native64, 128, 256, 512 | 2 | 168 | | stress, explicit opt-in | 8 | native64, 256, 512, 1024 | 2 | 64 | Native is run once per case/mode. Reference eig/SVD, contour/linear solves, candidate refinement, values-only API probes and verifier calls are separately counted. Every smoke/demo run also has **26 verification jobs**, as specified in `verification-jobs.json`: 8 V-S1, 4 V-S2, 4 V-S3, 3 V-A1, 3 V-A2 and 4 V-A3. A job may make several documented primitive/candidate/checker calls; 26 is the number of required top-level jobs, not the total number of numerical operations. Stress has no mandatory additional V schedule. Never count its absent V jobs as smoke/demo passes. Independent unit/adversarial tests are not included in the 26. ## 2. Common ordinary-solve checks Each MP smoke/demo row must have correct finite outputs, nonzero left/right columns, exact raw-input preservation, state restoration and valid bijective matching. The four normalized residuals in NUMERICS.md must be <= ```text tau_res = 2^16 * n^2 * 2^(-p). ``` Use MP arithmetic to build this envelope. In genuine defective cases a singular returned eigenvector matrix and unresolved simple-root condition estimates are legitimate; a zero vector column or unexplained exception is not. Do not require `inv(V)` or finite `cond(V)` there. For successful native rows record the same metrics but impose no forward/residual target and no prescribed failure pattern. A native solver exception is retained and makes the requested comparison incomplete. The model-generation/exactness tests are independent of accuracy. At the highest work precision of each mandatory profile every model must be represented exactly, including every integer coefficient. A below-guard lower-precision input is only permitted where the manifest explicitly allows rounding and records it. Native rounding is measured; no native model-rank assertion is made without an exact proof. ## 3. Highest-work-precision forward targets The following use model errors only when input equality with the model is proved. For a different frozen input label the two errors separately. Highest work bits are 256 for smoke and 512 for demo. Define scale `a_scale=max(mp(1),norm(A_model,"fro"))`. This scale is for ordinary forward diagnostics, not an independently verified norm. Report unscaled and relative errors as well when defined; do not use a large scale to conceal the additional circle, gap, or conditioning tests below. | Case class | Smoke | Demo | |---|---:|---:| | All simple or semisimple models | absolute bottleneck / a_scale <= 2^-80 | <= 2^-160 | | Frank orientations, additionally | relative bottleneck <= 2^-80 | <= 2^-160 | | Hadamard bidiagonal, additionally | absolute bottleneck <= 2^-80 | <= 2^-120 | | Forsythe nonzero original/scaled, additionally | circle bottleneck <= 2^-80 | <= 2^-120 | | True defective model groups | absolute bottleneck / a_scale <= 2^(-floor(p/(4*kmax))) | same formula | Here kmax is a **proved upper bound** on the maximum Jordan-block size: 2 for SIM_JORDAN and SIM_TWO_JORDAN; n for FORSYTHE_ZERO; ell for MKS's zero part. For MKS also require the nonzero-root subset, separated using the reduced model polynomial, to meet the simple-model target. For SIM defective families require the isolated simple roots outside the Jordan blocks to meet that target as well. Do not impose exponential-in-p simple-root accuracy on a size-k Jordan splitting. For the mixed zero/nonzero MKS model, matching uses all n roots including the algebraic zeros. The reduced polynomial must be square-free by an exact gcd test at the mandatory dimensions, not by a numerical root-gap guess. An unexpected multiple nonzero root is a specification failure to investigate. Analytic condition checks: on highest-precision HAD_BIDIAG/HAD_COMPLEX and TOEPLITZ/TOEPLITZ_SYM, compare each resolved simple-root condition estimate with its independently evaluated formula. Maximum relative disagreement <=2^-40 smoke, <=2^-80 demo. Pairing must be shared with the spectrum. Do not identify cond(D) with individual eigenvalue condition numbers. OO checks are stronger than merely small errors: exact intermediate products, Theorem-1 predicate, requested-versus-realized fields, paired conjugacy, fixed model identity across work bits, and the specified surviving/removed gaps all must pass. Treat formula violations as generation failure before eig is called. There is no adjacent-precision monotonicity or automatic-balancing-improvement gate. Lower-precision forward errors alone may be INSUFFICIENT_PRECISION. Fixed final work bits, reference settings and parameters cannot be changed silently. ## 4. V-S1: eight useful counted all-spectrum jobs Each job uses the highest-work-precision **nobalance** result of its core case, with the corresponding exact frozen input. Use those raw V and D as the first candidate. Compute an inverse candidate at q; this does not change the eig output. For these eight required jobs do not replace raw V,D with a higher-precision solve to pass a width target. The similarity checker verifies the actual supplied data. Require CERTIFIED_ALL, exactly n counted roots, n singleton components, and maximum disk radius / max(1,verified upper Frobenius norm of A) <=2^-40 smoke or 2^-64 demo. Additionally OO128_CLOSE's first pair must be certified as two separate singletons; a broad disk enclosing both is valid but fails this useful-case gate. The real complex-pair OO case certifies nonreal conjugate regions, not two real roots. The fixed cases are OO53_REAL, OO53_PAIR, OO128_CLOSE, TOEPLITZ, HAD_BIDIAG, FRANK0, WILKINSON and GRCAR. If a required raw candidate is not good enough, report that result, not a relabeled auxiliary solve. Extra rescue experiments are permitted under new candidate IDs, but do not change the mandatory result. ## 5. V-S2: four nontrivial cluster/subspace jobs Jobs use the explicitly smaller fixtures in `verification-jobs.json`, not a full n=32 Riccati problem. Candidate preparation is bounded by NUMERICS.md. Candidates may be computed at r1/r2, but their origin/bits and extra solves are recorded. Require all graph contraction inequalities, nonsingular full X, full-rank Y1, strict separation of the certified M and D2 spectral regions, exactly k cluster roots with complementary count n-k, and CERTIFIED_CLUSTER. No full-space identity projector counts. The certified raw-X1 orthogonal-projector error bound must be <=2^-40 smoke or <=2^-64 demo. For SIM_REPEAT, SIM_JORDAN and MKS-zero, require a certified cluster radius about the query center <=2^-24 smoke or <=2^-48 demo. For the **merged** two-Jordan group, with centers 1 and 1+d and query center 1+d/2, use radius <=2*d + that same target. The unavoidable physical cluster spread is not numerical certification error. The centered power enclosure is mandatory on defective jobs. Choosing another candidate basis or improving it within the bounded schedule is allowed; shrinking an interval by discarding outward uncertainty is not. The proof does not use the known generator basis, exact root multiplicity, or an unverified query contour. Also run a negative separated-cluster attempt with intentionally invalid claimed separation and require no false isolated-cluster certificate. An invariant-basis certificate without isolation is not the required CERTIFIED_CLUSTER result. ## 6. V-S3: four point/cell decisions Inside and outside points and cells have predetermined targets in the JSON file. Each must be classified with the polar/Weyl enclosure for the exact expression zI-A and, for cells, the certified Lipschitz radius. Preserve the input, SVD candidate and all proof terms. These are rigorous finite-matrix statements. Inside: simple/defective exact query center for a small Jordan-similarity matrix. Outside: a far point for Grcar. The cells have positive width; they are not point certificates renamed as cell certificates. Test scalar classification at a straddling interval separately and require INCONCLUSIVE. A coarse plot or observed SVD value is not evidence for any classification. ## 7. V-A1: compatible factors For the real and complex simple jobs, require simultaneously compatible right and dual left eigenfactor boxes and a true unitary triangular Schur factorization contained in the returned boxes. Show all root regions are simple/disjoint, all phase/gauge choices are consistent, and the interval exact-QR divisions have strictly positive lower bounds. Maximum component-radius divided by max(1,maximum candidate factor-entry magnitude) <=2^-40 smoke, <=2^-64 demo. For the defective job require the nontrivial leading two-dimensional invariant block and a unitary **block-upper-triangular** factorization; the lower-left block is zero by invariance. Do not zero the block's strictly lower triangle or claim a diagonal eigenfactorization exists. Use the same radius target. Report CERTIFIED_BLOCK_SCHUR explicitly, not CERTIFIED_SCHUR_TRIANGULAR. Negative phase/permutation and incompatible-factor tests must reject falsely small boxes. Interval factor products must enclose the target; this inclusion alone, without the existence proof, is not a substitute for the checker. ## 8. V-A2: finite pencils All three jobs require an outward nonsingularity witness for B, a reduction-error enclosure for B^(-1)A, and verified finite eigenvalue coverage of the original pencil. The simple real/complex jobs require n separated root regions, radius scaled by max(1,verified upper norm of C0) <=2^-32 smoke, <=2^-64 demo. Map left vectors with B^(-*) and check original-pencil residuals; never reuse ordinary left vectors untransformed. The defective job additionally requires its leading 2-root isolated invariant subspace with the V-S2 width/projector goals. Public eig(A,B) is an optional comparator; absence cannot omit this V-A2 target. The mandatory implementation is the verified finite solve-reduction. Reject a singular-B or unproved-invertible B case without a false finite-spectrum claim. Record infinite-root support as outside the declared domain, not implemented. ## 9. V-A3: four positive pair jobs Certify P, P', the positive diagonal-similarity model and its transpose on the specified small dimensions. Require positive vector box lower bounds, exact normalization equation, strict contraction, irreducibility witness and compatible root inclusion; intersect the Collatz--Wielandt root bound when it tightens it. Maximum root/vector interval radius, scaled by max(1,candidate magnitude), must be <=2^-32 smoke or <=2^-64 demo. The left stationary vector is nonuniform and must not be replaced by the teleportation r. Positivity and normalization are existence properties of the enclosed true pair, not just midpoint properties. The second-root/gap statement is separately checked on the MARKOV ordinary model and can be additionally certified using V-S1. It is not a conclusion of the Perron-only certificate. A rounded native matrix does not inherit exact row sums. ## 10. Negative tests, replay and task-level PASS Mandatory adversarial tests cover every proof precondition: interval crossing zero, nonfinite/range violations, singular or bad inverse candidates, touching spectral groups, duplicate roots, wrong complex transpose, graph gap collapse, defective individual-vector requests, SVD Gram defects, mixed gauges, singular B, negative matrix entries, reducibility and normalization errors. A broad mathematically valid enclosure is not itself a bug; a false narrow one is. Exact serialization must round-trip before and after process restart. Replay recomputes proof predicates on the recorded frozen targets without invoking eig or silently rebuilding the ideal model. Tampered input, shape, exponent, radius, method ID or bound must be detected. Zero-endpoint serialization is not negative zero preservation; signed floating zero is canonicalized to exact real zero. `scope_ok` is local to requested coverage; `ok` for all-tier smoke/demo requires all rows, all positive V jobs at their usefulness targets, all adversarial tests, no unresolved arithmetic contract, and no missing prerequisite. Ordinary error plots and stress cases have no authority to override these gates. Final completion also requires repository integration and clean-package QA from MILESTONES.md. mplapack-interop-0.5.1/docs/codex/neigt/SOURCES.md0000644000230300031750000002331215274353473021052 0ustar rafaelrafael# Primary-source ledger and attribution boundaries Checked: 2026-09-10. The title/authors/publication identifier below were matched against publisher or author/institution pages. Issue years are distinguished from online-first or preprint dates. No books are cited; ISBN checking is inapplicable. No licensed paper PDFs or third-party implementation source is redistributed. The finite verification methods in CERTIFICATES.md are original conservative baselines for the cited **targets**. They are not implementations of all cited algorithms or claims of their operation counts or sharpness. The OO generator is explicitly derived from that paper's Theorem 1, with suite-specific fixed inputs. ## OO22 — actual generator source Katsuhisa Ozaki; Takeshi Ogita. **Generation of test matrices with specified eigenvalues using floating-point arithmetic.** Numerical Algorithms **90**, 241--262 (2022). Online publication: 17 September 2021. DOI: **10.1007/s11075-021-01186-7**. ```text https://link.springer.com/article/10.1007/s11075-021-01186-7 ``` Publisher full HTML inspected: definitions and Theorem 1 for exact triple products, the rounded adjusted standard form, and paired-block construction. The implemented requested/realized distinction is essential. The selected X,Y, 53/128-bit models and parameter values are this suite's fixtures, not a claim to reproduce a numbered paper experiment. GENERATOR-OO.md includes all needed formulas. ## R22 — all eigenvalues/eigenvectors and exact Jordan similarity Siegfried M. Rump. **Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.** SIAM Journal on Matrix Analysis and Applications **43**(4), 1736--1754 (2022). DOI: **10.1137/21M1451440**. ```text https://epubs.siam.org/doi/10.1137/21M1451440 https://www.tuhh.de/ti3/paper/rump/Ru22a.pdf ``` Publisher metadata/abstract and author-manuscript parsed text inspected. The integer unit-triangular similarity preserving true Jordan structure is the source of SIM fixtures. V-S1 counts all roots and V-S2 targets invariant subspaces; our Gershgorin/graph baselines do not reproduce Rump's complete algorithm. The PDF screenshot tool failed during preparation; no numerical table values are transcribed or claimed visually verified. ## R01 — multiple/near-multiple eigenvalues and subspaces Siegfried M. Rump. **Computational error bounds for multiple or nearly multiple eigenvalues.** Linear Algebra and its Applications **324**(1--3), 209--226 (2001). DOI: **10.1016/S0024-3795(00)00279-2**. ```text https://www.sciencedirect.com/science/article/pii/S0024379500002792 ``` Publisher metadata/abstract matched. Motivates cluster/defective invariant-subspace inclusion and the distinction from individual eigenvectors. The dyadic two-Jordan fixture and this Riccati contraction baseline are independently specified here; not a literal reproduction of the paper's floating-point examples or code. ## NPT13 — Toeplitz reference formulas and sensitivity Silvia Noschese; Lionello Pasquini; Lothar Reichel. **Tridiagonal Toeplitz matrices: properties and novel applications.** Numerical Linear Algebra with Applications **20**(2), 302--326 (2013). Online-first: 2012. DOI: **10.1002/nla.1811**. ```text https://doi.org/10.1002/nla.1811 ``` Publisher metadata matched. The Toeplitz eigenvalue/eigenvector formulas specialize to the exact subdiagonal 1, diagonal 3, superdiagonal 2^-8 used here. The coefficient choice and explicit symmetric control are suite-designed. CASES.md gives direct identities sufficient for independent verification of their formulas. ## AMRVW18 — polynomial versus matrix backward error Jared L. Aurentz; Thomas Mach; Leonardo Robol; Raf Vandebril; David S. Watkins. **Fast and Backward Stable Computation of Roots of Polynomials, Part II: Backward Error Analysis; Companion Matrix and Companion Pencil.** SIAM Journal on Matrix Analysis and Applications **39**(3), 1245--1269 (2018). DOI: **10.1137/17M1152802**. ```text https://epubs.siam.org/doi/10.1137/17M1152802 ``` Publisher metadata matched. Supports keeping polynomial-coefficient and matrix backward errors distinct. No structured companion-QR/QZ algorithm from this paper is implemented here. Our rootwise coefficient perturbation formula has its own explicit complex/unconstrained-leading-coefficient convention. ## R06 — structured perturbations/pseudospectra Siegfried M. Rump. **Eigenvalues, pseudospectrum and structured perturbations.** Linear Algebra and its Applications **413**(2--3), 567--593 (2006). DOI: **10.1016/j.laa.2005.06.009**. ```text https://www.sciencedirect.com/science/article/pii/S0024379505003034 ``` Publisher metadata/abstract matched. Interpretation source: a structured perturbation class is not the same as unrestricted complex perturbations. Our required Grcar pseudospectrum is the unstructured complex 2-norm set, not a certified real-only or Toeplitz-preserving pseudospectrum. ## MKS25 — Toeplitz plus rank-one perturbation Saori Morimoto; Makoto Katori; Tomoyuki Shirai. **Eigenvalue and pseudospectrum processes generated by nonnormal Toeplitz matrices with rank 1 perturbations.** International Journal of Mathematics for Industry **17**(1), 2550013 (2025). DOI: **10.1142/S2661335225500133**. Preprint: arXiv:2401.08129, first submitted 2024. ```text https://doi.org/10.1142/S2661335225500133 https://arxiv.org/html/2401.08129v6 https://kyushu-u.elsevierpure.com/en/publications/eigenvalue-and-pseudospectrum-processes-generated-by-nonnormal-to/ ``` Author full HTML and institution publication record checked. Model 1 and its reduced nonzero-root polynomial are used; model 2 and the full stochastic/process study are not. The exact determinant identity is independently tested in the preparation script. The suite's n,m,delta choices are stated separately. ## F21 — related pseudospectrum enclosure target Andreas Frommer; Birgit Jacob; **Lukas Vorberg**; Christian Wyss; Ian Zwaan. **Pseudospectrum Enclosures by Discretization.** Integral Equations and Operator Theory **93**, article **9** (2021). Published 1 February 2021. DOI: **10.1007/s00020-020-02621-5**. ```text https://link.springer.com/article/10.1007/s00020-020-02621-5 ``` Publisher full HTML and metadata checked. The paper uses numerical ranges of shifted inverses and treats discretized operators. Our finite-matrix singular-value point/cell certifier is **not** that algorithm. It uses the closed pseudospectrum; the paper's open-set convention must not be silently substituted. No PDE/operator or entire-boundary convergence claim is made by the examples. ## RO24 — compatible matrix decomposition enclosures Siegfried M. Rump; Takeshi Ogita. **Verified Error Bounds for Matrix Decompositions.** SIAM Journal on Matrix Analysis and Applications **45**(4), 2155--2183 (2024). DOI: **10.1137/24M165096X**. ```text https://epubs.siam.org/doi/10.1137/24M165096X ``` Publisher metadata/abstract matched; eigendecomposition and Schur decomposition are among the targets. V-A1 here combines graph eigenfactor existence with interval evaluation of exact QR. It is a conservative independently proved baseline, not the paper's detailed algorithm or entrywise-optimal bounds. ## M14 — generalized eigenvalues and invariant subspaces Shinya Miyajima. **Fast Enclosure for All Eigenvalues and Invariant Subspaces in Generalized Eigenvalue Problems.** SIAM Journal on Matrix Analysis and Applications **35**(3), 1205--1225 (2014). DOI: **10.1137/140953150**. ```text https://epubs.siam.org/doi/10.1137/140953150 ``` Publisher metadata/abstract matched. Our verified B^-1 A reduction addresses finite nonsymmetric pencils with proved nonsingular B and accounts for reduction error. It does not implement general singular-B pencils, infinite eigenvalues, or all of this paper's methods. Those domain limits do not make the required nonsingular-B tests optional. ## M21 — Perron pair Shinya Miyajima. **Fast verification for the Perron pair of an irreducible nonnegative matrix.** Electronic Journal of Linear Algebra **37**, 402--415 (2021). Published 31 May 2021. DOI: **10.13001/ela.2021.5181**. ```text https://journals.uwyo.edu/index.php/ela/article/view/5181 ``` Journal metadata matched. Our Collatz--Wielandt plus normalized eigenpair contraction proves the same type of positive root/vector target, but is not a reproduction of the paper's specialized M-matrix-based method. It does not by itself certify the second eigenvalue or a mixing time. ## MPFR and repository contracts Official GNU MPFR manual: correctly rounded scalar operations and exponent/range semantics. The web manual version is not assumed to be the installed version. ```text https://www.mpfr.org/mpfr-current/mpfr.html ``` Target repository sources attempted during preparation: ```text https://github.com/nakatamaho/octave-mplapack https://raw.githubusercontent.com/nakatamaho/octave-mplapack/main/docs/eig.md https://raw.githubusercontent.com/nakatamaho/octave-mplapack/main/docs/precision-semantics.md ``` Those current repository fetches failed in this turn. Prior supplied NEIG/SVT specifications were read, but they are not proof of current code. The executor must audit the actual checkout and loaded package before relying on any API or rounding guarantee. No guessed current version/commit is embedded in this bundle. ## Cross-reference policy Each constructor records the source ID and whether it is a paper formula, specialization, or original control. Each verifier records its own method ID, source-inspired target and `paper_algorithm_reproduction=false`. Known algebraic model facts, high-precision consistency and certified inclusion are different metadata fields. Do not call the neighboring Hermitian/SVD verification theory a general nonsymmetric eigenvalue verifier. No new literature claim is accepted from a guessed DOI or from an uninspected citation chain. mplapack-interop-0.5.1/docs/codex/neigt/CASES.md0000644000230300031750000004013015274353473020562 0ustar rafaelrafael# Matrix cases: exact definitions, spectra, and independent checks All indices below are one-based unless stated otherwise. `cases.json` fixes the parameters. These are literature-derived deterministic fixtures, not claimed reproductions of the papers' numerical tables. All model entries are integers or dyadic rationals. Exact representability still requires enough significand bits. ## 0. Shared exact algebra N_n has N(i,i+1)=1, all other entries zero. H is the recursively generated Sylvester Hadamard matrix: H_1=[1], H_2m=[H_m,H_m;H_m,-H_m]. H*H'=n*I exactly. R is the reversal permutation matrix. Use exact small integers and powers of two. Use the exact inverse pair X=(I+N')*(I+N), Y=(I+N)^(-1)*(I+N')^(-1). Inverses are finite sums of powers of the strictly triangular parts. A=Y*J*X. Do not substitute a numerical inverse for this exact construction. For a real/complex exact dyadic product or sum, determine a sufficient evaluation precision before computing it. Put scalar terms over their common power-of-two denominator. If all integer terms have bit lengths <=b and there are t terms, `b+ceil_log2(max(1,t))+2` bits suffice for their sum. A product needs the sum of operand integer bit lengths plus a sign guard. Apply this to both matrix-product stages, including intermediates, then cancel powers of two only after the audit. The implementation may conservatively overestimate these guards. It must record them, reject insufficient exact-model precision, and verify equality after exact promotion. Cross-precision agreement by itself is not an exactness proof. For a normal work-precision construction below its guard, round an already exact model once, mark `rounded_model`, and preserve the changed matrix. Do not perform multiple low-precision polynomial/generator operations then call the resulting input the once-rounded model. OO generation is its own specified RN procedure. ## 1. OO53_REAL, OO53_PAIR, OO128_CLOSE [S1] Use GENERATOR-OO.md, including realized-spectrum storage and fixed generation precision. The exact triple-product generator is mandatory, not a generic fallback. ## 2. Exact similarities [S2] Use the inverse pair from Section 0. Fill unassigned diagonal entries after each cluster with 4,5,6,... in order, all distinct and separated from the target clusters. Use these J variants: - `SIM_SIMPLE`: leading block [1,1;0,1+d], d=2^-a. Other entries diagonal. All roots are simple; this is near-defective but diagonalizable. - `SIM_REPEAT`: leading block I_2. Other entries diagonal. The repeated root is **semisimple**, algebraic and geometric multiplicities both 2. - `SIM_JORDAN`: leading block [1,1;0,1]. Other entries diagonal. Root 1 has algebraic multiplicity 2 and geometric multiplicity 1. - `SIM_TWO_JORDAN`: leading two Jordan blocks of size 2 at 1 and 1+d, d=2^-a; remaining entries diagonal 4,5,... . Keep two-cluster and merged-cluster queries. Spectrum and Jordan multiplicities follow directly from J. The invariant subspace for a whole selected block is range(Y(:,J_indices)). A simple right vector is Y*v_J, a left column is X'*w_J; preserve complex conjugation if complex controls are added. For SIM_SIMPLE, a 2x2 triangular solve yields exact dyadic/rational vectors; the checker may instead use symbolic projectors or a high-precision reference. Never claim Y's coordinate columns individually diagonalize its non-diagonal 2x2 simple block. Model projectors are **orthogonal** projectors onto those ranges, constructed by high-precision QR for ordinary comparison. Their numerical evaluation is not a certificate; Tier V proves its own bounds without assuming the model answer. An oblique spectral projector Y(:,J)*X(J,:) is a different object, though exactly idempotent and commuting with A for a union of full J blocks. Label it separately. Tests: exact AX? Use `X*A=J*X` and `A*Y=Y*J` exactly. Verify small characteristic polynomials at integer arguments independently, along with the nilpotency order of the target block. A zero eigengap must not be treated as a simple-root failure of the solver. A full eigenbasis cannot exist in the Jordan cases. ## 3. Tridiagonal Toeplitz and symmetric control [S3, NPT13] ```text A = tridiag(1, 3, 2^(-2*b)) D = diag(2^(b*j), j=0..n-1) B = tridiag(2^-b, 3, 2^-b) D^(-1)*A*D = B ``` Construct B directly, not by a numerically computed inverse. Test A*D=D*B exactly. For theta_k=k*pi/(n+1), ```text lambda_k = 3 + 2^(1-b)*cos(theta_k) v_jk = 2^(b*(j-1))*sin(j*theta_k) w_jk = 2^(-b*(j-1))*sin(j*theta_k) ``` At reference precision evaluate MP pi/sin/cos, not native constants. Independent symmetric eig(B) is a reference cross-check. Set any exact symmetry endpoints consistently. Compute norms and overlaps of the analytic vectors in MP, then compare the individually normalized computed vectors up to a phase/sign when resolved. The analytic overlap is (n+1)/2 before column normalization. For b=4, the normwise matrix-condition upper bound is 1025/511, although the similarity scaling condition is 2^(4*(n-1)). Do not call that latter number the condition of each eigenvalue. Compute individual left/right conditions explicitly. The symmetric representation is a different coordinate system with different sensitivity and pseudospectrum. Original-coordinate output must stay labeled. ## 4. Forsythe split, scaled, and zero [S4] For r=2^-a, eps=r^n: ```text F = I+N; F(n,1)=eps P = N; P(n,1)=1 F_scaled=I+r*P D=diag(1,r,...,r^(n-1)) F*D=D*F_scaled lambda_k=1+r*exp(2*pi*i*k/n), k=0..n-1 ``` F_scaled is normal; construct it directly. Evaluate the circle in MP and set exact real endpoints explicitly. Circle error means matching `(lambda-1)/r` to the unit-circle roots, not ordinary relative error near 1. `FORSYTHE_ZERO` is F=I+N with eps=0. It is a genuine size-n Jordan block. No condition-number or unique-eigenvector success target applies. The whole-space projector I is a trivial oracle and **cannot satisfy** the mandatory nontrivial cluster-validation job by itself. Use SIM_JORDAN for that job. In stress only, an eps below the native exponent range can underflow. Record it as a changed input, not as an MP failure or exact-input native solve. ## 5. Hadamard-similar upper bidiagonal [A1] ```text T(i,i)=i; T(i,i+1)=s A=H*T*H'/n lambda_k=k ``` n is a power of two. Do not solve T instead of A. The condition reference is ```text kappa_k = sqrt(sum_{j=0}^{k-1} s^(2*j)/(j!)^2) * sqrt(sum_{j=0}^{n-k} s^(2*j)/(j!)^2). ``` Evaluate by MP multiplicative recurrences, not native factorials. Underlying right and left vectors of T have v_i=s^(k-i)/(k-i)! for i<=k and w_i=(-s)^(i-k)/(i-k)! for i>=k, both zero elsewhere; w'*v=1. Use the exact product bit guard; mandatory cases are native-exact as well. `HAD_COMPLEX`: Z=diag(1,i,-1,-i,...) and A_complex=Z*A*Z'. Spectrum and individual conditions are unchanged. All components remain dyadic. Test the complex left identity, not a transpose-only version. This case is demo-only in the core manifest. ## 6. Frank orientations [A2] ```text F0(i,j)=n+1-max(i,j) when j>=i-1; otherwise 0 F1=R*F0'*R ``` This explicitly fixes the reflected orientation. Compare with local gallery variants only after inspecting their definition; do not change these formulas to match a different flag convention. They are two orientations of one family. Both are exact integer Hessenberg matrices with the same spectrum. Independent symmetric reference: K has zero diagonal and K(j,j+1)=K(j+1,j)=sqrt(mp(j)). If z is an eigenvalue of K, use ```text f(z)=((z+sqrt(z*z+4))/2)^2 when z>=0 f(z)=(2/(sqrt(z*z+4)-z))^2 when z<0. ``` The characteristic polynomial satisfies P0=1, P1=x-1, Pn=(x-1)P(n-1)-(n-1)*x*P(n-2). This follows from the probabilists' Hermite recurrence under z=(x-1)/sqrt(x). Check small determinants independently: ```text n=2: [1,-3,1] n=3: [1,-6,6,-1] n=4: [1,-10,21,-10,1] n=5: [1,-15,55,-55,15,-1] ``` Check positivity, reciprocal pairing, and the odd-order central root 1. Use maximum relative as well as absolute error. A small determinant error alone is not enough. ## 7. Wilkinson companion and coefficient diagnostics [A3] p_n(z)=product(z-j,j=1..n)=z^n+c1*z^(n-1)+...+cn. Form the Frobenius matrix with first row -[c1,...,cn], ones on the first subdiagonal, all other entries zero. Build coefficients using exact integer recurrence, with sufficient precision. A conservative generation guard is n*ceil_log2(n+1)+2. A high-precision Horner check at integer roots needs at least 2*n*ceil_log2(n+1)+32 bits for exact intermediates. Do not use `mp(poly(1:n))` or `poly(eig(A))` as exact construction. Frozen native companion coefficients may differ from the exact polynomial. For a computed root z, report the rootwise **complex coefficientwise** backward error indicator ```text eta_poly(z) = abs(p(z)) / sum_{j=0}^n abs(c_j)*abs(z)^(n-j), c_0=1. ``` It permits relative perturbations of all nonzero coefficients, including c0; it is not the constrained-monic or real-coefficient backward error. Zero coefficients stay zero under this definition. The denominator-zero case is explicitly handled. Use a safely evaluated Horner denominator. Polynomial backward error does not replace eigenvalue forward error or mean the dense eig uses companion QR/QZ [AMRVW18]. Evaluate both model and frozen-input coefficient indicators with explicit labels. ## 8. Grcar [A4] G(i,j)=1 when 0<=j-i<=3; G(i,j)=-1 when i-j=1; otherwise 0. Exact 0,+/-1 input. Use general high-precision eig references at two precisions, and independent verification where required. No analytic spectrum is asserted. Optional ordinary Toeplitz perturbation diagnostics may project w*v' onto the Toeplitz linear space using its diagonal means and a declared Frobenius metric. Such a metric is not automatically the structured spectral-norm condition number from [R06]. The mandatory new feature is V-S3, not a loosely labeled contour plot. ## 9. Morimoto--Katori--Shirai model 1 [A5, MKS25] For 1<=m<=n, delta>0 dyadic: ```text A=N^m+delta*ones(n) ell=floor((n-1)/m)+1 q(z)=z^ell-delta*sum_{j=0}^{ell-1} (n-m*j)*z^(ell-1-j) char_A(z)=z^(n-ell)*q(z). ``` Use the polynomial form, never a rational formula singular at z=1. Its constant coefficient is -delta*(n-m*(ell-1))!=0. Hence zero has **exact algebraic multiplicity n-ell**. In the mandatory m=3 cases it is defective. Distinguish the geometric multiplicity m-1 (m0. For eps=2^-a define ```text P=(1-eps)*Q+eps*ones(n,1)*r' ``` All entries are positive and P*1=1 exactly **for the exact model**. P is not assumed normal. Its spectrum consists of ```text 1; 1-eps; (1-eps)*(1-a_b+a_b*exp(2*pi*i*k/h)), b=1,2, k=1..h-1. ``` Derivation: rank-one teleportation preserves the induced map on the quotient by span(1), while replacing one eigenvalue 1-eps by 1. The other block-constant mode has eigenvalue 1-eps. All other modes have modulus strictly below 1-eps. Thus the model's modulus spectral gap is eps; require h>=2. The stationary row is eps*r'*(I-(1-eps)*Q)^(-1); use a linear solve, not an inverse product, for its numerical reference. It is not equal to r' for these fixtures. Also compute it independently by a normalized stationary linear system. Do not use the formula as a certificate without verifying the solve. `PERRON_POS`: D=diag(2^j,j=0..n-1), A=(3/2)*D*P*D^(-1), constructed by exact row/column binary scaling. Its Perron root is 3/2; it is positive but not row stochastic. Spectrum scales by 3/2, right Perron vector is proportional to D*1, left is proportional to D^(-1)*pi. Verify normalization separately. A frozen rounded P need not remain **exactly** row-stochastic, even if printed row sums look like 1. Small positive teleportation entries can survive while subtraction from large diagonal entries is lost. Never force eigenvalue 1, replace a row sum, or infer reducibility from rounding without proof. Main MP cases have enough precision; native cases require input accounting. ## 11. Small verification-only targets These do not count as core eig rows. All use the same constructors. - SIM_SIMPLE, SIM_REPEAT, SIM_JORDAN, SIM_TWO_JORDAN at n=6 or 8 as in the V manifest. - A 4x4 simple complex case Z*(Y*diag(1,2,4,8)*X)*Z', Z=diag(1,i,-1,-i). - A 4x4 defective case with J2(1), 4, 8; for a nontrivial block Schur certificate. - Pencils: choose B=I+N (real) or Z*(I+N)*Z' (complex), C a specified small model, and A=B*C exactly. The checker receives only A,B and approximate data; the known C is validation data, not an unchecked replacement for B^(-1)*A. - Perron jobs at n=8, eps=2^-24 (smoke) or 2^-40 (demo), on P, P', A, A'. Exact input identity is mandatory for each job; record any allowed native rounding as a different target. Proof checkers must not receive a trusted root/multiplicity field from a generator and use it instead of their own numerical proof predicates. ## 11. Small verification-only fixtures These do not add measured core eig rows. Record all their solves as auxiliary. Use the same integer X=(I+N')*(I+N), Y=X^(-1) construction as Section S2, with independently verified exact products. - VS2 semisimple/Jordan: n=6; leading I2 or J2(1), complement diag(4,5,6,7). - VS2 two-Jordan: n=8; leading J2(1) and J2(1+d), complement diag(4,5,6,7). - VS2 MKS: A=N6^3+(1/8)*ones(6). Zero multiplicity 4; reduced roots `(3+sqrt(33))/8` and `(3-sqrt(33))/8`, separated from zero. These roots are independent test information, not trusted inputs to the graph proof. - VS3 inside target: n=4, A=Y*diag_blocks(J2(1),4,8)*X. Exact query z=1. Outside target: Grcar(8). Point/cell widths are in verification-jobs.json. - VA1 real simple: n=4, J=diag(1,2,4,8), A=Y*J*X. - VA1 complex simple: conjugate the preceding A by the diagonal matrix with entries [1,i,-1,-i]. This checks complex coordinates, not nonreal eigenvalues. Nonreal eigenvalues are already mandatory in OO53_PAIR and the VA2 complex job. - VA1 defective: n=4, J=diag_blocks(J2(1),4,8), A=Y*J*X. Leading k=2. - VA2 real simple: n=6, C=Y*diag(1,2,3,4,5,6)*X; B=I+N; A=B*C. - VA2 complex simple: n=6, use J=diag_blocks([1,1/2;-1/2,1],3,4,5,6), C0=Y*J*X; conjugate C0 and I+N coherently by Z=diag(1,i,-1,-i,1,i), giving C=Z*C0*Z', B=Z*(I+N)*Z', A=B*C. The first roots are 1+/-i/2. - VA2 defective: n=6, C=Y*diag_blocks(J2(1),4,5,6,7)*X; B=I+N; A=B*C. Certify the leading k=2 group and count the four complementary roots. - VA3: the MARKOV and PERRON_POS recipes at n=8 and the profile's epsilon, including their transposes. All are strictly positive exact dyadic models. `diag_blocks` above is mathematical block assembly, not an assumed public function. Build via existing indexing/concatenation. Known X,Y and J are used for independent constructor tests only; mandatory positive verification jobs prepare candidates from the frozen target with numerical routines and prove every checker predicate. mplapack-interop-0.5.1/docs/codex/neigt/PREPARATION.md0000644000230300031750000001041015274353473021506 0ustar rafaelrafael# Preparation evidence, not implementation acceptance Prepared 2026-09-10. No Octave or MPLAPACK execution was performed in this runtime; `command -v octave` found no executable. The numerical acceptance gates are predeclared targets to be executed by Codex in the user's checkout. A supplied instruction bundle is not proof of an implemented verifier. ## Exact rational checks actually executed `preparation/check_math.py` uses only Python's standard library, principally `fractions.Fraction` and integer arithmetic. It implements a rational binary RN model (ties to even) rather than assuming host floats are exact. | Check | Executed result | |---|---| | Ozaki--Ogita models | 6 fixtures: n=8/16, real53/pair53/close128; both products have zero rational rounding error | | Requested versus realized | Changes present in all 6; close128 retains exactly 2^-80 and removes the 2^-120 increment | | MKS characteristic formula | 168 exact determinant evaluations across n=3..9 and allowed m at four exact trial points | | Stochastic constructions | n=8, epsilon=2^-24 and n=16, epsilon=2^-80; exact positivity, row sums, nontrivial stationary equations and characteristic identities | | Outward primitives | 11,460 rational comparisons at q=64/128/256, including tiny values, four arithmetic operations and square roots | | Graph/inverse identities | A small nonzero-quadratic Riccati example, exact similarity and finite-pencil identities | The JSON result is `preparation/check-results.json`, with status `PASS_PREPARATION_ONLY`, `octave_executed=false`, `mplapack_executed=false`. The rational matrix hashes in that preparation file identify its own textual rational convention; they are not the production certificate binary hashes. The separate `preparation/validate_bundle.py` checks the two manifests, unique case/job IDs, 120/168/64 measured counts, 26 jobs per mandatory profile and 26 milestone headings; compiles bundled Python without creating cache files; checks Markdown fence balance; verifies exact square-freeness of the MKS reduced polynomials at (n,m)=(6,3),(12,3),(32,3),(64,5); and tests the installer in owned temporary Git-like directories. Its installer tests cover dry-run, initial copy, identical rerun, a conflicting file with all-file preflight, and symlink-parent rejection. `bundle-validation.json` records those preparation results. These checks are bug detectors, not exhaustive proofs of a completed implementation. In particular they do not audit a local mp binding's rounding, execute real MPFR calls through Octave, run eig/Schur/QR there, or prove a numerical result from a future implementation. The mathematical proofs and their locally enforced hypotheses in ARITHMETIC.md/CERTIFICATES.md are separate obligations. ## Reproduce checks without replacing existing evidence From the repository root after installing the instructions: ```bash python3 docs/codex/neigt/preparation/check_math.py --output /tmp/neigt-math-new.json python3 docs/codex/neigt/preparation/validate_bundle.py --bundle . --output /tmp/neigt-bundle-new.json ``` Use fresh output filenames. The bundle validator validates only paths in the bundle manifest; it does not certify unrelated repository contents or execute Octave. Its temporary install test reads the checksum manifest, so checksum verification must still be valid after copying the instructions. If any bundled specification is edited later, the original checksum mismatch is expected and must not be disguised as an unchanged bundle. ## Source-access qualifications Publisher/author full HTML was available for Ozaki--Ogita and the MKS preprint; publisher metadata and abstracts were used for the other listed identifiers as stated in SOURCES.md. The Rump2022 author PDF was parsed as text; web screenshot attempts failed, so no claims depend on visually reading its tables or figures. Current public GitHub repository fetches also failed in this preparation turn. Prior uploaded NEIG and SVT specifications were read for compatibility, but do not establish the executor's current code, API, package version or implemented verification primitives. NEIGT00/13 must establish those facts locally. No paper PDFs, licensed third-party source, font files, or compiled binaries are included. The ZIP contains instruction/source files and exact-arithmetic preparation evidence only. mplapack-interop-0.5.1/docs/codex/neigt/preparation/0000755000230300031750000000000015274353473021730 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/codex/neigt/preparation/validate_bundle.py0000644000230300031750000001204115274353473025422 0ustar rafaelrafael"""Check NEIGT manifests, installer safety and package invariants.""" from __future__ import annotations import hashlib import argparse import importlib.util import json from pathlib import Path import subprocess import sys import tempfile parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--bundle', type=Path, default=Path(__file__).resolve().parents[4]) parser.add_argument('--output', type=Path) args = parser.parse_args() root = args.bundle.expanduser().resolve() cases = json.loads((root/'docs/codex/neigt/cases.json').read_text()) jobs = json.loads((root/'docs/codex/neigt/verification-jobs.json').read_text()) counts={} for name, profile in cases['profiles'].items(): n=len(profile['cases']) assert n==profile['expected_case_count'] assert len({c['id'] for c in profile['cases']})==n rows=n*(len(profile['work_bits'])+1)*len(cases['standard_modes']) assert rows==profile['expected_measured_eig_rows'] counts[name]={'cases':n,'measured_rows':rows} if name in jobs['profiles']: block=jobs['profiles'][name] assert len(block['jobs'])==block['expected_job_count']==26 assert len({j['id'] for j in block['jobs']})==26 present={c['id'] for c in profile['cases']} assert all(j.get('core_case') in present for j in block['jobs'] if 'core_case' in j) prefixes={'VS1':8,'VS2':4,'VS3':4,'VA1':3,'VA2':3,'VA3':4} for prefix, number in prefixes.items(): assert {j['id'] for j in block['jobs'] if j['id'].startswith(prefix)}=={f'{prefix}-{i:02d}' for i in range(1,number+1)} counts[name]['verification_jobs']=26 text=(root/'docs/codex/neigt/MILESTONES.md').read_text() assert all(text.count(f'## NEIGT{i:02d} ')==1 for i in range(26)) listed_paths = [] for line in (root/'SHA256SUMS-NEIGT').read_text().splitlines(): checksum, relative = line.split(' ', 1) parts = Path(relative).parts assert not Path(relative).is_absolute() and '..' not in parts listed_paths.append(root/relative) for path in (p for p in listed_paths if p.suffix == '.md'): assert path.read_text().count('```') % 2 == 0, path for path in (p for p in listed_paths if p.suffix == '.py'): compile(path.read_text(), str(path), 'exec') # Exact reduced-polynomial square-freeness in every enabled MKS dimension. from fractions import Fraction as F def trim(a): while len(a)>1 and a[-1]==0:a.pop() return a def rem(a,b): a=a[:];b=trim(b[:]) while len(a)>=len(b) and a!=[F(0)]: off=len(a)-len(b); fac=a[-1]/b[-1] for k in range(len(b)):a[k+off]-=fac*b[k] trim(a) return a def gcd(a,b): while trim(b)!=[F(0)]:a,b=b,rem(a,b) return trim(a) gcd_cases=[] for n,m in [(6,3),(12,3),(32,3),(64,5)]: ell=(n-1)//m+1 q=[F(-(n-m*j),8) for j in reversed(range(ell))]+[F(1)] dq=[F(k)*q[k] for k in range(1,len(q))] assert len(gcd(q,dq))==1 gcd_cases.append({'n':n,'m':m,'degree':ell,'square_free':True}) # Installer checks after checksums have been generated. installer=root/'install-neigt.py' log=[] with tempfile.TemporaryDirectory(prefix='neigt-installer-test-') as tmp: base=Path(tmp) repo=base/'repo'; repo.mkdir(); (repo/'.git').mkdir() def run(*extra,ok=True): proc=subprocess.run([sys.executable,str(installer),'--repo',str(repo),*extra],text=True,capture_output=True) assert (proc.returncode==0)==ok,(proc.returncode,proc.stderr) log.append({'arguments':list(extra),'returncode':proc.returncode}) run() assert not (repo/'README-NEIGT.md').exists() run('--apply') for line in (root/'SHA256SUMS-NEIGT').read_text().splitlines(): expected,name=line.split(' ',1) assert hashlib.sha256((repo/name).read_bytes()).hexdigest()==expected run('--apply') (repo/'README-NEIGT.md').write_text('Unrelated existing content.\n') # This new destination would have been copied before the conflict if preflight # were per-file instead of all-file; it must remain absent after rejection. (repo/'docs/codex/NEIGT-GOAL.md').unlink() run('--apply',ok=False) assert not (repo/'docs/codex/NEIGT-GOAL.md').exists() assert (repo/'README-NEIGT.md').read_text()=='Unrelated existing content.\n' # Independent symlink rejection. repo2=base/'symlink-repo';repo2.mkdir();(repo2/'.git').mkdir() outside=base/'outside';outside.mkdir();(repo2/'docs').symlink_to(outside,target_is_directory=True) proc=subprocess.run([sys.executable,str(installer),'--repo',str(repo2),'--apply'],capture_output=True,text=True) assert proc.returncode!=0 assert list(outside.iterdir())==[] log.append({'case':'symlink_parent_rejection','returncode':proc.returncode}) result={'schema':'neigt-bundle-validation-v1','status':'PASS_BUNDLE_PREPARATION_ONLY', 'counts':counts,'milestones':26,'reduced_polynomial_gcd_checks':gcd_cases, 'installer_tests':log,'octave_executed':False,'mplapack_executed':False} print(json.dumps(result,indent=2)) if args.output is not None: with args.output.open('x', encoding='utf-8') as stream: stream.write(json.dumps(result, indent=2)+'\n') mplapack-interop-0.5.1/docs/codex/neigt/preparation/bundle-validation.json0000644000230300031750000000234215274353473026225 0ustar rafaelrafael{ "schema": "neigt-bundle-validation-v1", "status": "PASS_BUNDLE_PREPARATION_ONLY", "counts": { "smoke": { "cases": 20, "measured_rows": 120, "verification_jobs": 26 }, "demo": { "cases": 21, "measured_rows": 168, "verification_jobs": 26 }, "stress": { "cases": 8, "measured_rows": 64 } }, "milestones": 26, "reduced_polynomial_gcd_checks": [ { "n": 6, "m": 3, "degree": 2, "square_free": true }, { "n": 12, "m": 3, "degree": 4, "square_free": true }, { "n": 32, "m": 3, "degree": 11, "square_free": true }, { "n": 64, "m": 5, "degree": 13, "square_free": true } ], "installer_tests": [ { "arguments": [], "returncode": 0 }, { "arguments": [ "--apply" ], "returncode": 0 }, { "arguments": [ "--apply" ], "returncode": 0 }, { "arguments": [ "--apply" ], "returncode": 1 }, { "case": "symlink_parent_rejection", "returncode": 1 } ], "octave_executed": false, "mplapack_executed": false } mplapack-interop-0.5.1/docs/codex/neigt/preparation/check_math.py0000644000230300031750000002602015274353473024370 0ustar rafaelrafael#!/usr/bin/env python3 """Independent exact-rational preparation checks; not Octave/MPLAPACK tests.""" from __future__ import annotations import argparse from fractions import Fraction as F import hashlib import json from math import isqrt from pathlib import Path def p2(e: int) -> F: return F(2 ** e) if e >= 0 else F(1, 2 ** (-e)) def floor_log2(x: F) -> int: if x <= 0: raise ValueError("Expected a positive rational") e = x.numerator.bit_length() - x.denominator.bit_length() return e - 1 if x < p2(e) else e def rn(x: F, bits: int) -> F: """Exact model of binary round-to-nearest, ties-to-even, unbounded exponent.""" x = F(x) if not x: return F(0) sign = 1 if x > 0 else -1 x = abs(x) step = p2(floor_log2(x) - bits + 1) y = x / step k, rem = divmod(y.numerator, y.denominator) if 2 * rem > y.denominator or (2 * rem == y.denominator and k % 2): k += 1 return sign * k * step def rn_sqrt(x: F, bits: int) -> F: if x < 0: raise ValueError("Negative square root") if not x: return F(0) step = p2(floor_log2(x) // 2 - bits + 1) y = x / (step * step) k = isqrt(y.numerator // y.denominator) midpoint2 = F((2 * k + 1) ** 2, 4) if y > midpoint2 or (y == midpoint2 and k % 2): k += 1 return k * step def eye(n: int): return [[F(i == j) for j in range(n)] for i in range(n)] def zeros(m: int, n: int | None = None): return [[F(0) for _ in range(m if n is None else n)] for _ in range(m)] def mm(a, b, bits: int | None = None): out = zeros(len(a), len(b[0])) for i in range(len(a)): for j in range(len(b[0])): s = F(0) for k in range(len(b)): t = a[i][k] * b[k][j] if bits is not None: t = rn(t, bits) s = s + t if bits is not None: s = rn(s, bits) out[i][j] = s return out def add(a, b): return [[x + y for x, y in zip(ar, br)] for ar, br in zip(a, b)] def scale(a, s): return [[s * x for x in row] for row in a] def transpose(a): return [list(row) for row in zip(*a)] def inverse(a): n = len(a) b = [list(a[i]) + eye(n)[i] for i in range(n)] for j in range(n): pivot = next((i for i in range(j, n) if b[i][j]), None) if pivot is None: raise ValueError("Singular matrix") b[j], b[pivot] = b[pivot], b[j] t = b[j][j] b[j] = [x / t for x in b[j]] for i in range(n): if i != j: t = b[i][j] b[i] = [x - t * y for x, y in zip(b[i], b[j])] return [row[n:] for row in b] def det(a): b = [list(row) for row in a] n, result = len(b), F(1) for j in range(n): pivot = next((i for i in range(j, n) if b[i][j]), None) if pivot is None: return F(0) if pivot != j: b[j], b[pivot] = b[pivot], b[j] result = -result t = b[j][j] result *= t for i in range(j + 1, n): ratio = b[i][j] / t for k in range(j + 1, n): b[i][k] -= ratio * b[j][k] return result def last_bit(x: F) -> F: if not x: return F(0) x = abs(x) assert x.denominator & (x.denominator - 1) == 0 n = x.numerator return F(n & -n, x.denominator) def similarity_pair(n: int): l, u = eye(n), eye(n) for i in range(n - 1): l[i + 1][i] = u[i][i + 1] = F(1) x = mm(l, u) y = mm(inverse(u), inverse(l)) assert mm(x, y) == mm(y, x) == eye(n) return x, y def oo(n: int, kind: str, bits: int): x, y = similarity_pair(n) s = zeros(n) if kind == "real": for i in range(n): s[i][i] = F(i + 1) + p2(-45) if i + 1 < n: s[i][i + 1] = F(32) elif kind == "pair": for j in range(n // 2): a, b = F(2 * j + 1) + p2(-45), F(2 * j + 1, 8) + p2(-45) i = 2 * j s[i][i] = s[i + 1][i + 1] = a s[i][i + 1], s[i + 1][i] = b, -b if i + 2 < n: s[i][i + 2] = s[i + 1][i + 3] = F(8) elif kind == "close": for i in range(n): s[i][i] = F(i + 1) s[0][0] = F(1) s[1][1] = F(1) + p2(-80) + p2(-120) for i in range(n - 1): s[i][i + 1] = F(1) else: raise ValueError(kind) assert all(rn(t, bits) == t for row in s for t in row) phi, psi = [[last_bit(v) for v in row] for row in x], [[last_bit(v) for v in row] for row in y] beta = max(v / min(w for w in col if w) for col in transpose(phi) for v in col if v) gamma = max(p2(floor_log2(abs(x[i][j]))) / phi[i][j] for i in range(n) for j in range(n) if phi[i][j]) theta = max(v / min(w for w in row if w) for row in psi for v in row if v) omega = max(p2(floor_log2(abs(y[i][j]))) / psi[i][j] for i in range(n) for j in range(n) if psi[i][j]) ny = max(sum(bool(t) for t in row) for row in y) ns = max(sum(bool(t) for t in row) for row in s) nx = max(sum(bool(t) for t in col) for col in transpose(x)) nd = min(ns, nx) v = ny * nd * max(abs(t) for row in s for t in row) alpha = p2(floor_log2(v)) if alpha < v: alpha *= 2 product = beta * gamma * theta * omega assert 4 * ny * nd * p2(-bits) * product <= 1 sigma = 12 * alpha * product assert rn(sigma, bits) == sigma sp = [[rn(rn(sigma + t, bits) - sigma, bits) for t in row] for row in s] if kind == "pair": for j in range(n // 2): i = 2 * j sp[i + 1][i] = -sp[i][i + 1] assert sp[i][i] == sp[i + 1][i + 1] ax = mm(sp, x, bits) a = mm(y, ax, bits) assert ax == mm(sp, x) assert a == mm(y, mm(sp, x)) assert all(rn(t, bits) == t for row in a for t in row) assert a != transpose(a) assert any(a[i][j] for i in range(n) for j in range(i)) assert any(a[i][j] for i in range(n) for j in range(i + 1, n)) changed = sum(t != z for r, zrow in zip(s, sp) for t, z in zip(r, zrow)) assert changed > 0 if kind == "close": assert sp[1][1] - sp[0][0] == p2(-80) raw = json.dumps([[str(t) for t in row] for row in a], separators=(",", ":")) return {"n": n, "kind": kind, "generation_bits": bits, "changed_entries": changed, "beta_gamma_theta_omega": str(product), "sigma": str(sigma), "exact_rational_matrix_sha256": hashlib.sha256(raw.encode()).hexdigest()} def poly_eval(c, z): r = F(0) for x in c: r = r * z + x return r def mks_checks(): count = 0 for n in range(3, 10): for m in range(1, n + 1): d = F(1, 8) a = [[d + F(j - i == m) for j in range(n)] for i in range(n)] length = (n - 1) // m + 1 c = [F(1)] + [-d * (n - m * j) for j in range(length)] # Monic coefficients are in descending powers. for z in (F(-2), F(0), F(1), F(3)): lhs = det([[z * F(i == j) - a[i][j] for j in range(n)] for i in range(n)]) assert lhs == z ** (n - length) * poly_eval(c, z) count += 1 return count def markov(n, aexp): m, eps = n // 2, p2(-aexp) q = zeros(n) for b, a in enumerate((F(1, 4), F(1, 8))): for j in range(m): i = b * m + j q[i][i] += 1 - a q[i][b * m + (j + 1) % m] += a r = [p2(-j) for j in range(1, n)] + [p2(-(n - 1))] assert sum(r) == 1 p = [[(1 - eps) * q[i][j] + eps * r[j] for j in range(n)] for i in range(n)] assert all(sum(row) == 1 and all(t > 0 for t in row) for row in p) ident = eye(n) fundamental = inverse(add(ident, scale(q, -(1 - eps)))) stationary = scale(mm([r], fundamental), eps)[0] assert sum(stationary) == 1 and all(t > 0 for t in stationary) assert mm([stationary], p) == [stationary] assert stationary != r for z in (F(-1), F(0), F(2), F(3)): target = (z - 1) * (z - (1 - eps)) for a in (F(1, 4), F(1, 8)): num = (z - (1 - eps) * (1 - a)) ** m - ((1 - eps) * a) ** m target *= num / (z - (1 - eps)) assert det([[z * F(i == j) - p[i][j] for j in range(n)] for i in range(n)]) == target return {"n": n, "epsilon_exponent": aexp, "strictly_positive": True, "row_stochastic_exactly": True, "stationary_vector_nontrivial": True} def primitive_checks(): total = 0 for bits in (64, 128, 256): u = p2(-bits) vals = [F(0)] + [sign * F(k) * p2(e) for sign in (-1, 1) for k in (1, 3, 7) for e in (-1500, -50, 0, 50, 1500)] for a in vals: for b in vals: exacts = [a + b, a - b, a * b] if b: exacts.append(a / b) for z in exacts: r = rn(z, bits) if r: t = 8 * u * abs(r) lo, hi = rn(r - t, bits), rn(r + t, bits) else: assert z == 0 lo = hi = F(0) assert lo <= z <= hi total += 1 for a in (F(0), F(1), F(2), F(3), F(1, 3), p2(-3000), p2(3000)): r = rn_sqrt(a, bits) t = 8 * u * abs(r) lo, hi = rn(r - t, bits), rn(r + t, bits) lo = max(lo, F(0)) assert lo * lo <= a <= hi * hi total += 1 return total def graph_checks(): # k=m=1: C=[[1,1/4],[2^-20,3]], K=2, R=1/2. c, e, g, t = p2(-21), F(0), F(1, 8), p2(-19) assert c + e * t + g * t * t < t assert e + 2 * g * t < 1 f = lambda z: p2(-20) + 2 * z - z * z / 4 assert f(-t) < 0 < f(t) # Inverse identities used by the fixed-pencil and similarity checkers. a = [[F(2), F(1)], [F(1, 8), F(3)]] x = [[F(1), F(1, 4)], [F(0), F(1)]] t0 = mm(inverse(x), mm(a, x)) assert mm(a, x) == mm(x, t0) b = [[F(1), F(1)], [F(0), F(1)]] ap = mm(b, a) assert mm(inverse(b), ap) == a return {"riccati_self_map_strict": True, "riccati_contraction_strict": True, "similarity_and_pencil_identities": True} def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--output", type=Path) args = parser.parse_args() result = { "schema": "neigt-preparation-v1", "kind": "exact_rational_math_checks", "octave_executed": False, "mplapack_executed": False, "oo_checks": [oo(n, k, p) for n in (8, 16) for k, p in (("real", 53), ("pair", 53), ("close", 128))], "mks_characteristic_evaluations": mks_checks(), "markov_checks": [markov(8, 24), markov(16, 80)], "outward_primitive_checks": primitive_checks(), "graph_checks": graph_checks(), "status": "PASS_PREPARATION_ONLY" } text = json.dumps(result, indent=2, sort_keys=True) + "\n" if args.output: args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(text, encoding="utf-8") else: print(text, end="") if __name__ == "__main__": main() mplapack-interop-0.5.1/docs/codex/neigt/preparation/check-results.json0000644000230300031750000000461715274353473025407 0ustar rafaelrafael{ "graph_checks": { "riccati_contraction_strict": true, "riccati_self_map_strict": true, "similarity_and_pencil_identities": true }, "kind": "exact_rational_math_checks", "markov_checks": [ { "epsilon_exponent": 24, "n": 8, "row_stochastic_exactly": true, "stationary_vector_nontrivial": true, "strictly_positive": true }, { "epsilon_exponent": 80, "n": 16, "row_stochastic_exactly": true, "stationary_vector_nontrivial": true, "strictly_positive": true } ], "mks_characteristic_evaluations": 168, "mplapack_executed": false, "octave_executed": false, "oo_checks": [ { "beta_gamma_theta_omega": "64", "changed_entries": 8, "exact_rational_matrix_sha256": "8b7aa86a78482202313daf120c9dd2ad193f474717f8226e9f89b988b8c22a13", "generation_bits": 53, "kind": "real", "n": 8, "sigma": "393216" }, { "beta_gamma_theta_omega": "64", "changed_entries": 16, "exact_rational_matrix_sha256": "6e1214a50b04e05f6c8c98157c61b0c96675789a8f69bfbcd20f43e3661a6a13", "generation_bits": 53, "kind": "pair", "n": 8, "sigma": "196608" }, { "beta_gamma_theta_omega": "64", "changed_entries": 1, "exact_rational_matrix_sha256": "60edd128663ad40a6df914393d6981bfe59604bf18a8fcbeaa3d92f2f1d5ba34", "generation_bits": 128, "kind": "close", "n": 8, "sigma": "98304" }, { "beta_gamma_theta_omega": "256", "changed_entries": 16, "exact_rational_matrix_sha256": "623c639547521ec295e4feb33f487448a158cfafad1600ab26859fc104e0450f", "generation_bits": 53, "kind": "real", "n": 16, "sigma": "3145728" }, { "beta_gamma_theta_omega": "256", "changed_entries": 32, "exact_rational_matrix_sha256": "920a19872914b5dc5b4eab9896746d20aec713054e902be54ef8f1e94e3d764d", "generation_bits": 53, "kind": "pair", "n": 16, "sigma": "3145728" }, { "beta_gamma_theta_omega": "256", "changed_entries": 1, "exact_rational_matrix_sha256": "265bf2e19de195163e6ec369ab0f57333593b844ababca60a3a04c6885338740", "generation_bits": 128, "kind": "close", "n": 16, "sigma": "1572864" } ], "outward_primitive_checks": 11460, "schema": "neigt-preparation-v1", "status": "PASS_PREPARATION_ONLY" } mplapack-interop-0.5.1/docs/codex/neigt/GENERATOR-OO.md0000644000230300031750000001365015274353473021574 0ustar rafaelrafael# S1: the Ozaki--Ogita error-free triple-product generator Source [OO22], Theorem 1 and Section 4. This is a deterministic specialization, not a copy of the paper's MATLAB code or its large random experiments. ## 1. Fixed standard forms and inverse pairs Let N have ones on its first superdiagonal, L=I+N', U=I+N, X=L*U, and Y=U^(-1)*L^(-1). Compute unit-triangular inverses by the finite nilpotent series or exact forward/back substitution, **not a floating inverse taken on faith**. All entries are integers. Prove XY=YX=I with the exact-dyadic checker. Prepare S_requested at the manifest's fixed generation precision g: - `OO53_REAL`: S(i,i)=i+2^-45; S(i,i+1)=32. g=53. - `OO53_PAIR`: for j=0..n/2-1, put the block [a,b;-b,a] at indices 2j+1:2j+2, a=2j+1+2^-45, b=(2j+1)/8+2^-45. Put 8*I_2 on the first block superdiagonal. g=53. This is a real normal diagonal block, **not** a skew-symmetric block unless a=0. The full upper block-triangular S need not be normal. - `OO128_CLOSE`: diagonal [1,1+2^-80+2^-120,3,4,...,n], with ones on the first superdiagonal. g=128. The realized first gap must be exactly 2^-80 in the mandatory n=8/16 instances; the 2^-120 component is intentionally removed. g never follows the eig work precision. Freeze one generated matrix and its realized standard form per case. The g=53 cases are exactly binary64-representable inputs; the g=128 case need not be. Never regenerate S' separately for each eig row. ## 2. Quantization parameters For each nonzero dyadic x_ij write x_ij in phi_ij*Z but not 2*phi_ij*Z, with phi_ij a power of two; set phi=0 on zeros. Define psi analogously for Y. Obtain these from exact dyadic decomposition, not rounded logs. Set ```text beta = max over columns j: max(nonzero phi(:,j))/min(nonzero phi(:,j)) gamma = max over nonzero X entries: ufp(abs(x_ij))/phi_ij theta = max over rows i: max(nonzero psi(i,:))/min(nonzero psi(i,:)) omega = max over nonzero Y entries: ufp(abs(y_ij))/psi_ij nY = maximum nonzero count in a row of Y nS = maximum nonzero count in a row of S_requested nX = maximum nonzero count in a column of X nprime = min(nS,nX) ``` `ufp(x)=2^floor(log2(abs(x)))`, computed by exact comparisons/exponent search. Choose alpha as the smallest power of two >= nY*nprime*max(abs(S_requested(:))). The alpha search itself must not underestimate its exact target. ```text u = 2^-g P = beta*gamma*theta*omega require 4*nY*nprime*u*P <= 1 sigma = 12*alpha*P Sprime(i,j) = RN_g(RN_g(sigma + S_requested(i,j)) - sigma) A = RN_g(Y * RN_g(Sprime * X)) ``` Zero S returns zero with explicit metadata. Our mandatory cases are nonzero. Compute the two matrix products as sums of scalar products; no Strassen/Winograd, reassociation of the quantization expression, or unspecified GEMM evaluation route. The rounded addition and subtraction must be distinct operations at g. Under the source theorem's conditions these products are exact. Independently check **both** intermediates and the final product by exact dyadic evaluation; do not use the theorem as a reason to skip a generator regression test. Record alpha, sigma, beta/gamma/theta/omega, counts, inequality, and precision. The g=53 evaluator may use MP RN at 53 bits if the existing public constructor supports it. Otherwise use deliberately native binary64 scalar operations for this **explicit 53-bit generator only**, with the native RN/range contract audited. This is not an MP eig fallback. Do not silently change generation_bits to 64. All g=128 generation and all MP solves remain genuinely MP. ## 3. Paired real blocks and sign-copy rule For each 2x2 complex-pair block, quantize its shared diagonal once and copy it to both diagonal positions; quantize the upper b once and set the lower value to its exact negative. Quantizing b and -b separately must not be assumed antisymmetric. This is the paired-block modification described in [OO22] Section 4. For the mirrored entry, establish the same quantization lattice membership and magnitude bound used in the theorem, and verify the exact products independently. Copying a sign preserves that lattice and bound. Do not subsequently alter A. If b' is zero, record the realized multiplicity; never keep claiming a complex pair. The required pair fixtures have b' != 0 and must preserve their real block structure. ## 4. Outputs and mandatory checks Return S_requested, S_realized, X, Y, A_exact, requested and realized spectra, generation precision, source/method IDs, exactness guard, bit audit, and hashes. For triangular S', realized roots are diag(S'). For the paired block form they are a' +/- i*b'. These are exact complex dyadic values; do not recompute them with a general eigensolver. Actual measured eig(A) is a separate operation. Required checks: - XY=YX=I; output is neither symmetric nor triangular for mandatory fixtures. - The theorem inequality holds; every rounded product equals its exact counterpart. - Quantization changes at least one requested entry in each required case. - Requested and realized spectra are separately stored and never confused. - Both n=8 and n=16; negative entries, zeros, unequal bit lattices, and the paired rule. - Inverse pair is invalid -> reject. Inequality fails -> reject, no quiet extra bits. - Attempt to use a non-dyadic inverse as exact -> reject. - A small requested entry/gap lost in a mixed-scale standard form must be recorded as a realized change. Test the prescribed lost 2^-120 increment. Do not assume that uniformly scaling S to tiny numbers makes it collapse: alpha scales with S. Zero input has its separate explicit branch and is not a useful hard fixture. - Generation repeated at the same g is bit-identical. Increasing eig precision does not change generator hashes. A separate new g gets a separate model identity. The preparation script provides exact-rational checks for all six n/kind cases. Its rational-string hashes are preparation-only and use a different encoding from the certificate serializer; do not compare hashes across unlike encodings. mplapack-interop-0.5.1/docs/codex/neigt/NUMERICS.md0000644000230300031750000003072515274353473021162 0ustar rafaelrafael# Precision, ordinary diagnostics, references, and safe interpretation ## 1. Precision roles and value identity Record: generation bits g, actual eig input/work bits p, model-exactness guard, reference bits r1/r2, diagnostic/certificate bits q, and auxiliary-candidate bits. For smoke: r1=512,r2=640,q=768. For demo: r1=768,r2=896,q=1024. For explicit stress: r1=1536,r2=1664,q=2048. These are caps/settings, not a license to silently increase precision until a preferred output appears. For OO cases generation g is fixed independently of all of these. For other recipes construct the exact dyadic model with a proved sufficient precision, then represent that same model at p with one rounding per component. When p satisfies the guard, prove exact equality; otherwise label the rounded model. The native baseline is one rounding of this exact model to binary64, once per case, not once per MP row. Maintain immutable A_model, A_frozen and eig outputs for each run. Certificates name A_frozen by its exact binary content and shape. The intended/model forward error and solver-only error for the actual frozen input are different fields. Never compare to the ideal model while labeling the result frozen-input accuracy. Exact widening: audit maximum-operand-precision semantics, then use a target-q zero array added to an existing MP object; native values convert directly at q>=53. Prove/test that values are unchanged and the result has the intended precision. `mp(existing_mp)` and `mpbits(q)` alone do not necessarily widen the existing value. `mp(char(X))` is not an exact cross-precision widening operation. If public semantics changed, implement a tested equivalent via existing public operations only. All functions that change precision or path restore it on normal and exceptional return. Test ambient precision below and above p, aliases, injected errors, and all filtering/output/graphics failure paths. Do not inject a q-bit scalar into a p-bit input by assignment or concatenation and quietly change the solver precision. ### 1.1 Manifest numeric grammar Interpret numeric parameter strings with a bounded parser for signed integers, integer ratios, powers `2^k`, and the specifically used sum `1+2^k`. Construct these from exact small integers and MP binary scaling. Do not use eval, str2num, native floating-point decimal parsing, or a symbolic package. Enum/recipe strings are not expressions to execute. Validate dimensions and exponent bounds before allocation. The more elaborate OO standard forms are explicit constructor code, not arbitrary expressions supplied through JSON. ## 2. Measured solve workload For each ordinary case, frozen precision, and balance mode run `[V,D,W]=eig(A,mode)`. Time the solver only. Test values-only API consistency in small unit tests, not as additional core rows. Core counts follow cases.json. The left convention to audit is ```text A*V=V*D W'*A=D*W' A'*W=W*D' # conjugating D' for a complex spectrum ``` Keep raw order. Never independently reorder D,V,W. Store raw and matched view permutations separately. Each successful MP solve must return finite values, nonzero vector columns and correct shapes/types. Do not normalize, repair, replace, or real-project solver outputs before recording their residuals. ## 3. Bijective minimum-bottleneck spectrum comparison At q, construct the full cost matrix using MP arithmetic. Costs: ```text absolute: abs(mu_j-lambda_k) relative: abs(mu_j-lambda_k)/abs(lambda_k) # only all-nonzero reference groups circle: abs((mu_j-1)/r-unit_root_k) ``` Sort finite MP costs; binary-search the smallest threshold allowing a perfect bipartite matching; use deterministic augmenting paths for feasibility. Return threshold, bijection and traversal/metric metadata. A Hungarian minimum-sum match is not the same optimization. Solve each chosen metric separately. Absolute matching includes repeated and zero roots with multiplicity. Relative error at a zero reference is undefined; report absolute leakage for that group. Do not infer exact multiplicity from matching alone. Use the known model groups only in ordinary model comparisons; a verifier must establish its own root counts. Tests: identity/permutation, complex circles/conjugate pairs, duplicates, zeros, computed [0,0,2] versus [0,1,2] (bottleneck 1), [2,0] versus [1,3] (1), exhaustive permutations n<=6, and tiny positive distances 2^-700 and 2^-1500 at adequate MP precision. Reject nonfinite/mismatched inputs. No native-double comparisons. ## 4. Ordinary metrics (MEASURED, not certified) All use exactly widened A_frozen and the actual returned outputs at q. For A!=0: ```text rho_R = ||A*V-V*D||F/(||A||F*||V||F) rho_L = ||W'*A-D*W'||F/(||A||F*||W||F) eta_R = max_j ||A*v_j-mu_j*v_j||2 / ((||A||F+|mu_j|)*||v_j||2) eta_L = max_j ||A'*w_j-conj(mu_j)*w_j||2 / ((||A||F+|mu_j|)*||w_j||2) kappa_j = ||v_j||2*||w_j||2/abs(w_j'*v_j) ``` For an exact zero matrix use absolute residuals; never 0/0. A zero overlap yields an explicit unresolved/infinite condition, not a dropped column. kappa_j is a simple-eigenvalue condition estimate only for resolved simple eigenpairs. For semisimple or defective repeats label it NOT_APPLICABLE_SIMPLE_ROOT; a numerical finite value on an artificially split root is not the true condition of the multiple eigenvalue. `cond(column_normalized_V)` is a diagnostic of the computed basis, not proof the exact input is diagonalizable. Record imaginary parts for theoretically real models, but impose no fixed count of spurious complex values. Normwise residuals alone do not certify a common small decomposition perturbation when V is ill-conditioned. Cluster metrics: from a separately recorded QR basis Q_J, evaluate `M_J=Q_J'*A*Q_J` and `||A*Q_J-Q_J*M_J||F`, and compare orthogonal projectors to an independent model subspace when available. QR preparation does not alter the raw eig residual. For true defect, the span of numerically returned eigenvectors can be a poor subspace candidate; use the candidate procedure below and label its origin. For a model matrix change report ||A_frozen-A_model||F and the ratio to ||A_model||F. For the complex Hadamard case the reference similarity is unitary; for Toeplitz, Forsythe and Perron diagonal scaling it is generally not unitary. Never transfer norms or pseudospectral certificates between these coordinates without a proof. ## 5. References Exact dyadic roots: OO realized spectra, exact similarity blocks, Hadamard integers, Wilkinson integer roots, zero multiplicities. These need no general eig reference. Analytic evaluated roots: Toeplitz sin/cos formula, Forsythe circle, Markov complex modes. Evaluate at both r1/r2 from exact parameters; check absolute disagreement <=2^-160 smoke or 2^-224 demo, scaled by max(1,max|lambda|). Forsythe uses its circle metric. These are evaluated-consistent, not interval-certified transcendental values. Independent paths: Frank symmetric Hermite-Jacobi formula; MKS smaller companion plus exact zeros; Grcar general eig at r1/r2. For matching all-nonzero simple references also check relative consistency. Keep MKS repeated zeros algebraic. When a frozen input differs from the model, evaluate its own r1/r2 references. Report unresolved clustered references honestly; do not force the model roots into this reference. Inexact references block numerical solver-only forward claims, not valid certified inclusions for the same frozen input. A rigorous reference can come from certifying higher-precision approximate data. The certifier must still receive exactly the original frozen input. It may certify A using these new auxiliary candidates, but its widths must not be reported as a certificate around the earlier low-precision eigenvectors. Record candidate hashes and candidate_source_bits separately from measured work bits. For a certified disk D(c,r) known to contain a particular simple reference root, `|mu-c|+r` is an outward absolute-error upper bound. For a counted cluster, do not assign each of its member disks to a unique exact root without a justified matching. A precision-agreement reference remains a numerical reference unless such a separate certificate actually succeeds. ## 6. Candidate preparation for cluster/factor certificates The proof checker is independent of the approximation algorithm. It must never trust a generator's exact roots or basis. Supplied candidate data are suggestions; all existence, invertibility, counts and bounds come from CERTIFICATES.md. For well-separated simple cases, use computed V and a computed inverse candidate. For a selected k-cluster: 1. Try QR of the selected computed columns, completing to n columns. Preserve candidate origin and precision; do not treat a tolerance rank estimate as proof. 2. If columns are deficient or graph validation is inconclusive, use a bounded **candidate-only** contour projector preparation at r1 or r2. The query contour center/radius are chosen from approximate clusters, not asserted exact roots. For M=16,32,64 (in this order) and z_j=c+r*exp(2*pi*i*(j+1/2)/M), form `P_hat=(1/M)*sum((z_j-c)*((z_j*I-A)\I))`. Choose k independent-looking columns by deterministic norm-pivoted QR/Gram--Schmidt and complete a basis with coordinate vectors. Record all solves and errors. 3. Feed that point basis to the same graph checker. Quadrature convergence, the number k, or use of a model-centered query contour is **not** its proof. This computes an approximate invariant-subspace basis, not replacement eigenvalues. It is confined to small verification jobs and is not a new eig backend. A selected k may come from the requested test query; the checker must prove dimension and spectral separation itself. Public ordered Schur, if already present and audited, may supply an additional candidate route, never a required new binding. After either candidate route, permit at most four **candidate-only** Newton corrections of the invariant graph at the selected r1/r2. For point central blocks and current Z, solve the vectorized linearized equation using ```text K_Z = kron(I_k,C22-Z*C12) - kron(transpose(C11+C12*Z),I_h) K_Z * vec(dZ) = -vec(C21+C22*Z-Z*C11-Z*C12*Z). ``` Update the candidate range, recompute its thin QR, and build a new nonsingular completion. The graph checker then starts again at Z=0 in the new coordinates. These corrections are only approximation work; they prove nothing until the outward checker succeeds. They avoid making contour quadrature accuracy the ceiling of a certificate. Do not iterate without a cap or use a generator's exact invariant basis as the solution of a required verification job. For a nonnormal complement, try a completion consisting of the QR-normalized cluster columns and computed complementary invariant/eigenvector columns; it need not be unitary. In particular, the two nonzero MKS(6,3) eigenvectors make a useful complement to its four-dimensional zero-root subspace. Any such X still needs the verified nonsingularity test. When a unitary completion gives overly broad D2 Gershgorin disks, a different candidate completion is allowed, not weakened separation criteria. Record this bounded alternative (at most two completion strategies per candidate). At most the declared three node counts, four Newton corrections per candidate, two completion strategies, and two candidate precisions are used. A failed solve at a contour shift is logged; do not silently perturb the input. No successful graph predicate means INCONCLUSIVE and a failed mandatory positive gate, not PASS. A full-space identity projector does not count as a nontrivial cluster success. ## 7. Reporting statuses Use separate fields, not a single overloaded PASS: ```text solver_status: success | nonconverged | error input_status: exact_model | rounded_model | native_underflow | generator_rejected reference_status: exact_algebraic | evaluated_consistent | unresolved claim_status: MEASURED | CERTIFIED_ALL | CERTIFIED_CLUSTER | CERTIFIED_PAIR | CERTIFIED_INVARIANT_BASIS | CERTIFIED_EIGENFACTORS | CERTIFIED_SCHUR_TRIANGULAR | CERTIFIED_BLOCK_SCHUR | CERTIFIED_ALL_FINITE | CERTIFIED_PERRON_ROOT | CERTIFIED_INSIDE | CERTIFIED_OUTSIDE | CERTIFIED_PERRON_PAIR | INCONCLUSIVE | UNSUPPORTED_DOMAIN | ARITHMETIC_CONTRACT_FAILED | ERROR claim_quality: resolved | broad | not_identified | not_applicable ``` Individual vector identification at multiplicity uses an explicit `NOT_IDENTIFIABLE_INDIVIDUALLY` reason. An inconclusive verifier is not evidence of a nonexistent eigenpair, a singular matrix, or a solver error. However all mandatory positive verification jobs must satisfy their stated useful-width gates. mplapack-interop-0.5.1/docs/codex/neigt/COVERAGE.md0000644000230300031750000000675715274353473021140 0ustar rafaelrafael# Coverage map: no requested tier is optional | Requested item | Implementation | Method/source relationship | |---|---|---| | S1 Ozaki--Ogita | OO53_REAL, OO53_PAIR, OO128_CLOSE | Theorem-1 triple product with fixed generation precision; paired-block adaptation; not just a generic similarity | | S2 exact similarities | SIM_SIMPLE, SIM_REPEAT, SIM_JORDAN, SIM_TWO_JORDAN | Rump-style integer unit-triangular construction; deterministic suite parameters | | S3 tridiagonal Toeplitz | TOEPLITZ, TOEPLITZ_SYM | Closed-form spectrum/left/right vectors; exact original and symmetric control | | S4 Forsythe | FORSYTHE, FORSYTHE_SCALED, FORSYTHE_ZERO | Existing family extended; zero limit is not a diagonalization success test | | A1 Hadamard bidiagonal | HAD_BIDIAG | Reuse exact existing definition and analytic conditioning | | A2 Frank | FRANK0, FRANK1 | Opposite orientations of one family, not unrelated new spectra | | A3 Wilkinson companion | WILKINSON | Exact coefficients plus rootwise polynomial coefficient backward error | | A4 Grcar | GRCAR | Existing matrix plus verified pseudospectral probes | | A5 Morimoto--Katori--Shirai | MKS | Model 1 only, exact zero multiplicity and reduced nonzero-root polynomial | | A6 Perron/stochastic | MARKOV, PERRON_POS | Dyadic derived applications; known spectrum, nonuniform stationary vector | | Demo complex control | HAD_COMPLEX | Quarter-turn unitary diagonal similarity; conjugation/coordinate checks | | V-S1 all eigenvalues | VS1-01..08 | Verified similarity plus counted Gershgorin groups; conservative baseline, not Rump's full algorithm | | V-S2 cluster/subspace | VS2-01..04 | Verified Riccati-graph contraction, including defective/semisimple/merged cases | | V-S3 pseudospectrum | VS3-01..04 | Verified SVD and 1-Lipschitz cell classification; not Frommer's full algorithm | | V-A1 eigen/Schur factors | VA1-01..03 | Compatible eigentriples, interval exact QR, block-Schur for defect | | V-A2 generalized pencils | VA2-01..03 | Nonsingular-B verified solve reduction, all roots and selected subspace; no public generalized eig prerequisite | | V-A3 Perron pair | VA3-01..04 | Collatz--Wielandt plus normalized positive eigenpair contraction; not Miyajima's full M-matrix algorithm | ## Explicit first-release limits Finite dense point real/complex matrices; proof helpers also accept enclosing rectangles for an exact but indirectly represented matrix. Mandatory pencils have certifiably nonsingular B, hence finite eigenvalues. Singular-B/infinite-eigenvalue pencils, arbitrary interval-pencil regularity, general nonlinear eigenproblems, PDE discretization error, and an INTLAB clone are outside scope. The factor verifier proves a genuine triangular Schur factorization for separated simple cases. On the defective case it proves a unitary **block-upper-triangular** factorization with the declared invariant block. It must not label a dense block as triangular Schur form or claim a diagonalization exists. Pseudospectrum means the closed, complex-perturbation, unstructured 2-norm pseudospectrum. Real-only or Toeplitz-preserving pseudospectra are different sets. Ordinary structured sensitivity diagnostics are labeled MEASURED, never used as certified membership tests for these other sets. The suite does not promise validation of every arbitrary input. It must validate its specified positive tests, reject or remain inconclusive on adversarial tests, and preserve every assumption in the proof witness. These are implementable bounded baselines, not empty extension points for later work. mplapack-interop-0.5.1/docs/codex/SVT-LUNA-XHIGH.md0000644000230300031750000005100415274353473020676 0ustar rafaelrafael# SVT: Tier S, Tier A, and Tier V SVD examples for mplapack-interop ## 0. Execution contract Target repository: `nakatamaho/octave-mplapack`. Octave package: `mplapack-interop`. Executor: the user's selected Luna model, xhigh reasoning, in Codex. Prepared: 2026-09-10. Task namespace: **SVT00--SVT19**. Implement runnable examples, focused tests, verification examples, documentation, and measured reports. Do not stop at a plan. Read this file, the four companion specifications, and the JSON manifest before implementation: - `docs/codex/svt/CASES.md`: exact matrix definitions and reference contracts. - `docs/codex/svt/VERIFICATION.md`: finite-arithmetic enclosures and proofs. - `docs/codex/svt/MILESTONES.md`: sequential implementation gates. - `docs/codex/svt/SOURCES.md`: checked DOI and source-to-claim ledger. - `docs/codex/svt/cases.json`: normative smoke/demo/stress case manifest. The requested tiers are all in scope. Tier V is not satisfied by a bibliography, a high-precision comparison, a small residual, an empty adapter, or an optional INTLAB dependency. Implement the bounded, self-contained verification methods specified in VERIFICATION.md. They are deliberately modest, rigorous baselines, not reproductions of all algorithms in the three cited Rump papers. ### Relationship to previous work Preserve NEIG examples, existing difficult-SVD examples, SVD00--SVD10 reports, and all unrelated changes. This task may extend an implemented SVD suite, or provide an additive suite when only its earlier specification exists. Never assume that having a Markdown specification means the implementation exists or passed. During SVT00 choose one canonical implementation of each reusable constructor and metric. If existing helpers are suitable, reuse through a compatible facade or a small regression-tested internal extraction. Do not duplicate constructors with subtly different indices, precision rules, or matrix conventions. Preserve all existing user-facing entry points. Keep the new `mp_svd_tiers` facade even when it adapts existing code. Do not refactor unrelated eigenvalue code. The preparation environment could not refresh the public GitHub checkout during this revision. Earlier supplied specifications describe an API snapshot, not proof of the executor's current checkout. Audit local source, module resolution, and actual behavior. Do not infer current versions from this document's date. ## 1. Scope and boundaries ### 1.1 Required coverage **Tier S**: Nishi--Rump--Oishi (NRO) integer block matrices with two-level, three-level, and graded singular spectra; Jacobi--Stirling second-kind matrices; Lah matrices; symmetric and nonsymmetric shifted diagonally dominant paths. **Tier A**: lower and symmetric Pascal; dyadic-node Vandermonde; raw and mixed graded bidiagonal; tall and wide Lauchli; known geometric, close, repeated, rank-four, and rank-five Hadamard fixtures; bounded-integer NRO companion-like matrices. Include complex phase and global scaling controls in demo. **Tier V**: 1. V1: enclosures of all singular values and gap-certified positive singular subspace projector bounds, including internal multiplicity. 2. V2: existence and entrywise boxes for compatible SVD factors in the separated, positive, simple-singular-value setting. Use a common phase for each U/V pair. 3. V3: spectral-norm bounds, nonsingularity verification, inverse-norm bounds, and a certified positive lower bound for the smallest singular value when the Neumann residual test succeeds. ### 1.2 No backend expansion Use only the existing public `mp`, `mpbits`, arithmetic, matrix, SVD, and solve interfaces. New helpers belong in the example tree. Do not modify MPLAPACK, gmpfrxx, MPFR, MPC, BLAS/LAPACK, dependency headers, `src/`, or installed `@mp` methods. No new SVD driver, Jacobi backend, global precision hook, rounding-mode API, native bridge, or package dependency. No production reinstall. The verifier's local endpoint/rectangle structs are private example helpers, not a public interval library or an INTLAB clone. The implementation uses rigorous outward bounds from audited correctly rounded scalar operations; a rounding-mode setter is not required. If the necessary scalar contract cannot be established, Tier V is BLOCKED, not silently replaced with heuristic padding. Independent Tier S/A work may continue, but the overall task is not PASS. No Python, SymPy, MATLAB, symbolic package, interval package, Internet, or plotting backend is required to run the final Octave examples. Preparation Python files are mathematical checks, not substitutes for Octave acceptance. Do not vendor TNTool or copy INTLAB, GNU Octave gallery, or article source code. Optional existing structured comparators may be logged but may not become runtime dependencies. ### 1.3 Scientific restrictions - Never substitute a known spectrum for a computed result. - No `eig(A'*A)` oracle or production SVD. A named Lauchli negative control may form normal equations; Gram matrices of computed U/V in a proof are allowed. - Do not add eigenproblem balancing flags to SVD. General diagonal left/right scaling does not preserve singular values. - No forced binary64 failure, monotone-improvement requirement, or fixed count of numerically zero singular values. - No unique-vector acceptance criterion for a repeated singular value. - Do not label agreement at two precisions, HRA theory, or an ordinary residual as a verified enclosure. - Do not attribute these verifier baselines to Rump--Lange or Rump--Ogita as an implementation of their algorithms. Use the explicit method IDs below. - Broad valid intervals and failed sufficient conditions are legitimate numerical outcomes, not proof that an SVD does not exist. Mandatory resolved cases must nevertheless pass their declared targets. All source, comments, help, diagnostics, reports, and new repository documents must be English. Follow AGENTS.md and more-local instructions. Preserve dirty worktrees and untracked files. Do not reset, clean, rewrite history, push, merge, tag, publish, or change production installations. Use a topic branch only when safe; suggested name: `topic/svd-tier-sav-examples`. ## 2. Entry points and layout Suggested layout; reconcile actual test paths and next free example numbers: ```text docs/codex/SVT-LUNA-XHIGH.md docs/codex/SVT-GOAL.md docs/codex/svt/{CASES,VERIFICATION,MILESTONES,SOURCES}.md docs/codex/svt/cases.json examples/NN_svd_tier_s.m examples/NN_svd_tier_a.m examples/NN_svd_verified.m examples/svd_tiers/mp_svd_tiers.m examples/svd_tiers/mp_svd_tiers_selftest.m examples/svd_tiers/mp_svd_verify_examples.m examples/svd_tiers/private/svt_*.m test/test_svd_tiers.m test/test_svd_verification.m docs/svd-tiers.md docs/svd-verification.md svt00-report.md ... svt19-report.md ``` Each NN is separately allocated. Do not overwrite, renumber, or reuse an occupied example number. Reports must identify their validated code state. ```octave pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "svd_tiers")); results = mp_svd_tiers ("smoke"); results = mp_svd_tiers ("demo", struct ("tier", "all", ... "output_dir", fullfile (pwd (), "artifacts", "svt-demo"), "plot", false)); verification = mp_svd_verify_examples ("smoke"); mp_svd_tiers_selftest (); assert (results.ok); ``` `mp_svd_tiers` accepts profiles `smoke` (default), `demo`, `stress` and options: `tier` = `all|S|A|V`; `output_dir` = empty or new directory; `plot` = logical. Unknown options are errors. A tier filter is partial coverage and cannot certify all-task completion. `tier=all` includes S/A rows and the mandatory V jobs. `tier=V` uses the specified small/selected fixtures without relabeling that run as full S/A coverage. `mp_svd_verify_examples` is a thin facade, not a second implementation. A numbered example with a tier filter asserts its `scope_ok`; an all-tier task acceptance wrapper asserts `results.ok`. Do not make the filtered examples fail solely because the other tiers were intentionally not requested. Top-level numbered examples resolve helpers relative to their own files, not the working directory. Restore temporary path changes. No process-wide exit inside reusable functions. Test wrappers must exit nonzero on `results.ok == false`. ## 3. Audit the actual public API Earlier supplied source snapshots documented: ```octave s = svd (A); [U, S, V] = svd (A); [U, S, V] = svd (A, "econ"); ``` They rejected two outputs, used Rgesvd/Cgesvd, and returned V, not LAPACK's VT. Verify this locally; do not invent behavior or demand a stale implementation. For m-by-n, k=min(m,n), economy shapes must be U:m-by-k, S:k-by-k, V:n-by-k. Verify complex reconstruction `A=U*S*V'`, input-selected precision, no mutation, full/economy shapes, descending nonnegative values, and one-output consistency. Inspect real scalar add/subtract/multiply/divide/sqrt/abs/comparison implementation and prove the arithmetic contract needed by VERIFICATION.md. A few successful probes alone do not establish correct rounding. Record audited source paths and underlying MPFR rounding modes. Inspect lossless widening and exponent behavior. Use repository-supported environment/build/test wrappers. Record actual `which` paths, loaded modules, package versions, commit and dirty state. Never assume a root-level make target, CI command, or local installed package path exists. ## 4. Precision and input identity ### 4.1 Four precision roles Keep separate fields for: 1. work precision p of the actual SVD input; 2. model-construction precision used to represent the intended matrix exactly; 3. reference solve precision r; 4. interval evaluation precision q. For smoke use references at 512 and 640 bits and q=768. For demo use references at 768 and 896 bits and q=1024. For stress, if explicitly requested, references at 1536 and 1664 bits and q=2048. Reference agreement targets are 2^-160, 2^-224, and 2^-256 respectively for resolved positive values. These checks alone are `consistent_reference`, never `verified`. Do not silently increase reference precision. If a declared reference is unresolved, report evidence. An explicitly revised experiment must receive a new run ID. ### 4.2 Build, freeze, and preserve Build each MP input from its recipe at p. Prove exactness using CASES.md bounds. The below-guard DD rows (demo p=128; stress p=256/512) are intentional rounded-input experiments; label it `rounded_recipe`, show loss of tau, and do not treat the ideal positive spectrum as the exact spectrum of that actual input. Other exact-input fixtures must meet their guard; reject an incompatible manifest instead of silently widening. Build native baselines from an exact model at adequate precision, convert once to binary64, freeze, and reuse that same input for values-only and economy solves. Where representability is proved (NRO block/companion, Lauchli, etc.), assert exact entry equality after widening. Otherwise report the change without assuming rank. Store both the intended model and the actual represented input. Residuals and certificates always name and use their actual target. No reference overwrite of A. Keep work-input aliases unchanged. Do not leak ambient precision on failure. ### 4.3 Exact widening The previous snapshot used maximum-operand-precision arithmetic and identity construction `mp(existing_mp)`. Audit and test this candidate widening method: set the target default in a cleanup scope, then add a newly created target-precision zero array to an MP object; convert native binary64 directly to MP. Validate that q is not below the known source precision. Do not create a precision-inspection API. Do not widen through `char` followed by parsing: same-precision decimal round-trip is not cross-precision value preservation. Never replace a work-precision output with a new high-precision solve while keeping its original label. ### 4.4 Frozen-input references Compute references for the actual frozen native/MP inputs when they differ from the exact model; do not reuse the model spectrum without equality or a proof. A zero found numerically below a reference floor is not an exact-rank proof. The DD tau-loss case has an exact rank proof in CASES.md. For other ambiguous near-zero frozen references use `below_reference_resolution` and withhold relative solver-error claims rather than forcing model zeros onto the rounded matrix. For numerical comparison, a component is resolved if it exceeds `2^(-floor(r_low/2))*norm(A_input,"fro")` in both reference runs. Compare resolved components relatively; compare the remaining block by absolute norm-scaled error. This floor is only an observational convention. It is not a certificate. After SVT13, independently verify the higher-reference factorization and use its intervals to bound work-result errors. This is a posteriori certification even though the approximate factors came from the same solver: the certifier verifies finite-arithmetic inequalities, not solver agreement. ## 5. Ordinary diagnostics and acceptance For each distinct input/precision, run and time one-output SVD and three-output economy SVD separately. Do not demand bit-identical results between their paths. References, construction, and verification are excluded from SVD timings. Keep computed order and factors together. Values are expected descending; fail an ordering violation rather than repairing solver output. Ascending sorting of reference values for presentation is allowed only with a recorded permutation. No assignment algorithm is needed for sorted real nonnegative singular values. Mandatory diagnostic fields: - input Frobenius discrepancy and exactness/rounding status; - total/model forward error and frozen-input solver error, separately; - positive-tail relative error; norm-scaled absolute leakage for model zeros; - reconstruction `||A-U*S*V'||F / ||A||F`; - left/right triplet residuals `A*V-U*S`, `A'*U-V*S`; - `||U'*U-I||F`, `||V'*V-I||F`; - projector errors only for the declared clusters/null spaces; - maximum and minimum resolved singular values, condition estimate and status; - solver time, work/reference/evaluation precision, actual API path, statuses. Use the following scalar residual definitions for nonzero A: rho_rec = ||A-U*S*V'||F / ||A||F; rho_R = ||A*V-U*S||F / (||A||F*||V||F); rho_L = ||A'*U-V*S||F / (||A||F*||U||F). Reject zero-norm U/V when k>0. For the zero-A selftest, retain the absolute numerators and require they vanish within the separately declared absolute test tolerance; do not create a 0/0 normalized metric. These are ordinary diagnostics; the verifier recomputes its own rigorous bounds with outward arithmetic. Compute diagnostics at q from exactly widened outputs. Never form a badly scaled norm in binary64 before widening. The zero-matrix selftest has an explicit zero-norm branch. Native conversions for plots occur only after mathematical metrics/comparisons; compute log errors in MP before converting logs for plotting. For successful MP smoke/demo factor rows use the engineering envelope `2^16 * max(m,n)^2 * 2^(-p)` for each normalized triplet/reconstruction residual and each Frobenius orthogonality defect. These are fixed regression envelopes, not universal theorems. Lower-precision forward inaccuracy is allowed. Native rows have no prescribed failure or fixed accuracy expectation. At the highest work precision (256 smoke, 512 demo) every exact-model fixture must meet maximum relative error <= 2^-100 (smoke) or 2^-128 (demo) on positive singular values, and norm-scaled zero leakage <= the same threshold. All highest-precision fixtures meet their exactness guards. Model projector errors for the specified Hadamard/Lauchli groups must be <= 2^-80 (smoke), 2^-100 (demo). Before Tier V is implemented these gates use consistent numerical references and are provisional. Final acceptance uses rigorous reference enclosures when there is no exact analytic value. If a positive reference interval [l,h] has l>0, then `max(abs(s-l),abs(s-h))/l`, evaluated outward, is a valid upper bound on relative error. It must meet the same target. If l<=0, the relative claim is unresolved. Do not weaken the gate or replace the input when it fails. ## 6. Profiles and Tier V jobs The JSON manifest is normative. Smoke: 20 matrix cases, native plus 128/256 bits, two SVD modes = **120 measured SVD rows**. Demo: the same 20 base cases plus one complex and two global-scale controls, native plus 128/256/512 bits, two modes = **184 measured SVD rows**. References, inverse solves, shape tests, and verification jobs are separately counted. Stress is opt-in and has no fixed recovery target. V jobs for each completed profile: - V1 spectrum: certify every highest-work-precision economy row. Require resolved positive values and relative interval width <= 2^-90 smoke / 2^-120 demo for the mathematically positive values. Model zeros use scaled absolute width. - V1 projectors: close/repeated Hadamard pair J={3,4} and the Lauchli small group; include tall, wide, and the complex demo control. Require projector bounds <= 2^-60 smoke / 2^-80 demo. Internal multiplicity must not be a rejection. - V2 factors: geometric Hadamard, graded NRO block, and a separate 3-by-2 simple real/complex test. Require positive separated intervals and per-column vector radii <= 2^-60 smoke / 2^-80 demo. Reject individual identification of the exact repeated pair, and show that V1 still handles its subspace. - V3 norms/inverse: highest-precision NRO two-level, NRO companion, DD symmetric. Require residual norm <1 and a strictly positive certified sigma_min bound. A singular rank-four input and an intentionally poor approximate inverse must not receive a false nonsingularity certificate. - Adversarial verifier tests from VERIFICATION.md are mandatory, not optional. Also certify selected frozen native demo inputs (NRO two-level, geometric, DD symmetric). Broad intervals or inability to resolve positivity are expected possibilities; do not make these cases fail merely for being broad. They demonstrate the difference between a valid inclusion and a useful relative inclusion. The final `results.ok` requires complete S/A rows, all numerical gates, all mandatory V jobs, and no blocked prerequisite. A tier-only run has its own `scope_ok` but must not be presented as the full task passing. Use separate coverage fields. ## 7. Output and serialization When output_dir is empty, write no files. Otherwise require a new directory; never delete or overwrite a prior result to obtain a clean run. Tests use owned temporary paths. Required outputs: ```text summary.tsv singular-values.tsv verification.tsv certificates.json inputs-and-factors.json environment.txt report.md plots/ # only if requested ``` Version schema `svt-v1`. Record case/tier/representation/parameters, work/reference/q, input identity, output mode, accuracy metrics, statuses, certificate method ID, proof preconditions, interval widths, cluster indices and gaps, factor radii, inverse residual bound, timing categories, and source IDs. Store complex values as real/imaginary components. No numeric evidence is down-converted to double. Use exact dyadic serialization for certificate endpoints and certificate target snapshots as specified in VERIFICATION.md. Decimal strings are display fields, not inherently outward decimal interval endpoints. Include source precision and SHA-256 for the canonical snapshot bytes. A certificate must bind to the actual matrix and factors it checked. Decimal round-trip alone is not a proof of an outward decimal interval. Use method IDs `svt_polar_weyl_v1`, `svt_dilation_projector_v1`, `svt_dilation_factor_boxes_v1`, and `svt_neumann_inverse_v1`. Record `paper_algorithm_reproduction=false`. No names suggesting that Rump's full methods have been ported. Valid statuses separate `CERTIFIED`, `INCONCLUSIVE`, `UNSUPPORTED`, `INVALID_DATA`, and `ARITHMETIC_CONTRACT_UNPROVEN`. `CERTIFIED` with broad bounds is distinct from `meets_accuracy_target=true`. ## 8. Completion Execute milestones in MILESTONES.md, one at a time, with tests and a root report before advancing. Continue automatically after PASS; stop dependent work on a real prerequisite failure. Report contradictions in the specification rather than silently modifying mathematics, targets, or scope. Use the existing source-package builder and isolated package installation QA. Verify helpers and mp do not accidentally resolve from the developer checkout. Update the authoritative manual source, regenerate derived documentation, and run existing relevant numerical/doc/example regressions. No release or PPA work. Finish with the actual changed files, exact commands, measured S/A and V results, all 20 milestone statuses, limitations, source attribution, and tests not run. Do not report this preparation bundle's mathematical checks as Octave execution. mplapack-interop-0.5.1/docs/codex/NEIGT-LUNA-XHIGH.md0000644000230300031750000003053515274353473021076 0ustar rafaelrafael# NEIGT: Tier S/A nonsymmetric eigenproblems and Tier V-S/V-A verification Version: 1.0. Prepared: 2026-09-10. Target repository: `nakatamaho/octave-mplapack`. Octave package: `mplapack-interop`. Executor: the user's selected ChatGPT Luna model, xhigh reasoning, in Codex. Task namespace: **NEIGT00--NEIGT25**. ## 0. Deliver the implementation, not another plan Implement every mandatory S, A, V-S, and V-A target in this bundle. Deliver runnable Octave examples, tests, proof checkers, documentation, and real execution reports. A specification file, a bibliography, a placeholder verifier, an optional adapter, or agreement between high-precision computations is not implementation completion. Read, in this order: 1. `AGENTS.md` and every applicable more-local repository instruction. 2. This file and `neigt/COVERAGE.md`. 3. `neigt/CASES.md`, `neigt/GENERATOR-OO.md`, and `neigt/cases.json`. 4. `neigt/NUMERICS.md`, `neigt/ARITHMETIC.md`, and `neigt/CERTIFICATES.md`. 5. `neigt/ACCEPTANCE.md`, `neigt/verification-jobs.json`, and `neigt/MILESTONES.md`. 6. `neigt/SOURCES.md` and `neigt/PREPARATION.md`. Paths above are relative to `docs/codex/` except repository instructions. The JSON manifests define coverage and parameters; the mathematical documents define their meanings. A conflict is a specification defect to report with a reproducer. Do not choose whichever interpretation makes a failing test pass. ### What Tier V means here Implement the complete, explicitly proved **conservative baselines** specified in CERTIFICATES.md. They address the verification targets of the cited papers, but are not line-for-line implementations of Rump's, Miyajima's, or Frommer's complete algorithms, nor claims of their sharpness or cubic complexity. Method IDs and `paper_algorithm_reproduction=false` are mandatory for those baselines. S1 is different: implement the actual error-free triple-product construction of Ozaki--Ogita, Theorem 1, with the documented dyadic specializations and paired-block rule. Do not replace it by an unrelated prescribed-eigenvalue generator and call that an implementation of Ozaki--Ogita. All six requested V targets are mandatory. In particular: - V-A2 finite generalized pencils must work even when public `eig(A,B)` is absent, through the verified solve-reduction specified here, not unchecked `eig(B\A)`. - V-A1 includes compatible eigenfactor boxes, a true Schur certificate on separated simple cases, and a **block** Schur certificate on a defective cluster. - V-S3 uses verified singular-value point/cell tests; it is not Frommer's full shifted-resolvent/numerical-range algorithm or a continuous-operator certificate. ## 1. Scope and boundaries ### Required work Tier S: Ozaki--Ogita exact generators; exact integer/dyadic similarities with simple, semisimple, defective, and two-nearby-Jordan-block regimes; nonsymmetric tridiagonal Toeplitz plus a symmetric control; Forsythe split/scaled/zero regimes. Tier A: Hadamard-similar upper bidiagonal; both exact Frank orientations; Wilkinson companion with polynomial-coefficient diagnostics; Grcar; Morimoto--Katori--Shirai model 1; stochastic and positive nonsymmetric Perron controls. Include the complex diagonal-unitary similarity in the demo. Tier V-S: counted all-spectrum inclusion; invariant-subspace/cluster inclusion; verified pseudospectrum points and cells. Tier V-A: compatible eigen/Schur/block-Schur factor boxes; finite nonsymmetric pencil eigenvalues and subspaces; Perron root and normalized positive vector, including a nontrivial left stationary vector. ### No backend/API expansion Use existing public `mp`, `mpbits`, arithmetic, indexing, comparison, elementary functions, `eig`, `svd`, `qr`, and linear solves. Audit actual availability. All new numerical helpers live under the example tree. Do not modify MPLAPACK, MPFR, MPC, gmpfrxx, system BLAS/LAPACK, `src/`, installed `@mp` methods, dependency headers, or compiler floating-point semantics. No new installed precision/rounding/interval API, eigensolver, QZ/Schur binding, external numerical package, or native bridge. Example-local **candidate preparation** by QR and contour solves is explicitly allowed for verification. It must never replace or relabel the measured `eig` results. This is not authorization to implement another production eigensolver. If the arithmetic contract cannot be proved from the local implementation, Tier V is BLOCKED and the whole task cannot PASS. Independent S/A work may be completed and reported honestly. Unsupported singular-B pencils and non-identifiable individual vectors are deliberate domain boundaries, not excuses to skip the mandatory nonsingular-B or cluster jobs. No Python, SymPy, MATLAB, INTLAB, symbolic package, Internet, or plotting backend may be required to run the delivered Octave suite. Optional preparation Python in this bundle is not an Octave acceptance test. Do not copy proprietary INTLAB code, GNU Octave gallery implementations, or paper pseudocode verbatim. Implement mathematics independently and retain attribution. No paper PDFs are redistributed. ### Preserve previous work NEIG, SVD, SVT, and any NEIGV files may or may not be implemented. Inspect actual code and reports; a prior specification is not evidence of implementation or PASS. Preserve public example entry points and all existing reports. Reuse suitable constructors, matching, exact-widening, and SVT verification through a small facade or a regression-tested internal extraction. Do not duplicate incompatible versions or refactor unrelated code. This bundle is standalone when prior code is absent. All new code, comments, diagnostics, help, reports, and repository documentation must be English. Follow the repository license/style. Keep changes separable by milestone. Suggested branch: `topic/neig-tier-sav-examples`, only if safe locally. Do not reset/clean a dirty tree, switch away from uncommitted work, rewrite history, force-push, push, merge, tag, publish, or replace a production installation. ## 2. Suggested implementation layout Allocate four **different**, next-free example numbers; do not renumber old ones. Reconcile actual test/documentation directory conventions in NEIGT00. ```text examples/NN_neig_tier_s.m examples/NN_neig_tier_a.m examples/NN_neig_verified_vs.m examples/NN_neig_verified_va.m examples/neig_tiers/mp_neig_tiers.m examples/neig_tiers/mp_neig_verify_examples.m examples/neig_tiers/mp_neig_tiers_selftest.m examples/neig_tiers/mp_neig_certificate_replay.m examples/neig_tiers/private/net_*.m test/test_neig_tiers.m test/test_neig_verification.m docs/neig-tiers.md docs/neig-verification.md neigt00-report.md ... neigt25-report.md ``` The facade is an example-tree interface, not a new installed package API. ```octave pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "neig_tiers")); r = mp_neig_tiers ("smoke"); assert (r.ok); r = mp_neig_tiers ("demo", struct ("tier", "all", ... "output_dir", fullfile (pwd (), "artifacts", "neigt-demo-001"), ... "plot", false)); assert (r.ok); v = mp_neig_verify_examples ("smoke"); assert (v.scope_ok); mp_neig_tiers_selftest (); ``` Profiles: `smoke` (default), `demo`, `stress` (explicit opt-in). Options: `tier=all|S|A|V-S|V-A|V`, `output_dir=""`, `plot=false`. Reject unknown options. A filtered run has `scope_ok` and coverage metadata; it cannot claim all-task completion. The all-tier `ok` includes mandatory V jobs. Stress has exploratory coverage, not the smoke/demo accuracy contract. Numbered examples locate helper paths relative to `mfilename("fullpath")` and restore any path/precision changes on return and exceptions. Reusable functions must not call process-wide `exit`. Test wrappers must return nonzero process status on failure, not merely print FAIL. ## 3. Local API and environment audit The supplied historical specifications described real/complex three-output `[V,D,W]=eig(A, mode)` with `mode="balance"|"nobalance"`, maximum-operand precision arithmetic, identity construction `mp(existing_mp)`, and one-/three-output SVD. These are **historical expectations**, not a verified current GitHub snapshot. The preparation browser could not retrieve the target repository this turn. Read local source and run isolated probes for: - `mpbits` state, per-object work precision, scalar extraction, exact widening; - real/complex eig, left-vector convention, both modes, aliases and input immutability; - real/complex QR and solves, public Schur and generalized eig if present; - SVD values and three-output economy form, returned V versus VT; - scalar add/subtract/multiply/divide/sqrt/abs/comparisons and their actual rounding; - MP transcendental functions for nonrigorous analytic reference evaluation; - manual source/generation, example runner, source-package and clean-install tools. Record `which`/module paths, actual package/dependency versions where available, commit/dirty state, OS, architecture, commands, and existing focused-test results. Unknown version data stays unknown. No speculative build command or dependency upgrade. Missing supported essentials or a binding defect gets a minimal reproducer. ## 4. Non-negotiable numerical meanings 1. Keep requested standard form, realized exact model, frozen solver input, computed outputs, auxiliary candidates, and certificate targets distinct and hashed. 2. Generation precision is not eig work precision. Fix each OO model once at the manifest's generation precision and reuse it for all work precisions. 3. Do not widen by decimal round-trip, rebuild ideal data over rounded data, solve again at higher precision under an old label, or silently change work precision. 4. A genuine Jordan block has no full eigenvector basis. Use subspaces/block Schur; do not require diagonalization or compute a finite "true" simple-root condition. 5. Orthogonal projectors onto invariant subspaces are not generally `V_J*W_J'`. That expression is a spectral projector only under the requisite dual-basis normalization; distinguish orthogonal and oblique projectors explicitly. 6. Compare spectra by MP one-to-one **minimum-bottleneck** matching. Never real-part sorting or independent nearest-neighbor matches that reuse a reference root. 7. Balance/nobalance apply to ordinary eig runs. General diagonal similarity changes coordinates and pseudospectra; a certificate always names the original target. 8. Approximate or high-relative-accuracy results are not verified inclusions. Every certified inequality must use the proved arithmetic layer. 9. A Gershgorin group with k counted roots does not prove those roots are equal. Exact multiplicity from generator algebra and counted numerical inclusion are separate claims. A certified zero-containing disk does not prove a zero root. 10. No forced binary64 failure, required imaginary-root count, automatic-balancing improvement, monotonically decreasing errors, or forged execution evidence. ## 5. Output and completion With a new output directory write: ```text summary.tsv eigenvalues.tsv verification.tsv environment.json coverage.json report.md inputs/ # exact dyadic serialized targets and generator metadata certificates/ # proof witnesses, exact endpoints, method IDs and hashes plots/ # only when requested; never part of the proof ``` Use schema `neigt-v1`. Decimal fields are approximate displays at a recorded precision; exact certificate data use ARITHMETIC.md's binary encoding. Preserve raw solver order and output hashes. Distinguish solver status, model exactness, reference status, certificate validity, certificate usefulness, and coverage. Missing rows are not successful skips. Refuse to overwrite prior results. Every milestone has a focused test, a report, and PASS/FAIL/BLOCKED. Continue after PASS without routine confirmation. Stop dependent work on a genuine blocker; finish independent safe work where useful. No silent threshold weakening or parameter editing. A mathematical/specification defect must be demonstrated. Final acceptance requires all 120 smoke and 168 demo measured ordinary eig rows, all 26 declared verification jobs per profile, the extra jobs' documented solves, adversarial/replay tests, existing regressions, and isolated clean-package QA. References/candidate preparation/certification are separately counted and timed. Report stress and plotting as NOT_RUN unless actually executed. Finish with actual changed paths, exact commands, measured S/A and V results, all 26 milestone states, the clean-install evidence, and honest limitations. mplapack-interop-0.5.1/docs/codex/SVT-GOAL.md0000644000230300031750000000515615274353473020023 0ustar rafaelrafael# SVT execution prompt Use the user's selected Luna model with xhigh reasoning in the Codex session at the octave-mplapack repository root. Place the complete companion directory, not only the top-level specification. Model selection is a session setting; the text below does not change or assert availability of a particular model identifier. ```text /goal Implement docs/codex/SVT-LUNA-XHIGH.md and all four companion specifications plus docs/codex/svt/cases.json for the mplapack-interop Octave package. Read AGENTS.md and all applicable local instructions first. Execute SVT00 through SVT19 sequentially, run each gate, and write svtXX-report.md before advancing. Continue automatically after PASS; stop dependent work on a real blocker and provide a minimal reproducer. Preserve and reuse working NEIG/earlier SVD examples without assuming that a specification means an implementation exists. Implement all Tier S and Tier A cases, and the mandatory self-contained Tier V baselines for all singular-value inclusions, positive cluster projectors, compatible simple-pair factor boxes, and spectral/inverse-norm certification. Tier V is not satisfied by precision agreement, nonrigorous residuals, bibliography, empty adapters, or an optional external dependency. Audit the local scalar rounding/precision/range contract before using the stated outward-arithmetic proof. Use only existing public mp operations; do not add a backend, SVD driver, installed API, rounding setter, dependency, or MPLAPACK header change. Separate exact models, frozen solver inputs, work precision, reference precision, and certificate targets. Exactly widen returned values for diagnostics; never recompute and substitute a higher-precision answer. Run all 120 smoke SVD rows and 184 demo SVD rows, separately counted mandatory V jobs, adversarial checker tests, existing relevant regressions, and isolated clean-package QA. Stress is opt-in. Use the exact dyadic certificate serialization and replay tests, fixed acceptance targets, and explicit CERTIFIED/INCONCLUSIVE/UNSUPPORTED/error distinctions. Label the V methods as the specified conservative baselines, not full reproductions of the Rump paper algorithms. Do not force native failures, compare repeated vectors individually, treat nonrigorous reference agreement as verification, silently weaken gates or widen work inputs, use a binary64 numerical fallback, overwrite unrelated work or output, or push/merge/tag/publish. Do not stop at a plan. Finish with actual changed files, exact commands, measured S/A/V results, all 20 milestone statuses, source attribution, and honest limitations; unexecuted tests are never PASS. ``` mplapack-interop-0.5.1/docs/optimization.md0000644000230300031750000000131615274353473020245 0ustar rafaelrafael# Arbitrary-precision optimization `fminbnd` performs bounded scalar minimization with MPFR coordinates and MPFR objective values using a safeguarded golden-section search. `fminsearch` uses an MPFR Nelder-Mead simplex with MPFR centroid, reflection, expansion, contraction, shrink, and termination calculations. Both callbacks must return one finite real `mp` scalar; builtin binary64 objective results and complex objectives are rejected. `TolX`, `TolFun`, `MaxIter`, `MaxFunEvals`, and practical `Display` values are accepted through an options struct or name/value pairs. `OutputFcn` and `PlotFcns` are rejected explicitly. `fminunc` remains documented as a clean deferred API in `docs/todo/T14-fminunc.md`. mplapack-interop-0.5.1/docs/rank-condition.md0000644000230300031750000000273315274353473020442 0ustar rafaelrafael# Dense arbitrary-precision rank and condition numbers N03 adds `rank`, `cond`, and `rcond` for dense two-dimensional real and complex `mp` values. `rank(A)` obtains singular values through MPLAPACK `Rgesvd` or `Cgesvd`. Its default threshold is ```text max(size(A)) * sigma_max * Rlamch_mpfr("E") ``` where every term is evaluated at the one operation precision selected from the stored operand (or the maximum precision of an explicit MPFR tolerance). `rank(A,tol)` compares singular values against the supplied real tolerance; the comparison is strict, as in Octave. The default and 2-norm condition numbers use the largest and smallest MPFR singular values. `cond(A,"fro")` uses the Frobenius singular-value identity ```text sqrt(sum(sigma_i^2)) * sqrt(sum(1/sigma_i^2)) ``` for square matrices. Singular matrices return MPFR `Inf` for the condition number. `cond(A,1)`, `cond(A,Inf)`, and `rcond(A)` use operation-owned LU copies and MPLAPACK `Rgecon` or `Cgecon`; they do not form an explicit inverse. `rcond` is the 1-norm reciprocal estimate. The second output of `det(A)` is the same 1-norm reciprocal estimate. The 2-norm condition number is supported for rectangular matrices. The 1-norm, infinity-norm, and Frobenius condition forms, as well as `rcond`, require square matrices. Empty square inputs return `cond=0` and `rcond=Inf`; rank of an empty matrix is zero. Condition results are real MPFR `mp` values for both real and complex inputs, and public inputs remain unchanged. mplapack-interop-0.5.1/docs/release-checklist.md0000644000230300031750000000210515274353473021103 0ustar rafaelrafael# v0.1.0 release checklist M23 executes the upstream freeze and release-candidate subset. PPA1--PPA4 and the final tag remain subsequent release steps. - [x] Set and audit the authoritative version (`0.1.0`). - [x] Complete `DESCRIPTION`, `NEWS.md`, `README.md`, license, and API/help text. - [x] Verify the MPLAPACK feature probe, `pkg-config`, and runtime linkage. - [x] Build from a clean checkout with no source-tree/private dependency paths. - [x] Build and inspect two identical clean source/package archives. - [x] Install, load, smoke-test, unload, uninstall, reinstall, and smoke-test again. - [x] Run every shipped example and installed help audit. - [x] Run full local CI, ASan, UBSan, LSan, and the M00-M22 regression suite. - [x] Check archive contents, source checksums, generated-artifact policy, and no private reports. - [x] Review the Ubuntu 26.04/amd64 PPA handoff and MPLAPACK Debian package boundary. - [ ] Create the final release tag/source archive after the PPA release gate. - [ ] Build the PPA source package, Launchpad staging build, and `apt` install smoke test. mplapack-interop-0.5.1/docs/matrix-assignment.md0000644000230300031750000000361215274353473021172 0ustar rafaelrafael# Dense matrix indexed assignment M14 adds limited in-bounds parenthesis assignment for dense real `mp` values: ```octave A(i,j) = x; A(:,j) = v; A(i,:) = v; A(I,J) = B; A(k) = x; A(:) = scalar_or_rhs; ``` Assignment has value semantics. `mp` payloads are immutable, so each successful assignment validates its indices and right-hand side, deep-copies the complete left-hand side, applies the updates to the copy, and returns a new public `mp` value. Consequently an alias remains unchanged: ```octave B = A; B(1,1) = mp ("9"); ``` does not modify `A`. ## Precision `MpfrMatrixStorage` remains uniformly precisioned. For an `mp` left-hand side and `mp` right-hand side, the result precision is the maximum of their stored precisions. A builtin double right-hand side leaves the left-hand side precision unchanged. Higher-precision right-hand sides therefore widen the complete copied result; lower-precision values are embedded exactly as already represented and never recover discarded source information. The current `mpbits()` value and current-thread MPFR default do not participate. Copies and insertions use direct MPFR operations (`mpfr_set` and `mpfr_set_d`), preserving incoming binary64 semantics for double values. No MPLAPACK routine or precision scope is used. ## Supported and deferred behavior Indices use the M10 finite positive integer, colon, range, and `end` rules. Scalar right-hand sides expand over a selected region. Non-scalar right-hand sides must follow the verified Octave shape rules; vector orientation is accepted for row/column selections. All successful operations preserve the left-hand-side shape and column-major ordering. M14 is intentionally in-bounds only. Matrix growth, deletion with an empty right-hand side, logical assignment, general vector linear assignment, complex/sparse/N-D assignment, and chained/cell/field assignment remain unsupported and fail explicitly. mplapack-interop-0.5.1/docs/complex-compatibility.md0000644000230300031750000001164515274353473022043 0ustar rafaelrafael# Complex compatibility and limits The tested public runtime is GNU Octave 11.1.0 with the dense `mp` class and the controlled reference `mplapack_mpfr` backend. Supported syntax follows the forms listed in [`complex-api.md`](complex-api.md). Mixed operations promote when at least one operand is an `mp` value and any complex participant selects the MPC implementation. A builtin complex double may participate in mixed arithmetic, multiplication, solve, concatenation, and assignment; it is converted into the operation precision. A pair of raw builtin complex doubles remains an Octave operation and is outside this package's arbitrary-precision contract. The following complex operations are intentionally rejected by the package's compatibility firewall. They must fail cleanly without conversion to a binary64 result, crash, or recursive dispatch: - sparse generalized eig and standalone QZ APIs (dense generalized `eig(A,B)` is supported by N06 through the definite/QZ MPLAPACK paths); - ordered comparisons and sparse conversion; equality, logical conversion, logical operators, `any`/`all`, `find`, and logical indexing are supported by S03; - sparse matrices, N-dimensional matrices, growth/deletion assignment, and unsupported cell/text matrix forms. The package does not claim identical error text to builtin Octave. It does claim stable package-owned rejection behavior for the audited unsupported surface and no implicit binary64 fallback. Public LU follows real M21 and has no separate status output; native `Cgetrf INFO` is checked, and singular partial factors are preserved. N00 adds arbitrary-precision `norm` for real and complex vectors and dense matrices. Supported forms and deferred matrix p/options are documented in [`norm.md`](norm.md); the implementation uses MPFR/MPC-native absolute values, `Rlange`/`Clange`, `Rnrm2`/`RCnrm2`, and `Rgesvd`/`Cgesvd`. N01 adds arbitrary-precision `det` and `inv` for dense real and complex matrices. They use `Rgetrf`/`Rgetri` and `Cgetrf`/`Cgetri`, respectively, with stored-precision operation scopes, checked workspace queries, exact zero for singular determinants, and operation-owned destructive copies. N03 completes the determinant reciprocal-condition output. N02 adds dense arbitrary-precision `svd` through `Rgesvd`/`Cgesvd`, including one-output real singular values and full/economy three-output factors. Complex SVD returns real `S` and native MPC `U`/`V` factors; no binary64 fallback is used. N05 adds standard general `eig` through MPFR `Rgeevx` and MPC/MPFR `Cgeevx`. Real general outputs are represented as complex `mp` so conjugate pairs retain their imaginary parts. Balance and nobalance forms, right/left residuals, and the permanent Grcar regression are covered. N06 adds dense generalized eigenproblems with Octave-compatible `chol`/`qz` and `matrix`/`vector` options; no generalized path uses builtin binary64 arithmetic. N03 adds dense arbitrary-precision `rank`, `cond`, and `rcond`. Rank uses MPFR/MPC singular values and a stored-precision default threshold. The 2-norm condition path uses those same singular values; 1-norm and infinity-norm conditions, `rcond`, and the second output of `det` use native `Rgecon`/`Cgecon` estimators. Frobenius condition numbers are computed from the singular values. All condition results are real MPFR values, including for complex inputs, and square-only norm variants reject nonsquare matrices. N04 adds standard structured `eig` for exactly symmetric real and Hermitian complex matrices. Real input uses MPFR `Rsyevd`; complex input uses MPC/MPFR `Cheevd`. Eigenvalues and diagonal output are real `mp`; real eigenvectors are real `mp`, and complex eigenvectors are complex `mp`. The public path performs an exact represented symmetry/Hermitian check and rejects general matrices until N05. Destructive LAPACK calls receive operation-owned copies. S01 adds native MPFR/MPC element-wise power and the audited elementary functions (`sqrt`, `exp`, `expm1`, `log`, `log1p`, `log10`, `log2`, the trigonometric and hyperbolic families, and `cbrt`). Complex `log2` is routed through the gmpfrxx `mpfrxx::log2` MPC compatibility wrapper, so the binding does not require a direct `mpc_log2` symbol. Real-domain crossings promote to MPC with Octave-compatible principal branches; no builtin binary64 numerical fallback is used. S02 adds native MPFR/MPC reductions and extrema. Complex reductions preserve MPC storage and precision; complex `sumsq` returns a real MPFR magnitude sum. The supported complex extrema path uses native magnitude/phase ordering and does not convert values through builtin binary64 arithmetic. ## Lifecycle The native module is locked while public values or registered native types are live. Public values remain valid across ordinary clear and package unload/ reload tests. Reinstallation is tested with the same real and complex smoke operations. The controlled installation uses only the reference MPFR backend; optimized complex workers are not claimed. mplapack-interop-0.5.1/docs/matrix-inspection.md0000644000230300031750000000311015274353473021166 0ustar rafaelrafael# Dense matrix inspection M10 adds a read-only inspection surface for dense real `mp` matrices. The public `mp` object still contains one private native `MpfrMatrixStorage` payload; indexing and conversion operate directly on that payload. ## Indexing Supported forms are `A(i,j)`, `A(:,j)`, `A(i,:)`, `A(I,J)`, scalar linear indexing `A(k)`, `A(:)`, and the corresponding two-dimensional `end` forms. Indices are validated as finite, positive, integer-valued, in-bounds numeric indices. Selection order and repeated indices are preserved. Slices are deep copies with the source matrix precision, and a `1x1` selection is normalized to the scalar native payload. General vector linear indexing and logical indexing remain deferred. ## Conversion and display `double(A)` creates a builtin real matrix of the same shape. Each element is converted directly with MPFR round-to-nearest, ties-to-even; no text or binary64 intermediate is used for the source value. `disp(A)` formats each element through the canonical scalar MPFR formatter, preserving source precision and ignoring Octave's `format short`/`format long` settings. Neither operation changes the project default or current-thread MPFR default. Matrix `char` and logical indexing remain outside M10; M14 adds the separate value-semantic in-bounds assignment surface. M11 builds direct element-wise arithmetic on the same precision-preserving matrix payload. M12 adds read-only transpose, conjugate transpose for real values, and column-major reshape; these structural copies preserve the source precision and do not consult the current default. mplapack-interop-0.5.1/docs/interpolation.md0000644000230300031750000000121215274353473020401 0ustar rafaelrafael# Arbitrary-precision interpolation The interpolation surface is split into the closed scalar-output 1-D core and the closed 2-D grid core: - [`interpolation-1d.md`](interpolation-1d.md) documents `interp1`, `pchip`, `spline`, `ppval`, `mkpp`, `unmkpp`, `ppder`, and `ppint`. - [`interpolation-2d.md`](interpolation-2d.md) documents `interp2`. - Matrix-valued PP output and N-D interpolation are deferred; see [`todo/T10-matrix-valued-pp.md`](todo/T10-matrix-valued-pp.md) and [`todo/T11-ND-interpolation.md`](todo/T11-ND-interpolation.md). Both closed cores retain MPFR/MPC values and do not convert grids or query points through binary64. mplapack-interop-0.5.1/docs/public-api-inventory.md0000644000230300031750000012312115274353473021576 0ustar rafaelrafael# Public API inventory This is the machine-auditable DOC00 coverage matrix. The inventory is derived from the public `inst/@mp/*.m` methods and package-level `inst/*.m` functions. Files below `inst/@mp/private/` and `inst/private/` are implementation helpers and are intentionally excluded. Status meanings: `SUPPORTED` is part of the tested public surface; `PARTIAL` means only the listed forms are supported; `DEFERRED` is not a supported call; `INTERNAL` is an Octave dispatch hook rather than a user entry point. A supported entry has a help block, a manual/MP note, a pasteable example or grouped example, and a backend/algorithm reference. The difficult nonsymmetric eigensystem harness under `examples/nonsymmetric_eig/` is a repository-local example/QA surface built from existing public APIs. It intentionally has no additional package-level API row; its runnable entry point and coverage are recorded in `docs/nonsymmetric-eig-suite.md` and the compatibility matrix. ## Repository-local NEIGT example/QA interfaces These names are intentionally not package-level `inst/` APIs. They are documented, runnable entry points for the NEIGT source-package QA harness and are included in the source archive together with their private helpers and JSON manifests. The one-case worked-example decomposition is indexed by `docs/examples/tiered/README.md`; it adds no package-level `inst/` entry. | Name | Kind | Status | Contract/example | |---|---|---|---| | `mp_neig_tiers` | example runner | SUPPORTED-REPOSITORY | Ordinary Tier-S/Tier-A smoke/demo rows; `examples/14_neig_tier_s.m`, `examples/15_neig_tier_a.m` | | `mp_neig_verify_examples` | example runner | SUPPORTED-REPOSITORY | 26 manifest V-S/V-A jobs per profile; `examples/16_neig_verified_vs.m`, `examples/17_neig_verified_va.m` | | `mp_neig_write_outputs` | QA result writer | SUPPORTED-REPOSITORY | New-directory-only TSV/environment/exact-proof bundle; replayable with `mp_neig_replay` | | `mp_neig_replay` | QA proof replay | SUPPORTED-REPOSITORY | Hash-bound V-S1 replay without `eig` or ideal-model reconstruction | The helpers preserve stored MP precision and ambient-default restoration. The V results are conservative proof baselines, not a new interval or generalized eigenvalue API. Optional plots are display-only. | API | Kind | Status | Manual/MP notes | Help | Example | Backend/Doxygen | |---|---|---|---|---|---|---| | `mp` | @mp method/constructor | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/01_scalar_precision.m` | `docs/backend-map.md`; Doxygen | | `Inf` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `NaN` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `abs` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `acos` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `acosh` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `all` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `and` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `angle` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `any` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `arg` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `asin` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `asinh` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `atan` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `atan2` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `atanh` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `balance` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `bounds` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `cat` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `cbrt` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `ceil` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `char` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `chol` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `colon` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `columns` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `compan` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `cond` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `conj` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `contour3` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `conv` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `cos` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `cosh` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `ctranspose` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `cumprod` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `cumsum` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `deconv` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `det` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `diag` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `diff` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `disp` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `double` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `eig` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `end` |dispatch method| INTERNAL | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `eps` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `eq` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `erf` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `erfc` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `exp` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `expm` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `expm1` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `eye` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `find` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `fix` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `flip` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `fliplr` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `flipud` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `floor` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `gamma` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `gammaln` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `ge` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `gt` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `hess` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `horzcat` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `hypot` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `imag` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `inf` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `intersect` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `inv` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `isempty` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `isequal` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `isequaln` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `isfinite` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `isinf` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `ismember` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `isnan` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `isnumeric` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `isreal` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `kron` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `le` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `length` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `lgamma` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `linspace` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `loadobj` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/09_serialization_rng.m` or grouped | `docs/backend-map.md`; Doxygen | | `log` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `log10` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `log1p` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `log2` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `logical` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `loglog` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `logm` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `logspace` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `lt` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `lu` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `max` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mean` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `median` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mesh` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `meshc` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `min` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `minus` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mldivide` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mod` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mpower` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mrdivide` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mtimes` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `nan` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `ndims` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `ne` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `norm` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `not` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `null` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `numel` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `ones` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `or` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `orth` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `pinv` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `plot` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `plot3` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `plus` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `poly` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `polyder` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `polyint` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `polyval` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `polyvalm` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `power` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `prod` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `properties` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `qr` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `qz` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `range` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `rank` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `rcond` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `rdivide` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `real` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `rem` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `repmat` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `reshape` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `roots` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `rot90` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `round` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `rows` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `rref` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `saveobj` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/09_serialization_rng.m` or grouped | `docs/backend-map.md`; Doxygen | | `scatter` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `scatter3` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `schur` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `semilogx` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `semilogy` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `setdiff` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `setxor` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `sign` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `signbit` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `sin` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `sinh` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `size` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `sort` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `sqrt` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `sqrtm` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/08_advanced_dense.m` or grouped | `docs/backend-map.md`; Doxygen | | `stairs` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `std` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `stem` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `subsasgn` |dispatch method| INTERNAL | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `subsref` |dispatch method| INTERNAL | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `sum` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `sumsq` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `surf` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `surfc` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `svd` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/07_svd_hilbert.m` or grouped | `docs/backend-map.md`; Doxygen | | `tan` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `tanh` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `times` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `transpose` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `tril` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `triu` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `uminus` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `union` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `unique` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `uplus` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `var` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `vertcat` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `waterfall` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/12_graphics_boundary.m` or grouped | `docs/backend-map.md`; Doxygen | | `xor` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `zeros` | @mp method| SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `fminbnd` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/11_solvers_quadrature_optimization.m` or grouped | `docs/backend-map.md`; Doxygen | | `fminsearch` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/11_solvers_quadrature_optimization.m` or grouped | `docs/backend-map.md`; Doxygen | | `fsolve` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/11_solvers_quadrature_optimization.m` or grouped | `docs/backend-map.md`; Doxygen | | `fzero` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/11_solvers_quadrature_optimization.m` or grouped | `docs/backend-map.md`; Doxygen | | `integral` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/11_solvers_quadrature_optimization.m` or grouped | `docs/backend-map.md`; Doxygen | | `interp1` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/10_interpolation.m` or grouped | `docs/backend-map.md`; Doxygen | | `interp2` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/10_interpolation.m` or grouped | `docs/backend-map.md`; Doxygen | | `mkpp` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/10_interpolation.m` or grouped | `docs/backend-map.md`; Doxygen | | `mpbits` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mpdigits` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mplapack_version` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/02_matrix_arithmetic.m` or grouped | `docs/backend-map.md`; Doxygen | | `mprand` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/09_serialization_rng.m` or grouped | `docs/backend-map.md`; Doxygen | | `mprandi` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/09_serialization_rng.m` or grouped | `docs/backend-map.md`; Doxygen | | `mprandn` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/09_serialization_rng.m` or grouped | `docs/backend-map.md`; Doxygen | | `mprng` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/09_serialization_rng.m` or grouped | `docs/backend-map.md`; Doxygen | | `pchip` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/10_interpolation.m` or grouped | `docs/backend-map.md`; Doxygen | | `ppder` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/10_interpolation.m` or grouped | `docs/backend-map.md`; Doxygen | | `ppint` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/10_interpolation.m` or grouped | `docs/backend-map.md`; Doxygen | | `ppval` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/10_interpolation.m` or grouped | `docs/backend-map.md`; Doxygen | | `quadgk` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/11_solvers_quadrature_optimization.m` or grouped | `docs/backend-map.md`; Doxygen | | `spline` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/10_interpolation.m` or grouped | `docs/backend-map.md`; Doxygen | | `unmkpp` | package function | SUPPORTED | User manual § API quick reference; precision/compatibility notes | yes | `examples/10_interpolation.m` or grouped | `docs/backend-map.md`; Doxygen | ## Intentionally deferred public forms | API/form | Status | Re-entry record | |---|---|---| | `funm` | DEFERRED | [docs/todo/T02-funm.md](docs/todo/T02-funm.md) | | `polyfit` | DEFERRED | [docs/todo/T03-polyfit-polyeig.md](docs/todo/T03-polyfit-polyeig.md) | | `polyeig` | DEFERRED | [docs/todo/T03-polyfit-polyeig.md](docs/todo/T03-polyfit-polyeig.md) | | `ismembertol` | DEFERRED | [docs/todo/T04-ismembertol.md](docs/todo/T04-ismembertol.md) | | `meshgrid` | DEFERRED | [docs/todo/T08-meshgrid.md](docs/todo/T08-meshgrid.md) | | `interp3` | DEFERRED | [docs/todo/T11-ND-interpolation.md](docs/todo/T11-ND-interpolation.md) | | `interpn` | DEFERRED | [docs/todo/T11-ND-interpolation.md](docs/todo/T11-ND-interpolation.md) | | `fminunc` | DEFERRED | [docs/todo/T14-fminunc.md](docs/todo/T14-fminunc.md) | | `ArrayValued` | DEFERRED | [docs/todo/T13-array-valued-quadrature.md](docs/todo/T13-array-valued-quadrature.md) | The deferred forms are not included as supported rows and must fail through the documented compatibility boundary; they must never fall through to builtin binary64 numerical execution. mplapack-interop-0.5.1/docs/v0.3-api.md0000644000230300031750000000541615274353473016761 0ustar rafaelrafael# mplapack-interop 0.3.1 numerical API The 0.3.1 release provides dense, arbitrary-precision real and complex `mp` values for the following public operations: | Operation | Supported forms | Native backend | |---|---|---| | construction/precision | `mp`, `mpbits`, `mpdigits` | MPFR/MPC storage | | arithmetic | `+`, `-`, `.*`, `./`, unary signs, `*`, `\`, `/` | native MPFR/MPC; `Rgemm`/`Cgemm`; `Rgesv`/`Cgesv`/`Rgelss`/`Cgelsy` | | structure | indexing, assignment, transpose, ctranspose, reshape, concat | native operation-owned storage | | factorizations | `chol`, `qr`, pivoted `qr`, `lu` | `Rpotrf`/`Cpotrf`, `Rgeqrf`/`Cgeqrf`, `Rgeqp3`/`Cgeqp3`, `Rgetrf`/`Cgetrf` | | norms | vector and dense matrix supported norm forms | native MPFR/MPC; `Rlange`/`Clange`; `Rgesvd`/`Cgesvd` | | determinant/inverse | `det`, `inv` | `Rgetrf`/`Rgetri`; `Cgetrf`/`Cgetri` | | SVD | values, full/economy factors | `Rgesvd`/`Cgesvd` | | rank/condition | `rank`, `cond`, `rcond` | singular values; `Rgecon`/`Cgecon` | | standard eig | structured/general, balance/nobalance, vector/matrix, left vectors | `Rsyevd`/`Cheevd`; `Rgeevx`/`Cgeevx` | | generalized eig | `eig(A,B)`, `chol`/`qz`, vector/matrix, left vectors | `Rsygvd`/`Chegvd`; `Rggev`/`Cggev` | | right division | dense `A / B`, scalar and matrix forms, rank-deficient minimum norm | conjugate-transpose solve; `Rgesv`/`Rgelss` or `Cgesv`/`Cgelsy` | Every numerical operation selects one operation precision from its stored operands. It normalizes native temporaries to that precision, enters the corresponding MPFR or MPFR/MPC scope, and returns operation-owned uniform storage. Destructive LAPACK calls never receive public storage directly. Existing values retain their precision when `mpbits` changes. No supported complex operation silently falls back to builtin binary64 arithmetic, and real-only operations remain on real MPLAPACK paths. Generalized eigensystems use `A*V = B*V*D`; three-output forms additionally return `W` satisfying `W'*A = D*W'*B`. Real QZ conjugate pairs are represented as complex `mp`, and `beta = 0` preserves an infinite eigenvalue. An exact symmetric/Hermitian pair uses the definite driver by default when `B` is positive definite; `"qz"` forces QZ and `"chol"` requires the structured pair. The tested interface is GNU Octave 11.1.0 with the controlled MPLAPACK MPFR backend. Unsupported or intentionally deferred APIs include sparse and N-dimensional matrix values, standalone `qz`, `schur`, `hess`, `expm`, `logm`, general unimplemented matrix functions, powers, and comparisons/logical values. These fail through package-owned or clean Octave diagnostics without implicit binary64 conversion. Dense right division is implemented through the conjugate-transpose identity `(B' \ A')'`; scalar denominators use native element-wise division. mplapack-interop-0.5.1/docs/interpolation-1d.md0000644000230300031750000000311015274353473020702 0ustar rafaelrafael# One-dimensional interpolation The package provides MP-aware `interp1`, `pchip`, `spline`, and `ppval`, as well as scalar-output `mkpp`, `unmkpp`, `ppder`, and `ppint`. The supported data shape for this milestone is a one-dimensional grid and one data vector; general matrix-valued data and N-dimensional interpolation remain outside this T10 core and are considered by T11 only where the contract is explicit. The grid is normalized to an increasing MP column vector. A decreasing grid is reversed together with its data, repeated points are rejected, and no MP grid or query point is converted to binary64. Ordinary numeric inputs are promoted into MP arithmetic at the selected operation precision. `interp1` supports `nearest`, `previous`, `next`, `linear`, `pchip`, and `spline`, default NaN for out-of-range queries, numeric extrapolation values, the `"extrap"` option, and the compatible `interp1(x,y,method,"pp")` form. `pchip` uses Fritsch-Carlson weighted slopes for real data and cubic Hermite coefficients. Complex data use the corresponding weighted complex Hermite slopes; scalar ordering-based shape preservation is not defined for complex values. `spline` solves the not-a-knot second-derivative system with the MP linear solve path. Both produce local descending-power coefficient rows. `ppval` selects the first/last piece for extrapolation and evaluates each coefficient row with MP Horner arithmetic. The derivative and integral helpers preserve the MP coefficients; `ppint` chooses a continuous integral with zero initial constant unless an MP/numeric constant is supplied. mplapack-interop-0.5.1/docs/qr.md0000644000230300031750000000217615274353473016146 0ustar rafaelrafael# Dense real `mp` QR factorization M18 adds non-pivoted dense real QR through the installed MPLAPACK MPFR `Rgeqrf` and `Rorgqr` routines. M19 adds three-output column-pivoted QR through `Rgeqp3` and `Rorgqr` (see `pivoted-qr.md`): ```octave R = qr (A); [Q, R] = qr (A); R = qr (A, "econ"); [Q, R] = qr (A, "econ"); ``` The single-output form returns `R`. Full QR has `Q` of size `m x m` and `R` of size `m x n`; economy QR uses `Q` of size `m x n` and `R` of size `n x n` when `m > n`, and has the same shapes as full QR when `m <= n`. The numeric `0` option is accepted as a deprecated economy alias; prefer `"econ"`. `Rgeqrf` computes an operation-owned Householder representation and `Rorgqr` generates `Q` only for two-output calls. Public values are immutable and the input matrix is never overwritten. Every result uses the stored precision of `A`; the current `mpbits()` setting and ambient MPFR default do not affect the operation precision. M18 supports dense real scalar and two-dimensional matrix values only. Pivoted three-output QR is provided by M19. `qr(A,B)`, sparse, complex, N-D, and QR update operations remain deferred. mplapack-interop-0.5.1/docs/mrdivide.md0000644000230300031750000000275215274353473017327 0ustar rafaelrafael# Dense right division N08 adds dense arbitrary-precision right division to mplapack-interop. For A of shape m x n and B of shape p x n, X = A / B returns an m x p result satisfying X * B = A for a consistent full-rank system, or Octave-compatible least-squares/minimum-norm semantics otherwise. The public function form mrdivide (A, B) is equivalent to the operator. The matrix path uses the identity (B' \ A')' where ' is the conjugate transpose for complex values. Full-rank square systems use the existing Rgesv/Cgesv backend; rectangular and rank-deficient systems use Rgelss/Cgelsy. A square singular coefficient matrix first follows the existing mldivide Rgesv/Cgesv path and, only for right division, retries through the rank-revealing backend to obtain the minimum-norm result. The public square-singular mldivide error contract is unchanged. When one operand is builtin double, it is converted once into the other operand's stored precision. The operation chooses p_op as the maximum stored precision of its mp operands, uses operation-owned copies for destructive LAPACK calls, and never invokes builtin binary64 complex arithmetic as a numerical fallback. A scalar denominator uses the existing native element-wise rdivide path and does not call LAPACK. Empty two-dimensional matrices and finite, infinite, and NaN values follow the established dense mp storage and backend behavior. Invalid dimensions are rejected with the package's existing mplapack:mp:DimensionMismatch diagnostic. mplapack-interop-0.5.1/docs/packaging.md0000644000230300031750000000340715274353473017446 0ustar rafaelrafael# Packaging architecture The GNU Octave package identity for the forward release is `mplapack-interop`; `octave-mplapack` remains the repository name. The historical D00 package name `mplapack` is retained only in historical release records. The binary architecture and B01–B05 handoff are specified in [`binary-distribution.md`](binary-distribution.md). The intended dependency and delivery flow is: ```text MPLAPACK packages | v installed development interface | v mplapack-interop source package | v mplapack-interop binary package | v GNU Octave users ``` MPLAPACK runtime and development packages remain conceptually separate from the `octave-mplapack` source and binary packages. System dependencies are preferred where possible; arbitrary dependency copies must not be bundled. PPA work begins only after the M10 numerical baseline is stable enough. Publication goes to a staging PPA before any stable archive. Launchpad builds from source packages, and the stable artifacts must retain source/build provenance rather than being silently rebuilt from different source. Ubuntu 26.04 LTS is the first target. Ubuntu 24.04 LTS is secondary and must not block the initial Octave 11 design. Actual Debian metadata belongs to P01 and is intentionally absent during M00. M20 audited the installed MPFR complex symbols and found them in the same `libmplapack_mpfr.so.3` dependency already used by the real backend. The forward binary architecture treats the package-local runtime closure and its license notices as explicit B01–B05 deliverables; no global private-library install is allowed. The old real-only PPA notes are historical and do not authorize PPA work in D01R1. No PPA upload occurs before the PPA packaging milestones. mplapack-interop-0.5.1/docs/architecture.md0000644000230300031750000002734515274353473020213 0ustar rafaelrafael# Architecture contract ## Layering The intended implementation has the following layers: ```text GNU Octave user code | v @mp and public helper functions | v private native .oct interface | v native multiprecision value/matrix representation | v MPLAPACK MPFR BLAS/LAPACK routines ``` The public API follows ordinary Octave numeric syntax. Backend routine names such as `Rgemm` and `Rgesv` are implementation details, not the primary public interface. Ordinary `.m` code must not handle native storage details, raw pointers, or integerized pointer handles. Octave's normal `double` matrix implementation remains untouched. Octave's system BLAS and LAPACK also remain untouched. `mp` values are separate numeric objects whose MPLAPACK operations work directly on native MPFR-backed storage; the project will not use `LD_PRELOAD` or silently route through binary64. Through M21 the only public backend is real MPFR arithmetic. M20 audits and freezes the future MPC-valued architecture but intentionally adds no public complex values. GMP, DD, QD, binary80, and binary128 backends are outside this baseline. ## Native representation and ownership M02 establishes an internal scalar class derived from Octave 11.1's installed `octave_base_dld_value` API. Its registered identity is `mplapack_mpfr_scalar_internal`, not the future public `mp` class. The Octave representation owns a project `MpfrScalarStorage`, which in turn owns the same RAII `mpfrxx::mpfr_class` type used as MPLAPACK MPFR `REAL`. The pure storage layer is independent of Octave headers. The native scalar: - uses deterministic RAII ownership; - initializes and clears every MPFR value exactly once; - copies and moves safely, with copy assignment preserving source precision; - remains safe for Octave temporaries, assignments, and error paths; - stores explicit per-object precision; - is immutable at the Octave boundary and reports shape `1 x 1`; and - uses neither a process-global object registry nor user-visible pointer handles. Octave assignment may share an immutable representation. `clone()` and the M02 explicit clone diagnostic deep-copy value and precision. Future destructive LAPACK operations must copy public inputs into operation-owned storage. The matrix container, dimensions, and column-major layout remain M07 decisions; the selected native scalar is safe in contiguous C++ containers. Every representation's DLD-aware base retains an `octave::auto_shlib` reference to the containing module, including the prototype stored by type registration. The DLD function object is also locked when the internal type is initialized. Ordinary clear cannot invalidate live values. Octave 11.1 package unload removes the function name, but isolated lifecycle QA proves that a live value retains usable type/vtable metadata and is destroyed safely; package reload reasserts the lock without duplicate registration. Octave-specific subclass, type-registration, checked-cast, and function-locking code remains localized for future compatibility work. ## Dependency and build boundary MPLAPACK is an installed, separate dependency and is never vendored or modified by this project. Discovery defaults to: ```sh pkg-config --modversion mplapack_mpfr pkg-config --cflags mplapack_mpfr pkg-config --libs mplapack_mpfr ``` The initial baseline requires MPLAPACK 3.0.0 or newer unless later evidence establishes a better boundary. M01 must record which installation is used and prove that no MPLAPACK source or build tree is required. The native bridge will use Octave's normal external-module mechanism and the private name `__mplapack_core__.oct`. Package tooling supplies `mkoctfile`, and the build respects `MKOCTFILE` rather than hard-coding an executable. Explicit `MPLAPACK_CFLAGS` and `MPLAPACK_LIBS` overrides are supported, while `pkg-config` remains the default. M01 proves that an Octave `.oct` module can link to and call the installed MPLAPACK MPFR backend. The private `version` command calls `Rlamch_mpfr("E")`; the public `mplapack_version()` wrapper only reports the diagnostic result. The source package is generated explicitly and tested by installation under an isolated Octave HOME. M01 does not choose a native `mp` representation or implement arithmetic. M02 proves that an immutable custom Octave scalar can own, copy, clone, and destroy explicit-precision MPLAPACK MPFR storage safely. The private `__mplapack_core__` test commands exercise lifecycle behavior only. The public wrapper and all arithmetic remain unimplemented until later milestones. M03 exposes that scalar as an Octave 11.1 classdef value named `mp`. Its one native payload property is private and hidden; native QA retrieves it through localized checked classdef APIs. Decimal text is parsed directly by MPFR, while a double is converted directly from its existing IEEE binary64 value. Both paths pass the project-owned default explicitly into each scalar. The public object reports `1 x 1`, preserves M02 lifetime safety, and provides only a nonnumeric placeholder display before M05. M03 deliberately rejects numeric matrices, text/cell matrices, empty values, and concatenation. Public dense `mp` matrices will not be represented as Octave arrays or cells of independent scalar wrapper objects. M07 owns dense native storage, matrix constructors, empty representation, and matrix shape. M04 exposes the one project-owned default precision state through `mpbits` and `mpdigits`. A fresh Octave process starts at 512 bits. Bits remain canonical; decimal requests map to `ceil(n log2(10))` bits without hidden guard bits, and the digit getter reports `floor(p log10(2))` complete digits. Directed MPFR interval calculations certify both integer conversions. Atomic native state persists across clear and package unload/reload in one process, is never saved to disk, and is passed explicitly into each newly constructed immutable value. M05 adds logically const scalar conversion methods to `MpfrScalarStorage`. Canonical decimal text comes directly from `mpfr_get_str` with base 10, its precision-derived round-trip digit count, and `MPFR_RNDN`; MPFR-owned text is released by project RAII. Explicit binary64 conversion calls `mpfr_get_d` with `MPFR_RNDN` and never passes through text. Public `char` and `double` delegate to checked native bridge commands, while `disp` writes the same canonical text without observing Octave's binary64 format setting. All formatting uses the immutable object's precision, not the current default. Unsupported numerical functions and matrix operators do not implicitly fall back through `double`. M06 adds direct scalar MPFR arithmetic below the Octave method layer. Native storage methods call `mpfr_add`, `mpfr_sub`, `mpfr_mul`, `mpfr_div`, and `mpfr_neg` with `MPFR_RNDN`, allocate independent results, and never mutate operands. For two `mp` values result precision is the greater operand precision. For mixed real scalar binary64 arithmetic the `mp` precision is used and the binary64 input is converted directly with `mpfr_set_d`. The current default is neither consulted nor changed. Public result wrappers are formed inside class methods from the validated native payload, without calling the public constructor or exposing `payload_`. M07 adds a second private DLD-aware native type, `mplapack_mpfr_matrix_internal`, while preserving one public class `mp`. One public matrix wrapper owns one `MpfrMatrixStorage`; matrices are never Octave object arrays or cells of scalar wrappers. Storage is a contiguous column-major `std::vector` with one explicit immutable precision, checked dimensions, and `ld = rows` (or one for zero rows). Its native pointer is exactly the `mpfr_class *` required by the installed MPLAPACK MPFR `Rgemm` and `Rgesv` interfaces, with no packing. M07 executes neither routine. Native deep copies provide future operation-owned mutable work buffers while public matrices remain immutable. Double matrices transfer binary64 values directly; text-cell matrices parse decimal directly. Public shape queries work, while indexing, matrix conversion, and all matrix operators remain explicit firewalls. M08 adds dense `mtimes` through the installed MPLAPACK MPFR reference `Rgemm`. It chooses `max(lhs,rhs)` as the operation precision, promotes operation-owned copies to that uniform precision, enters `MplapackMpfrPrecisionScope`, validates the calling-thread uniform-precision contract, and invokes `Rgemm` directly. The project default is restored after the operation. Matrix/scalar scaling remains native MPFR; matrix element-wise arithmetic, indexing, and conversion remain deferred. M09 adds square `mldivide` through `Rgesv`; destructive factorization always uses operation-owned copies of the immutable public operands. M10 adds read-only dense inspection. Native indexing selects and deep-copies MPFR elements in column-major order, preserving the source matrix precision. `double(A)` calls `mpfr_get_d` for each element and `disp(A)` reuses the canonical scalar formatter. These operations do not consult or mutate the current precision default; matrix assignment and matrix `char` remain deferred. M11 adds direct MPFR element-wise arithmetic for dense matrices. A common native kernel implements `+`, `-`, `.*`, and `./` (plus unary signs), applies two-dimensional singleton expansion without materializing broadcast copies, and rounds directly into destination storage at the operand-derived precision. These operations do not call MPLAPACK or enter its precision scope; the current default remains unchanged. M12 adds read-only `transpose`, `ctranspose`, and two-dimensional `reshape`. They allocate independent dense storage and copy existing MPFR values directly, preserving source precision and column-major linear order. Structural operations do not call MPLAPACK, enter a precision scope, or consult the current default. M13 adds native dense `horzcat` and `vertcat`. Bracket concatenation validates the complete argument list before allocating one immutable column-major result at `p_cat`, the maximum precision of all participating `mp` operands (including empty operands). Values are copied directly from MPFR storage, while real double inputs retain their incoming binary64 semantics. Concatenation performs no arithmetic, broadcasting, MPLAPACK call, precision-scope entry, or default precision mutation, and never creates an Octave object array of `mp` wrappers. M14 adds in-bounds parenthesis assignment with value semantics. The bridge validates the complete assignment before allocating a uniformly precise deep copy of the lhs, then applies the selected updates to that copy. Higher- precision `mp` RHS values widen the complete result; builtin double RHS values retain lhs precision. No MPLAPACK routine or MPFR precision scope is used. M20 freezes the design for a future complex extension. The installed MPLAPACK type is `mpfrxx::mpc_class`, and future complex scalars/matrices will use it directly in separate payload kinds with one equal precision for real and imaginary components. Real storage and all accepted real backend paths remain unchanged. Complex numerical calls will use operation-owned contiguous `COMPLEX` buffers, a single `p_op` for all REAL/COMPLEX work, and a controlled MPFR/MPC precision scope. See `docs/complex-architecture.md`; no public complex implementation is part of M20. M21 adds dense real LU factorization through MPLAPACK MPFR `Rgetrf`. The factorization receives an operation-owned copy at the stored input precision; `IPIV` is replayed into final row-permutation data for Octave's packed, two-output, matrix-permutation, and vector-permutation forms. Singular `INFO > 0` is retained as factorization status rather than converted into the solve error used by `Rgesv`, and the existing real `Rgemm`, `Rgesv`, `Rgelss`, `Rpotrf`, QR, and pivoted-QR paths remain unchanged. mplapack-interop-0.5.1/docs/svd.md0000644000230300031750000000307315274353473016315 0ustar rafaelrafael# Singular value decomposition The 0.3.0 development line provides dense arbitrary-precision real and complex singular value decomposition through MPLAPACK `Rgesvd` and `Cgesvd`. ```octave s = svd (A) [U, S, V] = svd (A) [U, S, V] = svd (A, "econ") [U, S, V] = svd (A, 0) ``` The one-output result is a real `mp` column containing the `min (rows(A), columns(A))` singular values in descending order. In the three-output form, `S` is a real `mp` diagonal matrix and the factors satisfy `A = U*S*V'`; for complex input the transpose is conjugating. The full form returns `U` as `m x m`, `S` as `m x n`, and `V` as `n x n`. Economy mode returns `U` as `m x k`, `S` as `k x k`, and `V` as `n x k`, where `k = min(m,n)`. The numeric `0` option is accepted as the deprecated economy spelling. Empty two-dimensional shapes follow the corresponding Octave full/economy shape rules. A scalar is treated as a `1 x 1` dense input and preserves its stored precision in all returned `mp` values. ## Precision and ownership Each call uses the stored operand precision as its operation precision. The destructive LAPACK input buffer, singular-value buffer, U/VT factors, and workspace all have uniform MPFR or MPC precision under one operation-owned precision scope. The complex path converts VT to V with native MPC conjugation. Ambient `mpbits` changes do not alter existing values or SVD precision, and the input remains unchanged after the query and execution calls. No SVD path converts through binary64 or calls builtin Octave `svd`. Real inputs stay on `Rgesvd`; complex inputs stay on `Cgesvd`. mplapack-interop-0.5.1/docs/elementwise-arithmetic.md0000644000230300031750000000400615274353473022166 0ustar rafaelrafael# Dense `mp` element-wise arithmetic M11 extends the existing scalar MPFR arithmetic to real, two-dimensional dense `mp` matrices. The native kernel writes directly into explicitly precisioned `MpfrMatrixStorage` and does not call MPLAPACK or convert through binary64. ## Operations The supported operations are `+`, `-`, `.*`, `./`, unary `+`, and unary `-`. For binary operands the result precision is: | operands | result precision | | --- | --- | | `mp(pA)` and `mp(pB)` | `max(pA, pB)` | | `mp(pA)` and real `double` | `pA` | | real `double` and `mp(pB)` | `pB` | | unary operation on `mp(p)` | `p` | All arithmetic uses direct `mpfr_add`, `mpfr_sub`, `mpfr_mul`, `mpfr_div`, or `mpfr_neg` with `MPFR_RNDN`. The current `mpbits()` value and the current thread MPFR default do not select the arithmetic precision, and M11 does not enter an MPLAPACK precision scope. ## Singleton expansion Binary matrix operands use normal two-dimensional singleton expansion. Equal dimensions or a dimension of one are compatible; the non-singleton dimension is used for the result. Scalar `mp` values are `1x1` operands. Source matrices are indexed directly in column-major order, without materializing expanded copies. Empty dimensions follow the same compatibility rule as builtin Octave dense arrays. Incompatible dimensions raise a dimension error before result allocation. ## Mixed binary64 values and special values Real builtin doubles are transferred directly with `mpfr_set_d` into an explicitly precisioned native value. Decimal text is not used, so incoming binary64 `0.1` remains distinct from decimal text `"0.1"`, while dyadic `0.125` agrees. NaN, infinities, signed zeros, and division by zero follow the underlying MPFR semantics. ## Immutability and non-goals Public operands are immutable and results own independent native storage. MPLAPACK `Rgemm`/`Rgesv` remain the implementations of `*` and `\`. Matrix assignment, transpose, power, comparisons, logical indexing, reductions, complex values, and sparse values remain outside M11. mplapack-interop-0.5.1/docs/matrix-structure.md0000644000230300031750000000161215274353473021060 0ustar rafaelrafael# Dense `mp` transpose and reshape M12 adds read-only structural operations for real two-dimensional `mp` matrices. `transpose` and `ctranspose` allocate independent native storage and copy each MPFR value exactly into the transposed column-major position. The current backend is real-only, so conjugate transpose has the same numeric result as transpose while remaining a separate public method for future complex support. `reshape(A,m,n)` and `reshape(A,[m n])` preserve Octave's column-major linear element order. One `[]` dimension may be inferred from the source element count; two unknown dimensions are rejected. Structural operations preserve the source matrix precision and do not consult or modify `mpbits()` or the current thread MPFR default. A one-element result is normalized to the existing scalar native representation. N-D reshape, assignment, permutation, and views remain outside M12. mplapack-interop-0.5.1/docs/serialization.md0000644000230300031750000000323415274353473020375 0ustar rafaelrafael# Exact `mp` serialization T07 provides versioned persistence for real and complex `mp` values through Octave's `saveobj`/`loadobj` hooks and the native payload boundary. The schema is `octave-mplapack-mp`, version `1`, with these fields: ```text schema version kind = real-scalar | complex-scalar | real-matrix | complex-matrix rows columns precision_bits elements = column-major cell array of canonical text ``` Each finite element is emitted by the native MPFR/MPC storage at its stored precision. Zero sign, infinity, NaN classification, and the real and imaginary components of complex values are encoded independently. The text encoding is independent of MPFR limb layout, host endianness, word size, and C++ ABI; no pointers, raw `mpfr_t` bytes, `double(mp(...))`, or `eval` are used. NaN payload bits are not a public contract, but NaN classification and component sign behavior are preserved by the supported MPFR/MPC encoding. The normal user workflow is: ```octave pkg load mplapack-interop mpbits (1024); A = mp ({'1.234567890123456789', '-0'; 'Inf', 'NaN'}); save ('result.mat', 'A'); clear A; load ('result.mat'); ``` Binary and text save formats are tested. The package must be loaded before loading an `mp` file so the `mp` methods and native type are available. A loaded legacy user-class object carries only the validated plain schema until the native bridge first consumes it; the bridge then reconstructs the exact MPFR/MPC payload and retains its recorded precision. Malformed schema versions, dimensions, element counts, precision values, and element text are rejected before native reconstruction. Future schema versions are rejected rather than guessed. mplapack-interop-0.5.1/docs/goals/0000755000230300031750000000000015274353473016301 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/goals/D01R1-mplapack-interop-status.md0000644000230300031750000001272015274353473024141 0ustar rafaelrafael# D01R1 status — `mplapack-interop` identity and binary architecture Status: **PASS — MPLAPACK-INTEROP IDENTITY FROZEN** The D01R1 release-freeze branch is complete. The historical `mplapack` 0.2.0 identity and `v0.2.0` tag were not modified. The renamed package is frozen as `mplapack-interop` 0.2.1. ## Frozen package identity ```text Repository: nakatamaho/octave-mplapack Branch: topic/d01r1-0.2.1-release-freeze Freeze commit: b19f679aa4864c991c11bd05a78b0e4b1cbe4cc6 Version: 0.2.1 Tag: v0.2.1 Tag target: b19f679aa4864c991c11bd05a78b0e4b1cbe4cc6 Archive: mplapack-interop-0.2.1.tar.gz Archive size: 247628 bytes SHA256 A: 28769e877e0588a59d9c0d6736fb875624df8b836f570cc9e87eda7d74936d0f SHA256 B: 28769e877e0588a59d9c0d6736fb875624df8b836f570cc9e87eda7d74936d0f Hashes identical: YES Remote tag target: verified Archive from tagged tree: verified identical ``` The final archive is also installed at: ```text /home/docker/src/mplapack-interop-0.2.1.tar.gz ``` The `/home/docker`-specific local installer remains in the repository for developer use but is intentionally excluded from the public source archive. The external helper `/home/docker/install-local-octave-mplapack.sh` defaults to the frozen release archive and records the same SHA256. ## Dependency evidence ```text gmpfrxx_mkII: version: 1.4.1 commit: 32a7fb797202cdf92312ed9d133f96fdbcda590a tag: v1.4.1 archive: gmpfrxx_mkII.1.4.1.tar.xz SHA256: 395b9c4bd5819cf0f61758cee5f7eb400e25e2959b51a75d40a922ed41d711c4 MPLAPACK: version: 3.0.1 tested source commit: c21a9f56224308afda9e7424ca9928d4cf840f7a archive: mplapack-3.0.1.tar.xz SHA256: f969c5039a3147f9ea412b051993c62e83854ceebf8515947ac9887bd8852ad1 size: 85807808 bytes runtime: libmplapack_mpfr.so.3 ``` The MPLAPACK archive supplied for D01R1 contains the macOS shell/load-probe fixes, the external-gmpfrxx pkg-config include-path fix, the public `mplapack_mpfr_precision.h`, and generated release files. MPLAPACK release QA and `v3.0.1` tag creation remain owned by the release maintainer; this worktree did not create or alter that tag. The clean installed consumer and full Octave regression below used this exact archive and commit identity. ## Completed gates ### G-D01R1-NAME-SYNTAX — PASS GNU Octave 11.1.0 accepted the exact hyphenated package name through isolated install, list, describe, load, unload, and uninstall operations. ### G-D01R1-DEPS — PASS The final Octave build used the supplied MPLAPACK 3.0.1 archive with `pkg-config mplapack_mpfr` version 3.0.1, the public precision-scope header, and runtime `libmplapack_mpfr.so.3`. Include, library, SONAME, dependency, and external-consumer provenance checks passed. The external MPLAPACK release tag itself is intentionally not claimed here. ### G-D01R1-RENAME — PASS `DESCRIPTION`, README/NEWS/INDEX, help text, examples, tests, package lifecycle checks, and release tooling use `mplapack-interop`. Historical D00 documentation deliberately retains the old `mplapack` identity. ### G-D01R1-IDENTITY — PASS The release source has `Name: mplapack-interop`, `Version: 0.2.1`, archive `mplapack-interop-0.2.1.tar.gz`, and tag `v0.2.1` points exactly at the freeze commit. The old `v0.2.0` tag is unchanged. ### G-D01R1-NUMERICAL-EQUIVALENCE — PASS D01R1 changed package identity and release tooling only. No numerical implementation, public `mp` API, backend, or fallback behavior was changed. ### G-D01R1-REGRESSION — PASS The final local CI used the frozen installed stack from the gmpfrxx 1.4.1 and MPLAPACK 3.0.1 candidate archives. It passed: ```text M00-M23 real regression: PASS C00-C12 complex regression: PASS C11L complex Cgetrf: PASS 1024-bit and 2048-bit precision canaries: PASS ambient/default precision and scope restoration: PASS compatibility firewall: PASS ASan: PASS UBSan: PASS LSan: PASS package install/load/smoke/unload/uninstall/reinstall: PASS ``` The native wall included real Rgemm/Rgesv/Rgels/Rgelss/Rpotrf/Rgeqrf/Rorgqr/ Rgeqp3/Rgetrf and complex Cgemm/Cgesv/Cgelsy/Cpotrf/Cgeqrf/Cungqr/Cgeqp3/ Cgetrf coverage, lifetime tests, and dependency negative tests. ### G-D01R1-REPRODUCIBLE — PASS Two independent deterministic source-package generations from the final source produced identical file lists, top-level directory, size, and SHA256. A clean extraction build and package lifecycle passed without Git metadata or source-worktree headers. ### G-D01R1-BINARY-ARCH — PASS The source/binary boundary, Octave API key, package-local runtime layout, Linux `$ORIGIN`/`DT_RUNPATH`, macOS `@loader_path`/`@rpath`, Windows DLL strategy, naming matrix, and license handoff are documented in `docs/binary-distribution.md`. No B01-B05 production binary was built. ## Release engineering commits ```text dd123dcb Freeze mplapack-interop 0.2.1 package metadata dfc23fd4 Use Bash syntax checks for Bash release helpers 0354f74 Make the local installer default to the frozen 0.2.1 archive d2e0db5 Exclude the developer-only local installer from release archives b19f679 Record the final 0.2.1 source archive checksum ``` The branch and `v0.2.1` tag were pushed. The tag is annotated; its peeled target was verified remotely. ## Restrictions observed No Debian package, PPA modification/upload, Launchpad upload, Octave Packages registry submission, GitHub Release, or B01-B05 binary-distribution build was performed. ## Result ```text D01R1 PASS — MPLAPACK-INTEROP IDENTITY FROZEN B01-READY ``` The next item in the active numerical/API sequence is N00. B01 is not started automatically. mplapack-interop-0.5.1/docs/goals/D01R1-mplapack-interop.md0000644000230300031750000005755515274353473022637 0ustar rafaelrafael# /goal — D01R1 Rename to `mplapack-interop` and Freeze Binary-Distribution Architecture ## Mission Rename the GNU Octave package currently identified as: ```text Name: mplapack ``` to: ```text Name: mplapack-interop ``` and revise the post-D00 distribution handoff so that all future binary packages, Octave Packages registration, and PPA work use the unambiguous package identity `mplapack-interop`. D01R1 also freezes the binary-distribution architecture to be consumed by: ```text B01 Linux x86_64 B02 Linux arm64 B03 macOS arm64 B04 macOS x86_64 B05 Windows x86_64 F00 Octave Packages registration PPA1-G / PPA1-M / PPA2 / PPA3 / PPA4 ``` This is a package-identity and distribution-architecture revision only. Do not change accepted numerical behavior. Do not modify frozen `gmpfrxx_mkII` or MPLAPACK numerical source. Do not begin B01-B05 production binary builds. Do not begin Debian/PPA packaging. Do not submit to the Octave Packages index. --- # 0. D00 baseline D00 froze: ```text gmpfrxx_mkII: version: 1.4.1 commit: 32a7fb797202cdf92312ed9d133f96fdbcda590a tag: v1.4.1 archive: gmpfrxx_mkII.1.4.1.tar.xz sha256: 395b9c4bd5819cf0f61758cee5f7eb400e25e2959b51a75d40a922ed41d711c4 MPLAPACK: version: 3.0.1 commit: fa3ccb4376d2a52c2672322e5b7199a9224bed7f tag: v3.0.1 archive: mplapack-3.0.1.tar.xz sha256: 7c8d1d7759a487bc01e8c1625599ec77b6c7e297c19b20ca45e8c342f5165e64 octave-mplapack historical D00 state: repository: nakatamaho/octave-mplapack package Name: mplapack version: 0.2.0 commit: 4a3eb50843a6bf365bdab1e82146ef1900a219f6 tag: v0.2.0 archive: mplapack-0.2.0.tar.gz sha256: 0e83e26182b0fbd95a064437a97307eb74d9291b49d91c6e53dac181b24a94db ``` The old v0.2.0 state is a historical pre-public release checkpoint. Do not rewrite it. --- # 1. Why rename The Octave package name `mplapack` is too easily confused with the upstream numerical library MPLAPACK. The intended public identities are: ```text upstream numerical library: MPLAPACK Git repository: octave-mplapack GNU Octave package: mplapack-interop ``` The public Octave usage target is: ```octave pkg load mplapack-interop mpbits (512); A = mp (...); ``` --- # 2. Version policy Do not reuse or retarget `v0.2.0`. The renamed package must use: ```text Name: mplapack-interop Version: 0.2.1 ``` A temporary development version `0.2.1-dev` may be used during the milestone, but the final D01R1 source freeze must be `0.2.1`. The final source archive must be: ```text mplapack-interop-0.2.1.tar.gz ``` or the exact canonical archive basename generated from the final Octave package metadata. Do not create a new archive named `mplapack-0.2.1.tar.gz`. --- # 3. Repository name Do not rename the GitHub repository. Keep: ```text nakatamaho/octave-mplapack ``` unless the user separately requests a repository rename. Do not rename the public numeric class: ```text @mp mp mpbits mpdigits ``` --- # 4. Frozen dependency policy D01R1 must consume exactly: ```text gmpfrxx_mkII 1.4.1 commit 32a7fb797202cdf92312ed9d133f96fdbcda590a MPLAPACK 3.0.1 commit fa3ccb4376d2a52c2672322e5b7199a9224bed7f pkg-config mplapack_mpfr 3.0.1 runtime libmplapack_mpfr.so.3 ``` No dependency source changes are allowed. If D01R1 proves that one of these frozen dependencies requires a source-level modification: ```text D01R1 BLOCKED — D00R1 REQUIRED ``` Stop instead of patching the frozen dependency. --- # 5. Octave hyphenated-name preflight Before changing the real package, prove that Octave 11.1.0 supports the exact package name: ```text mplapack-interop ``` Create a tiny throwaway package outside the real project with: ```text Name: mplapack-interop ``` Use an isolated Octave package database/prefix and verify: ```text pkg install pkg list pkg describe mplapack-interop pkg load mplapack-interop pkg unload mplapack-interop pkg uninstall mplapack-interop ``` Record actual output and package-manager identity. Hard gate: ```text G-D01R1-NAME-SYNTAX PASS ``` If exact `pkg load mplapack-interop` behavior fails: ```text D01R1 BLOCKED — OCTAVE HYPHENATED PACKAGE NAME ``` Do not continue. --- # 6. Rename public package identity Update all current, nonhistorical package identity surfaces as appropriate: ```text DESCRIPTION Name DESCRIPTION version/date source archive basename source archive top-level directory README NEWS INDEX/package metadata help text examples tests package lifecycle scripts local package database tests developer scripts release verification scripts release manifests compatibility docs binary-distribution docs future Octave Packages docs future PPA naming docs ``` Search: ```bash rg -n \ 'Name:[[:space:]]*mplapack|pkg load mplapack|pkg unload mplapack|pkg uninstall mplapack|pkg describe mplapack|mplapack-0\.2\.0|mplapack-0\.2\.1' \ . ``` Classify every match. Historical D00/M23/C12 reports may retain historical identities. Do not blindly rewrite historical evidence. --- # 7. Internal symbols normally remain unchanged Do not rename internal implementation symbols only for cosmetic consistency. These may remain unchanged unless technically necessary: ```text __mplapack_core__.oct internal C++ namespaces private bridge commands MplapackMpfrPrecisionScope MPLAPACK backend routine names repository name octave-mplapack ``` The purpose is public package identity clarity, not an internal refactor. --- # 8. No old-name compatibility package Default policy: ```text no alias package named mplapack no duplicate package registration no permanent compatibility shim ``` The package was not yet publicly distributed under the final identity. Document migration from the historical v0.2.0 checkpoint instead. --- # 9. Migration QA In an isolated package prefix: ```text install historical mplapack 0.2.0 verify pkg list pkg unload mplapack pkg uninstall mplapack install mplapack-interop 0.2.1 verify pkg list pkg describe mplapack-interop pkg load mplapack-interop run real smoke run complex smoke pkg unload mplapack-interop ``` Verify there is no stale old package entry. Do not attempt to support simultaneous loading of both package identities. --- # 10. Numerical equivalence Define: ```text OLD_OCTAVE_FREEZE_COMMIT = 4a3eb50843a6bf365bdab1e82146ef1900a219f6 ``` At the final renamed source freeze define: ```text MPLAPACK_INTEROP_FREEZE_COMMIT ``` Audit the diff. Allowed changes: ```text package identity version metadata docs tests release tooling binary-distribution architecture docs/probes ``` Numerical behavior must be unchanged. If native/numerical source changes only because package-name/help strings are embedded, classify this explicitly. Gate: ```text G-D01R1-NUMERICAL-EQUIVALENCE PASS ``` --- # 11. Full regression wall Run against the unchanged frozen dependencies: ```text M00-M23 real regression C00-C12 complex regression C11L complex LU compatibility firewall dependency probes package lifecycle ``` Retain all high-precision canaries: ```text 1024-bit / 2^-700 2048-bit / 2^-1500 real rank real chol real QR real pivoted QR real LU complex scalar Cgemm Cgesv Cgelsy Cpotrf Cgeqrf/Cungqr Cgeqp3 Cgetrf mixed real/complex ``` --- # 12. Sanitizers Run: ```text ASan UBSan LSan ``` through the accepted real+complex native suite. --- # 13. Rename package lifecycle From the final renamed source archive: ```text pkg install pkg list pkg describe mplapack-interop pkg load mplapack-interop real smoke complex smoke help examples pkg unload mplapack-interop pkg uninstall mplapack-interop reinstall second smoke ``` All PASS. --- # 14. Freeze renamed source Freeze: ```text Name: mplapack-interop Version: 0.2.1 ``` Generate: ```text mplapack-interop-0.2.1.tar.gz ``` Build it twice from independent clean trees. Require: ```text same archive file list same normalized metadata same SHA256 ``` Record: ```text MPLAPACK_INTEROP_FREEZE_COMMIT MPLAPACK_INTEROP_ARCHIVE MPLAPACK_INTEROP_ARCHIVE_SIZE MPLAPACK_INTEROP_SHA256 ``` --- # 15. Preserve old D00 artifact Do not overwrite/delete: ```text mplapack-0.2.0.tar.gz SHA256: 0e83e26182b0fbd95a064437a97307eb74d9291b49d91c6e53dac181b24a94db ``` Treat it as historical D00 provenance. --- # 16. New tag Do not modify: ```text v0.2.0 ``` After all rename/source gates pass, create: ```text v0.2.1 ``` pointing exactly to: ```text MPLAPACK_INTEROP_FREEZE_COMMIT ``` Use the same annotated-tag policy established by the repository. Verify local and remote dereferenced tag target. Do not create a GitHub Release yet. --- # 17. Revised release-stack manifest Do not rewrite the historical D00 report. Update the canonical forward-looking manifest or create: ```text docs/dependency-release-stack-r1.md ``` It must record: ```text gmpfrxx_mkII: 1.4.1 unchanged MPLAPACK: 3.0.1 unchanged historical Octave package: Name: mplapack Version: 0.2.0 Tag: v0.2.0 historical only current distribution package: Name: mplapack-interop Version: 0.2.1 Commit: Tag: v0.2.1 Archive: mplapack-interop-0.2.1.tar.gz SHA256: ``` All B/F/PPA work must consume the R1 identity. --- # 18. D01R1 binary-distribution architecture mission After the rename source is proven, define the architecture for downloadable prebuilt Octave packages. Do not produce final B01-B05 artifacts in D01R1. Prototype/probe work is allowed. The final architecture must cover: ```text B01 Linux x86_64 B02 Linux arm64 B03 macOS arm64 B04 macOS x86_64 B05 Windows x86_64 ``` --- # 19. Audit Octave `pkg build` Using Octave 11.1.0, audit: ```octave pkg build BUILDDIR mplapack-interop-0.2.1.tar.gz ``` Record: ```text produced archive name/layout DESCRIPTION identity architecture-dependent directory .oct placement PKG_ADD/PKG_DEL behavior pkg install result pkg list result pkg load result pkg unload result pkg uninstall result ``` The binary form must itself be normally installable by `pkg`. --- # 20. Octave ABI compatibility key Determine the binary compatibility identity from actual Octave tooling. Record at minimum: ```text Octave version Octave API version target OS target architecture mkoctfile identity compiler/toolchain C++ ABI assumptions ``` Define the exact compatibility key B01-B05 use. Do not promise binary compatibility across different Octave API versions without evidence. --- # 21. Public binary artifact naming Choose a deterministic pattern after ABI audit. Preferred conceptual pattern: ```text mplapack-interop-0.2.1-octave--.tar.gz ``` Examples may become: ```text mplapack-interop-0.2.1-octave11-linux-x86_64.tar.gz mplapack-interop-0.2.1-octave11-linux-aarch64.tar.gz mplapack-interop-0.2.1-octave11-macos-arm64.tar.gz mplapack-interop-0.2.1-octave11-macos-x86_64.tar.gz mplapack-interop-0.2.1-octave11-windows-x86_64.tar.gz ``` Do not freeze the exact `octave11` component until the API audit determines whether an Octave API identifier is better. Internal DESCRIPTION remains: ```text Name: mplapack-interop Version: 0.2.1 ``` --- # 22. User UX target Normal binary-package usage must be: ```octave pkg install .tar.gz pkg load mplapack-interop mpbits () ``` Expected default: ```text 512 ``` No compiler required. Normal users should not need to configure: ```text LD_LIBRARY_PATH DYLD_LIBRARY_PATH PKG_CONFIG_PATH CMAKE_PREFIX_PATH ``` --- # 23. Source package vs binary package Maintain distinct release classes: ```text source: mplapack-interop-0.2.1.tar.gz binary: platform/ABI-qualified binary package ``` Source install may require development dependencies. Binary install must not require a compiler. --- # 24. Runtime dependency closure Determine the actual runtime closure of `__mplapack_core__.oct`. At minimum audit: ```text gmpfrxx default-context provider library if dynamically required libmplapack_mpfr MPC MPFR GMP C++ runtime compiler runtime Octave libraries other actual dependencies ``` Derive from built artifacts. Do not guess. --- # 25. Preferred runtime model Prefer a self-contained package-local runtime for B01-B05 where technically and legally appropriate. Do not install private dependency libraries globally from an Octave binary package. Design: ```text Octave package ├── normal package files ├── architecture-specific __mplapack_core__.oct └── private runtime libraries ``` Determine the exact package-safe locations. --- # 26. Linux loader strategy Audit/prototype: ```text $ORIGIN DT_RUNPATH DT_RPATH link-time -Wl,-rpath patchelf only if justified ``` Goal: ```text .oct resolves its package-local private runtime without LD_LIBRARY_PATH ``` Audit transitive shared-library resolution as well. --- # 27. macOS loader strategy Define/prototype plan: ```text @loader_path @rpath install_name otool -L install_name_tool if required codesigning implications ``` Goal: ```text .oct and bundled dylibs resolve package-locally without DYLD_LIBRARY_PATH ``` Production builds belong to B03/B04. --- # 28. Windows loader strategy Define: ```text package-local DLL layout DLL search behavior Octave/MinGW ABI compatibility MPLAPACK/MPFR/MPC/GMP DLL closure ``` Determine the expected placement relative to `.oct`. Production build belongs to B05. --- # 29. Bundle/system dependency matrix Create a table: ```text Dependency | Linux | macOS | Windows | Bundle? | System? | Reason | License ``` Cover: ```text gmpfrxx runtime provider MPLAPACK MPFR runtime MPC MPFR GMP libstdc++ / libc++ compiler runtime Octave runtime ``` Do not bundle Octave itself. Do not casually bundle system C libraries. --- # 30. Licensing and source correspondence Create/update: ```text docs/binary-redistribution-licenses.md ``` Record redistribution obligations for: ```text mplapack-interop MPLAPACK gmpfrxx_mkII GMP MPFR MPC any compiler/runtime library planned for bundling ``` Define how binary releases refer users to exact corresponding source: ```text version tag source URL SHA256 ``` D01R1 is an architecture/license inventory, not legal advice. --- # 31. Binary manifest Define a manifest included in each B01-B05 binary artifact. It must record: ```text package Name package Version source commit source archive SHA256 gmpfrxx version/tag/SHA256 MPLAPACK version/tag/SHA256 Octave version Octave API version OS architecture compiler/toolchain bundled runtime files runtime licenses/notices build provenance ``` Choose a package location that survives `pkg build`/`pkg install`. Verify rather than assume. --- # 32. Install/unload/uninstall architecture A binary package must support: ```text pkg install pkg load mplapack-interop pkg unload mplapack-interop pkg uninstall mplapack-interop ``` No package-local runtime files may be orphaned. Avoid copying SO/dylib/DLL files to global system directories. --- # 33. Old/new coexistence Audit whether historical: ```text mplapack 0.2.0 ``` and: ```text mplapack-interop 0.2.1 ``` can coexist. Because both expose the same `mp` class, supported user guidance should normally be: ```text uninstall old mplapack before installing mplapack-interop ``` Do not add complicated conflict management unless necessary. --- # 34. F00 identity Future Octave Packages registration must use: ```text mplapack-interop ``` not `mplapack`. Record: ```text package index name: mplapack-interop repository: https://github.com/nakatamaho/octave-mplapack ``` Do not submit in D01R1. --- # 35. Future PPA identity Correct future PPA assumptions. Recommended user-facing Debian binary package candidate: ```text octave-mplapack-interop ``` The exact Debian source/binary naming is finalized in the PPA policy milestone. Dependency order remains: ```text gmpfrxx_mkII -> MPLAPACK -> mplapack-interop ``` Do not create Debian metadata here. --- # 36. Linux proof-of-architecture On the current Linux host, build one non-release proof-of-architecture binary package if practical. Requirements: ```text renamed package builds binary archive installs package reports mplapack-interop __mplapack_core__.oct loads runtime relocation concept is demonstrated real smoke passes complex smoke passes ``` This is not B01. Do not publish this prototype. If final relocation work is clearly B01-owned, document the proven design and remaining bounded B01 work. --- # 37. No absolute-path runtime design The accepted binary architecture must not require: ```text /home//... /tmp/... custom /usr/local prefix ``` at runtime. Any prototype using temporary prefixes must prove how B01 makes the final artifact relocatable. --- # 38. Documentation Create/update: ```text docs/binary-distribution.md docs/binary-redistribution-licenses.md docs/dependency-release-stack-r1.md docs/octave-compatibility.md README.md NEWS.md docs/goals/D01R1-mplapack-interop-binary-architecture.md reports/D01R1-report.md ``` Keep historical D00 material historical. --- # 39. B01-B05 handoff contract Common immutable source input after D01R1: ```text package: mplapack-interop version: 0.2.1 source commit: MPLAPACK_INTEROP_FREEZE_COMMIT source archive: mplapack-interop-0.2.1.tar.gz source SHA256: dependencies: gmpfrxx_mkII 1.4.1 MPLAPACK 3.0.1 ``` B01-B05 may not silently change numerical source. --- # 40. B target matrix Output a final table for: ```text B01 Linux x86_64 B02 Linux arm64 B03 macOS arm64 B04 macOS x86_64 B05 Windows x86_64 ``` For each record: ```text target Octave version/API toolchain artifact filename pattern runtime dependency strategy loader strategy test environment dependency-inspection tool smoke tests license bundle binary manifest ``` Do not build final artifacts during D01R1. --- # 41. Gates ## G-D01R1-NAME-SYNTAX PASS only if exact `mplapack-interop` install/load/unload/uninstall behavior is proven with Octave 11.1.0. ## G-D01R1-DEPS PASS only if frozen gmpfrxx/MPLAPACK identity remains unchanged and provenance is verified. ## G-D01R1-RENAME PASS only if all current public package identity surfaces use `mplapack-interop`. ## G-D01R1-IDENTITY PASS only if: ```text Name = mplapack-interop Version = 0.2.1 archive = mplapack-interop-0.2.1.tar.gz pkg load identity = mplapack-interop old v0.2.0 untouched v0.2.1 tag correct ``` ## G-D01R1-NUMERICAL-EQUIVALENCE PASS only if no numerical behavior changed. ## G-D01R1-REGRESSION PASS only if M00-M23, C00-C12, C11L, canaries, firewall, and sanitizers pass. ## G-D01R1-REPRODUCIBLE PASS only if the renamed source archive reproduces byte-identically. ## G-D01R1-BINARY-ARCH PASS only if the complete B01-B05 architecture is frozen. --- # 42. Overall gate D01R1 PASS requires: ```text G-D01R1-NAME-SYNTAX PASS G-D01R1-DEPS PASS G-D01R1-RENAME PASS G-D01R1-IDENTITY PASS G-D01R1-NUMERICAL-EQUIVALENCE PASS G-D01R1-REGRESSION PASS G-D01R1-REPRODUCIBLE PASS G-D01R1-BINARY-ARCH PASS ``` Final conclusion: ```text D01R1 PASS — MPLAPACK-INTEROP IDENTITY FROZEN B01-READY ``` --- # 43. Failure classifications If hyphenated package loading fails: ```text D01R1 BLOCKED — OCTAVE HYPHENATED PACKAGE NAME ``` If numerical behavior changes: ```text D01R1 FAIL — NUMERICAL REGRESSION ``` If old v0.2.0 history is rewritten: ```text D01R1 FAIL — RELEASE HISTORY REWRITE ``` If the archive name changes but DESCRIPTION remains `mplapack`: ```text D01R1 FAIL — COSMETIC-ONLY RENAME ``` If frozen dependencies require source modification: ```text D01R1 BLOCKED — D00R1 REQUIRED ``` If accepted runtime architecture requires developer absolute paths: ```text D01R1 FAIL — NON-RELOCATABLE BINARY ARCHITECTURE ``` --- # 44. Git policy Suggested branch: ```text topic/d01r1-mplapack-interop ``` Do not force-push. Before commits: ```bash git status --short git diff --check ``` Do not commit production binary artifacts. Do not rewrite historical tags. --- # 45. Suggested commits Prefer: ```text 1. D01R1: rename Octave package to mplapack-interop 2. D01R1: close renamed package lifecycle and migration QA 3. D01R1: define relocatable binary-distribution architecture 4. D01R1: freeze mplapack-interop 0.2.1 source identity 5. docs: record D01R1 report/handoff ``` --- # 46. Final report Produce: ```text # D01R1 RESULT ## Result D01R1 PASS / FAIL / BLOCKED Release identity conclusion: MPLAPACK-INTEROP IDENTITY FROZEN / NOT-FROZEN Binary distribution conclusion: B01-READY / NOT-READY ## Historical D00 package identity Repository: Old package Name: Old version: Old freeze commit: Old tag: Old archive: Old SHA256: Old tag unchanged: ## Frozen dependencies ### gmpfrxx_mkII Version: Commit: Tag: Archive: SHA256: Changed during D01R1: ### MPLAPACK Version: Commit: Tag: Archive: SHA256: Runtime SONAME: Changed during D01R1: ## Package-name preflight Octave: Temporary package: Name: Install: pkg list: pkg describe: pkg load: pkg unload: pkg uninstall: Hyphen supported: Result: ## New package identity Repository: Package Name: Version: Freeze commit: Tag: Tag target: Archive: Archive size: SHA256 A: SHA256 B: Hashes identical: Top-level directory: pkg list identity: pkg describe identity: pkg load identity: Result: ## Rename diff audit DESCRIPTION: README: NEWS: INDEX: Help: Examples: Tests: Release tooling: Package lifecycle: Historical docs preserved: Internal symbols renamed: Numerical source changed: Result: ## Migration QA Old 0.2.0 install: Old unload: Old uninstall: New 0.2.1 install: New pkg list: New load: Real smoke: Complex smoke: Stale old package entry: Result: ## Full regression M00-M23: C00-C12: C11L: 1024: 2048: Compatibility firewall: ASan: UBSan: LSan: Package lifecycle: Result: ## Octave binary package audit pkg build: Binary archive internal Name: Architecture-dependent path: .oct location: Install: Load: Unload: Uninstall: Result: ## ABI compatibility key Octave version: Octave API version: OS: Architecture: Compiler/toolchain: Required key for B01-B05: Result: ## Runtime dependency closure gmpfrxx runtime: MPLAPACK runtime: MPC: MPFR: GMP: C/C++ runtimes: Octave libraries: Other: Result: ## Binary runtime layout Common layout: Package-local runtime directory: .oct location: Manifest location: ### Linux Loader strategy: Prototype: Environment variable required: Result: ### macOS Loader strategy: Planned tools: Environment variable required: Result: ### Windows DLL strategy: Planned placement: Environment variable required: Result: ## Licensing Project license: MPLAPACK: gmpfrxx: GMP: MPFR: MPC: Bundled-runtime notice strategy: Corresponding-source strategy: File: Result: ## Binary artifact naming Source: Linux x86_64: Linux arm64: macOS arm64: macOS x86_64: Windows x86_64: ## B01-B05 handoff ### B01 ... ### B02 ... ### B03 ... ### B04 ... ### B05 ... ## F00 handoff Octave Packages name: Repository: Source release identity: Index work started: Result: ## PPA naming handoff Recommended Debian source: Recommended Debian binary: Dependency order: PPA work started: ## Revised release stack gmpfrxx_mkII: version: commit: tag: archive: sha256: MPLAPACK: version: commit: tag: archive: sha256: mplapack-interop: version: commit: tag: archive: sha256: ## Gates G-D01R1-NAME-SYNTAX: G-D01R1-DEPS: G-D01R1-RENAME: G-D01R1-IDENTITY: G-D01R1-NUMERICAL-EQUIVALENCE: G-D01R1-REGRESSION: G-D01R1-REPRODUCIBLE: G-D01R1-BINARY-ARCH: ## Changes ... ## Commits ... ## Push / PR Branch: PR: Remote tip: Tag push: CI: ## Known limitations ... ## Next milestone If D01R1 PASS: Proceed to: B01 — Linux x86_64 binary package B01 must consume exactly the frozen `mplapack-interop` source commit/archive/ SHA256 and the unchanged D00 dependency stack recorded here. Do not modify numerical source in B01. If B01 discovers a source-level problem, stop and reopen the appropriate freeze rather than patching the release silently. Do not begin B01 automatically. ``` --- # 47. Stop After the D01R1 report: ```text STOP ``` Do not begin: ```text B01 B02 B03 B04 B05 F00 PPA1-G PPA1-M PPA2 PPA3 PPA4 ``` automatically. mplapack-interop-0.5.1/docs/goals/N08-D02R1-mrdivide-status.md0000644000230300031750000000543415274353473023046 0ustar rafaelrafael# N08 / D02R1 status Updated: 2026-09-08 ## Final state N08 and D02R1 are complete on `topic/d02r1-0.3.1-release-freeze`. ```text N08 PASS — DENSE REAL+COMPLEX MRDIVIDE COMPLETE D02R1 PASS — MPLAPACK-INTEROP 0.3.1 SOURCE REFREEZE ``` The immutable release tag is `v0.3.1`, pointing to `41123b30a03b594aefaa9dec8ac82c8690a128df`. The historical `v0.3.0` release and real-only checkpoint remain unchanged. ## N08 source identity ```text implementation: 5a4f2fd Implement dense real and complex mrdivide test hardening: 05a2636 Harden mrdivide regression expectations reference hardening: 2ec10d506e609aca4c3e5ef4c5039a3683c5442c N08 completion: 05da88ec0cc65febfed063a551e8cfc2fb0863e8 branch: topic/n08-mrdivide release branch: topic/d02r1-0.3.1-release-freeze ``` Dense real and complex right division covers scalar, square, rectangular, rank-deficient, mixed, empty, special-value, immutable-input, and Grcar cases. Square paths use `Rgesv`/`Cgesv`; rectangular and forced rank-revealing paths use the accepted MPFR/MPC backend paths. Destructive calls receive operation-owned copies, and no real-only operation is routed through a complex kernel. ## D02R1 frozen identity ```text gmpfrxx_mkII 1.4.1: 32a7fb797202cdf92312ed9d133f96fdbcda590a MPLAPACK 3.0.1: c21a9f56224308afda9e7424ca9928d4cf840f7a octave-mplapack 0.3.1: 41123b30a03b594aefaa9dec8ac82c8690a128df tag: v0.3.1 archive SHA256: 21a7c6751a17e783196c0e28e45d521a9251a1e3f2c210f38ab733fc89e0624b archive size: 306951 bytes ``` The final archive was generated twice from independent clean trees. Both archives had identical top-level directory, file list, size, and SHA256. A fresh extraction of that exact archive built and passed the full M00-M23, C00-C12/C11L, and N00-N08 regression wall, followed by package smoke. ## Gates ```text G-N08-SCALAR: PASS G-N08-MATRIX-SCALAR: PASS G-N08-MATRIX-MATRIX: PASS G-N08-REAL: PASS G-N08-COMPLEX: PASS G-N08-MIXED: PASS G-N08-SQUARE: PASS G-N08-RECTANGULAR: PASS G-N08-RANK-DEFICIENT: PASS G-N08-MINIMUM-NORM: PASS G-N08-CONJUGATE-TRANSPOSE: PASS G-N08-PRECISION: PASS G-N08-EMPTY: PASS G-N08-SPECIAL: PASS G-N08-IMMUTABILITY: PASS G-N08-OCTAVE: PASS G-N08-GRCAR-INTEGRATION: PASS G-N08-REGRESSION: PASS G-D02R1-SOURCE-FREEZE: PASS G-D02R1-VERSION: PASS G-D02R1-REPRODUCIBLE: PASS G-D02R1-N08: PASS G-D02R1-FULL-REGRESSION: PASS G-D02R1-PACKAGE-LIFECYCLE: PASS G-D02R1-RUNTIME-CLOSURE: PASS G-D02R1-DOCS: PASS G-D02R1-TAG: PASS G-D02R1-BINARY-HANDOFF: PASS D02R1-G source/version freeze: PASS D02R1-S frozen three-archive rebuild: PASS D02R1-R source archive reproducibility: PASS D02R1-Q regression/sanitizer/provenance/lifecycle: PASS D02R1-T v0.3.1 tag target and remote verification: PASS D02R1-H dependency handoff manifest: PASS ``` No D01, binary, Debian, PPA, Launchpad, or registry work has started. mplapack-interop-0.5.1/docs/goals/T00-T14-status.md0000644000230300031750000001413415274353473021060 0ustar rafaelrafael# T00–T14 controller status This document tracks the continuation after the immutable D03 baseline. ## Immutable D03 baseline | Item | Identity | |---|---| | D03 freeze commit | `34993eb569bfaa0d7665ae913a3a1f5a97ac2e31` | | D03 report/status commit | `ca78481559e00f80534aa4c89dedaa838fdf3953` | | D03 tag | `v0.4.0` | | D03 archive | `/home/docker/src/mplapack-interop-0.4.0.tar.gz` | | D03 archive SHA256 | `6bc87d42fbda49fa72830db34fbede7b8b9f46b7614b14dc53e7619c7781536c` | The D03 tag, archive, and freeze commit are historical and are not modified. ## Development identity The T-series development version is `0.5.0-dev`. D04 owns the final release version and tag freeze. ## Milestones | Milestone | Result | Evidence | |---|---|---| | T00 Schur/QZ | PASS | `reports/T00-report.md` | | T01 advanced dense utilities | PASS | `reports/T01-report.md` | | T02 matrix functions | PASS | `reports/T02-report.md` | | T03 polynomial core | PASS | `reports/T03-report.md` | | T04 exact sets | PASS | `reports/T04-report.md` | | T05 gamma/erf | PASS | `reports/T05-report.md` | | T06 special-function audit | PASS | `reports/T06-report.md`, `docs/special-functions-backend-matrix.md` | | T07 serialization | PASS | `reports/T07-report.md`, `docs/serialization.md` | | T08 3-D graphics | PASS | `reports/T08-report.md`, `docs/graphics.md` | | T09 arbitrary-precision RNG | PASS | `reports/T09-report.md`, `docs/rng.md` | | T10 1-D interpolation | PASS | `reports/T10-report.md`, `docs/interpolation-1d.md` | | T11 2-D interpolation | PASS | `reports/T11-report.md`, `docs/interpolation-2d.md`, `docs/todo/T11-ND-interpolation.md` | | T12 nonlinear equations | PASS | `reports/T12-report.md`, `docs/nonlinear-solvers.md` | | T13 quadrature | PASS | `reports/T13-report.md`, `docs/quadrature.md` | | T14 optimization | PASS | `reports/T14-report.md`, `docs/optimization.md` | | T05R1 late recheck | NOT-NEEDED | `reports/T05R1-report.md` | ## Precision contract All numerical paths remain one-operation/one-precision MPFR/MPC paths. The new T00 drivers use operation-owned copies for destructive LAPACK calls and establish the matching real and complex precision scopes at every backend boundary. No builtin binary64 fallback is part of the T-series interface. ## Controller closure Result: `T00-T14 CONTROLLER PASS` Acceptance: `T00-T14: ACCEPT` Last required PASS milestone: `T14` T05R1: `NOT NEEDED — T05 ALREADY CLOSED` Final tested controller HEAD: `8ba6d849fa188765b372d9aa9f899d9de98a78cf` Final dependency identities used by the controller: | Dependency | Tested identity | |---|---| | gmpfrxx_mkII | `32a7fb797202cdf92312ed9d133f96fdbcda590a` / `v1.4.1` | | MPLAPACK | `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d` / MPFR 3.0.1 interface | The T00–T14 development milestone history referenced gmpfrxx_mkII `32a7fb797202cdf92312ed9d133f96fdbcda590a` (`v1.4.1`) and the historical MPLAPACK development/interface commit `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d`. Neither dependency repository was modified during T00–T14. For D04 release-candidate QA, the authoritative MPLAPACK dependency is instead the MPLAPACK 3.0.1 release candidate identified in the following section by commit, tarball, and SHA256. ## D04 release-candidate provenance `T00-T14: ACCEPT` and `D04-READY: YES` have been recorded. The first documented D04 candidate was MPLAPACK 3.0.1 commit `c21a9f56224308afda9e7424ca9928d4cf840f7a`, represented by the local release- candidate archive `~/src/mplapack-3.0.1.tar.xz` and the archived QA copy `release/logs/20260907_143628/source/mplapack-3.0.1.tar.xz`. The expected SHA256 for both artifacts is `f969c5039a3147f9ea412b051993c62e83854ceebf8515947ac9887bd8852ad1`; the release-QA evidence directory is `release/logs/20260907_143628/`. The local candidate archive hash was verified in the previous candidate environment. D04 must verify the archived QA copy has the same hash before the source freeze. Until the release process completes, this dependency must be described as the `MPLAPACK 3.0.1 release candidate`, not as finally released MPLAPACK 3.0.1. ### Current D04 RC update — 2026-09-09 The current MPLAPACK 3.0.1 release candidate supersedes the previous candidate identity: ```text commit: c7e56f15dd4dc6413a1dc80b9d1c4109b77d5078 archive: mplapack-3.0.1.tar.xz SHA256: 77008a2d6cc7b2d310a4d606e013003923872a6840f1098dda8b6f337f137afa ``` The D04 source-freeze and regression evidence must use this exact commit or an installed MPLAPACK build demonstrably derived from an archive with this SHA256. The local archive `/home/docker/src/mplapack-3.0.1.tar.xz` now verifies against this SHA256 and has size `85562992` bytes. The archived QA copy from the previous candidate evidence directory is not present in this worktree and must be checked separately if it is used for D04 provenance. The dependency must continue to be described as the `MPLAPACK 3.0.1 release candidate` until the release process completes. Historical T-series identities such as `a59e5a0...` and earlier release- preparation commits such as `fa3ccb...` remain milestone provenance. They are not D04 release-QA provenance and require no reconciliation. D04 may consume the local archive directly or an installed build demonstrably derived from it; no rebuild is required solely to reconcile those historical Git SHAs. The final wall passed M00–M23, C00–C12 including C11L, N00–N08, S00–S08, T00–T14, Grcar/generalized eig, serialization, graphics, RNG, interpolation, fzero/fsolve, quadrature, optimization, the unsupported API firewall, and the installed-package lifecycle. Native ASan, UBSan, and LSan completed successfully. The only CI repair was allowing the existing `0.5.0-dev` development version in `tools/local-ci.sh`; no numerical behavior was changed by that repair. The final documentation audit added the complete advanced-numerics index, structured deferred TODO records, and common metadata to every individual milestone report. The report/status pointer is updated by the following documentation-only commit; the tested controller source and evidence remain unchanged. D04-READY: yes T15-T20-READY-FOR-PLANNING: yes D04 and T15–T20 were not started automatically. mplapack-interop-0.5.1/docs/goals/D01R1-mplapack-interop-binary-architecture.md0000644000230300031750000000224115274353473026557 0ustar rafaelrafael# D01R1 — Binary architecture handoff D01R1 freezes the architecture for future `mplapack-interop` binary packages; it does not start B01–B05 production builds, Debian/PPA packaging, or Octave Packages registration. The package identity is `mplapack-interop`, the repository remains `nakatamaho/octave-mplapack`, and the public numeric API remains `mp`, `mpbits`, and `mpdigits`. The ABI key is the complete Octave version/API, OS, architecture, and compiler toolchain. The audited host is GNU Octave 11.1.0, API `api-v61`, `x86_64-pc-linux-gnu`, GNU C++ 15.2.0. Binary archives use package-local runtime libraries and relative loader identities (`$ORIGIN` on ELF, `@loader_path`/`@rpath` on macOS, and package-local DLL search on Windows). The exact runtime closure, license inventory, manifest fields, and B01–B05 target matrix are maintained in: - [`docs/binary-distribution.md`](../binary-distribution.md) - [`docs/binary-redistribution-licenses.md`](../binary-redistribution-licenses.md) - [`docs/dependency-release-stack-r1.md`](../dependency-release-stack-r1.md) The current `pkg build` audit is a design probe only. Production artifacts remain the next milestones. mplapack-interop-0.5.1/docs/goals/DOC00-documentation-closure-before-D04-status.md0000644000230300031750000000646315274353473027030 0ustar rafaelrafael# DOC00 status DOC00 closes the documentation gap before D04. Work is on `topic/t00-t14-continuation`, whose development version is `0.5.0-dev`. The documentation implementation freeze commit is `8f8bbdc0d75ccf4bc572ba843ad6b1ebf4ae0f75`. | Gate | Result | Evidence | |---|---|---| | G-DOC00-API-INVENTORY | PASS | `docs/public-api-inventory.md`; 202 supported, 9 deferred, 3 internal entries | | G-DOC00-USER-MANUAL | PASS | `doc/mplapack-interop.texi`, task-oriented 24-chapter manual | | G-DOC00-PRECISION-CHAPTER | PASS | stored precision, `mpbits`, `p_op`, promotion, and graphics boundary documented | | G-DOC00-PER-API-MP-NOTES | PASS | grouped user entries, inventory notes, API help, and backend map | | G-DOC00-HELP-TEXT | PASS | all public `inst/@mp/*.m` and `inst/*.m` entries have help blocks; representative lookups pass | | G-DOC00-DOXYGEN | PASS | `docs/doxygen/Doxyfile`, main page, native contracts, HTML generated | | G-DOC00-BACKEND-MAP | PASS | `docs/backend-map.md` covers native entry, backend, copy, and precision rules | | G-DOC00-EXAMPLES | PASS | 12 deterministic runnable examples under `examples/` | | G-DOC00-EXAMPLE-CI | PASS | `tools/test-doc-examples.sh`; all examples and selected help lookups pass | | G-DOC00-SERIALIZATION-DOC | PASS | manual, `docs/serialization.md`, and exact round-trip example | | G-DOC00-GRAPHICS-DOC | PASS | manual, boundary documentation, and headless graphics example | | G-DOC00-RNG-DOC | PASS | manual, `docs/rng.md`, and deterministic state example | | G-DOC00-DEFERRED-DOC | PASS | indexed deferred list and links under `docs/todo/` | | G-DOC00-README | PASS | README landing page links to manual, inventory, compatibility, examples, and developer docs | | G-DOC00-NEWS | PASS | unreleased 0.5.0-dev user-facing section and D04 RC wording | | G-DOC00-MANUAL-BUILD | PASS | `tools/build-docs.sh`; HTML, Info/plaintext, and Doxygen HTML generated | | G-DOC00-CONSISTENCY | PASS | `tools/check-docs.sh` | | G-DOC00-REGRESSION | PASS | `tools/local-ci.sh`, M/C/N/S/T wall, sanitizer wall, and package lifecycle | ## Verification log - `tools/check-tree.sh`: PASS - `tools/check-format.sh`: PASS - `tools/check-docs.sh`: PASS - `tools/test-doc-examples.sh`: PASS; examples 01--12, help lookups, Grcar, Hilbert SVD, serialization/RNG, interpolation, solvers, and graphics - `tools/build-docs.sh`: PASS with `makeinfo` and Doxygen 1.15; Info/plaintext is the manual artifact because this host has no TeX engine - `tools/local-ci.sh`: PASS with the installed MPLAPACK 3.0.1 MPFR interface; this re-ran M00--M23, C00--C12 including C11L, N00--N08, S00--S08, T00--T14, native ASan/UBSan/LSan, clean rebuild, archive checks, and the isolated package lifecycle - DOC00 source package: PASS; two `SOURCE_DATE_EPOCH=0` builds had identical SHA256 `21f2bffd547246f24f0d884aa034157e55db7157e21e08c61bc760f1bee40154`. The archive contains documentation sources and examples, and excludes generated `docs/.build` output. ## Scope No numerical or native implementation was changed for DOC00. Changes are documentation, Octave help text, runnable examples, documentation/build tooling, and the source-package file-selection fix needed to ship the manual while excluding generated output. ## Result ```text DOC00 PASS — USER/DEVELOPER DOCUMENTATION CLOSED D04-READY ``` D04 was not started automatically. mplapack-interop-0.5.1/docs/goals/D00-dependency-release-freeze.md0000644000230300031750000000513715274353473024164 0ustar rafaelrafael# D00 — Dependency Release Freeze ## Objective Freeze the complete source stack for the first public real-plus-complex `octave-mplapack` release: ```text gmpfrxx_mkII 1.4.1 -> MPLAPACK 3.0.1 -> octave-mplapack 0.2.0 ``` D00 is release engineering only. It does not add numerical routines, create Debian packages, upload to Launchpad, modify `octave-mplapack-ppa`, register the package with Octave Packages, or begin D01. A source-level change is permitted only when it repairs a release-blocking defect already exposed by the accepted C00–C12 contract. ## Accepted baseline The historical real-only checkpoint is `0bef79cddd3fdd70abafdf38bc1a4ab492652d33` and remains unchanged. The C12 tested heads are gmpfrxx `32a7fb797202cdf92312ed9d133f96fdbcda590a`, MPLAPACK `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d`, and octave-mplapack `36cd341a8c14ce2d0a6790b287e5f7a7b0846cd3`. The C12 result is `COMPLEX GOAL PASS`, `REAL-COMPLEX-API-CLOSED`, and `DEPENDENCY-FREEZE-READY`. ## Gating order ```text D00-G gmpfrxx freeze -> D00-M MPLAPACK 3.0.1 freeze -> D00-O octave-mplapack 0.2.0 freeze -> D00-S frozen-stack rebuild and regression -> D00-R archive reproducibility -> D00-T release tags -> D00-H D01 handoff ``` Each layer must be independently installable from its source archive, and all headers, pkg-config metadata, runtime libraries, SONAMEs, and source commits must be traceable to the frozen stack. The one-operation/one-precision MPFR/MPC contract remains mandatory: no builtin binary64 complex fallback, no real-only-to-complex routing, and destructive backend calls receive operation-owned copies. ## Required evidence The gates cover clean scalar consumers, public precision-scope installation, 1024-bit and 2048-bit canaries, ambient/default precision and lifetime tests, MPFR/MPC thread-scope probes, real M00–M23 regression, complex C00–C12 regression including C11L `Cgetrf`, compatibility firewall, ASan/UBSan/LSan, package lifecycle, standalone archive builds, provenance, and reproducible archives. Tags are created only after all gates pass and must point exactly to the freeze commits. The authoritative handoff is [`docs/dependency-release-stack.md`](../dependency-release-stack.md); the complete evidence is in [`reports/D00-report.md`](../../reports/D00-report.md) and the running state is in [`D00-dependency-release-freeze-status.md`](D00-dependency-release-freeze-status.md). ## Stop condition After recording `D00 PASS — RELEASE STACK FROZEN` and `D01-READY`, stop. D01 is a separate goal and must consume exactly the versions, commits, tags, source archives, and SHA256 values recorded by D00. mplapack-interop-0.5.1/docs/goals/COMPLEX-C00-C12-status.md0000644000230300031750000000650215274353473022121 0ustar rafaelrafael# COMPLEX C00-C12 status REAL_V0_1_RC_COMMIT: `0bef79cddd3fdd70abafdf38bc1a4ab492652d33` COMPLEX_START_COMMIT: `4aed479ef9cb8dff24f0326e1c2ec2a7c1ed83a3` Current milestone: COMPLETE Last PASS milestone: C12 octave-mplapack tested implementation: `topic/complex-c00-c12` / `36cd341a8c14ce2d0a6790b287e5f7a7b0846cd3` MPLAPACK tested commit: `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d` (`topic/octave-mplapack-complex-mpfr-scope`) gmpfrxx_mkII tested commit: `32a7fb797202cdf92312ed9d133f96fdbcda590a` (`main`) Upstream fixes: - MPLAPACK `a59e5a0a4`: install the required `mplapack_mpfr_precision.h` MPFR scope header and include it from the public MPFR interfaces. Blockers: none. Full regression status: C12 PASS. C00 storage/scope/TLS/lifetime/special value probe PASS at 128, 256, 512, 1024, and 2048 bits under ASan/UBSan/LSan; C01 scalar construction/conversion, C02 dense complex construction, inspection/indexing/assignment, C03 real/imag/conj/transpose/ctranspose, C04 complex element-wise arithmetic, C05 complex Cgemm, C06 complex Cgesv, and C07 complex rank-revealing `Cgelsy` tests PASS; C07 native and public walls include the complete M00-M23 real regression wall. C06 exercised multiple RHS, installed `mplapackint` pivots, singular behavior, 1024/2^-700 and 2048/2^-1500 real and imaginary tails, ambient precision, input immutability, and output lifetime. C07 audited `Cgelsy`, `Cgelss`, and `Cgelsd`, and exercised full-rank, rank-deficient, minimum-norm, precision-sensitive rank, workspace, mixed-operand, ambient precision, immutability, and lifetime behavior. C08 exercised selected-triangle Hermitian upper/lower Cholesky, diagonal imaginary handling, partial non-PD status, one-/two-output behavior, ambient precision, input immutability, output lifetime, and real `Rpotrf` parity. C09 exercised full/economy/wide complex QR, R-only dispatch, exact R zeros, complex orthogonality and reconstruction, workspace queries, 1024/2^-700 and 2048/2^-1500 canaries, ambient precision, immutability, lifetime, and real QR parity. C10 exercised full/economy/wide pivoted complex QR, exact JPVT permutation mapping for matrix/vector outputs, reconstruction, orthogonality, 1024/2048-bit pivot-order canaries, ambient precision, immutability, lifetime, empty shapes, and real Rgeqp3 parity. Full regression status: C11 PASS. The full native real+complex sanitizer wall and complete public M01-M23+C01-C11 wall pass. C11 mixed real/complex promotion, Cgemm/Cgesv/Cgelsy participation, concat, assignment, structural reshape, builtin-double mixing, no-demotion, ambient precision, lifetime, and the full native/public C11 walls pass. C11L complex `Cgetrf` packed/two-output/ matrix-permutation/vector-permutation LU, rectangular and singular factors, source-precision pivots, ambient precision, immutability, lifetime, and the full native/public C11L walls pass. C12 API, documentation, compatibility firewall, complete real/complex regression, precision, TLS/thread, sanitizer, package lifecycle, and upstream provenance gates pass. The development archive name and checksum are recorded in the repository-only root master report `c12-report.md`. Final state: `COMPLEX GOAL PASS`, `REAL-COMPLEX-API-CLOSED`, `DEPENDENCY-FREEZE-READY`. Release policy: MPLAPACK 3.0.1 remains a planned dependency version. No release commit, archive, or final tags are frozen in C00-C12. mplapack-interop-0.5.1/docs/goals/S00-S08-D03-status.md0000644000230300031750000002600215274353473021402 0ustar rafaelrafael# S00-S08 / D03 status Updated: 2026-09-08 ## Current state ```text branch: topic/s00-s08-script-compat baseline: D02R1 v0.3.1 freeze, tag v0.3.1 preserved active package version: 0.4.0 S00: PASS; committed and pushed as c17b48c0a8bf7e39c3c9a111bcc8e3ae0c60e048 S01: PASS; committed and pushed as 29f3539 (full SHA in git history) S02: PASS; committed and pushed as 07c047d08d64ecd8c0d623cd2e1e621882b6c8b9 S03: PASS; committed and pushed as a71c13f and 5714787 S04: PASS; committed and pushed as 2247480a4835519f27cb53b6a39173d05f16bdc8 S05: PASS; committed and pushed as b97ed2ea231cbb9bb1fd8b7334911d86cb2db7db S06: PASS; committed and pushed as 0f3e9c8dd4bb00067c117e2144d0e1f3c7179d0b S07: PASS; committed and pushed as 384987bb6dbddd0758915debcda064acd15caaee S08: PASS; committed and pushed as 51a0b420b6a47df3d84eba99bb27ec4b1d96a622 D03: PASS; frozen and tagged as v0.4.0 at 34993eb569bfaa0d7665ae913a3a1f5a97ac2e31 ``` S00 adds native MPFR/MPC `abs`, `arg`, `angle`, and `sign`; logical `isnan`, `isinf`, and `isfinite`; exact `isequal`/`isequaln`; and the missing `isnumeric` class predicate. Existing `isreal`, `isscalar`, `isvector`, `ismatrix`, and `isempty` behavior was audited. The old `v0.3.1` source tag and the frozen gmpfrxx/MPLAPACK dependencies remain unchanged. ## S00 evidence ```text real abs/angle/sign: PASS complex abs/angle/sign: PASS complex conjugate/quadrant and signed zero: PASS isnan/isinf/isfinite: PASS isequal/isequaln: PASS isscalar/isvector/ismatrix/isempty/isnumeric/isreal: PASS special values +0/-0/Inf/NaN: PASS native MPFR/MPC implementation: PASS binary64 numerical fallback: NONE ``` ## Gates ```text G-S00-COMPAT-MATRIX: PASS G-S00-ABS: PASS G-S00-ANGLE: PASS G-S00-SIGN: PASS G-S00-PREDICATES: PASS G-S00-ISEQUAL: PASS G-S00-SPECIAL: PASS G-S00-PRECISION: PASS G-S00-REGRESSION: PASS ``` ```text S00 PASS — COMPATIBILITY AUDIT AND BASIC PREDICATES CLOSED ``` ## S01 evidence ```text real/complex/mixed element-wise power: PASS integer scalar and square-matrix mpower: PASS MPFR/MPC elementary family: PASS domain promotion and branch fixtures: PASS 1024/2048 precision tails: PASS ambient precision independence: PASS binary64 numerical fallback: NONE ``` ```text G-S01-POWER: PASS G-S01-MPOWER: PASS G-S01-EXPLOG: PASS G-S01-TRIG: PASS G-S01-HYPERBOLIC: PASS G-S01-DOMAIN-PROMOTION: PASS G-S01-COMPLEX-BRANCH: PASS G-S01-BROADCAST: PASS G-S01-PRECISION: PASS G-S01-REGRESSION: PASS ``` ```text S01 PASS — ELEMENT-WISE POWER AND ELEMENTARY FUNCTIONS CLOSED ``` ## S02 evidence Implementation/report commit: `07c047d08d64ecd8c0d623cd2e1e621882b6c8b9`. ```text sum/prod/sumsq: PASS — native MPFR/MPC reduction accumulators cumsum/cumprod: PASS — dimensions and forward/reverse direction dimension/default/all forms: PASS omitnan/includenan: PASS min/max values and first indices: PASS pairwise extrema and singleton expansion: PASS complex magnitude/phase ordering: PASS 1024/2048 precision and ambient default isolation: PASS binary64 numerical fallback: NONE ``` ```text G-S02-SUM: PASS G-S02-PROD: PASS G-S02-CUMSUM: PASS G-S02-CUMPROD: PASS G-S02-SUMSQ: PASS G-S02-DIM: PASS G-S02-NANFLAG: PASS G-S02-MINMAX: PASS G-S02-COMPLEX-ORDER: PASS G-S02-INDICES: PASS G-S02-PRECISION: PASS G-S02-REGRESSION: PASS ``` ```text S02 PASS — REDUCTIONS AND EXTREMA CLOSED ``` ## S03 evidence Implementation commits: `a71c13f` and `5714787`. ```text comparisons: native MPFR real relations and native MPC equality/inequality logicals: native MPFR/MPC truth classification and &, |, xor, ~ any/all: dimensions and all reduction forms find: linear, row/column, value, count, and direction forms indexing: numeric vectors, logical masks, and value-semantic assignment complex ordered comparisons: explicit rejection retained 1024/2048 precision and ambient default isolation: PASS binary64 numerical fallback: NONE ``` ```text G-S03-COMPARE: PASS G-S03-COMPLEX-EQUALITY: PASS G-S03-ORDER-FIREWALL: PASS G-S03-LOGICAL: PASS G-S03-ANY-ALL: PASS G-S03-FIND: PASS G-S03-INDEX: PASS G-S03-ASSIGNMENT: PASS G-S03-PRECISION: PASS G-S03-REGRESSION: PASS ``` ```text S03 PASS — COMPARISONS, LOGICALS, AND LOGICAL INDEXING CLOSED ``` ## S04 evidence Implementation commits: `2247480a4835519f27cb53b6a39173d05f16bdc8` and `a742fce4dc6f3c372a050e41f25eefe886561dab` (native matrix-structure backend). ```text diag construction/extraction and offsets: PASS triu/tril dense copies and offsets: PASS; "pack" explicitly rejected zeros/ones/eye/NaN/Inf "like" constructors: PASS repmat scalar/vector dimensions: PASS flip/fliplr/flipud/rot90: PASS cat(1/2): PASS through native concat paths real/complex precision preservation: PASS 1024/2048 precision and ambient default isolation: PASS binary64 numerical fallback: NONE ``` ```text G-S04-DIAG: PASS G-S04-TRIU: PASS G-S04-TRIL: PASS G-S04-LIKE-CONSTRUCTORS: PASS G-S04-REPMAT: PASS G-S04-FLIP: PASS G-S04-ROT90: PASS G-S04-CAT: PASS G-S04-PRECISION: PASS G-S04-REGRESSION: PASS ``` The post-milestone wall passed M00–M23, C00–C12/C11L, N00–N08, S00–S04, native ASan/UBSan/LSan, clean rebuild #2, deterministic package generation, and isolated install/lifecycle QA against the frozen dependencies. ```text S04 PASS — MATRIX UTILITIES AND CONSTRUCTORS CLOSED ``` ## S05 evidence Implementation commit: `b97ed2ea231cbb9bb1fd8b7334911d86cb2db7db`. ```text colon/range forms: PASS — native MPFR increasing, decreasing, empty, and high-precision step cases linspace: PASS — native MPFR real and MPC complex endpoints, counts, and endpoint semantics logspace: PASS — native MPFR powers of ten and Octave pi endpoint special case floor/ceil/fix/round: PASS — native MPFR element-wise rounding rem/mod: PASS — native MPFR signs and two-dimensional singleton expansion hypot/atan2: PASS — native MPFR utility arithmetic and singleton expansion signbit: PASS — native MPFR signed-zero and matrix logical results eps: PASS — local stored-precision MPFR spacing complex unsupported forms: PASS — explicit firewall for complex colon/logspace/rounding utilities 1024/2048 precision and ambient default isolation: PASS binary64 numerical fallback: NONE ``` ```text G-S05-COLON: PASS G-S05-LINSPACE: PASS G-S05-LOGSPACE: PASS G-S05-ROUNDING: PASS G-S05-REM: PASS G-S05-MOD: PASS G-S05-UTILITY: PASS G-S05-EPS: PASS G-S05-PRECISION: PASS G-S05-REGRESSION: PASS ``` The post-milestone `tools/local-ci.sh` wall passed M00–M23, C00–C12/C11L, N00–N08, S00–S05, native ASan/UBSan/LSan, clean rebuild #2, deterministic package generation, and isolated install/lifecycle QA against the frozen dependencies. ```text S05 PASS — RANGES, ROUNDING, AND UTILITY ARITHMETIC CLOSED ``` ## S06 evidence Implementation commit: `0f3e9c8dd4bb00067c117e2144d0e1f3c7179d0b`. ```text mean: PASS — native MPFR real and MPC complex accumulators median: PASS — native MPFR ordering/sorting and complex magnitude/phase audit var: PASS — native two-pass MPFR/MPC stable variance, N-1 and N normalization std: PASS — native MPFR square root and optional second-output mean range: PASS — native min/max ordering and subtraction bounds: PASS — native lower/upper values and two-output form real dimensions/all forms: PASS complex mean/median/variance/range/bounds audit: PASS omitnan/includenan: PASS with Octave defaults preserved stability: PASS — mean-then-deviation accumulation, no naive cancellation formula 1024/2048 precision and ambient default isolation: PASS binary64 numerical fallback: NONE ``` ```text G-S06-MEAN: PASS G-S06-MEDIAN: PASS G-S06-VAR: PASS G-S06-STD: PASS G-S06-RANGE: PASS G-S06-BOUNDS: PASS G-S06-REAL: PASS G-S06-COMPLEX-AUDIT: PASS G-S06-NANFLAG: PASS G-S06-STABILITY: PASS G-S06-PRECISION: PASS G-S06-REGRESSION: PASS ``` The post-milestone `tools/local-ci.sh` wall passed M00–M23, C00–C12/C11L, N00–N08, S00–S06, native ASan/UBSan/LSan, clean rebuild #2, deterministic package generation, and isolated install/lifecycle QA against the frozen dependencies. ```text S06 PASS — BASIC DESCRIPTIVE STATISTICS CLOSED ``` ## S08 evidence Implementation/report commit: `51a0b420b6a47df3d84eba99bb27ec4b1d96a622`. ```text ordinary script corpus A-F: PASS sort real/complex dimensions, direction, indices, NaN order: PASS find implementation reverified: PASS diff real/complex order and dimension forms: PASS length/size/rows/columns/numel/ndims/isempty audit: PASS unsupported surface graphics firewall: PASS 1024-bit 2^-700 and 2048-bit 2^-1500 precision tails: PASS ambient precision restoration: PASS native MPFR/MPC sequence test: PASS binary64 numerical fallback: NONE ``` ```text G-S08-CORPUS: PASS G-S08-SORT: PASS G-S08-FIND: PASS G-S08-DIFF: PASS G-S08-STRUCTURAL: PASS G-S08-FIREWALL: PASS G-S08-DOCS: PASS G-S08-REAL: PASS G-S08-COMPLEX: PASS G-S08-PRECISION: PASS G-S08-ASAN: PASS G-S08-UBSAN: PASS G-S08-LSAN: PASS G-S08-FULL-REGRESSION: PASS ``` Dedicated `test/script-compat/s08.tst` passed 12/12 tests. The native sequence test passed with ASan/UBSan and leak detection. The post-milestone `tools/local-ci.sh` wall passed M00–M23, C00–C12 including mandatory C11L, N00–N08, S00–S08, clean rebuild #2, deterministic source-package generation, and isolated install/unload/uninstall/reinstall QA against the frozen dependencies. Known gnuplot and singular-matrix host warnings were harmless. ```text S08 PASS — ORDINARY SCRIPT COMPATIBILITY CLOSED D03-READY ``` ## D03 evidence ```text source freeze commit: 34993eb569bfaa0d7665ae913a3a1f5a97ac2e31 source tag: v0.4.0 tag target: 34993eb569bfaa0d7665ae913a3a1f5a97ac2e31 remote tag target: 34993eb569bfaa0d7665ae913a3a1f5a97ac2e31 version: 0.4.0 archive: mplapack-interop-0.4.0.tar.gz archive size: 361088 bytes archive SHA256 A: 6bc87d42fbda49fa72830db34fbede7b8b9f46b7614b14dc53e7619c7781536c archive SHA256 B: 6bc87d42fbda49fa72830db34fbede7b8b9f46b7614b14dc53e7619c7781536c archive placement: /home/docker/src/mplapack-interop-0.4.0.tar.gz ``` The final tagged archive was independently reproducible with identical file lists and SHA256. The final `tools/local-ci.sh` wall passed the D00 prerequisites, M00-M23, C00-C12 including mandatory C11L, N00-N08, S00-S08, native ASan/UBSan/LSan, clean rebuild #2, archive checks, isolated install, help/examples, real and complex smoke tests, unload, uninstall, reinstall, and second smoke. The runtime audit resolved `libmplapack_mpfr.so.3` from the frozen MPLAPACK prefix and MPC/MPFR/GMP from the recorded host prerequisites without source-worktree or stale-prefix leakage. The exact final master report is [`reports/D03-report.md`](../../reports/D03-report.md). ```text G-D03-SOURCE-FREEZE: PASS G-D03-VERSION: PASS G-D03-REPRODUCIBLE: PASS G-D03-FULL-REGRESSION: PASS G-D03-SCRIPT-CORPUS: PASS G-D03-PACKAGE-LIFECYCLE: PASS G-D03-GRAPHICS: PASS G-D03-RUNTIME-CLOSURE: PASS G-D03-DOCS: PASS G-D03-TAG: PASS G-D03-BINARY-HANDOFF: PASS ``` ```text D03 PASS — MPLAPACK-INTEROP SCRIPT-COMPAT SOURCE FROZEN B01-READY ``` ## Next milestone B01 — Linux x86_64 binary package is the next separate goal. It was not started automatically. No numerical source, dependency tag, Debian package, PPA, Launchpad upload, or Octave Packages registry entry was created during D03. mplapack-interop-0.5.1/docs/goals/N00-N07-D02-status.md0000644000230300031750000005036015274353473021372 0ustar rafaelrafael# N00-N07-D02 status Status: **D02 PASS — mplapack-interop 0.3.0 source frozen** The D01R1 frozen package identity remains unchanged as historical provenance. N00, N01, N02, N03, N04, N05, N06, N07, and D02 are complete. The final package identity is `mplapack-interop` 0.3.0 with tag `v0.3.0`. ## N00 identity ```text Repository: nakatamaho/octave-mplapack Branch: topic/d01r1-mplapack-interop Current source before N00 commit: 9384236f6c7f360e86e8a3616e1c0bdb36873b57 N00 commit: dbe320fa4ed7f1d5541991796ab2df20e2687ec2 N01 implementation commit: 91a034d2f1acdf739b7ec3b30cc5e333ee6de4f1 N02 implementation commit: 9f05418f3fc700914727e00b4321ee3ecd061dfe N03 implementation commit: ab8ed68fb4e04c821bb50a0e08e578474ee1cfcd N04 implementation commit: 455b5df72c65bb4475c6436429dae005910eb88f N05 implementation commit: 61e8afa0c6af780f30948347f51c95b60d397d1a N06 implementation commit: 9929b2360b717f7817005bccc9eb5fa193697aa2 N07 implementation commit: 473143f5bab22478f232c734b8c79049c65e33dc D02 source-freeze commit: 392b72786f34d0bc1efcf35e2fd0cf0de58ec64f D02 tag: v0.3.0 (target 392b72786f34d0bc1efcf35e2fd0cf0de58ec64f) Release version: 0.3.0 Frozen predecessor: mplapack-interop 0.2.1 / v0.2.1 Historical predecessor commit: b19f679aa4864c991c11bd05a78b0e4b1cbe4cc6 ``` ## Dependency identity used by the gates ```text gmpfrxx_mkII: 1.4.1 / 32a7fb797202cdf92312ed9d133f96fdbcda590a gmpfrxx SHA256: 395b9c4bd5819cf0f61758cee5f7eb400e25e2959b51a75d40a922ed41d711c4 MPLAPACK: 3.0.1 / c21a9f56224308afda9e7424ca9928d4cf840f7a MPLAPACK archive SHA256: f969c5039a3147f9ea412b051993c62e83854ceebf8515947ac9887bd8852ad1 MPLAPACK runtime: libmplapack_mpfr.so.3 ``` The implementation was built and tested against the installed prefixes derived from these archives. No source-worktree include or library path was used by the N00 gates. ## N00 implementation The public `@mp/norm` wrapper and native `norm` dispatch support real and complex vectors and matrices with the accepted Octave forms: ```text vectors: default/2, 1, 2, Inf, -Inf, 0, Fro, and positive finite p matrices: 1, 2, Inf, and Fro ``` Real standard matrix paths use MPLAPACK Rlange and Rnrm2; complex standard matrix paths use Clange and RCnrm2. Matrix 2-norms use singular-values-only Rgesvd/Cgesvd helpers. Inputs are copied before destructive LAPACK calls. MPFR/MPC precision scopes are operation-owned and no builtin binary64 complex fallback is used. Unsupported matrix p forms and invalid requests are rejected explicitly. Special values, empty values, scalar values, precision preservation, and ambient-precision behavior are covered by the native and public tests. ## Gates ```text G-N00-API: PASS — @mp/norm and native dispatch are present and documented G-N00-REAL: PASS — real vector/matrix norms use the MPFR backend G-N00-COMPLEX: PASS — complex vector/matrix norms use the MPC/MPFR backend G-N00-MATRIX: PASS — supported matrix norms and explicit deferrals behave correctly G-N00-VECTOR: PASS — vector p forms, finite p, and special values pass G-N00-2NORM: PASS — Rgesvd/Cgesvd and Rnrm2/RCnrm2 paths pass G-N00-PRECISION: PASS — 512-bit, 1024-bit, 2048-bit, and ambient precision pass G-N00-SPECIAL: PASS — empty, Inf, NaN, zero, and invalid-request tests pass G-N00-REGRESSION: PASS — complete local CI and required regression wall pass ``` ## Regression evidence ```text tools/check-tree.sh: PASS tools/check-format.sh: PASS native make -C src check-norm: PASS public norm smoke and invalid-request probes: PASS M00-M23 real regression: PASS C00-C12 complex regression: PASS C11L complex Cgetrf: PASS 1024-bit / 2^-700 canary: PASS 2048-bit / 2^-1500 canary: PASS low/high ambient precision and scope restoration: PASS operation-owned input and native lifetime tests: PASS ASan: PASS UBSan: PASS LSan: PASS clean archive extraction build: PASS package install/load/smoke/help/examples/unload/uninstall/reinstall: PASS clean rebuild and retest: PASS full tools/local-ci.sh: PASS (exit code 0) ``` The full N00 wall used `SOURCE_DATE_EPOCH=0` and explicitly selected the installed D01R1 gmpfrxx/MPLAPACK prefix. The development package archive was tested as `mplapack-interop-0.3.0-dev`; no release tag or 0.3.0 archive was created by N00. ## Scope and deferrals N00 adds only `norm`; N01 adds only `det` and `inv`; N02 adds only `svd`. Symmetric and general eigenvalue routines, generalized eigenvalue routines, and final closure remain assigned to N04-N07. No Debian, PPA, Launchpad, registry, or binary-distribution work was started. ## Result ```text N00 PASS — NORM API AND BACKEND COMPLETE N01 PASS — DETERMINANT AND INVERSE COMPLETE N02 PASS — SVD COMPLETE N03 PASS — RANK / COND / RCOND COMPLETE NEXT: N06 — generalized eig(A,B) ``` ## N01 — `det` / `inv` ### Implementation ```text det real: Rgetrf, pivot parity, U diagonal product det complex: Cgetrf, pivot parity, U diagonal product inv real: Rgetrf, checked Rgetri workspace query, Rgetri inv complex: Cgetrf, checked Cgetri workspace query, Cgetri singular determinant: exact MPFR/MPC zero singular inverse: mplapack:mp:SingularMatrix det second reciprocal-condition output: explicitly deferred to N03 ``` All destructive calls use operation-owned copies. Real inputs remain on real MPLAPACK kernels, complex inputs remain on MPC kernels, and no builtin binary64 fallback was introduced. ### N01 gates ```text G-N01-DET: PASS G-N01-DET-PIVOT: PASS G-N01-INV: PASS G-N01-WORKSPACE: PASS G-N01-SINGULAR: PASS G-N01-PRECISION: PASS G-N01-IMMUTABILITY: PASS G-N01-REAL-COMPLEX: PASS G-N01-REGRESSION: PASS ``` ### N01 regression wall ```text native N01 sanitizer test: PASS public N01 det/inv tests: PASS M00-M23 real regression: PASS C00-C12 complex regression: PASS C11L complex Cgetrf: PASS 1024-bit / 2^-700 canary: PASS 2048-bit / 2^-1500 canary: PASS ambient precision and scope restoration: PASS input immutability and singular diagnostics: PASS ASan: PASS UBSan: PASS LSan: PASS clean 0.3.0-dev archive rebuild/retest: PASS package install/load/smoke/help/examples/unload/uninstall/reinstall: PASS full tools/local-ci.sh: PASS (exit code 0) ``` N01 implementation is committed as `91a034d2f1acdf739b7ec3b30cc5e333ee6de4f1` on `topic/d01r1-mplapack-interop` and pushed. The D01R1 0.2.1 tag and archive remain unchanged. The next milestone is N03. ## N02 — `svd` ### Implementation ```text real one-output singular values: existing N00 Rgesvd helper complex one-output singular values: existing N00 Cgesvd helper real factors: Rgesvd full/economy U, diagonal S, V from VT transpose complex factors: Cgesvd full/economy U, diagonal real S, V from VT conjugate transpose full shapes: U m-by-m, S m-by-n, V n-by-n economy shapes: U m-by-k, S k-by-k, V n-by-k, k=min(m,n) numeric 0 option: accepted as deprecated economy spelling empty and scalar shapes: covered without invalid zero-size LAPACK calls ``` All LAPACK inputs are operation-owned copies. Real values stay on `Rgesvd`, complex values stay on `Cgesvd`, the S output is real `mp` for complex input, workspace queries and INFO are checked, and no binary64 fallback exists. ### N02 gates ```text G-N02-BACKEND: PASS G-N02-ONE-OUTPUT: PASS G-N02-FULL: PASS G-N02-ECON: PASS G-N02-REAL: PASS G-N02-COMPLEX: PASS G-N02-RECONSTRUCTION: PASS G-N02-ORTHOGONALITY: PASS G-N02-WORKSPACE: PASS G-N02-PRECISION: PASS G-N02-REGRESSION: PASS ``` ### N02 regression wall ```text native sanitized SVD test: PASS public real/complex SVD tests: PASS full/economy/numeric-0 shape tests: PASS scalar and empty shape tests: PASS reconstruction and orthogonality/unitarity: PASS input immutability: PASS 1024-bit / 2^-700 canary: PASS 2048-bit / 2^-1500 canary: PASS ambient precision and scope restoration: PASS M00-M23 real regression: PASS C00-C12 complex regression: PASS C11L complex Cgetrf: PASS ASan: PASS UBSan: PASS LSan: PASS clean archive extraction build and lifecycle: PASS full tools/local-ci.sh: PASS (exit code 0) ``` N02 implementation is committed as `9f05418f3fc700914727e00b4321ee3ecd061dfe` on `topic/d01r1-mplapack-interop` and pushed. The D01R1 0.2.1 tag and archive remain unchanged. N03 is now complete; the next milestone is N04. ## N03 — `rank` / `cond` / `rcond` ### Implementation ```text rank(A): MPFR/MPC singular values with stored-precision default threshold rank(A,tol): explicit real MPFR tolerance, promoted to p_op cond(A), cond(A,2): Rgesvd/Cgesvd singular-value ratio cond(A,1): Rgetrf/Rgecon or Cgetrf/Cgecon 1-norm estimator cond(A,Inf): Rgetrf/Rgecon or Cgetrf/Cgecon infinity-norm estimator cond(A,"fro"): Frobenius singular-value identity for square matrices rcond(A): Rgetrf/Rgecon or Cgetrf/Cgecon 1-norm reciprocal estimator det(A) second output: same 1-norm reciprocal estimator ``` Rank uses `max(size(A))*sigma_max*Rlamch_mpfr("E")`, with all terms formed at the one operation precision. Condition and reciprocal-condition paths use operation-owned destructive copies. Real input remains on real MPLAPACK kernels, complex input remains on complex MPLAPACK kernels, condition outputs are real MPFR values, and no binary64 fallback or explicit inverse is used. The initial N03 native test exposed that the frozen MPLAPACK `Rgecon` implementation consumes four contiguous real work blocks, not three. The operation was corrected to allocate 4n real work values; the corresponding complex `Cgecon` path uses its audited 2n complex plus 2n real work arrays. This was a release-contract integration defect in the new estimator path and was repaired before the full gate. ### N03 gates ```text G-N03-RANK: PASS G-N03-RANK-PRECISION: PASS G-N03-COND2: PASS G-N03-COND1: PASS G-N03-CONDINF: PASS G-N03-CONDFRO: PASS G-N03-RCOND: PASS G-N03-SINGULAR: PASS G-N03-REAL: PASS G-N03-COMPLEX: PASS G-N03-PRECISION: PASS G-N03-REGRESSION: PASS ``` ### N03 regression wall ```text tools/check-tree.sh: PASS tools/check-format.sh: PASS native rank/condition sanitizer test: PASS public N03 rank/condition tests: PASS det two-output reciprocal-condition test: PASS M00-M23 real regression: PASS C00-C12 complex regression: PASS C11L complex Cgetrf: PASS 1024-bit / 2^-700 canary: PASS 2048-bit / 2^-1500 canary: PASS ambient precision and scope restoration: PASS input immutability and singular/empty behavior: PASS ASan: PASS UBSan: PASS LSan: PASS clean 0.3.0-dev archive extraction build: PASS isolated package lifecycle: PASS deterministic source archive contents: PASS full tools/local-ci.sh: PASS (exit code 0) ``` N03 was the preceding completed milestone. Its implementation and report were committed and pushed before continuing automatically to N04. The D01R1 0.2.1 tag and archive remain unchanged. ## N04 — structured symmetric/Hermitian `eig` ### Implementation ```text real symmetric input: exact represented symmetry check, MPFR Rsyevd complex Hermitian input: exact represented Hermitian check, MPC/MPFR Cheevd lambda = eig(A): real mp eigenvalue column vector [V,D] = eig(A): real mp diagonal D [V,d] = eig(A,"vector"): real mp eigenvalue column vector d real symmetric eigenvectors: real mp complex Hermitian eigenvectors: complex mp general and generalized eig: rejected and deferred to N05/N06 ``` The native backend uses operation-owned destructive copies and one MPFR or composed MPFR/MPC precision scope at the stored input precision. It performs no binary64 fallback and never routes real input through the complex kernel. Repeated-eigenvalue QA checks residuals and orthogonality rather than non-unique eigenvector entries. High-dynamic-range 1024/2048-bit fixtures, ambient precision, exact detection, and input immutability are covered. ### Gates ```text G-N04-DETECTION: PASS G-N04-REAL-SYMMETRIC: PASS G-N04-COMPLEX-HERMITIAN: PASS G-N04-VECTOR: PASS G-N04-MATRIX: PASS G-N04-RESIDUAL: PASS G-N04-ORTHOGONALITY: PASS G-N04-DEGENERATE: PASS G-N04-PRECISION: PASS G-N04-REGRESSION: PASS ``` ### Regression evidence ```text tools/check-tree.sh: PASS tools/check-format.sh: PASS for current N04 files native Rsyevd/Cheevd sanitizer test: PASS public N04 structured eig tests: PASS M00-M23 real regression: PASS C00-C12 complex regression: PASS C11L complex Cgetrf: PASS 1024-bit / 2^-700 canary: PASS 2048-bit / 2^-1500 canary: PASS ambient precision and scope restoration: PASS input immutability and exact rejection: PASS ASan: PASS UBSan: PASS LSan: PASS ``` The complete N04 wall passed before the N04 implementation, report, and status were committed and pushed. The D01R1 0.2.1 tag and archive remain unchanged. ## N05 — general standard `eig` and mandatory Grcar QA ### Implementation ```text real nonsymmetric input: MPFR Rgeevx complex non-Hermitian input: MPC/MPFR Cgeevx structured exact symmetric/Hermitian input: retained N04 Rsyevd/Cheevd dispatch lambda = eig(A): complex mp eigenvalue column for the general path [V,D] = eig(A): complex mp right vectors and diagonal matrix [V,d] = eig(A,"vector"): complex mp right vectors and eigenvalue column [V,D] = eig(A,"matrix"): explicit matrix form [V,D,W] = eig(A): complex mp right/diagonal/left outputs eig(A,"balance"): explicit Rgeevx/Cgeevx balancing path eig(A,"nobalance"): explicit Rgeevx/Cgeevx nobalance path ``` Real LAPACK conjugate-pair columns are converted explicitly to complex MPC storage. General real outputs are therefore complex `mp` even when the eigenvalues are all real. Every destructive call uses an operation-owned copy, one stored-precision MPFR or MPFR/MPC scope, checked workspace/INFO, and uniform-precision work arrays. No real input is routed through a complex kernel and no builtin binary64 fallback exists. The compatibility firewall now rejects only deferred generalized `eig(A,B)` for this area. The permanent Grcar fixture exercises default/balance equivalence, explicit balance/nobalance, right and left residuals, and 128/256/512-bit precision progression. Near-Jordan, nearly repeated, badly scaled, 1024-bit `2^-700`, 2048-bit `2^-1500`, ambient precision, and input immutability cases are covered. ### Gates ```text G-N05-BACKEND: PASS G-N05-REAL-GENERAL: PASS G-N05-COMPLEX-GENERAL: PASS G-N05-BALANCE: PASS G-N05-NOBALANCE: PASS G-N05-RIGHT-EIGENVECTORS: PASS G-N05-LEFT-EIGENVECTORS: PASS G-N05-GRCAR: PASS G-N05-NEAR-DEFECTIVE: PASS G-N05-PRECISION: PASS G-N05-REGRESSION: PASS ``` ### Regression evidence ```text tools/check-tree.sh: PASS tools/check-format.sh: PASS native Rgeevx/Cgeevx sanitizer test: PASS public N04/N05 eig tests: PASS M00-M23 real regression: PASS C00-C12 complex regression: PASS C11L complex Cgetrf: PASS 1024-bit / 2^-700 canary: PASS 2048-bit / 2^-1500 canary: PASS ambient precision and scope restoration: PASS input immutability and native lifetime tests: PASS ASan: PASS UBSan: PASS LSan: PASS clean archive extraction build: PASS package install/load/smoke/help/examples/unload/uninstall/reinstall: PASS deterministic source archive contents: PASS full tools/local-ci.sh: PASS (exit code 0) ``` N05 is complete and N06 generalized `eig(A,B)` is now complete. The N06 implementation uses the frozen MPLAPACK MPFR/MPC backend and preserves the one-operation/one-precision contract. The D01R1 0.2.1 tag and archive remain unchanged. ## N06 implementation N06 adds dense generalized real and complex eigenproblems. Exactly symmetric or Hermitian pairs use `Rsygvd`/`Chegvd` for the default definite path; a non-positive-definite `B` falls back to QZ, and explicit `"qz"` uses `Rggev`/`Cggev`. Explicit `"chol"` requires the exact structured pair. The public wrapper supports Octave-compatible `matrix`/`vector` layouts, one-output diagonal/vector forms, three-output right/eigenvalue/left forms, mixed real/complex promotion, and rejection of generalized balance options. The native backend divides `alpha/beta` at the operation precision, preserves infinite eigenvalues for `beta = 0`, converts real conjugate pairs to complex MP storage, and keeps all destructive calls on owned copies. ## N06 gates ```text G-N06-API: PASS G-N06-QZ: PASS G-N06-CHOL: PASS G-N06-REAL: PASS G-N06-COMPLEX: PASS G-N06-INFINITE-EIGENVALUES: PASS G-N06-RIGHT-EIGENVECTORS: PASS G-N06-LEFT-EIGENVECTORS: PASS G-N06-MATRIX-VECTOR: PASS G-N06-PRECISION: PASS G-N06-REGRESSION: PASS ``` ## N06 regression evidence ```text tools/check-tree.sh: PASS tools/check-format.sh: PASS native make -C src check-generalized-eig: PASS public test/eig_generalized.tst: PASS full test/run_tests.m: PASS (M00-M23, C00-C12 including C11L, N00-N06) full tools/local-ci.sh: PASS (exit code 0) ASan: PASS UBSan: PASS LSan: PASS real/complex definite and QZ residuals: PASS singular-B infinity and alpha/beta handling: PASS matrix/vector and three-output left-vector forms: PASS mixed real/complex pair: PASS 1024-bit 2^-700 and 2048-bit 2^-1500: PASS ambient precision restoration: PASS input immutability: PASS clean package archive extraction/build/install/lifecycle: PASS deterministic source package archive: PASS ``` N06 is complete. N07 now closes the documented 0.3.0-dev numerical API surface and adds no new numerical algorithm. The next milestone is D02 final source freeze. No D02 release tag or final 0.3.0 archive is created here. ## N07 — numerical API closure N07 completes the development-line API and documentation audit for the accepted dense real/complex surface. It documents norm, determinant/inverse, SVD, rank/condition, standard and generalized eigenvalue interfaces, the precision/ownership contract, supported inputs, and explicit compatibility deferrals. The permanent `examples/06_grcar_eig.m` example uses a 32-by-32 Grcar matrix at 1024-bit MP precision and evaluates its residual with native high-precision operations. The N07 compatibility firewall verifies clean rejection of standalone `schur`, `qz`, `hess`, `expm`, `logm`, sparse/N-dimensional values, powers, comparisons/logical operations, and right division. Generalized eigensystems remain supported through the N06 real/complex definite and QZ paths. ### N07 gates ```text G-N07-API: PASS G-N07-DOCS: PASS G-N07-GRCAR: PASS G-N07-FIREWALL: PASS G-N07-REGRESSION: PASS ``` ### N07 regression evidence ```text tools/check-tree.sh: PASS tools/check-format.sh: PASS native N00-N06 backend/unit tests: PASS N07 public compatibility firewall: PASS N07 permanent Grcar(32) residual: PASS Grcar high-precision example at 1024 bits: PASS full test/run_tests.m: PASS (M00-M23, C00-C12 including C11L, N00-N07) ASan: PASS UBSan: PASS LSan: PASS 1024-bit / 2^-700 and 2048-bit / 2^-1500: PASS ambient precision and scope restoration: PASS input immutability and native lifetime tests: PASS clean archive extraction build: PASS deterministic source archive contents: PASS package install/load/smoke/help/examples/unload/uninstall/reinstall: PASS full tools/local-ci.sh: PASS (exit code 0) ``` N07 is complete. D02 completed the release-engineering freeze without changing numerical implementation or dependency identity. ## D02 — final 0.3.0 source freeze ```text G-D02-SOURCE-FREEZE: PASS — 392b72786f34d0bc1efcf35e2fd0cf0de58ec64f G-D02-VERSION: PASS — DESCRIPTION version 0.3.0 G-D02-REPRODUCIBLE: PASS — independent clean-tree A/B archives identical G-D02-REGRESSION: PASS — M00-M23, C00-C12/C11L, N00-N07, full CI G-D02-PACKAGE-LIFECYCLE: PASS — install/load/help/examples/unload/uninstall/reinstall G-D02-RUNTIME-CLOSURE: PASS — frozen MPLAPACK SONAME and N06 symbols verified G-D02-DOCS: PASS — binary handoff and dependency identity updated G-D02-TAG: PASS — annotated v0.3.0, local/remote target verified G-D02-BINARY-HANDOFF: PASS — exact 0.3.0 source identity recorded ``` ```text Archive: mplapack-interop-0.3.0.tar.gz Archive size: 306282 bytes SHA256 A: 1282f77f98bb7b137d1a8800d1d6d426ed06000595aebc03e5fa5ac48b3bdf98 SHA256 B: 1282f77f98bb7b137d1a8800d1d6d426ed06000595aebc03e5fa5ac48b3bdf98 Top-level directory: mplapack-interop-0.3.0/ Tagged archive: identical to pre-tag archive Installed copy: /home/docker/src/mplapack-interop-0.3.0.tar.gz ``` D02 is complete. The next milestone is B01 binary distribution architecture; it is not started automatically by this status update. mplapack-interop-0.5.1/docs/goals/D01R1-N00-N07-D02-goal.md0000644000230300031750000005176115274353473021524 0ustar rafaelrafael# /goal — D01R1 -> N00-N07 -> D02 Numerical Completion and Final Source Freeze ## Mission Complete the first broadly useful dense real+complex arbitrary-precision linear-algebra release of `mplapack-interop` before platform binary distribution. Controller sequence: ```text D01R1 -> N00 norm -> N01 det / inv -> N02 svd -> N03 rank / cond / rcond -> N04 symmetric / Hermitian eig -> N05 general eig -> N06 generalized eig(A,B) -> N07 numerical API closure -> D02 final mplapack-interop 0.3.0 source freeze ``` Continue automatically after every PASS. Do not ask the user to continue between milestones. Stop only for a genuine unresolved blocker. Do not begin B01-B05, F00, or PPA work automatically. --- # 0. Frozen dependency baseline Consume exactly the D00-frozen dependency stack: ```text gmpfrxx_mkII 1.4.1 commit 32a7fb797202cdf92312ed9d133f96fdbcda590a tag v1.4.1 archive gmpfrxx_mkII.1.4.1.tar.xz sha256 395b9c4bd5819cf0f61758cee5f7eb400e25e2959b51a75d40a922ed41d711c4 MPLAPACK 3.0.1 commit fa3ccb4376d2a52c2672322e5b7199a9224bed7f tag v3.0.1 archive mplapack-3.0.1.tar.xz sha256 7c8d1d7759a487bc01e8c1625599ec77b6c7e297c19b20ca45e8c342f5165e64 pkg-config mplapack_mpfr 3.0.1 runtime libmplapack_mpfr.so.3 ``` These dependency release tags are immutable in this controller. If an N-series milestone proves a genuine backend defect in frozen gmpfrxx_mkII or MPLAPACK: ```text STOP Nxx BLOCKED — DEPENDENCY RELEASE REVISION REQUIRED ``` Produce a minimal installed-library reproducer and identify the owning upstream repository. Do not silently patch a frozen release or move its tag. A dependency source fix requires a separate D00R1-style release revision. --- # 1. D01R1 first Expected file: ```text docs/goals/D01R1-mplapack-interop.md ``` If D01R1 has not PASSed, read and execute it first. Require: ```text D01R1 PASS — MPLAPACK-INTEROP IDENTITY FROZEN B01-READY ``` Do not start B01 after D01R1. Continue here to N00. If D01R1 already PASSed, verify its report/status and resume from N00. Expected identity after D01R1: ```text Name: mplapack-interop Version: 0.2.1 ``` Before N00 implementation, change active development version to: ```text 0.3.0-dev ``` Do not rewrite `v0.2.1`. --- # 2. Repository / state policy Preferred repository layout: ```text work/ ├── gmpfrxx_mkII/ # frozen/read-only ├── mplapack/ # frozen/read-only ├── octave-mplapack/ # writable └── octave-mplapack-ppa/ # DO NOT MODIFY ``` Maintain: ```text docs/goals/N00-N07-D02-status.md ``` with D01R1 identity, current milestone, last PASS milestone, current project commit, frozen dependency identities, blockers, and full regression status. On resume, continue from the first incomplete milestone. Never force-push published history. --- # 3. Global numerical invariants For every new operation: ```text p_op = stored operand-derived arbitrary precision ``` Ambient `mpbits()` is not authoritative for existing values. Mixed real/complex promotion follows the accepted C12 contract. Never implement a numerical API through: ```text double(mp) -> builtin double/complex operation -> mp(...) ``` Explicit `double()` conversion is the only binary64 conversion path. Real input should remain on real MPLAPACK kernels when a real backend exists. Do not route all real problems through complex routines for convenience. Destructive LAPACK calls use operation-owned copies. Public inputs remain immutable/value-semantic. High-precision QA must use MPFR/MPC-native values and precision-scaled residuals, with mandatory 1024-bit/`2^-700` and 2048-bit/`2^-1500` coverage where applicable. --- # 4. N00 — `norm` ## Required vector/scalar API Support real and complex: ```octave norm (x) norm (x, 1) norm (x, 2) norm (x, Inf) norm (x, -Inf) norm (x, "fro") norm (x, 0) ``` Audit and implement additional finite vector p values if a direct MPFR implementation is clean and Octave-compatible. ## Required matrix API Support real and complex: ```octave norm (A) norm (A, 1) norm (A, 2) norm (A, Inf) norm (A, "fro") ``` Other induced matrix p values may remain cleanly unsupported and must be documented. ## Backend audit Prefer/audit installed equivalents of: ```text Rlange / Clange for standard matrix norms Rnrm2 / Cnrm2 for vector 2-norm SVD singular values for matrix 2-norm ``` Introduce a private singular-values-only helper for matrix 2-norm. N02 later reuses/generalizes this helper. Complex absolute value must remain arbitrary precision. Audit empty/NaN/Inf and `rows`/`columns`/`cols` options against Octave 11.1. Implement only supported forms that fit the current 2-D architecture cleanly; document deferrals explicitly. ## Gates ```text G-N00-API G-N00-REAL G-N00-COMPLEX G-N00-MATRIX G-N00-VECTOR G-N00-2NORM G-N00-PRECISION G-N00-SPECIAL G-N00-REGRESSION ``` --- # 5. N01 — `det` / `inv` Implement dense real+complex: ```octave det (A) inv (A) ``` ## det Reuse real/complex LU infrastructure (`Rgetrf` / `Cgetrf` or shared helpers). Compute determinant at source precision from permutation parity and the product of `diag(U)`. Singular determinant must be exact zero according to Octave semantics. Audit any optional second `det` output. If it is reciprocal-condition information and correct implementation naturally depends on N03, support one-output det in N01 and explicitly close the second output in N03. ## inv Audit/use: ```text Rgetri Cgetri ``` with checked workspace queries and operation-owned LU copies. Do not implement inverse by converting to double or by changing `A\b` into `inv(A)*b`. Match Octave singular behavior through differential QA. ## Gates ```text G-N01-DET G-N01-DET-PIVOT G-N01-INV G-N01-WORKSPACE G-N01-SINGULAR G-N01-PRECISION G-N01-IMMUTABILITY G-N01-REAL-COMPLEX G-N01-REGRESSION ``` --- # 6. N02 — `svd` Implement dense real+complex: ```octave s = svd (A) [U,S,V] = svd (A) [U,S,V] = svd (A, "econ") [U,S,V] = svd (A, 0) ``` Audit exact Octave 11.1 shape semantics for square/tall/wide/full/econ/0/empty/scalar. ## Backend audit Audit frozen MPLAPACK 3.0.1 for: ```text Rgesvd / Cgesvd Rgesdd / Cgesdd other available SVD drivers ``` Default production baseline should prefer `gesvd` unless MPLAPACK-specific evidence strongly supports another driver. Do not choose `gesdd` only for speed. Record workspace, accuracy, threading, and precision behavior. ## Output semantics One-output singular values are real `mp` values for real or complex input. Three-output contract: ```text A = U*S*V' ``` with conjugate transpose for complex input. Audit whether `S` should be real `mp` and match Octave's public shape/type semantics. Generic tests use singular values, reconstruction, and orthogonality/unitarity rather than fragile sign/phase equality. Mandatory 1024/2048 tail-sensitive and near-rank-deficient fixtures. ## Gates ```text G-N02-BACKEND G-N02-ONE-OUTPUT G-N02-FULL G-N02-ECON G-N02-REAL G-N02-COMPLEX G-N02-RECONSTRUCTION G-N02-ORTHOGONALITY G-N02-WORKSPACE G-N02-PRECISION G-N02-REGRESSION ``` --- # 7. N03 — `rank` / `cond` / `rcond` Implement dense real+complex: ```octave rank (A) rank (A, tol) cond (A) cond (A, p) rcond (A) ``` ## rank Use N02 singular values. Default threshold follows Octave conceptually: ```text tol = max(size(A)) * sigma_max * eps_at_stored_operation_precision ``` Never use binary64 `eps` for `mp` rank. Rank is structural output, not arbitrary-precision payload, unless Octave differential QA dictates another representation. Mandatory real and complex source-precision rank canaries: lower stored precision and higher stored precision must classify appropriately and ambient precision must not control the result. ## cond Required forms: ```octave cond (A) cond (A, 2) cond (A, 1) cond (A, Inf) cond (A, "fro") ``` Audit rectangular/singular semantics. 2-norm condition uses singular values when applicable. For 1/Inf condition, audit stable estimators such as: ```text Rgecon / Cgecon ``` on LU factors. Do not form an explicit inverse if a condition estimator exists. Implement Frobenius condition consistently with Octave semantics and document method. ## rcond Audit/use `Rgecon/Cgecon` or exact frozen equivalents for square dense matrices. Return a real scalar. If Octave `det` has a second reciprocal-condition output, close it here using the accepted condition machinery. ## Gates ```text G-N03-RANK G-N03-RANK-PRECISION G-N03-COND2 G-N03-COND1 G-N03-CONDINF G-N03-CONDFRO G-N03-RCOND G-N03-SINGULAR G-N03-REAL G-N03-COMPLEX G-N03-PRECISION G-N03-REGRESSION ``` --- # 8. N04 — symmetric / Hermitian `eig` Implement the structured standard eigenproblem path for: ```text real symmetric complex Hermitian ``` Public `eig` dispatch may be introduced here for structured matrices. General matrices are completed in N05. Audit/support relevant Octave forms: ```octave lambda = eig (A) [V,D] = eig (A) [V,D] = eig (A, "matrix") [V,d] = eig (A, "vector") ``` Do not implement generalized `eig(A,B)` here. ## Detection Audit Octave's dense symmetry/Hermitian decision. Do not use a fuzzy binary64 tolerance. Prefer exact represented symmetry/Hermitian checks unless Octave requires otherwise. ## Backend candidates Audit frozen MPLAPACK equivalents such as: ```text Rsyev / Rsyevd Cheev / Cheevd ``` Select by correctness, precision, workspace, threading, and eigenvector behavior rather than speed alone. ## Output Symmetric/Hermitian eigenvalues are real `mp`. Eigenvectors: ```text real symmetric -> real mp complex Hermitian -> complex mp ``` Validate: ```text A*V = V*D V'*V = I ``` For repeated/degenerate eigenvalues, test invariant subspaces/residuals rather than elementwise eigenvectors. Include nearly repeated and high-dynamic-range 1024/2048 fixtures. ## Gates ```text G-N04-DETECTION G-N04-REAL-SYMMETRIC G-N04-COMPLEX-HERMITIAN G-N04-VECTOR G-N04-MATRIX G-N04-RESIDUAL G-N04-ORTHOGONALITY G-N04-DEGENERATE G-N04-PRECISION G-N04-REGRESSION ``` --- # 9. N05 — general `eig` + mandatory Grcar QA Implement full dense algebraic eigenvalue problems for: ```text real nonsymmetric complex general ``` including balancing and left/right eigenvectors. ## Required public forms Audit Octave 11.1 and support at minimum: ```octave lambda = eig (A) [V,D] = eig (A) [V,d] = eig (A, "vector") [V,D] = eig (A, "matrix") [V,D,W] = eig (A) ... = eig (A, "balance") ... = eig (A, "nobalance") ``` `V` = right eigenvectors; `W` = left eigenvectors. Match Octave's default preliminary balancing and exact option conflicts/errors. ## Backend audit Audit: ```text Rgeev / Rgeevx Cgeev / Cgeevx ``` To implement explicit `balance`/`nobalance`, prefer the expert driver where frozen MPLAPACK evidence supports it. Do not fake `nobalance`. Real nonsymmetric input may yield complex eigenpairs. Correctly convert the real LAPACK conjugate-pair representation into public complex `mp` values/eigenvectors. Prefer real backend for real input rather than routing all real problems through complex kernels. ## Equations Right residual: ```text A*V - V*D ``` Left residual: ```text W'*A - D*W' ``` or equivalent columnwise normalized forms. ## Mandatory Grcar regression Use: ```octave A = gallery ("grcar", n); Amp = mp (A); ``` At minimum: ```text n = 8 or 16 for routine regression n = 32 for deeper stress/release QA when runtime permits ``` Exercise: ```octave eig (Amp) eig (Amp, "balance") eig (Amp, "nobalance") [V,D] = eig (Amp) ``` Grcar is highly nonnormal. Do not use naive elementwise equality with binary64 eigenvalues as the main oracle. Mandatory Grcar checks: ```text A*V - V*D residual default == explicit balance API behavior nobalance path actually exercised precision progression (e.g. 128/256/512/1024 where practical) eigenvalue-set comparison uses matching, not raw ordering sensitivity is documented ``` Do not call a high-precision answer incorrect merely because it differs visibly from binary64 for Grcar. ## Additional difficult fixtures Add: ```text near-Jordan block nearly repeated eigenvalues badly scaled nonsymmetric matrix ``` Use residuals and precision convergence. Do not compare eigenvectors elementwise because sign/phase/scaling is nonunique. Add a deterministic small 512/1024 and 1024/2048 eig precision canary separate from Grcar. ## Gates ```text G-N05-BACKEND G-N05-REAL-GENERAL G-N05-COMPLEX-GENERAL G-N05-BALANCE G-N05-NOBALANCE G-N05-RIGHT-EIGENVECTORS G-N05-LEFT-EIGENVECTORS G-N05-GRCAR G-N05-NEAR-DEFECTIVE G-N05-PRECISION G-N05-REGRESSION ``` Keep at least one Grcar test permanently after N05. --- # 10. N06 — generalized `eig(A,B)` Implement dense generalized problems: ```text A*x = lambda*B*x ``` for real and complex inputs. ## Public forms Audit Octave 11.1 and implement relevant forms: ```octave lambda = eig (A, B) [V,D] = eig (A, B) [V,D,W] = eig (A, B) ... = eig (A, B, "chol") ... = eig (A, B, "qz") ... = eig (..., "matrix") ... = eig (..., "vector") ``` Match Octave's option conflicts. Do not accept `balance/nobalance` for generalized forms if Octave rejects them. ## Algorithm dispatch Audit Octave's structured policy: ```text A symmetric/Hermitian AND B symmetric/Hermitian positive definite -> generalized-definite/Cholesky path unless qz forced otherwise -> QZ/general generalized path ``` ## Backends Audit frozen MPLAPACK candidates: ```text Rggev / Cggev Rsygv / Rsygvd Chegv / Chegvd other exact equivalents ``` Do not assume availability; verify installed headers/source. ## Generalized eigenvalues Handle backend `alpha/beta` representation in arbitrary precision. Correctly support: ```text beta = 0 -> infinite eigenvalue complex alpha/beta real input with complex conjugate eigenpairs ``` No binary64 conversion. ## Residuals Right generalized residual uses the exact public D representation. Left residual should verify the corresponding generalized left-eigenvector equation. Audit singular `B` and infinite-eigenvalue semantics against Octave. Do not reject all singular B if QZ supports it. Structured-definite QA includes real symmetric and complex Hermitian pairs, plus comparison of `chol` and `qz` eigenvalues where both are mathematically valid. ## Gates ```text G-N06-API G-N06-QZ G-N06-CHOL G-N06-REAL G-N06-COMPLEX G-N06-INFINITE-EIGENVALUES G-N06-RIGHT-EIGENVECTORS G-N06-LEFT-EIGENVECTORS G-N06-MATRIX-VECTOR G-N06-PRECISION G-N06-REGRESSION ``` --- # 11. N07 — numerical API closure No new major numerical algorithm. Finalize/document: ```text norm det inv svd rank cond rcond symmetric/Hermitian eig general eig generalized eig ``` Create/update: ```text docs/norm.md docs/determinant-inverse.md docs/svd.md docs/rank-condition.md docs/eig.md docs/generalized-eig.md docs/octave-compatibility.md docs/v0.3-api.md README.md NEWS.md examples/ ``` Include a Grcar example using `gallery("grcar",32)` and high-precision eig residuals. ## Firewall Audit still-unsupported functions, e.g.: ```text schur qz as standalone public API hess expm logm other matrix functions sparse N-D ordered complex comparisons where unsupported ``` Require clean failure with no binary64 fallback, crash, or recursion. ## Full regression Run: ```text M00-M23 C00-C12 C11L D01R1 N00-N06 ``` plus all high-precision canaries and sanitizers. ## Package lifecycle Under `pkg load mplapack-interop`, smoke: ```text real/complex core norm det/inv svd rank/cond/rcond structured eig general eig Grcar eig generalized eig ``` Require: ```text N07 PASS — NUMERICAL API CLOSED D02-READY ``` --- # 12. D02 — final `mplapack-interop 0.3.0` source freeze D02 is release engineering only. Do not add numerical features. Unless an earlier N milestone stopped for a dependency revision, dependencies remain exactly D00-frozen: ```text gmpfrxx_mkII 1.4.1 MPLAPACK 3.0.1 ``` ## Version Freeze: ```text Name: mplapack-interop Version: 0.3.0 ``` Define exact: ```text MPLAPACK_INTEROP_0_3_0_FREEZE_COMMIT ``` No source-changing commits after it except report-only metadata. ## Archive Generate: ```text mplapack-interop-0.3.0.tar.gz ``` from two independent clean trees. Require identical SHA256/file list/metadata. Record archive name, top-level directory, size, SHA256 A/B. ## Tag After every D02 gate passes, create: ```text v0.3.0 ``` pointing exactly to the freeze commit. Do not move `v0.2.0` or `v0.2.1`. Do not create GitHub Release unless a later distribution milestone explicitly owns that action. ## Frozen regression Run full N07 regression against the exact freeze tree and extracted archive. ## Extracted archive lifecycle From archive only: ```text install pkg list pkg load mplapack-interop real+complex core smoke norm det/inv svd rank/cond/rcond structured eig Grcar general eig generalized eig help examples unload uninstall reinstall second smoke ``` ## Binary-distribution handoff revision Update D01R1 binary architecture so B01-B05/F00/PPA consume exactly: ```text Name: mplapack-interop Version: 0.3.0 Source commit: MPLAPACK_INTEROP_0_3_0_FREEZE_COMMIT Source archive: mplapack-interop-0.3.0.tar.gz Source SHA256: Dependencies: gmpfrxx_mkII 1.4.1 + MPLAPACK 3.0.1 ``` Re-audit final `.oct` runtime closure because N00-N06 may add dependency symbols/routines, even though library SONAMEs remain frozen. ## Gates ```text G-D02-SOURCE-FREEZE G-D02-VERSION G-D02-REPRODUCIBLE G-D02-REGRESSION G-D02-PACKAGE-LIFECYCLE G-D02-RUNTIME-CLOSURE G-D02-DOCS G-D02-TAG G-D02-BINARY-HANDOFF ``` All PASS: ```text D02 PASS — MPLAPACK-INTEROP 0.3.0 SOURCE FROZEN B01-READY ``` --- # 13. Eigenvalue test policy General eigenvalues are unordered and eigenvectors are nonunique up to scaling/phase. Never write fragile tests that compare general eigenvalues by raw position or eigenvectors elementwise. Use a stable set-matching strategy for eigenvalues, such as minimum-cost matching by arbitrary-precision complex distance in test code. Tolerance must derive from precision, scale, dimension, and conditioning. For ill-conditioned Grcar/Jordan-like problems, residual correctness and precision trends are more important than equality to binary64 output. --- # 14. Octave differential QA policy Use builtin Octave 11.1 as the structural/API oracle for: ```text argument parsing output count output shape/type matrix vs vector eigenvalue output balance/nobalance semantics chol/qz generalized selection empty/scalar cases error/non-error behavior ``` Do not use binary64 numerical output as the sole high-precision correctness oracle. --- # 15. Reports / status Maintain: ```text docs/goals/N00-N07-D02-status.md reports/N00-report.md reports/N01-report.md reports/N02-report.md reports/N03-report.md reports/N04-report.md reports/N05-report.md reports/N06-report.md reports/N07-report.md reports/D02-report.md ``` or the repository's established equivalent. After each PASS, update status and continue automatically. --- # 16. Common N-report content Each N report must record: ```text Repository / branch / starting commit / implementation commit / branch tip / PR Frozen gmpfrxx identity Frozen MPLAPACK identity Public API Backend routine(s) Workspace Precision policy Real semantics Complex semantics Octave differential QA 1024 result 2048 result Ambient-low/high Immutability ASan / UBSan / LSan Full previous regression Compatibility firewall Gates Nxx PASS / FAIL / BLOCKED ``` --- # 17. Master completion gate Complete only if: ```text D01R1 PASS N00 PASS N01 PASS N02 PASS N03 PASS N04 PASS N05 PASS N06 PASS N07 PASS D02 PASS ``` Final state: ```text MPLAPACK-INTEROP NUMERICAL COMPLETION PASS MPLAPACK-INTEROP 0.3.0 SOURCE FROZEN B01-READY ``` --- # 18. Final master report Produce: ```text # D01R1 -> N00-N07 -> D02 RESULT Result: PASS / FAIL / BLOCKED ## Package identity Repository: Name: Version: Final freeze commit: Tag: Archive: SHA256: ## Frozen dependencies gmpfrxx_mkII: MPLAPACK: ## Milestones D01R1: N00 norm: N01 det/inv: N02 svd: N03 rank/cond/rcond: N04 symmetric/Hermitian eig: N05 general eig: N06 generalized eig: N07 closure: D02 freeze: ## Final supported numerical API ... ## Grcar QA Matrix sizes: balance: nobalance: residual: precision progression: permanent test: ## Eigen backend map real symmetric: complex Hermitian: real general: complex general: real generalized: complex generalized: structured generalized: ## SVD backend map real: complex: driver: economy: ## Rank / condition backend map ... ## Precision regression 1024: 2048: source-precision rank: source-precision eig: ambient independence: ## Sanitizers ASan: UBSan: LSan: ## Package lifecycle ... ## Binary-distribution handoff Source commit: Source archive: Source SHA256: Octave package Name: Version: D01R1 ABI architecture: Runtime closure: B01-ready: ## Known limitations ... ## Next milestone If PASS: Proceed to B01 — Linux x86_64 binary package using exactly the D02-frozen mplapack-interop 0.3.0 source identity. Do not modify numerical source in B01. If B01 exposes a source-level defect, reopen the appropriate source/dependency freeze instead of silently patching the binary artifact. Do not begin B01 automatically. ``` --- # 19. Stop After the final master report: ```text STOP ``` Do not begin: ```text B01 B02 B03 B04 B05 F00 PPA1-G PPA1-M PPA2 PPA3 PPA4 ``` automatically. mplapack-interop-0.5.1/docs/goals/D00-dependency-release-freeze-status.md0000644000230300031750000001330115274353473025475 0ustar rafaelrafael# D00 dependency release freeze status Controller: [`D00-dependency-release-freeze.md`](D00-dependency-release-freeze.md) ## Current state Current substage: `D00-H` handoff gate Last completed substage: `D00-T` release tags Overall result: `D00 PASS — RELEASE STACK FROZEN` The source freeze identities, reproducible archives, and remote release tags are fixed and verified. The handoff manifest and final report are complete. ## Substage record | Substage | Result | Evidence | |---|---|---| | D00-G gmpfrxx_mkII | PASS | Version 1.4.1, existing tag `v1.4.1`, commit `32a7fb797202cdf92312ed9d133f96fdbcda590a`, clean install, 156/156 CTest, scalar/precision/TLS/MPC probes, published GitHub archive verified; local A/B archive reproduction retained below | | D00-M MPLAPACK 3.0.1 | PASS | Freeze `fa3ccb4376d2a52c2672322e5b7199a9224bed7f`; C12 scope work retained; archive-only build against frozen gmpfrxx; public precision header and external consumers pass; archive SHA256 `7c8d1d7759a487bc01e8c1625599ec77b6c7e297c19b20ca45e8c342f5165e64` | | D00-O octave-mplapack 0.2.0 | PASS | Source freeze `4a3eb50843a6bf365bdab1e82146ef1900a219f6`; version 0.2.0; release QA script corrected for complex/public-header coverage; source archive SHA256 `0e83e26182b0fbd95a064437a97307eb74d9291b49d91c6e53dac181b24a94db` | | D00-S frozen-stack rebuild | PASS | Three-layer rebuild from source archives only; clean Octave archive build/install; M00-M23 real wall, C00-C12 complex wall, C11L, sanitizer wall, and package lifecycle pass | | D00-R reproducibility | PASS | Local gmpfrxx A/B, MPLAPACK A/B, and octave-mplapack A/B source archives have identical SHA256 and identical file lists/top-level directory; the published gmpfrxx asset is separately recorded as the canonical distribution artifact and has an extraction-equivalent XZ stream | | D00-T tags | PASS | MPLAPACK `v3.0.1` and octave-mplapack `v0.2.0` pushed and verified against their exact freeze commits | | D00-H handoff | PASS | Final manifest and report contain versions, commits, tags, archives, hashes, sizes, licenses, dependency graph, SONAMEs, and regression evidence | ## Frozen identities ```text GMPFRXX_C12_TESTED_COMMIT=32a7fb797202cdf92312ed9d133f96fdbcda590a GMPFRXX_FREEZE_COMMIT=32a7fb797202cdf92312ed9d133f96fdbcda590a GMPFRXX_RELEASE_VERSION=1.4.1 GMPFRXX_RELEASE_TAG=v1.4.1 GMPFRXX_ARCHIVE=gmpfrxx_mkII.1.4.1.tar.xz GMPFRXX_ARCHIVE_URL=https://github.com/nakatamaho/gmpfrxx_mkII/releases/download/v1.4.1/gmpfrxx_mkII.1.4.1.tar.xz GMPFRXX_ARCHIVE_SIZE=15176064 GMPFRXX_SHA256=395b9c4bd5819cf0f61758cee5f7eb400e25e2959b51a75d40a922ed41d711c4 GMPFRXX_D00_REPRODUCTION_ARCHIVE_SIZE=15176072 GMPFRXX_D00_REPRODUCTION_SHA256=93fbf257ab3c3e00342109fea9096f43cf32e29fd1b7dbafd91f8e23f81b3890 MPLAPACK_C12_TESTED_COMMIT=a59e5a0a429b05e8f07cf7a8feab1f48aef7431d MPLAPACK_C12_INTEGRATION_COMMIT=e6e1bcbf9513e9de47cb6c70afbd791e30868aae MPLAPACK_FREEZE_COMMIT=fa3ccb4376d2a52c2672322e5b7199a9224bed7f MPLAPACK_RELEASE_VERSION=3.0.1 MPLAPACK_RELEASE_TAG=v3.0.1 MPLAPACK_ARCHIVE=mplapack-3.0.1.tar.xz MPLAPACK_ARCHIVE_SIZE=86024224 MPLAPACK_SHA256=7c8d1d7759a487bc01e8c1625599ec77b6c7e297c19b20ca45e8c342f5165e64 OCTAVE_MPLAPACK_C12_TESTED_COMMIT=36cd341a8c14ce2d0a6790b287e5f7a7b0846cd3 OCTAVE_MPLAPACK_FREEZE_COMMIT=4a3eb50843a6bf365bdab1e82146ef1900a219f6 OCTAVE_MPLAPACK_RELEASE_VERSION=0.2.0 OCTAVE_MPLAPACK_RELEASE_TAG=v0.2.0 OCTAVE_MPLAPACK_ARCHIVE=mplapack-0.2.0.tar.gz OCTAVE_MPLAPACK_ARCHIVE_SIZE=231432 OCTAVE_MPLAPACK_SHA256=0e83e26182b0fbd95a064437a97307eb74d9291b49d91c6e53dac181b24a94db ``` ## D00-M defect audit The D00-M release-line audit found four release-blocking defects. They were fixed without changing numerical algorithms: 1. The bundled gmpfrxx source was 1.4.0 instead of the frozen 1.4.1 source: `85b581ea0c9183cdbaf44d34eb48d7cc8eb3dcb2`. 2. `make dist` emitted nondeterministic PAX atime/ctime metadata: `f4e5818135dada8c6ef0a7f11954c53f11f4202a`. 3. The standalone archive omitted generated gmpfrxx `Makefile.in` and could not configure after extraction: `3786c35a825ae3927b8621bed380e14877d17912`. 4. External gmpfrxx include flags were missing from `mplapack_mpfr.pc`: `fa3ccb4376d2a52c2672322e5b7199a9224bed7f`. `mpblas.h` and `mplapack.h` are internal aggregate headers. They use internal `INTEGER`/`REAL` definitions and are intentionally not installed. A temporary attempt to promote them was removed from the D00 branch by force-push and is not part of the release tree. The external M20/M21 probes were validated through the installed public backend headers instead. The canonical gmpfrxx archive record uses the existing GitHub Release asset, which is already published from tag `v1.4.1`. Its size is `15176064` bytes and its SHA256 is `395b9c4bd5819cf0f61758cee5f7eb400e25e2959b51a75d40a922ed41d711c4`. The independently generated local D00 A/B archives remain recorded as `15176072` bytes with SHA256 `93fbf257ab3c3e00342109fea9096f43cf32e29fd1b7dbafd91f8e23f81b3890` each. The extracted trees and tar metadata are equivalent; the byte difference is limited to the XZ compression stream. ## Policy confirmations - The gmpfrxx raw GMP `mpf` default remains process-global; this is not represented as TLS. MPFR thread-local behavior and MPC environment behavior remain separate and are tested as such. - The MPLAPACK public scope establishes/restores current-thread MPFR default precision, supports nested same-thread temporary construction, and can be used at worker entry. It does not propagate parent-thread TLS state into new workers. - No builtin binary64 complex fallback was used or added. - Existing real-only operations were not routed through complex kernels. - No Debian package, Launchpad upload, PPA change, release tag outside D00-T, or D01 work was performed. mplapack-interop-0.5.1/docs/goals/COMPLEX-C00-C12-goal.md0000644000230300031750000007522115274353473021524 0ustar rafaelrafael# /goal ― Complete Complex `mp` Implementation C00C12 ## Goal Implement the complete first-generation **dense arbitrary-precision complex** support for `nakatamaho/octave-mplapack`, from native storage through complex BLAS/LAPACK integration, while preserving the frozen real-only v0.1 release candidate as an immutable checkpoint. This goal is a **multi-milestone controller**: ```text C00 -> C01 -> C02 -> C03 -> C04 -> C05 -> C06 -> C07 -> C08 -> C09 -> C10 -> C11 -> C12 ``` Continue automatically from one milestone to the next whenever the current milestone is `PASS`. Do not ask the user to manually issue another prompt between normal milestones. If a proven upstream defect is found in `gmpfrxx_mkII` or MPLAPACK, create the minimal upstream topic branch/fix, validate it, record the exact commit, rebuild the controlled dependency, and resume the blocked complex milestone. Do not begin Debian/PPA packaging in this goal. --- # 0. Immutable real checkpoint The real-only v0.1 checkpoint is immutable: ```text REAL_V0_1_RC_COMMIT = 0bef79cddd3fdd70abafdf38bc1a4ab492652d33 REAL_V0_1_ARCHIVE = mplapack-0.1.0.tar.gz REAL_V0_1_ARCHIVE_SHA256 = 35d004adf831c79fe470ff890ce3698dfe7e6f624ea31c174b1d60a03d110db6 ``` Never rewrite, amend, retag, or mutate this checkpoint. The complex development line is separate. Use the real checkpoint for: ```text regression comparison behavior comparison historical provenance possible emergency real-only release ``` --- # 1. Required repository layout Preferred workspace: ```text work/ ├── gmpfrxx_mkII/ # upstream dependency; writable for real upstream fixes ├── mplapack/ # upstream MPLAPACK; writable for real upstream fixes ├── octave-mplapack/ # complex implementation happens here └── octave-mplapack-ppa/ # parked; DO NOT modify during C00-C12 ``` Discover actual repository locations if the layout differs. Do not hard-code user-specific absolute paths. Use repository identity: ```bash git remote -v git rev-parse --show-toplevel ``` --- # 2. File placement inside `octave-mplapack` Place this master goal at: ```text octave-mplapack/ └── docs/ └── goals/ └── COMPLEX-C00-C12-goal.md ``` Use/create: ```text octave-mplapack/ ├── docs/ │ ├── goals/ │ │ ├── COMPLEX-C00-C12-goal.md │ │ └── COMPLEX-C00-C12-status.md │ │ │ ├── complex-architecture.md │ ├── complex-api.md │ ├── complex-precision.md │ ├── complex-backends.md │ ├── complex-compatibility.md │ ├── complex-release-checklist.md │ │ │ └── milestones/ │ ├── C00-complex-scaffold.md │ ├── C01-complex-scalar.md │ ├── C02-complex-matrix.md │ ├── C03-complex-structural.md │ ├── C04-complex-elementwise.md │ ├── C05-complex-gemm.md │ ├── C06-complex-square-solve.md │ ├── C07-complex-rectangular-solve.md │ ├── C08-complex-cholesky.md │ ├── C09-complex-qr.md │ ├── C10-complex-pivoted-qr.md │ ├── C11-mixed-real-complex-closure.md │ └── C12-complex-release-closure.md │ ├── reports/ │ └── complex/ │ ├── C00-report.md │ ├── C01-report.md │ ├── C02-report.md │ ├── C03-report.md │ ├── C04-report.md │ ├── C05-report.md │ ├── C06-report.md │ ├── C07-report.md │ ├── C08-report.md │ ├── C09-report.md │ ├── C10-report.md │ ├── C11-report.md │ └── C12-report.md │ ├── test/ │ ├── complex/ │ │ ├── native/ │ │ ├── public/ │ │ └── probes/ │ └── ... │ ├── src/ ├── inst/ └── tools/ ``` If release/package policy would ship `reports/`, explicitly exclude `reports/` from release archives. Do not reorganize historical M00-M23 files only for style. --- # 3. Controller state / resume Maintain: ```text docs/goals/COMPLEX-C00-C12-status.md ``` with: ```text REAL_V0_1_RC_COMMIT COMPLEX_START_COMMIT current milestone last PASS milestone octave-mplapack branch/tip MPLAPACK tested commit gmpfrxx_mkII tested commit upstream fixes blockers full regression status ``` On restart: 1. read status; 2. inspect all repository HEADs; 3. verify recorded commits exist; 4. detect completed milestones; 5. continue from the first incomplete milestone. Do not duplicate already accepted work. --- # 4. Branch policy Preferred main controller branch: ```text topic/complex-c00-c12 ``` If repository policy strongly prefers one branch/PR per milestone, use: ```text topic/c00-complex-scaffold ... topic/c12-complex-release-closure ``` and merge accepted milestones in sequence. For upstream fixes: ```text gmpfrxx_mkII: topic/octave-mplapack-complex- mplapack: topic/octave-mplapack-complex- ``` Do not mix unrelated upstream fixes. Do not force-push published history. --- # 5. Starting state Inspect all three development repositories: ```bash git status --short git branch --show-current git rev-parse HEAD git log --oneline --decorate -40 git remote -v ``` Identify: ```text COMPLEX_START_COMMIT ``` as the accepted post-M23 development base. Keep separate: ```text REAL_V0_1_RC_COMMIT COMPLEX_START_COMMIT ``` The complex line may start from the merged M23 state if later commits are report/metadata only. --- # 6. Development version After C00 baseline validation, move the development package version to: ```text 0.2.0-dev ``` unless project policy already defines another post-v0.1 development suffix. Do not tag `v0.2.0`. D00 after C12 freezes final dependency/release versions. --- # 7. M20 architecture is normative M20 decisions are the default architecture: ```text complex scalar: mpfrxx::mpc_class complex dense matrix: contiguous column-major std::vector public class: one public class `mp` payload kinds: real scalar real dense matrix complex scalar complex dense matrix one complex object: one precision p real component: p imag component: p mixed result: any complex participant -> complex mixed precision: p_op = max(all participating mp precisions) real -> complex: exact represented real + exact +0i at p_op implicit complex -> real demotion: forbidden ``` Do not redesign these without a concrete blocker. Any change to M20 decisions must be: ```text evidence-backed documented tested called out in the milestone report ``` --- # 8. Known complex backends M20 audited: ```text complex scalar: mpfrxx::mpc_class GEMM: Cgemm square solve: Cgesv Cholesky: Cpotrf QR: Cgeqrf Cungqr pivoted QR: Cgeqp3 rectangular solve candidates: Cgelsy Cgelss Cgelsd ``` Each numerical milestone must re-audit the exact installed declaration and exact controlled source path. --- # 9. Uniform complex precision contract Normative rule: ```text ONE COMPLEX MPLAPACK INVOCATION = ONE p_op ``` For one invocation: ```text all COMPLEX components = p_op all COMPLEX arrays = p_op all participating REAL = p_op all REAL workspace = p_op all COMPLEX workspace = p_op executing-thread MPFR/MPC context = p_op ``` Mixed component precision inside one public complex value is unsupported. Mixed precision inside one complex MPLAPACK call is unsupported. --- # 10. C00 must resolve MPFR/MPC scope composition M20 left: ```text MPC override can diverge from MPFR scope ``` as an open issue. C00 must establish one project policy so numerical code cannot accidentally run with: ```text MPFR default = p_op MPC default/override != p_op ``` Preferred architecture: ```text one RAII complex precision/rounding scope ``` or a verified composition of the existing MPLAPACK MPFR scope and the gmpfrxx_mkII MPC context. Nested scopes and exception/error restoration must work. --- # 11. Upstream-fix policy If a milestone exposes an upstream defect in `gmpfrxx_mkII` or MPLAPACK, do not hide it downstream. Examples: ```text wrong default precision mixed component precision unsafe mpc_class copy/move worker precision leak Cgemm temporary precision defect Cgesv/Cpotrf/Cgeqrf/Cgeqp3 precision defect workspace precision defect backend result wrong outside Octave wrapper ``` Required workflow: ```text 1. produce a minimal native reproducer 2. prove defect outside public octave-mplapack dispatch 3. identify owning upstream repository 4. create bounded topic branch 5. implement minimal upstream fix 6. add upstream regression 7. run relevant upstream CI/tests 8. rebuild/reinstall controlled dependency 9. rerun external probe 10. record exact fix commit 11. resume current milestone ``` No downstream numerical workaround for an upstream bug. --- # 12. Dependency provenance Maintain: ```text docs/complex-backends.md ``` with: ```text gmpfrxx_mkII repository/commit MPLAPACK repository/commit installed headers pkg-config identities runtime SONAMEs upstream fixes introduced by C00-C12 ``` These are development commits, not final Debian versions. D00 freezes final dependency releases. --- # 13. Real regression wall Every C00-C12 milestone preserves M00-M23 real behavior. Hard invariants: ```text real * real -> Rgemm real square \ real -> Rgesv real rectangular \ real -> Rgelss real chol -> Rpotrf real qr -> Rgeqrf/Rorgqr real pivoted qr -> Rgeqp3/Rorgqr real lu -> Rgetrf real transpose/ctranspose -> accepted M12 behavior ``` Do not route real operations through complex kernels. --- # 14. No binary64 fallback Unsupported/incomplete complex operations must fail cleanly. Never: ```text convert complex mp -> builtin complex double perform builtin operation convert back ``` unless the operation is explicitly `double()`. Expand fallback-firewall QA throughout the C-series. --- # 15. Value semantics Public `mp` remains value-semantic. Destructive complex BLAS/LAPACK calls use operation-owned copies. Test output lifetime after: ```octave B = f(A); clear A; ``` for every major path. --- # C00 ― Complex Scaffold, Payloads, Precision Context ## Mission Implement the internal complex foundation: ```text mpc_class ownership complex scalar storage complex matrix storage four-kind payload dispatch uniform precision MPFR/MPC scope composition copy/move/lifetime special values ``` No broad public complex arithmetic yet. ## Storage Add repository-consistent equivalents of: ```text MpfrComplexScalarStorage MpfrComplexMatrixStorage ``` Matrix: ```text contiguous column-major std::vector one stored precision p ``` Provide checked: ```text rows columns leading_dimension data() precision ``` ## Complex scope Implement/adopt one RAII abstraction that saves/restores the complete current-thread complex operation context: ```text MPFR precision/default MPC precision override/default relevant rounding mode ``` Set round-to-nearest for both components. Nested scopes must work. ## Probes Test: ```text 128 256 512 1024 2048 ``` for: ```text default construction explicit precision copy move vector allocation signed real zero signed imag zero Inf NaN thread-local independence nested scope restoration exception-path restoration ``` ## Gates ```text G-C00-TYPE G-C00-STORAGE G-C00-PRECISION G-C00-TLS G-C00-LIFETIME G-C00-SPECIAL G-C00-REAL-REGRESSION ``` All PASS -> `C00 PASS`. --- # C01 ― Complex Scalar Constructor and Conversion ## Mission Make complex scalar `mp` first-class. ## Mandatory public support ```octave mp(complex_double) ``` using direct binary64 real/imag conversion. Add one exact arbitrary-precision construction path. Preferred after API audit: ```octave mp(real_text, imag_text) ``` or an equally unambiguous explicit form. No binary64 intermediate for exact text. ## `double` ```octave double(z) ``` returns builtin complex double through component-wise round-to-nearest conversion. ## `char` Define a deterministic round-trip-safe scalar grammar: ```text locale independent source-precision safe unambiguous Inf/NaN aware signed-zero aware as representable ``` ## `disp` Human-readable, arbitrary precision, no double conversion. ## Preserve real kind Real constructors remain real payloads. ## Precision canaries 1024-bit: ```text real = 1 + 2^-700 imag = 2^-700 ``` 2048-bit: ```text real = 1 + 2^-1500 imag = -2^-1500 ``` ## Gates ```text G-C01-CONSTRUCT G-C01-DOUBLE G-C01-CHAR G-C01-DISP G-C01-PRECISION G-C01-SPECIAL G-C01-REAL-PARITY ``` All PASS -> `C01 PASS`. --- # C02 ― Complex Dense Matrix, Inspection, Indexing, Display ## Mission Make dense complex matrices first-class public `mp`. ## Construction Support builtin complex double matrices. Convert binary64 real/imag components directly at destination precision. Do not invent an unverified exact text-cell complex grammar. ## Indexing Mirror accepted real behavior: ```octave A(i,j) A(:,j) A(i,:) A(I,J) A(k) A(:) end ``` Scalar extraction -> complex scalar. Slices -> complex matrix. Preserve precision. ## Assignment Implement complex->complex assignment with M14 value semantics. Real/complex storage-kind promotion is closed in C11. No growth/deletion/logical assignment unless real API already supports it. ## `double` Builtin complex double matrix. ## `disp` Direct arbitrary-precision component formatting. ## Empty Audit: ```text 0x0 0xN Mx0 ``` ## Gates ```text G-C02-CONSTRUCT G-C02-STORAGE G-C02-INDEX G-C02-ASSIGN G-C02-DOUBLE G-C02-DISP G-C02-EMPTY G-C02-LIFETIME G-C02-REAL-REGRESSION ``` All PASS -> `C02 PASS`. --- # C03 ― `real`, `imag`, `conj`, Transpose, Ctranspose ## Mandatory semantics ```octave real(Z) -> real mp, same precision/shape imag(Z) -> real mp, same precision/shape conj(Z) -> complex mp, same precision/shape Z.' -> transpose only Z' -> transpose + conjugation ``` Real `mp` keeps accepted M12 behavior. Conjugation must correctly flip imaginary signed zero. ## Gates ```text G-C03-REAL G-C03-IMAG G-C03-CONJ G-C03-TRANSPOSE G-C03-CTRANSPOSE G-C03-SIGNED-ZERO G-C03-REAL-PARITY ``` All PASS -> `C03 PASS`. --- # C04 ― Complex Element-wise Arithmetic ## Operations ```text + - .* ./ unary + unary - ``` ## Result-kind table ```text real op real -> real real op complex -> complex complex op real -> complex complex op complex -> complex ``` ## Precision ```text p_op = max(all participating mp precisions) ``` Builtin double/complex double contributes represented binary64 values but does not create a higher arbitrary precision. Allocate destination explicitly at `p_op`. Avoid ambient-default temporaries. ## Broadcasting Use the accepted real M11 2-D singleton expansion model. ## Special values Audit Inf/NaN/signed-zero/division-by-zero. ## Gates ```text G-C04-SCALAR G-C04-MATRIX G-C04-MIXED-KIND G-C04-MIXED-PRECISION G-C04-BROADCAST G-C04-SPECIAL G-C04-REAL-REGRESSION ``` All PASS -> `C04 PASS`. --- # C05 ― Complex Matrix Multiplication via `Cgemm` ## Dispatch ```text real * real -> existing Rgemm real * complex -> Cgemm complex * real -> Cgemm complex * complex -> Cgemm ``` ## Promotion Normalize complex-participating operands to one `p_op`. Real values promote with exact `+0i`. Builtin complex double converts directly from binary64 components. ## Uniform boundary At Cgemm: ```text A/B/C alpha/beta temporaries current-thread complex context ``` all use `p_op`. Audit exact installed signature/source/threading. If optimized workers lack precision setup: ```text C05 BLOCKED ― COMPLEX GEMM WORKER PRECISION CONTRACT ``` Fix upstream. ## Precision canaries Mandatory: ```text 1024 / 2^-700 2048 / 2^-1500 ``` real and imaginary tails. ## Gates ```text G-C05-UPSTREAM G-C05-DISPATCH G-C05-CGEMM G-C05-PRECISION G-C05-MIXED G-C05-SHAPES G-C05-IMMUTABILITY G-C05-REAL-RGEMM-PARITY ``` All PASS -> `C05 PASS`. --- # C06 ― Complex Square Solve via `Cgesv` Extend square `A\B` with complex participation. ## Dispatch ```text real square A + real B -> Rgesv any complex participant -> Cgesv ``` ## Precision ```text p_op = max(all participating mp precisions) ``` Use operation-owned uniformly p_op complex A/B. Pivot type = installed `mplapackint`. Multiple RHS mandatory. Singular behavior must match established square-solve semantics. ## Gates ```text G-C06-UPSTREAM G-C06-CGESV G-C06-MIXED G-C06-PIVOT G-C06-SINGULAR G-C06-MULTIRHS G-C06-PRECISION G-C06-IMMUTABILITY G-C06-REAL-RGESV-PARITY ``` All PASS -> `C06 PASS`. --- # C07 ― Complex Rank-Revealing Rectangular Solve Extend rectangular `A\B` to complex participation. ## Mandatory candidate audit Compare: ```text Cgelsy Cgelss Cgelsd ``` using the exact controlled dependency. Test: ```text full-column-rank overdetermined full-row-rank underdetermined rank zero rank one inconsistent rank deficient multiple RHS precision-sensitive rank workspace complexity REAL workspace precision COMPLEX workspace precision thread/worker precision ``` M20 suggested Cgelsy first, but select from evidence. ## Semantics Target: ```text minimum norm rank deficient supported one p_op rank classification controlled by stored operand precision ambient independent ``` ## RCOND / threshold Must derive from `p_op`. Never use: ```text DBL_EPSILON hard-coded decimal ambient mpbits() ``` ## Workspace All REAL and COMPLEX workspace/state participating in arithmetic must use `p_op`. ## Gates ```text G-C07-CANDIDATE-AUDIT G-C07-UPSTREAM G-C07-FULL-RANK G-C07-RANK-DEF G-C07-MIN-NORM G-C07-RANK-PRECISION G-C07-WORKSPACE G-C07-MIXED G-C07-IMMUTABILITY G-C07-REAL-RGELSS-PARITY ``` All PASS -> `C07 PASS`. --- # C08 ― Hermitian Cholesky via `Cpotrf` Extend: ```octave chol(A) chol(A,"upper") chol(A,"lower") [R,p] = chol(...) ``` to complex. ## Selected triangle Preserve M17: ```text upper -> only upper triangle authoritative lower -> only lower triangle authoritative ``` Selected complex triangle defines a Hermitian matrix. Do not enforce agreement of the ignored triangle. ## Contract Upper: ```text R' * R = H_upper(A) ``` Lower: ```text L * L' = H_lower(A) ``` where `'` is conjugate transpose. Audit complex diagonal imaginary-component behavior against Cpotrf and builtin Octave. Preserve one/two-output non-PD semantics where compatible. ## Gates ```text G-C08-UPSTREAM G-C08-HERMITIAN G-C08-SELECTED-TRIANGLE G-C08-UPPER G-C08-LOWER G-C08-NONPD G-C08-STATUS G-C08-PRECISION G-C08-IMMUTABILITY G-C08-REAL-CHOL-PARITY ``` All PASS -> `C08 PASS`. --- # C09 ― Non-pivoted Complex QR via `Cgeqrf` / `Cungqr` Extend M18 forms: ```octave R = qr(A) [Q,R] = qr(A) R = qr(A,"econ") [Q,R] = qr(A,"econ") R = qr(A,0) [Q,R] = qr(A,0) ``` ## Critical semantics One output is R. One-output path does not construct Q. Preserve full/economy shapes. Complex orthogonality: ```text Q' * Q = I ``` not `Q.'*Q`. R structural lower zeros are exact complex zero. Audit Cgeqrf/Cungqr workspace and threading. ## Gates ```text G-C09-UPSTREAM G-C09-FULL G-C09-ECON G-C09-ONE-OUTPUT G-C09-WORKSPACE G-C09-ORTHOGONALITY G-C09-RECONSTRUCTION G-C09-PRECISION G-C09-REAL-QR-PARITY ``` All PASS -> `C09 PASS`. --- # C10 ― Pivoted Complex QR via `Cgeqp3` Extend M19 forms: ```octave [Q,R,P] = qr(A) [Q,R,P] = qr(A,"matrix") [Q,R,p] = qr(A,"vector") [Q,R,P] = qr(A,"econ") [Q,R,p] = qr(A,0) ``` Production: ```text Cgeqp3 Cungqr ``` ## Permutation Unchanged: ```text Q*R = A*P Q*R = A(:,p) ``` P/p remain builtin real structural data. Initialize JPVT all zero. Audit exact complex JPVT mapping. ## Precision pivot canary Create a complex norm fixture where lower/higher stored precision changes pivot order. Ambient precision must not change it. Real 3-output QR remains Rgeqp3. ## Gates ```text G-C10-UPSTREAM G-C10-PERMUTATION G-C10-MATRIX-P G-C10-VECTOR-P G-C10-ECON G-C10-PIVOT-PRECISION G-C10-RECONSTRUCTION G-C10-ORTHOGONALITY G-C10-REAL-RGEQP3-PARITY ``` All PASS -> `C10 PASS`. --- # C11 ― Mixed Real/Complex Closure Close the first-generation mixed public surface. ## Mandatory promotion ```text real mp op real mp -> real real mp op complex mp -> complex complex mp op real mp -> complex complex mp op complex mp -> complex p_op = max(all participating mp precisions) ``` ## Operations At minimum: ```text + - .* ./ * \ ``` ## Concatenation ```octave [A_real, B_complex] [A_real; B_complex] [A_complex, B_real] ``` returns one complex matrix. ```text p_cat = max(all participating mp precisions) ``` ## Assignment ```octave B = A_real; B(i,j) = complex_rhs; ``` B becomes complex. A remains unchanged. ```text p_assign = max(lhs,rhs mp precisions) ``` Complex LHS + real RHS remains complex. ## Structural interoperability Complex reshape/indexing/transpose/ctranspose/disp/double all compose. ## Builtin mixing Audit real/complex builtin double participation through direct binary64 component conversion. ## No demotion Never downgrade a complex result just because current imaginary values are zero. ## Gates ```text G-C11-PROMOTION G-C11-PRECISION G-C11-ARITHMETIC G-C11-MTIMES G-C11-MLDIVIDE G-C11-CONCAT G-C11-ASSIGN G-C11-STRUCTURAL G-C11-BUILTIN-DOUBLE G-C11-NO-DEMOTION G-C11-REAL-REGRESSION ``` All PASS -> `C11 PASS`. --- # C11L ― Mandatory Complex LU via `Cgetrf` Complex LU is mandatory in this goal. Reproduce M21 semantics through MPLAPACK `Cgetrf`: ```text packed one-output two-output A=L*U three-output P*A=L*U vector A(p,:)=L*U rectangular singular factors source-precision pivoting ``` Do not implement complex LU as an incidental side change; C11L is a required milestone between C11 and C12. --- # C12 ― Real + Complex Release Closure No new major numerical feature. ## Finalize docs ```text docs/complex-api.md docs/complex-compatibility.md docs/complex-release-checklist.md docs/complex-backends.md ``` ## Supported surface inventory Record exact implemented forms for: ```text complex scalar complex matrix double char scalar disp indexing assignment real imag conj transpose ctranspose + - .* ./ * square \ rectangular \ chol qr pivoted qr mixed real/complex concat assignment complex lu status ``` ## Compatibility firewall Probe unsupported complex functions: ```text eig svd det inv rank cond norm power unimplemented transcendentals ordered comparison logical sparse ``` Require: ```text clean unsupported behavior no binary64 fallback no crash no recursion ``` ## Full regression Run: ```text M00-M23 real regression C00-C11L complex regression all upstream probes ``` ## Precision regression Mandatory 1024/2048 tail coverage across: ```text scalar round trip element-wise Cgemm Cgesv rectangular solve Cpotrf Cgeqrf/Cungqr Cgeqp3 mixed real/complex ``` plus all existing real canaries. ## TLS/thread regression Alternate: ```text 256 1024 2048 512 ``` with low/high ambient defaults. Run thread-local probes where supported. ## Sanitizers ```text ASan UBSan LSan ``` ## Package lifecycle Build/install/unload/reinstall the normal Octave package and run real+complex smoke. No Debian package. ## Version Remain development: ```text 0.2.0-dev ``` D00 freezes final versions. ## Final gates ```text G-C12-API G-C12-DOCS G-C12-FIREWALL G-C12-REAL-REGRESSION G-C12-COMPLEX-REGRESSION G-C12-PRECISION G-C12-TLS G-C12-SANITIZERS G-C12-PACKAGE-LIFECYCLE G-C12-UPSTREAM-PROVENANCE ``` All PASS: ```text C12 PASS ― REAL-COMPLEX-API-CLOSED DEPENDENCY-FREEZE-READY ``` --- # 16. Complex constructor grammar must be frozen by C12 C01 must settle a documented exact complex constructor/char grammar. Do not leave public exact complex construction dependent on an undocumented parser. If a single-string grammar is risky, prefer an explicit two-component text constructor. Correctness and round-trip safety take priority over syntactic mimicry. --- # 17. Octave differential QA Use builtin Octave complex double for structural/API semantics: ```text shape output count option parsing empty behavior transpose/ctranspose chol status qr shapes permutation representation ``` Do not use builtin double as the high-precision numerical oracle. Use MPFR/MPC and algebraic invariants for numerical gates. --- # 18. High-precision QA rule Never gate arbitrary-precision correctness only with: ```text double() 1e-12 DBL_EPSILON ``` Use: ```text p_op MPFR/MPC values dimension-scaled precision-aware bounds exact fixtures ``` --- # 19. Special values Audit throughout: ```text real +0/-0 imag +0/-0 Inf NaN ``` Require: ```text no crash no lifetime defect no precision leak documented deterministic behavior ``` Do not over-specify NaN pivot ordering. --- # 20. Empty matrices Every complex public area deliberately covers: ```text 0x0 0xN Mx0 ``` Do not assume real empty dispatch is automatically correct for complex payloads. --- # 21. Scalar normalization Where project convention normalizes 1x1 real matrix results to scalar payloads, apply the analogous complex scalar normalization consistently. Audit before assuming. --- # 22. Threading / optimized backend policy M20 identified optimized complex worker precision as high risk. For every enabled optimized complex path: ```text audit worker entry audit p_op establishment audit default temporaries ``` If only reference `libmplapack_mpfr` is tested, document that. Do not claim optimized complex support unless audited. --- # 23. Dependency modification boundary Allowed during C00-C12: ```text gmpfrxx_mkII mplapack octave-mplapack ``` only for real correctness needs of complex implementation. Forbidden: ```text octave-mplapack-ppa Debian packaging Launchpad upload PPA version strings ``` --- # 24. Upstream fix record For every upstream fix, append to `docs/complex-backends.md`: ```text Repository Problem Reproducer Topic branch Fix commit Tests First milestone requiring it ``` C12 records final tested dependency commits. D00 freezes versions/tags/archives. --- # 25. MPLAPACK 3.0.1 is the planned release version. However, do not freeze the 3.0.1 release commit/tag before the complex C00-C12 implementation has completed. If complex implementation discovers required gmpfrxx_mkII or MPLAPACK fixes, those fixes should be completed and fully regressed before the MPLAPACK 3.0.1 release commit is frozen. D00 owns the final 3.0.1 commit/tag/archive/SHA256 decision. --- # 26. Do not package gmpfrxx_mkII yet Likewise determine the exact required/fixed gmpfrxx_mkII commit through C00-C12. No Debian package/version yet. D00 will freeze: ```text gmpfrxx_mkII commit/tag/version/archive/SHA256 MPLAPACK commit/tag/version/archive/SHA256 octave-mplapack commit/version/archive/SHA256 ``` before PPA work. --- # 27. Controller progression After each milestone: ```text PASS -> commit report/status -> push if workflow permits -> continue automatically proven upstream defect -> fix upstream -> validate -> update provenance -> resume same milestone downstream defect -> fix octave-mplapack -> rerun milestone unresolved external blocker -> stop with exact BLOCKED classification ``` Do not stop merely because a test fails initially. --- # 28. Minimal user round trips Do not ask for confirmation between C00-C12. Do not ask "continue?" after PASS. Use the preferred defaults in this document when a choice is already provided. Stop only for a genuine blocker that cannot be solved with the available repositories/environment. --- # 29. Git discipline Before milestone commits: ```bash git status --short git diff --check ``` Do not stage unrelated changes. Do not commit: ```text build artifacts private credentials PPA secrets temporary prefixes ``` No force push. --- # 30. Build/dependency isolation After an upstream dependency fix: ```text rebuild/install gmpfrxx_mkII if needed rebuild/install MPLAPACK against intended gmpfrxx verify headers/pkg-config/runtime build octave-mplapack ``` Detect stale `/usr/local`, `/tmp`, or old-prefix selection. Record exact runtime identity. --- # 31. Sanitizer policy Add sanitizer coverage as native paths appear. At minimum relevant sanitizer runs at: ```text C00 C02 C05 C06 C07 C08 C09 C10 C11 C12 ``` Do not defer memory safety entirely to C12. --- # 32. Common milestone report Each report: ```text # Cxx RESULT Repository: Branch: Starting commit: Final implementation commit: Branch tip: PR: ## Dependency identity - gmpfrxx_mkII: - MPLAPACK: - pkg-config: - runtime SONAME: ## Scope - implemented: - deferred: ## Architecture ... ## Precision ... ## Public semantics ... ## Native/backend audit ... ## QA - native: - public: - 1024: - 2048: - ambient low: - ambient high: - ASan: - UBSan: - LSan: - full real regression: ## Upstream fixes ... ## Gates ... Cxx PASS / FAIL / BLOCKED ## Known limitations ... ## Recommended next action ... ``` --- # 33. C12 D00 handoff C12 final report must record: ```text REAL_V0_1_RC_COMMIT COMPLEX_START_COMMIT COMPLEX_FINAL_COMMIT gmpfrxx_mkII final tested commit MPLAPACK final tested commit octave-mplapack final tested commit all upstream fixes supported complex API unsupported complex API real regression complex regression precision regression TLS/thread regression sanitizers package lifecycle ``` D00 section: ```text gmpfrxx_mkII commit to freeze: MPLAPACK commit to freeze: octave-mplapack commit to freeze: dependency version numbers: NOT YET ― D00 Debian/PPA packaging started: NO ``` --- # 34. Master completion gate Complete only if: ```text C00 PASS C01 PASS C02 PASS C03 PASS C04 PASS C05 PASS C06 PASS C07 PASS C08 PASS C09 PASS C10 PASS C11 PASS C12 PASS ``` C11L PASS. Final: ```text COMPLEX GOAL PASS REAL-COMPLEX-API-CLOSED DEPENDENCY-FREEZE-READY ``` --- # 35. Stop after C12 Do not begin D00 automatically. Do not begin Debian/PPA packaging. Do not upload to Launchpad. Do not modify `octave-mplapack-ppa`. Do not create final dependency tags/releases. The next separate goal is: ```text D00 ― Dependency Release Freeze ``` Then: ```text PPA1-G -> PPA1-M -> PPA2 -> PPA3 -> PPA4 ``` --- # 36. Final master report Produce: ```text # COMPLEX C00-C12 RESULT REAL_V0_1_RC_COMMIT: COMPLEX_START_COMMIT: COMPLEX_FINAL_COMMIT: ## Milestones - C00: - C01: - C02: - C03: - C04: - C05: - C06: - C07: - C08: - C09: - C10: - C11: - C11L: - C12: ## Final API ... ## Final dependency development heads ### gmpfrxx_mkII - commit: - fixes: ### MPLAPACK - commit: - fixes: ### octave-mplapack - commit: - version: ## Precision contract ... ## Real regression ... ## Complex regression ... ## Sanitizers ... ## Compatibility firewall ... ## Known limitations ... ## D00 handoff ... COMPLEX GOAL PASS / FAIL / BLOCKED Release conclusion: REAL-COMPLEX-API-CLOSED / NOT-CLOSED Dependency conclusion: DEPENDENCY-FREEZE-READY / NOT-READY ``` Stop after this report. mplapack-interop-0.5.1/docs/complex-backends.md0000644000230300031750000001223515274353473020740 0ustar rafaelrafael# Complex backend provenance This file records the development dependencies used by the C00-C12 complex implementation. These are tested development commits, not final release tags. ## Tested repositories - `gmpfrxx_mkII`: `main` at `32a7fb797202cdf92312ed9d133f96fdbcda590a`; - `mplapack`: `topic/octave-mplapack-complex-mpfr-scope` at `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d`. ## Controlled installation - prefix: `/home/docker/work/complex-prefix`; - pkg-config identity: `mplapack_mpfr 3.0.1`; - headers: `mplapack/mpblas_mpfr.h`, `mplapack/mplapack_mpfr.h`, `mplapack/mplapack_utils_mpfr.h`, and the installed `mplapack/mplapack_mpfr_precision.h`; - link interface: `-lmplapack_mpfr -lmpc -lmpfr -lgmp`; - runtime library: `libmplapack_mpfr.so.3` (installed file version `libmplapack_mpfr.so.3.0.1`). The controlled C05 build uses MPFR support with the reference backend and disables GMP, QD, DD, binary80, binary128, optimized, test, and benchmark variants. MPLAPACK's public MPFR `Cgemm` declaration accepts `mpc_class` arguments and is implemented by `mpblas/reference/Cgemm.cpp`. The C06 square-solve audit confirms that the public MPFR declaration of `Cgesv` uses `mpc_class` A/B arrays and `mplapackint *ipiv`; its controlled source is `mplapack/reference/Cgesv.cpp`, which delegates to reference `Cgetrf` and `Cgetrs`. The C07 rank-revealing audit directly exercises the public MPFR declarations and controlled reference sources for `Cgelsy`, `Cgelss`, and `Cgelsd`. `Cgelsy` was selected for production because its QR-with-column-pivoting contract supplies the required rank control and minimum-norm solve with complex work plus `2*n` real workspace. `Cgelss` uses the real workspace in its SVD path, while `Cgelsd` additionally requires larger real workspace and `mplapackint` `iwork`. All workspace arrays are allocated at the operation precision, and all integer arrays use the installed `mplapackint` type. The C08 audit confirms that the installed `Cpotrf` declaration uses `mpc_class` storage and `mplapackint` dimensions/status. The controlled `mplapack/reference/Cpotrf.cpp` source uses selected-triangle Hermitian semantics through reference `Cherk`, `Cgemm`, `Ctrsm`, and `Cpotrf2`. The binding therefore does not precheck the ignored triangle, explicitly clears the non-selected output triangle, and preserves the backend's real diagonal behavior. The C09 audit confirms that the installed `Cgeqrf` and `Cungqr` declarations use `mpc_class` reflector and workspace arrays with `mplapackint` dimensions. The controlled reference sources use blocked complex Householder helpers; the binding performs precision-scoped workspace queries and invokes `Cungqr` only for two-output calls. The C10 audit confirms that the installed `Cgeqp3` declaration uses `mpc_class` factor, reflector, and complex workspace arrays, an `mplapackint*` `JPVT`, and MPFR real workspace. The controlled reference source uses the complex pivoted Householder path. The binding initializes `JPVT` to zero, validates the returned one-based permutation, maps it to the public matrix/vector forms, and reuses the precision-scoped `Cungqr` path. The C11L audit confirms that the installed `Cgetrf` declaration uses `mpc_class` factor storage, `mplapackint` dimensions/status, and an `mplapackint*` pivot array. The controlled reference implementation is `mplapack/reference/Cgetrf.cpp`. The binding replays the destructive routine's swap sequence into the public row permutation, constructs packed and canonical factors at the source precision, and retains the real M21 two-output/matrix/vector conventions. No new upstream defect was exposed by C11L. The C11 structural audit confirms that mixed concatenation copies real and complex operands directly into an MPC destination at the maximum stored MP precision. Mixed numerical operations continue to select the existing real or complex implementation from operand kind; no real-only operation is rerouted through a complex kernel. ## Upstream fixes introduced during C00-C12 ### MPLAPACK MPFR precision scope header - Repository: `mplapack`; - Problem: the public MPFR headers did not install the uniform-precision scope interface needed to establish one MPFR/MPC operation precision at complex LAPACK boundaries; - Reproducer: a clean consumer build using `pkg-config mplapack_mpfr` failed the required installed-header check for `mplapack_mpfr_precision.h`; - Topic branch: `topic/octave-mplapack-complex-mpfr-scope`; - Fix commit: `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d`; - Tests: controlled shared MPFR installation, `check-deps`, native real and complex sanitizer walls, public M01–M23+C01–C11L wall, and package install/load/unload/reinstall smoke; - First milestone requiring it: C00 complex precision scaffold. No `gmpfrxx_mkII` fix was required through C12. D04R1 uses the official 1.5.0 release interface and routes complex `log2` through `mpfrxx::log2`; the binding does not link directly to `mpc_log2`. The C00–C12 development goal did not freeze an upstream release. D04 now uses the official MPLAPACK 3.0.1 release source baseline `953d7a4916554546937a753a30b0619691072841`, tag `v3.0.1`, archive SHA256 `47ebb653b21f0c62e8144c1e515e94d76965d9d0d4b7ba216b034d778570cbaa`. mplapack-interop-0.5.1/docs/quadrature.md0000644000230300031750000000241415274353473017674 0ustar rafaelrafael# Arbitrary-precision quadrature `integral` and `quadgk` accept real MP endpoints and invoke a scalar callback with MP real arguments. A callback may return a real or complex MP scalar; builtin double or array-valued results are rejected at the boundary. The implementation is adaptive tanh-sinh (double-exponential) quadrature, using the Takahasi–Mori map ```text x = tanh((pi/2) sinh(t)) ``` and its MP derivative as the quadrature weight. `pi`, nodes, weights, interval transformations, and the successive-level error estimate are all formed as MP values. The method avoids evaluating the callback at finite interval endpoints, which covers ordinary algebraic/logarithmic endpoint singularities such as `1/sqrt(x)` and `log(x)`. Finite, semi-infinite, and two-sided infinite intervals are supported. Finite `Waypoints`, `AbsTol`, and `RelTol` are supported in a scalar options struct or name/value form. `ArrayValued` is explicitly unsupported until an MP shape-preserving reduction contract is defined; the re-entry record is [`todo/T13-array-valued-quadrature.md`](todo/T13-array-valued-quadrature.md). The public `quadgk` name is retained for compatibility, while its backend is the more endpoint-robust double-exponential rule rather than a binary64 Gauss–Kronrod table. mplapack-interop-0.5.1/docs/ppa-plan.md0000644000230300031750000000446215274353473017234 0ustar rafaelrafael# Real-only PPA handoff plan Forward user-facing package identity: `mplapack-interop`. The repository is still `octave-mplapack`; a future Debian binary package may be named `octave-mplapack-interop`, subject to the PPA policy milestone. No Debian metadata or PPA work is performed in D01R1. M20 established `REAL-PPA-GO`; complex support is not a prerequisite for the real-only release. M23 freezes the upstream candidate and records the exact source/archive handoff. No Debian upload or PPA publication is performed here. ## Planned stages | Stage | Deliverable | |---|---| | PPA1 | Debian package for the accepted MPLAPACK MPFR dependency, including the uniform-precision interface | | PPA2 | `octave-mplapack` source/binary package and autopkgtest smoke coverage | | PPA3 | Launchpad staging build and install/linkage checks | | PPA4 | Public real-only v0.1 PPA and final tag after staging | The initial target is Ubuntu 26.04 with Octave 11.1.0. Deep package QA has validated amd64; other architectures remain a source-portability goal, not a release claim. macOS packaging is separate and does not block the Ubuntu PPA. ## Package boundary proposal Names are proposals for PPA1/PPA2 policy review: ```text libmplapack-mpfr3 libmplapack-mpfr-dev octave-mplapack ``` The MPLAPACK development package must provide the pinned uniform-precision interface (including `mplapack_mpfr_precision.h`) and the MPFR library through `pkg-config`. A future runtime closure is expected to contain Octave, `libmplapack_mpfr.so.3`, MPC, MPFR, and GMP. The octave package's draft Build-Depends are `debhelper-compat`, `octave-dev`, `pkg-config`, the MPLAPACK MPFR development package, MPFR/MPC/GMP as needed or propagated, and standard C++ build tools. The public package name for future PPA policy is `octave-mplapack-interop`; the Octave package loaded by users is `mplapack-interop`. Final Debian names, symbols, shlibs, and license files belong to PPA1/PPA2. No source-tree path, temporary prefix, or Git checkout is allowed in a package build. ## Handoff blockers Before upload, PPA work must package the exact accepted MPLAPACK revision, confirm Launchpad's Octave 11.1 availability, complete amd64 build/install tests, and decide the multi-series architecture matrix. These are packaging tasks, not blockers to the real-only architecture decision. mplapack-interop-0.5.1/docs/graphics.md0000644000230300031750000000174115274353473017321 0ustar rafaelrafael# Arbitrary-precision graphics boundary T08 supports `plot3`, `scatter3`, `mesh`, `surf`, `contour3`, `meshc`, `surfc`, and `waterfall` when their data are vectors or two-dimensional matrices. The existing `mp_graphics_args` helper is the single boundary: only an `mp` data value is converted explicitly to builtin `double` for the Octave graphics API. Handles, strings, style arguments, property names, property values, and ordinary builtin numeric inputs are passed unchanged. Numerical construction and transformation must happen before this boundary. Values outside the binary64 range can become zero or infinity when displayed; users should scale or transform them in `mp` first. T08 does not add general N-dimensional storage or volume graphics such as `slice`, `isosurface`, or volume rendering. An MP-aware `meshgrid` wrapper is also deferred; see [`todo/T08-meshgrid.md`](todo/T08-meshgrid.md) and [`todo/T08-volume-graphics-after-ND.md`](todo/T08-volume-graphics-after-ND.md). mplapack-interop-0.5.1/docs/examples/0000755000230300031750000000000015274353473017012 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/examples/tiered/0000755000230300031750000000000015274353473020266 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/0000755000230300031750000000000015274353473022263 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/dd_sym.md0000644000230300031750000002341215274353473024066 0ustar rafaelrafael# Symmetric diagonally dominant path (Tier S4) ## Quick idea S4-DD-SYM isolates The smallest singular value is the tiny diagonal-dominance margin tau, while neighboring values are controlled by a path Laplacian. It is a one-case, deterministic Tier S example: the matrix is small enough to inspect, but the singular spectrum or factors expose a failure mode that a generic smoke matrix would hide. Tier S describes the requested mathematical depth; it does not claim that the public dense svd call implements the cited structured algorithm. ## Mathematical problem Smoke: $n=8$, $b=32$, $\rho=1$. Demo: $n=24$, $b=160$, $\rho=1$. The positive shift is $\tau=2^{-b}$. ```math A_{11}=1+\tau,\quad A_{12}=-1; ``` ```math A_{i,i-1}=-1,\quad A_{ii}=2+\tau,\quad A_{i,i+1}=-1,\\ A_{n,n-1}=-1,\quad A_{nn}=1+\tau. ``` The exact ascending singular values are ```math \sigma_k=\tau+4\sin^2\!\left(\frac{k\pi}{2n}\right), \qquad k=0,\ldots,n-1. ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} \frac{4294967297}{4294967296} & -1 & 0 & 0 & 0 & 0 & 0 & 0 \\ -1 & \frac{8589934593}{4294967296} & -1 & 0 & 0 & 0 & 0 & 0 \\ 0 & -1 & \frac{8589934593}{4294967296} & -1 & 0 & 0 & 0 & 0 \\ 0 & 0 & -1 & \frac{8589934593}{4294967296} & -1 & 0 & 0 & 0 \\ 0 & 0 & 0 & -1 & \frac{8589934593}{4294967296} & -1 & 0 & 0 \\ 0 & 0 & 0 & 0 & -1 & \frac{8589934593}{4294967296} & -1 & 0 \\ 0 & 0 & 0 & 0 & 0 & -1 & \frac{8589934593}{4294967296} & -1 \\ 0 & 0 & 0 & 0 & 0 & 0 & -1 & \frac{4294967297}{4294967296} \end{bmatrix}. ``` This is the full concrete smoke fixture for `S4-DD-SYM`. The matching [`dd_sym.m`](../../../../examples/tiered/svd-tier-s/dd_sym.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The smallest singular value is the tiny diagonal-dominance margin tau, while neighboring values are controlled by a path Laplacian. This makes loss of tau in a low-precision or native construction immediately visible. The symmetric case has an analytic positive-term formula, but its trigonometric evaluation is not itself an outward interval proof. The exact model, any analytic/reference construction, and measured SVD output are separate records. A convenient formula is a reference or invariant check; it is never silently substituted for the matrix sent to the public solver. ## What the Octave example computes The matching [dd_sym.m](../../../../examples/tiered/svd-tier-s/dd_sym.m) selects only S4-DD-SYM from the fixed manifest. The matching dd_sym.m constructs the path directly, runs public svd, and compares with the MP formula after setting $\sigma_0=\tau$ exactly. It reports the explicit model, any below-guard rounded input, reconstruction, orthogonality, and the smallest-value error. The demo deliberately records when $p=128$ is below the exact construction guard for $b=160$. The runner records dimensions, case parameters, input/model identity, work/reference precision, measured rows, and any native control. ## Construction and exactness Each row has dominance margin $\tau$ and the dyadic inputs are checked. For $\rho=1$, SPD and the path eigenvalue formula provide independent checks; $\pi$ and sine are evaluated in MP. A separate V1 certificate is required for rigorous enclosures. Native $\tau$ loss is logged as an altered input, not called an MP failure. The source audit distinguishes exactness of the constructed matrix from agreement between two floating computations. All arithmetic on the model and measured path remains MPFR/MPC; conversion to binary64 is limited to explicitly labelled presentation controls. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, $U$, $\Sigma$, and $V$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For repeated singular values compare the associated left/right subspaces, not individual columns. Also inspect the value-wise forward bottleneck against the exact or analytic reference, the rank/cluster diagnostic when applicable, and any inverse or projector check. Keep the residuals as MP values until display. A small reconstruction residual does not certify every singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain A. Forward singular-value error compares each returned value with the mathematical value of the stored model and depends on gaps, scaling, and conditioning. For a repeated group, the stable forward object is a subspace/projector. For rank-deficient data, an exact model rank proof is distinct from thresholding tiny measured values. ## What arbitrary precision changes Input/source precision determines whether tau is present; arithmetic precision controls construction, SVD, and formula. Mathematical conditioning is severe at the small end even in the symmetric case. More bits preserve tau and reduce solver error but cannot recover it from a pre-rounded zero. Input/source precision identifies the stored matrix and any deliberate once-rounded model. Arithmetic/work precision is the MPFR/MPC precision used by the constructor, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a singular-value tail lost in the input or make repeated factors unique. Ambient-precision and restoration tests ensure operation precision is owned by the stored operands. ## Reading the output The first singular value should equal $\tau$ in the exact model. Read its absolute and relative errors separately, because $\tau$ is tiny. A good reconstruction and orthogonality result does not compensate for a rounded input with $\tau=0$. The sorted values are the measured spectrum, not an insertion of the formula. A PASS line is scoped to the named case and profile. Compare only rows with identical parameters and model identity. If a cluster, rank, or exactness field is not claimed, do not infer it from a stable display. ## Common mistakes Do not use 2-2cos as the small-value formula, call tau loss a solver failure, use native trigonometric constants for MP reference, or claim the formula alone is a certified interval. For diagnosis, first verify case ID and shape, then model hash and input precision, then reconstruction/orthogonality, then the appropriate value or subspace metric. Do not alter parameters after seeing a failure and report the changed matrix as the original case. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Froilán M. Dopico and Plamen Koev, Perturbation theory for the LDU factorization and accurate computations for diagonally dominant matrices. Numerische Mathematik 119 (2011), 337–371. DOI: 10.1007/s00211-011-0382-3](https://doi.org/10.1007/s00211-011-0382-3) — Diagonal-dominance representation context; the path formulas here are suite adaptations. - [Netlib LAPACK, DLASQ1 documentation, current reference page](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) — A relative-accuracy bidiagonal comparator; it is not the dense SVD implementation used by this case. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology used when discussing exact dyadic inputs. The cited works provide external mathematical context. The dimensions, powers of two, acceptance thresholds, and executable implementation are suite-specific adaptations unless explicitly identified as a formula above. ## Project provenance - Runnable case: [dd_sym.m](../../../../examples/tiered/svd-tier-s/dd_sym.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope and conservative baselines: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/dd_nonsym.md0000644000230300031750000002322715274353473024605 0ustar rafaelrafael# Nonsymmetric diagonally dominant path (Tier S4) ## Quick idea S4-DD-NONSYM isolates Biasing the subdiagonal destroys symmetry while retaining diagonal dominance. It is a one-case, deterministic Tier S example: the matrix is small enough to inspect, but the singular spectrum or factors expose a failure mode that a generic smoke matrix would hide. Tier S describes the requested mathematical depth; it does not claim that the public dense svd call implements the cited structured algorithm. ## Mathematical problem Smoke: $n=8$, $b=32$, $\rho=1/2$. Demo: $n=24$, $b=160$, $\rho=1/2$. The same $\tau=2^{-b}$ margin is used. ```math A_{11}=1+\tau,\quad A_{12}=-1; ``` ```math A_{i,i-1}=-\rho,\quad A_{ii}=1+\rho+\tau,\quad A_{i,i+1}=-1, ``` with A_{n,n-1}=-rho and A_{nn}=rho+tau. The row sums show A 1 = tau 1, which is an eigenvalue relation, not a singular-value formula. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} \frac{4294967297}{4294967296} & -1 & 0 & 0 & 0 & 0 & 0 & 0 \\ -2^{-1} & \frac{6442450945}{4294967296} & -1 & 0 & 0 & 0 & 0 & 0 \\ 0 & -2^{-1} & \frac{6442450945}{4294967296} & -1 & 0 & 0 & 0 & 0 \\ 0 & 0 & -2^{-1} & \frac{6442450945}{4294967296} & -1 & 0 & 0 & 0 \\ 0 & 0 & 0 & -2^{-1} & \frac{6442450945}{4294967296} & -1 & 0 & 0 \\ 0 & 0 & 0 & 0 & -2^{-1} & \frac{6442450945}{4294967296} & -1 & 0 \\ 0 & 0 & 0 & 0 & 0 & -2^{-1} & \frac{6442450945}{4294967296} & -1 \\ 0 & 0 & 0 & 0 & 0 & 0 & -2^{-1} & \frac{2147483649}{4294967296} \end{bmatrix}. ``` This is the full concrete smoke fixture for `S4-DD-NONSYM`. The matching [`dd_nonsym.m`](../../../../examples/tiered/svd-tier-s/dd_nonsym.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult Biasing the subdiagonal destroys symmetry while retaining diagonal dominance. The constant row-sum relation gives a useful eigenvalue control but does not determine σ_min. This is a direct guard against replacing a nonsymmetric SVD problem by an eigenvalue calculation. The small tau can also disappear in a below-guard rounded input. The exact model, any analytic/reference construction, and measured SVD output are separate records. A convenient formula is a reference or invariant check; it is never silently substituted for the matrix sent to the public solver. ## What the Octave example computes The matching [dd_nonsym.m](../../../../examples/tiered/svd-tier-s/dd_nonsym.m) selects only S4-DD-NONSYM from the fixed manifest. The matching dd_nonsym.m builds the biased path, runs public svd, and compares with a high-precision dense reference. It checks row sums as an eigen diagnostic, but evaluates singular values through svd and reconstruction. The symmetric DD case is an analytic control only; its formula is not copied as the nonsymmetric answer. The runner records dimensions, case parameters, input/model identity, work/reference precision, measured rows, and any native control. ## Construction and exactness The dyadic rows and dominance margins are audited. For $\tau=0$, principal determinant recurrence explains rank $n-1$ for this path; for $\tau>0$, strict dominance proves nonsingularity. These are model facts, not replacements for measured SVD. Any $p=128$ below-guard demo input is stored and labelled as rounded. The source audit distinguishes exactness of the constructed matrix from agreement between two floating computations. All arithmetic on the model and measured path remains MPFR/MPC; conversion to binary64 is limited to explicitly labelled presentation controls. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, $U$, $\Sigma$, and $V$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For repeated singular values compare the associated left/right subspaces, not individual columns. Also inspect the value-wise forward bottleneck against the exact or analytic reference, the rank/cluster diagnostic when applicable, and any inverse or projector check. Keep the residuals as MP values until display. A small reconstruction residual does not certify every singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain A. Forward singular-value error compares each returned value with the mathematical value of the stored model and depends on gaps, scaling, and conditioning. For a repeated group, the stable forward object is a subspace/projector. For rank-deficient data, an exact model rank proof is distinct from thresholding tiny measured values. ## What arbitrary precision changes Input precision controls retention of tau and rho; arithmetic precision controls dense SVD and reference. Mathematical conditioning is affected by nonsymmetry and the small dominance margin. More bits improve the computation but cannot turn the biased matrix into the symmetric path. Input/source precision identifies the stored matrix and any deliberate once-rounded model. Arithmetic/work precision is the MPFR/MPC precision used by the constructor, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a singular-value tail lost in the input or make repeated factors unique. Ambient-precision and restoration tests ensure operation precision is owned by the stored operands. ## Reading the output Do not expect the first singular value to equal $\tau$. Read the row-sum eigen residual separately from $r_{\mathrm{svd}}$ and the smallest measured singular value. A numerical zero in a rounded input is not the exact $\tau>0$ model. Factor vectors remain phase ambiguous. A PASS line is scoped to the named case and profile. Compare only rows with identical parameters and model identity. If a cluster, rank, or exactness field is not claimed, do not infer it from a stable display. ## Common mistakes Do not assert $\sigma_{\min}=\tau$, replace svd with eig, borrow the symmetric formula, or hide a below-guard rounded input. Do not infer nonsymmetric singular values from row sums. For diagnosis, first verify case ID and shape, then model hash and input precision, then reconstruction/orthogonality, then the appropriate value or subspace metric. Do not alter parameters after seeing a failure and report the changed matrix as the original case. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Froilán M. Dopico and Plamen Koev, Perturbation theory for the LDU factorization and accurate computations for diagonally dominant matrices. Numerische Mathematik 119 (2011), 337–371. DOI: 10.1007/s00211-011-0382-3](https://doi.org/10.1007/s00211-011-0382-3) — Diagonal-dominance representation context; the path formulas here are suite adaptations. - [Netlib LAPACK, DLASQ1 documentation, current reference page](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) — A relative-accuracy bidiagonal comparator; it is not the dense SVD implementation used by this case. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology used when discussing exact dyadic inputs. The cited works provide external mathematical context. The dimensions, powers of two, acceptance thresholds, and executable implementation are suite-specific adaptations unless explicitly identified as a formula above. ## Project provenance - Runnable case: [dd_nonsym.m](../../../../examples/tiered/svd-tier-s/dd_nonsym.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope and conservative baselines: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/nro_three.md0000644000230300031750000002243215274353473024575 0ustar rafaelrafael# NRO three-level block: extreme and unit singular groups (Tier S1) ## Quick idea S1-NRO-THREE isolates This variant adds a true unit group to the extreme reciprocal groups. It is a one-case, deterministic Tier S example: the matrix is small enough to inspect, but the singular spectrum or factors expose a failure mode that a generic smoke matrix would hide. Tier S describes the requested mathematical depth; it does not claim that the public dense svd call implements the cited structured algorithm. ## Mathematical problem Smoke: $m=4$, $b=12$. Demo: $m=16$, $b=40$. The first half of the weights are $2^b$ and the second half are zero. ```math B=H_m\mathrm{diag}(2^b,\ldots,2^b,0,\ldots,0), \qquad A=\begin{bmatrix}I_m&B\\0&I_m\end{bmatrix}. ``` For a nonzero weight the pair is $(a_j,b_j)$ above; for $w_j=0$, $\beta_j=0$ and both singular values are exactly 1. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 0 & 0 & 0 & 4096 & 4096 & 0 & 0 \\ 0 & 1 & 0 & 0 & 4096 & -4096 & 0 & 0 \\ 0 & 0 & 1 & 0 & 4096 & 4096 & 0 & 0 \\ 0 & 0 & 0 & 1 & 4096 & -4096 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `S1-NRO-THREE`. The matching [`nro_three.m`](../../../../examples/tiered/svd-tier-s/nro_three.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult This variant adds a true unit group to the extreme reciprocal groups. It checks whether a solver and its matching logic preserve multiplicity rather than treating the middle values as accidental. The matrix remains nonsingular even though B is rank deficient, because A is block unit triangular. Individual singular vectors in the unit group are not identifiable; the correct comparison is a subspace/projector comparison. The exact model, any analytic/reference construction, and measured SVD output are separate records. A convenient formula is a reference or invariant check; it is never silently substituted for the matrix sent to the public solver. ## What the Octave example computes The matching [nro_three.m](../../../../examples/tiered/svd-tier-s/nro_three.m) selects only S1-NRO-THREE from the fixed manifest. The matching nro_three.m selects the three-level case, measures the complete 2m singular spectrum, checks the exact inverse and reconstruction, and compares the unit group as a cluster. It records the expected number of unit singular values separately from the extreme group. No known singular values are inserted into measured output. The runner records dimensions, case parameters, input/model identity, work/reference precision, measured rows, and any native control. ## Construction and exactness The zero weights are represented exactly, the Hadamard entries are integer, and the inverse identity is checked directly. The stable two-by-two formula gives $a=b=1$ when $\beta=0$; this is an analytic reference, not an SVD shortcut. The exact rank of $B$ and full rank of $A$ are checked separately. The source audit distinguishes exactness of the constructed matrix from agreement between two floating computations. All arithmetic on the model and measured path remains MPFR/MPC; conversion to binary64 is limited to explicitly labelled presentation controls. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, $U$, $\Sigma$, and $V$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For repeated singular values compare the associated left/right subspaces, not individual columns. Also inspect the value-wise forward bottleneck against the exact or analytic reference, the rank/cluster diagnostic when applicable, and any inverse or projector check. Keep the residuals as MP values until display. A small reconstruction residual does not certify every singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain A. Forward singular-value error compares each returned value with the mathematical value of the stored model and depends on gaps, scaling, and conditioning. For a repeated group, the stable forward object is a subspace/projector. For rank-deficient data, an exact model rank proof is distinct from thresholding tiny measured values. ## What arbitrary precision changes Input precision records the zero/nonzero dyadic weights. Arithmetic precision controls dense construction and the SVD. Mathematical conditioning is determined by the extreme beta values, while the unit cluster has multiplicity and basis nonuniqueness. More bits should protect the extreme values but cannot make a repeated factor basis unique. Input/source precision identifies the stored matrix and any deliberate once-rounded model. Arithmetic/work precision is the MPFR/MPC precision used by the constructor, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a singular-value tail lost in the input or make repeated factors unique. Ambient-precision and restoration tests ensure operation precision is owned by the stored operands. ## Reading the output Expect a reciprocal extreme group plus a repeated unit group. $r_{\mathrm{svd}}$ and factor orthogonality describe the computed factors; a projector or subspace metric describes the repeated unit group. Sorting is done only in the reference and does not impose a basis order on the returned factors. A PASS line is scoped to the named case and profile. Compare only rows with identical parameters and model identity. If a cluster, rank, or exactness field is not claimed, do not infer it from a stable display. ## Common mistakes Do not interpret rank(B)=m/2 as rank(A)<2m, compare unit singular vectors one by one, or append known ones to the measured spectrum. Do not cancel the small reciprocal values. For diagnosis, first verify case ID and shape, then model hash and input precision, then reconstruction/orthogonality, then the appropriate value or subspace metric. Do not alter parameters after seeing a failure and report the changed matrix as the original case. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Tetsuo Nishi, Siegfried M. Rump, and Shin'ichi Oishi, On the generation of very ill-conditioned integer matrices. Nonlinear Theory and Its Applications, IEICE 2(2) (2011), 226–245. DOI: 10.1587/nolta.2.226](https://doi.org/10.1587/nolta.2.226) — The block family and bounded-integer motivation; the chosen dimensions are suite fixtures. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology used when discussing exact dyadic inputs. The cited works provide external mathematical context. The dimensions, powers of two, acceptance thresholds, and executable implementation are suite-specific adaptations unless explicitly identified as a formula above. ## Project provenance - Runnable case: [nro_three.m](../../../../examples/tiered/svd-tier-s/nro_three.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope and conservative baselines: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/nro_two.md0000644000230300031750000002323715274353473024303 0ustar rafaelrafael# NRO two-level block: reciprocal singular groups (Tier S1) ## Quick idea S1-NRO-TWO isolates The input is integer/dyadic and full rank, but the off-diagonal block makes reciprocal singular values as large and small as beta. It is a one-case, deterministic Tier S example: the matrix is small enough to inspect, but the singular spectrum or factors expose a failure mode that a generic smoke matrix would hide. Tier S describes the requested mathematical depth; it does not claim that the public dense svd call implements the cited structured algorithm. ## Mathematical problem Smoke: $m=4$, $b=12$, giving a $2m=8$ square matrix. Demo: $m=16$, $b=40$, giving a 32-by-32 matrix. ```math B=H_m\mathrm{diag}(w_1,\ldots,w_m),\qquad A=\begin{bmatrix}I_m&B\\0&I_m\end{bmatrix},\qquad w_j=2^b. ``` With $\beta_j=\sqrt{m}\,w_j$, the two singular values contributed by each block are ```math a_j=\frac{\sqrt{\beta_j^2+4}+\beta_j}{2},\qquad b_j=\frac{2}{\sqrt{\beta_j^2+4}+\beta_j}. ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 0 & 0 & 0 & 4096 & 4096 & 4096 & 4096 \\ 0 & 1 & 0 & 0 & 4096 & -4096 & 4096 & -4096 \\ 0 & 0 & 1 & 0 & 4096 & 4096 & -4096 & -4096 \\ 0 & 0 & 0 & 1 & 4096 & -4096 & -4096 & 4096 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `S1-NRO-TWO`. The matching [`nro_two.m`](../../../../examples/tiered/svd-tier-s/nro_two.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The input is integer/dyadic and full rank, but the off-diagonal block makes reciprocal singular values as large and small as beta. Orthogonal reduction shows the spectrum exactly, while a dense SVD must still materialize A and compute factors. The small value must be evaluated by the reciprocal formula; subtracting nearly equal square roots would create an avoidable loss. The demo reaches a large condition range without asking native arithmetic to fail. The exact model, any analytic/reference construction, and measured SVD output are separate records. A convenient formula is a reference or invariant check; it is never silently substituted for the matrix sent to the public solver. ## What the Octave example computes The matching [nro_two.m](../../../../examples/tiered/svd-tier-s/nro_two.m) selects only S1-NRO-TWO from the fixed manifest. The matching nro_two.m selects S1-NRO-TWO, builds the block through the public MP path, runs svd(A), and compares sorted values with the stable two-by-two reference. It checks A times the explicit inverse formula, reconstruction, and factor orthogonality. The inverse formula is a construction invariant, not a replacement for the measured SVD. The runner records dimensions, case parameters, input/model identity, work/reference precision, measured rows, and any native control. ## Construction and exactness $H_m$ is generated with integer entries and the block inverse is ```math \begin{bmatrix} I & -B\\ 0 & I \end{bmatrix}. ``` The generator records the significand/range guard and verifies $\det(A)=1$ and every dyadic entry. The singular reference follows from applying orthogonal factors to $B$, not from forming $A^{\mathsf H}A$. Exactness is checked independently of the returned factors. The source audit distinguishes exactness of the constructed matrix from agreement between two floating computations. All arithmetic on the model and measured path remains MPFR/MPC; conversion to binary64 is limited to explicitly labelled presentation controls. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, $U$, $\Sigma$, and $V$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For repeated singular values compare the associated left/right subspaces, not individual columns. Also inspect the value-wise forward bottleneck against the exact or analytic reference, the rank/cluster diagnostic when applicable, and any inverse or projector check. Keep the residuals as MP values until display. A small reconstruction residual does not certify every singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain A. Forward singular-value error compares each returned value with the mathematical value of the stored model and depends on gaps, scaling, and conditioning. For a repeated group, the stable forward object is a subspace/projector. For rank-deficient data, an exact model rank proof is distinct from thresholding tiny measured values. ## What arbitrary precision changes The source/input values are exact dyadics at the selected m,b. Work precision controls B, A, svd, and the stable beta formula; mathematical conditioning is approximately the square of beta across the reciprocal pair. More bits preserve the small singular value but do not reduce the condition number. The scaled demo remains the same named model at every work precision. Input/source precision identifies the stored matrix and any deliberate once-rounded model. Arithmetic/work precision is the MPFR/MPC precision used by the constructor, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a singular-value tail lost in the input or make repeated factors unique. Ambient-precision and restoration tests ensure operation precision is owned by the stored operands. ## Reading the output Read the largest and smallest singular values as a reciprocal pair, then inspect $r_{\mathrm{svd}}$ and the two orthogonality residuals. A good reconstruction can coexist with a poor relative error in the smallest value when its condition is extreme. The factor columns are not required to match a particular Hadamard basis when values are repeated. A PASS line is scoped to the named case and profile. Compare only rows with identical parameters and model identity. If a cluster, rank, or exactness field is not claimed, do not infer it from a stable display. ## Common mistakes Do not form $A^{\mathsf H}A$ as the primary SVD algorithm, use cancellation for the small value, compare individual repeated vectors, or claim native failure is required. Do not turn the inverse invariant into a measured SVD result. For diagnosis, first verify case ID and shape, then model hash and input precision, then reconstruction/orthogonality, then the appropriate value or subspace metric. Do not alter parameters after seeing a failure and report the changed matrix as the original case. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Tetsuo Nishi, Siegfried M. Rump, and Shin'ichi Oishi, On the generation of very ill-conditioned integer matrices. Nonlinear Theory and Its Applications, IEICE 2(2) (2011), 226–245. DOI: 10.1587/nolta.2.226](https://doi.org/10.1587/nolta.2.226) — The block family and bounded-integer motivation; the chosen dimensions are suite fixtures. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology used when discussing exact dyadic inputs. The cited works provide external mathematical context. The dimensions, powers of two, acceptance thresholds, and executable implementation are suite-specific adaptations unless explicitly identified as a formula above. ## Project provenance - Runnable case: [nro_two.m](../../../../examples/tiered/svd-tier-s/nro_two.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope and conservative baselines: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/nro_scale_down.md0000644000230300031750000001613115274353473025603 0ustar rafaelrafael# NRO scale-down control (Tier S1) ## Quick idea S1-NRO-SCALE-DOWN is the underflow-boundary companion to the NRO two-level matrix. It keeps the exact block construction and makes the entire matrix smaller by a dyadic factor $2^{-600}$. The question is whether a genuine MP path preserves scale and factor identities without silently converting the result to binary64. ## Mathematical problem The demo uses $m=16$, $b=40$, and scale exponent $s=-600$. Let $H_m$ be a Sylvester Hadamard matrix and $B=H_m\mathrm{diag}(2^b)$. The unscaled block is ```math A_0=\begin{bmatrix}I_m&B\\0&I_m\end{bmatrix},\qquad A=2^s A_0. ``` The singular values of $A$ are $2^s$ times the reciprocal pairs generated by $\beta=\sqrt{m}\,2^b$: ```math a=\frac{\sqrt{\beta^2+4}+\beta}{2},\qquad b_{\mathrm{small}}=\frac{2}{\sqrt{\beta^2+4}+\beta}. ``` ## Why this problem is numerically difficult A large scale stresses exponent range and norm calculations while preserving an exact dyadic model. It is not the same as merely printing a large number after a binary64 computation. The matrix must be built, factorized, and reconstructed at a precision that retains the scale; overflow or a hidden conversion changes the measured problem. The reciprocal pair is still ill-conditioned, so range safety and forward accuracy are separate questions. ## What the Octave example computes The matching [nro_scale_down.m](../../../../examples/tiered/svd-tier-s/nro_scale_down.m) selects the demo scale-down case and runs public svd on the scaled dense matrix. It records the scale exponent, checks the block inverse relation after scaling, compares all singular values with the scaled analytic reference, and checks reconstruction and unitarity. It does not rescale the measured result into binary64 before computing diagnostics. ## Construction and exactness The Hadamard entries, $2^b$ block, and $2^{-600}$ scale are exact dyadics in the intended MP range. The constructor verifies the source hash and the scaling identity $A=2^{-600}A_0$. The stable reciprocal expression is used for the small values. An exactness proof checks the block inverse and dyadic range guard independently of SVD. ## Diagnostics For the measured $A=U\Sigma V^{\mathsf H}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` Report absolute scale, relative singular-value error, and whether any norm operation overflowed or underflowed. ## Backward error versus forward error $r_{\mathrm{svd}}$ measures a factorization equation defect relative to the stored scaled matrix. Forward error in the smallest singular value is affected by the reciprocal condition number and by scaling. A small relative reconstruction residual is not a proof that the small pair has its displayed digits. ## What arbitrary precision changes The input/source precision is the exact dyadic scale-down model. Arithmetic/work precision provides the exponent range and significand needed for the scaled products and SVD. Mathematical conditioning remains that of the unscaled NRO pair; multiplication by $2^{-600}$ changes units, not the relative condition. More bits protect the range and tail but do not make the reciprocal pair well-conditioned. ## Parameter boundary and comparison protocol The scale exponent is part of the model identity. Keep the unscaled A0, the scaled A, the scale exponent, and the scaled reference values in separate records. Compare relative quantities only after the scale has been accounted for; a binary64 presentation can make a perfectly valid MP value look ordinary while hiding whether the computation ever represented its exponent. The runner must therefore perform norms, reconstruction, and value matching before any optional display conversion. This is a range control, not a request to weaken the acceptance threshold. If an intermediate overflows, underflows, or loses a dyadic scale, record the exact operation and the changed value. A run that succeeds after silently rescaling the input is a different experiment. Conversely, a stable scaled result does not prove that the reciprocal NRO pair is well conditioned. The useful conclusion is narrower: the public MP path preserved the declared scale and satisfied its factorization checks. ## Reading the output Confirm the scale exponent and source hash first. Then inspect whether the largest value, smallest value, and reciprocal relation survived. A PASS requires reconstruction, unitarity, spectrum matching, and range checks. A binary64 display of a final result is presentation only and must not be used to claim the computation was binary64. ## Common mistakes Do not multiply by $2^{600}$ before measuring and call the result the original run, use $A^{\mathsf H}A$ as the primary path, use cancellation for the small value, or infer range safety from a finite display. Do not treat a range failure as evidence that the mathematical model is wrong. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## Range-specific interpretation The scale-down row is useful only when the reported norms are computed in the same MP range as the matrix. The smallest entries and singular values must remain distinguishable from an underflowed zero. Record exponent-range checks for inputs, intermediate products, norms, and reconstruction separately. A finite output after an implicit up-scale is not evidence for this case. The scale factor changes units, while the relative condition of the NRO block is unchanged. ## References - [Tetsuo Nishi, Siegfried M. Rump, and Shin'ichi Oishi, “On the generation of very ill-conditioned integer matrices.” Nonlinear Theory and Its Applications, IEICE 2(2) (2011), 226–245. DOI: 10.1587/nolta.2.226](https://doi.org/10.1587/nolta.2.226) — The block family and controlled ill-conditioning context; this scale is a suite control. - [GNU MPFR project, MPFR 4.2 manual](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct rounding and exponent-range terminology. ## Project provenance - Runnable case: [nro_scale_down.m](../../../../examples/tiered/svd-tier-s/nro_scale_down.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - The family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/nro_graded.md0000644000230300031750000002244315274353473024716 0ustar rafaelrafael# NRO graded block: geometric singular scales (Tier S1) ## Quick idea S1-NRO-GRADED isolates The graded weights test a spectrum with several scales rather than only one extreme. It is a one-case, deterministic Tier S example: the matrix is small enough to inspect, but the singular spectrum or factors expose a failure mode that a generic smoke matrix would hide. Tier S describes the requested mathematical depth; it does not claim that the public dense svd call implements the cited structured algorithm. ## Mathematical problem Smoke: $m=4$, $g=4$. Demo: $m=16$, $g=3$. The weights are $w_j=2^{g(j-1)}$. ```math B=H_m\mathrm{diag}\!\left(2^{g(j-1)}\right),\qquad A=\begin{bmatrix}I_m&B\\0&I_m\end{bmatrix}. ``` Each $\beta_j=\sqrt{m}\,2^{g(j-1)}$ produces a reciprocal pair $a_j$ and $b_j$, so the singular values span multiple exact powers of two before the square-root transformation. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 0 & 0 & 0 & 1 & 16 & 256 & 4096 \\ 0 & 1 & 0 & 0 & 1 & -16 & 256 & -4096 \\ 0 & 0 & 1 & 0 & 1 & 16 & -256 & -4096 \\ 0 & 0 & 0 & 1 & 1 & -16 & -256 & 4096 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `S1-NRO-GRADED`. The matching [`nro_graded.m`](../../../../examples/tiered/svd-tier-s/nro_graded.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The graded weights test a spectrum with several scales rather than only one extreme. The matrix entries remain powers of two, but the singular values are algebraic expressions with different magnitudes, making sorting and relative comparisons important. A single normwise reconstruction residual can hide one lost small group. The chosen m is a power of four so the Sylvester Hadamard construction is exact and deterministic. The exact model, any analytic/reference construction, and measured SVD output are separate records. A convenient formula is a reference or invariant check; it is never silently substituted for the matrix sent to the public solver. ## What the Octave example computes The matching [nro_graded.m](../../../../examples/tiered/svd-tier-s/nro_graded.m) selects only S1-NRO-GRADED from the fixed manifest. The matching nro_graded.m builds the graded B and dense A, runs public svd, and reports all pairs after a bijective MP match. It checks the inverse identity, the sorted reference spectrum, reconstruction, and factor unitarity. The demo is the broad dynamic-range control; it is not a claim that the source paper’s published table is reproduced. The runner records dimensions, case parameters, input/model identity, work/reference precision, measured rows, and any native control. ## Construction and exactness Weights and Hadamard entries are exact under the declared guard. The reference uses beta_j and the cancellation-safe reciprocal expression independently for each j. The block inverse and determinant are checked before SVD. Cross-precision equality does not replace the exact power-of-two audit. The source audit distinguishes exactness of the constructed matrix from agreement between two floating computations. All arithmetic on the model and measured path remains MPFR/MPC; conversion to binary64 is limited to explicitly labelled presentation controls. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, $U$, $\Sigma$, and $V$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For repeated singular values compare the associated left/right subspaces, not individual columns. Also inspect the value-wise forward bottleneck against the exact or analytic reference, the rank/cluster diagnostic when applicable, and any inverse or projector check. Keep the residuals as MP values until display. A small reconstruction residual does not certify every singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain A. Forward singular-value error compares each returned value with the mathematical value of the stored model and depends on gaps, scaling, and conditioning. For a repeated group, the stable forward object is a subspace/projector. For rank-deficient data, an exact model rank proof is distinct from thresholding tiny measured values. ## What arbitrary precision changes Input/source precision is exact dyadic. Work precision controls each pair and the dense SVD; mathematical conditioning varies geometrically with j and g. More bits improve the smallest groups only if the input and reference remain unchanged. The generator is not regenerated from the solve precision. Input/source precision identifies the stored matrix and any deliberate once-rounded model. Arithmetic/work precision is the MPFR/MPC precision used by the constructor, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a singular-value tail lost in the input or make repeated factors unique. Ambient-precision and restoration tests ensure operation precision is owned by the stored operands. ## Reading the output Inspect pairwise reciprocal structure, per-value relative error, $r_{\mathrm{svd}}$, and the count of all $2m$ values. A stable global residual does not prove the smallest group has the requested relative digits. Factor phases and order are arbitrary. A PASS line is scoped to the named case and profile. Compare only rows with identical parameters and model identity. If a cluster, rank, or exactness field is not claimed, do not infer it from a stable display. ## Common mistakes Do not use one absolute tolerance for every scale, sort factors by raw columns, form $A^{\mathsf H}A$, or assume a geometric input makes geometric singular values. Do not claim dense SVD has become a structured bidiagonal algorithm. For diagnosis, first verify case ID and shape, then model hash and input precision, then reconstruction/orthogonality, then the appropriate value or subspace metric. Do not alter parameters after seeing a failure and report the changed matrix as the original case. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Tetsuo Nishi, Siegfried M. Rump, and Shin'ichi Oishi, On the generation of very ill-conditioned integer matrices. Nonlinear Theory and Its Applications, IEICE 2(2) (2011), 226–245. DOI: 10.1587/nolta.2.226](https://doi.org/10.1587/nolta.2.226) — The block family and bounded-integer motivation; the chosen dimensions are suite fixtures. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology used when discussing exact dyadic inputs. The cited works provide external mathematical context. The dimensions, powers of two, acceptance thresholds, and executable implementation are suite-specific adaptations unless explicitly identified as a formula above. ## Project provenance - Runnable case: [nro_graded.m](../../../../examples/tiered/svd-tier-s/nro_graded.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope and conservative baselines: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/nro_scale_up.md0000644000230300031750000001615715274353473025270 0ustar rafaelrafael# NRO scale-up control (Tier S1) ## Quick idea S1-NRO-SCALE-UP is the range stress companion to the NRO two-level matrix. It keeps the exact block construction and makes the entire matrix larger by a dyadic factor $2^{600}$. The question is whether a genuine MP path preserves scale and factor identities without silently converting the result to binary64. ## Mathematical problem The demo uses $m=16$, $b=40$, and scale exponent $s=600$. Let $H_m$ be a Sylvester Hadamard matrix and $B=H_m\mathrm{diag}(2^b)$. The unscaled block is ```math A_0=\begin{bmatrix}I_m&B\\0&I_m\end{bmatrix},\qquad A=2^s A_0. ``` The singular values of $A$ are $2^s$ times the reciprocal pairs generated by $\beta=\sqrt{m}\,2^b$: ```math a=\frac{\sqrt{\beta^2+4}+\beta}{2},\qquad b_{\mathrm{small}}=\frac{2}{\sqrt{\beta^2+4}+\beta}. ``` ## Why this problem is numerically difficult A large scale stresses exponent range and norm calculations while preserving an exact dyadic model. It is not the same as merely printing a large number after a binary64 computation. The matrix must be built, factorized, and reconstructed at a precision that retains the scale; overflow or a hidden conversion changes the measured problem. The reciprocal pair is still ill-conditioned, so range safety and forward accuracy are separate questions. ## What the Octave example computes The matching [nro_scale_up.m](../../../../examples/tiered/svd-tier-s/nro_scale_up.m) selects the demo scale-up case and runs public svd on the scaled dense matrix. It records the scale exponent, checks the block inverse relation after scaling, compares all singular values with the scaled analytic reference, and checks reconstruction and unitarity. It does not rescale the measured result into binary64 before computing diagnostics. ## Construction and exactness The Hadamard entries, $2^b$ block, and $2^{600}$ scale are exact dyadics in the intended MP range. The constructor verifies the source hash and the scaling identity $A=2^{600}A_0$. The stable reciprocal expression is used for the small values. An exactness proof checks the block inverse and dyadic range guard independently of SVD. ## Diagnostics For the measured $A=U\Sigma V^{\mathsf H}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` Report absolute scale, relative singular-value error, and whether any norm operation overflowed or underflowed. ## Backward error versus forward error $r_{\mathrm{svd}}$ measures a factorization equation defect relative to the stored scaled matrix. Forward error in the smallest singular value is affected by the reciprocal condition number and by scaling. A small relative reconstruction residual is not a proof that the small pair has its displayed digits. ## What arbitrary precision changes The input/source precision is the exact dyadic scale-up model. Arithmetic/work precision provides the exponent range and significand needed for the scaled products and SVD. Mathematical conditioning remains that of the unscaled NRO pair; multiplication by $2^{600}$ changes units, not the relative condition. More bits protect the range and tail but do not make the reciprocal pair well-conditioned. ## Parameter boundary and comparison protocol The scale exponent is part of the model identity. Keep the unscaled A0, the scaled A, the scale exponent, and the scaled reference values in separate records. Compare relative quantities only after the scale has been accounted for; a binary64 presentation can make a perfectly valid MP value look ordinary while hiding whether the computation ever represented its exponent. The runner must therefore perform norms, reconstruction, and value matching before any optional display conversion. This is a range control, not a request to weaken the acceptance threshold. If an intermediate overflows, underflows, or loses a dyadic scale, record the exact operation and the changed value. A run that succeeds after silently rescaling the input is a different experiment. Conversely, a stable scaled result does not prove that the reciprocal NRO pair is well conditioned. The useful conclusion is narrower: the public MP path preserved the declared scale and satisfied its factorization checks. ## Reading the output Confirm the scale exponent and source hash first. Then inspect whether the largest value, smallest value, and reciprocal relation survived. A PASS requires reconstruction, unitarity, spectrum matching, and range checks. A binary64 display of a final result is presentation only and must not be used to claim the computation was binary64. ## Common mistakes Do not divide by $2^{600}$ before measuring and call the result the original run, use $A^{\mathsf H}A$ as the primary path, use cancellation for the small value, or infer range safety from a finite display. Do not treat a range failure as evidence that the mathematical model is wrong. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## Range-specific interpretation The scale-up row is useful only when the reported norms are computed in the same MP range as the matrix. The largest singular value may be large while the smallest member of the reciprocal pair is still representable; both must be retained in the report. Record exponent-range checks for inputs, intermediate products, norms, and reconstruction separately. A finite output after an implicit rescale is not evidence for this case. The scale factor changes units, while the relative condition of the NRO block is unchanged. ## References - [Tetsuo Nishi, Siegfried M. Rump, and Shin'ichi Oishi, “On the generation of very ill-conditioned integer matrices.” Nonlinear Theory and Its Applications, IEICE 2(2) (2011), 226–245. DOI: 10.1587/nolta.2.226](https://doi.org/10.1587/nolta.2.226) — The block family and controlled ill-conditioning context; this scale is a suite control. - [GNU MPFR project, MPFR 4.2 manual](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct rounding and exponent-range terminology. ## Project provenance - Runnable case: [nro_scale_up.m](../../../../examples/tiered/svd-tier-s/nro_scale_up.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - The family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/README.md0000644000230300031750000001121215274353473023537 0ustar rafaelrafael# Singular value decompositions — Tier S Tier S is the SVD learning path for matrices whose singular values, subspaces, or exponent ranges defeat a residual-only reading. The NRO family begins with exact integer block matrices, Jacobi–Stirling and Lah cases exercise combinatorial growth, and the diagonally dominant pair separates an analytic symmetric tail from a genuinely nonsymmetric SVD. The detailed pages print every small smoke matrix in full with exact integer or dyadic entries. The source/model matrix, fixed-generation precision, any exact widening, and the measured SVD output are kept as distinct objects; the exact matrix audit is `tools/check-smoke-matrices.sh`. ## Core equation For $A\in\mathbb{C}^{m\times n}$, the measured factorization is ```math A=U\Sigma V^{\mathsf H}. ``` Use ```math r_{\mathrm{svd}}= \frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\qquad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` A small reconstruction residual is a backward-style factorization check. Forward singular-value error depends on scale and gaps; repeated groups require subspace/projector comparisons. ## Learning map | Case | Mathematical object | Main question | Start here | Detailed page | External primary context | |---|---|---|---|---|---| | S1-NRO-TWO | NRO block with all weights $w=2^b$ | reciprocal extreme values | [nro_two.m](../../../../examples/tiered/svd-tier-s/nro_two.m) | [nro_two.md](./nro_two.md) | [Nishi–Rump–Oishi (2011)](https://doi.org/10.1587/nolta.2.226) | | S1-NRO-THREE | same block with zero-weight half | unit and reciprocal groups | [nro_three.m](../../../../examples/tiered/svd-tier-s/nro_three.m) | [nro_three.md](./nro_three.md) | [Nishi–Rump–Oishi (2011)](https://doi.org/10.1587/nolta.2.226) | | S1-NRO-GRADED | powers-of-two graded w_j | several singular scales | [nro_graded.m](../../../../examples/tiered/svd-tier-s/nro_graded.m) | [nro_graded.md](./nro_graded.md) | [Nishi–Rump–Oishi (2011)](https://doi.org/10.1587/nolta.2.226) | | S1-NRO-SCALE-UP | $2^{600}$ times NRO block | large exponent range | [nro_scale_up.m](../../../../examples/tiered/svd-tier-s/nro_scale_up.m) | [nro_scale_up.md](./nro_scale_up.md) | [MPFR manual](https://www.mpfr.org/mpfr-current/mpfr.html) | | S1-NRO-SCALE-DOWN | $2^{-600}$ times NRO block | small exponent range | [nro_scale_down.m](../../../../examples/tiered/svd-tier-s/nro_scale_down.m) | [nro_scale_down.md](./nro_scale_down.md) | [MPFR manual](https://www.mpfr.org/mpfr-current/mpfr.html) | | S2-JS | Jacobi–Stirling unit lower triangle | combinatorial growth | [jacobi_stirling.m](../../../../examples/tiered/svd-tier-s/jacobi_stirling.m) | [jacobi_stirling.md](./jacobi_stirling.md) | [Delgado–Peña (2014)](https://doi.org/10.1016/j.amc.2014.03.047) | | S3-LAH | unsigned Lah lower triangle | growth and small tail | [lah.m](../../../../examples/tiered/svd-tier-s/lah.m) | [lah.md](./lah.md) | [Delgado–Orera–Peña (2019)](https://doi.org/10.1002/nla.2217) | | S4-DD-SYM | symmetric shifted path | exact tiny $\sigma_{\min}$ | [dd_sym.m](../../../../examples/tiered/svd-tier-s/dd_sym.m) | [dd_sym.md](./dd_sym.md) | [Dopico–Koev (2011)](https://doi.org/10.1007/s00211-011-0382-3) | | S4-DD-NONSYM | biased diagonally dominant path | eigenvalue is not $\sigma_{\min}$ | [dd_nonsym.m](../../../../examples/tiered/svd-tier-s/dd_nonsym.m) | [dd_nonsym.md](./dd_nonsym.md) | [Dopico–Koev (2011)](https://doi.org/10.1007/s00211-011-0382-3) | The source papers motivate the families. The selected dimensions, dyadic values, exactness guards, and SVD acceptance thresholds are suite-specific. ## How to run ~~~octave pkg load mplapack-interop run ("examples/tiered/svd-tier-s/nro_two.m"); ~~~ For counted coverage: ~~~octave pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "svd_tiers")); result = mp_svd_tiers ("smoke", struct ("tier", "S", "plot", false)); ~~~ The smoke profile has seven Tier S cases and the demo adds the scale-up, scale-down, and complex controls. Keep the analytic or exact reference separate from the measured U, Sigma, and V. ## Suggested order Start with NRO-TWO, then NRO-THREE and NRO-GRADED. Use the scale controls to learn input range versus arithmetic precision. Read Jacobi–Stirling and Lah for combinatorial growth, then compare the symmetric and nonsymmetric DD paths. The distinction between input loss, solver error, and mathematical conditioning should be explicit in every report. See the [master map](../README.md), [SVT cases](../../../../docs/codex/svt/cases.json), [SVT verification limits](../../../../docs/codex/svt/VERIFICATION.md), and [SVT sources](../../../../docs/codex/svt/SOURCES.md). mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/jacobi_stirling.md0000644000230300031750000002222115274353473025746 0ustar rafaelrafael# Jacobi–Stirling second-kind matrix (Tier S2) ## Quick idea S2-JS isolates The entries grow combinatorially while the diagonal remains one. It is a one-case, deterministic Tier S example: the matrix is small enough to inspect, but the singular spectrum or factors expose a failure mode that a generic smoke matrix would hide. Tier S describes the requested mathematical depth; it does not claim that the public dense svd call implements the cited structured algorithm. ## Mathematical problem Smoke: $n=8$ and $z=1$. Demo: $n=16$ and $z=1$. Indices $i,j$ are zero-based in the recurrence. ```math J(0,0)=1,\qquad J(i,j)=J(i-1,j-1)+j(j+1)J(i-1,j),\qquad 1\le j\le i. ``` The matrix is lower triangular with unit diagonal; its leading rows are [1], [0 1], [0 2 1], [0 4 8 1]. Therefore det(J)=1. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 2 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 4 & 8 & 1 & 0 & 0 & 0 & 0 \\ 0 & 8 & 52 & 20 & 1 & 0 & 0 & 0 \\ 0 & 16 & 320 & 292 & 40 & 1 & 0 & 0 \\ 0 & 32 & 1936 & 3824 & 1092 & 70 & 1 & 0 \\ 0 & 64 & 11648 & 47824 & 25664 & 3192 & 112 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `S2-JS`. The matching [`jacobi_stirling.m`](../../../../examples/tiered/svd-tier-s/jacobi_stirling.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The entries grow combinatorially while the diagonal remains one. A rounded lower-triangular input can still have full rank but a materially different small singular spectrum. The structural zero pattern also makes the phrase totally positive unsafe if it means every minor is strictly positive; the appropriate nonnegative terminology is part of the documentation. The exact model, any analytic/reference construction, and measured SVD output are separate records. A convenient formula is a reference or invariant check; it is never silently substituted for the matrix sent to the public solver. ## What the Octave example computes The matching [jacobi_stirling.m](../../../../examples/tiered/svd-tier-s/jacobi_stirling.m) selects only S2-JS from the fixed manifest. The matching jacobi_stirling.m generates the integer recurrence in MP, runs public svd, and compares the complete spectrum with a high-precision reference. It checks unit diagonal, lower-triangular structure, determinant, small known rows, reconstruction, and factor orthogonality. The SVD call is dense; it is not advertised as an implementation of the paper’s structured bidiagonal-factor method. The runner records dimensions, case parameters, input/model identity, work/reference precision, measured rows, and any native control. ## Construction and exactness The recurrence is evaluated with an explicit conservative bit budget and row-sum bound. $n=1$ and small rows are checked independently. The exact matrix is serialized before the SVD and reconstructed at a wider precision to distinguish source exactness from solver agreement. The source audit distinguishes exactness of the constructed matrix from agreement between two floating computations. All arithmetic on the model and measured path remains MPFR/MPC; conversion to binary64 is limited to explicitly labelled presentation controls. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, $U$, $\Sigma$, and $V$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For repeated singular values compare the associated left/right subspaces, not individual columns. Also inspect the value-wise forward bottleneck against the exact or analytic reference, the rank/cluster diagnostic when applicable, and any inverse or projector check. Keep the residuals as MP values until display. A small reconstruction residual does not certify every singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain A. Forward singular-value error compares each returned value with the mathematical value of the stored model and depends on gaps, scaling, and conditioning. For a repeated group, the stable forward object is a subspace/projector. For rank-deficient data, an exact model rank proof is distinct from thresholding tiny measured values. ## What arbitrary precision changes Input/source precision is exact integer recurrence data. Arithmetic precision controls recurrence, dense SVD, and reference. Mathematical conditioning grows with combinatorial entries and can dominate after arithmetic residuals are small. More bits protect relative accuracy but do not change J’s unit diagonal structure. Input/source precision identifies the stored matrix and any deliberate once-rounded model. Arithmetic/work precision is the MPFR/MPC precision used by the constructor, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a singular-value tail lost in the input or make repeated factors unique. Ambient-precision and restoration tests ensure operation precision is owned by the stored operands. ## Reading the output Read singular values in descending order, then the full reconstruction and orthogonality diagnostics. A small singular value can be sensitive even when det(J)=1. Repeated or near-repeated values require subspace interpretation; individual factors are phase/sign ambiguous. A PASS line is scoped to the named case and profile. Compare only rows with identical parameters and model identity. If a cluster, rank, or exactness field is not claimed, do not infer it from a stable display. ## Common mistakes Do not compute entries with binary64 factorials, infer SVD accuracy from $\det(A)=1$, claim every minor is strictly positive, or call the dense run a structured TN/Jacobi–Stirling algorithm. For diagnosis, first verify case ID and shape, then model hash and input precision, then reconstruction/orthogonality, then the appropriate value or subspace metric. Do not alter parameters after seeing a failure and report the changed matrix as the original case. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Jorge Delgado and Juan Manuel Peña, Fast and accurate algorithms for Jacobi–Stirling matrices. Applied Mathematics and Computation 236 (2014), 253–259. DOI: 10.1016/j.amc.2014.03.047](https://doi.org/10.1016/j.amc.2014.03.047) — The recurrence family and high-relative-accuracy motivation. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology used when discussing exact dyadic inputs. The cited works provide external mathematical context. The dimensions, powers of two, acceptance thresholds, and executable implementation are suite-specific adaptations unless explicitly identified as a formula above. ## Project provenance - Runnable case: [jacobi_stirling.m](../../../../examples/tiered/svd-tier-s/jacobi_stirling.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope and conservative baselines: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-s/lah.md0000644000230300031750000002217015274353473023353 0ustar rafaelrafael# Unsigned Lah matrix (Tier S3) ## Quick idea S3-LAH isolates Lah entries grow rapidly down the triangle, producing a full-rank matrix whose smallest singular values are sensitive to small relative entry errors. It is a one-case, deterministic Tier S example: the matrix is small enough to inspect, but the singular spectrum or factors expose a failure mode that a generic smoke matrix would hide. Tier S describes the requested mathematical depth; it does not claim that the public dense svd call implements the cited structured algorithm. ## Mathematical problem Smoke: $n=8$. Demo: $n=20$. The matrix is lower triangular with exact integer entries and unit diagonal. ```math L_{ij}=\binom{i-1}{j-1}\frac{i!}{j!}\quad (j\le i), \qquad L_{ij}=0\quad (j>i). ``` Equivalently L(i,j)=L(i-1,j-1)+(i+j-1)L(i-1,j), with out-of-range entries zero. The first rows are [1], [2 1], [6 6 1], [24 36 12 1]. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 2 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 6 & 6 & 1 & 0 & 0 & 0 & 0 & 0 \\ 24 & 36 & 12 & 1 & 0 & 0 & 0 & 0 \\ 120 & 240 & 120 & 20 & 1 & 0 & 0 & 0 \\ 720 & 1800 & 1200 & 300 & 30 & 1 & 0 & 0 \\ 5040 & 15120 & 12600 & 4200 & 630 & 42 & 1 & 0 \\ 40320 & 141120 & 141120 & 58800 & 11760 & 1176 & 56 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `S3-LAH`. The matching [`lah.m`](../../../../examples/tiered/svd-tier-s/lah.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult Lah entries grow rapidly down the triangle, producing a full-rank matrix whose smallest singular values are sensitive to small relative entry errors. The unit diagonal proves nonsingularity but says little about the conditioning of the singular vectors or the relative accuracy of σ_min. A recurrence and closed form give two independent construction checks. The exact model, any analytic/reference construction, and measured SVD output are separate records. A convenient formula is a reference or invariant check; it is never silently substituted for the matrix sent to the public solver. ## What the Octave example computes The matching [lah.m](../../../../examples/tiered/svd-tier-s/lah.m) selects only S3-LAH from the fixed manifest. The matching lah.m generates L by the integer recurrence, runs public svd, and compares the measured values with a wider MP reference. It checks the first rows, unit diagonal, lower-triangular pattern, reconstruction, and unitarity. It does not compute factorials through native binary64 and does not replace the SVD with a structured algorithm. The runner records dimensions, case parameters, input/model identity, work/reference precision, measured rows, and any native control. ## Construction and exactness The recurrence has a declared conservative budget based on the largest multiplier 2i and a maximum-entry bound. The closed form is checked for small indices using exact MP arithmetic. The source matrix is frozen before any SVD call; a wider reconstruction is evidence about the solver, not about the generator alone. The source audit distinguishes exactness of the constructed matrix from agreement between two floating computations. All arithmetic on the model and measured path remains MPFR/MPC; conversion to binary64 is limited to explicitly labelled presentation controls. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, $U$, $\Sigma$, and $V$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For repeated singular values compare the associated left/right subspaces, not individual columns. Also inspect the value-wise forward bottleneck against the exact or analytic reference, the rank/cluster diagnostic when applicable, and any inverse or projector check. Keep the residuals as MP values until display. A small reconstruction residual does not certify every singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain A. Forward singular-value error compares each returned value with the mathematical value of the stored model and depends on gaps, scaling, and conditioning. For a repeated group, the stable forward object is a subspace/projector. For rank-deficient data, an exact model rank proof is distinct from thresholding tiny measured values. ## What arbitrary precision changes The source is exact integer recurrence data. Arithmetic precision controls entry generation, SVD, and references; mathematical conditioning is driven by the combinatorial growth. More bits improve the measured factorization but cannot make a poorly conditioned singular value well conditioned. Input/source precision identifies the stored matrix and any deliberate once-rounded model. Arithmetic/work precision is the MPFR/MPC precision used by the constructor, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a singular-value tail lost in the input or make repeated factors unique. Ambient-precision and restoration tests ensure operation precision is owned by the stored operands. ## Reading the output Inspect $\sigma_i$ relative errors across the full range, not only the largest value. $r_{\mathrm{svd}}$ can be small while $\sigma_{\min}$ loses relative digits. Factor columns may change sign or phase and should be matched only under a separation condition. A PASS line is scoped to the named case and profile. Compare only rows with identical parameters and model identity. If a cluster, rank, or exactness field is not claimed, do not infer it from a stable display. ## Common mistakes Do not infer spectral accuracy from unit diagonal or determinant, use binary64 factorials, compare factor columns without phase matching, or claim the reference is a published numerical table. For diagnosis, first verify case ID and shape, then model hash and input precision, then reconstruction/orthogonality, then the appropriate value or subspace metric. Do not alter parameters after seeing a failure and report the changed matrix as the original case. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Jorge Delgado, Héctor Orera, and Juan Manuel Peña, Accurate computations with Laguerre matrices. Numerical Linear Algebra with Applications 26(1) (2019), e2217. DOI: 10.1002/nla.2217](https://doi.org/10.1002/nla.2217) — Lah-factor data and accurate singular-value context. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology used when discussing exact dyadic inputs. The cited works provide external mathematical context. The dimensions, powers of two, acceptance thresholds, and executable implementation are suite-specific adaptations unless explicitly identified as a formula above. ## Project provenance - Runnable case: [lah.m](../../../../examples/tiered/svd-tier-s/lah.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope and conservative baselines: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/0000755000230300031750000000000015274353473022241 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/bidiag_mixed.md0000644000230300031750000002454315274353473025200 0ustar rafaelrafael# Two-sided Hadamard-mixed bidiagonal (Tier A3) ## Quick idea A3-BDI-MIXED is a Tier A control. The mixed matrix has the same singular spectrum as the raw bidiagonal but dense signed entries and a different reduction path. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=8$, $a=4$. Demo: $n=16$, $a=8$. $A=HBG^{\mathsf T}/n$, with $G$ a cyclic row-shift of $H$. ```math A=\frac{1}{n}HBG^{\mathsf T}, \qquad HH^{\mathsf T}=GG^{\mathsf T}=nI. ``` The two-sided orthogonal equivalence preserves singular values exactly, but it is not an eigenvalue similarity. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-31} \begin{bmatrix} 108558727 & 429496729 & 126322567 & 409442407 & 108627577 & 429418087 & 126253177 & 409364377 \\ 158824073 & 378967703 & 143165577 & 392730473 & 158763383 & 379021673 & 143226743 & 392784023 \\ 109541753 & 426154343 & 125339513 & 412653721 & 109479559 & 426206873 & 125401223 & 412706663 \\ 159938167 & 376018537 & 142051447 & 395810711 & 160008585 & 375941527 & 141981577 & 395733097 \\ 108562041 & 429483623 & 126318713 & 409429913 & 108624263 & 429431193 & 126257031 & 409376871 \\ 158828919 & 378956137 & 143161207 & 392718487 & 158758537 & 379033239 & 143231113 & 392796009 \\ 109545095 & 426141337 & 125335687 & 412641127 & 109476217 & 426219879 & 125405049 & 412719257 \\ 159943049 & 376007063 & 142047113 & 395798633 & 160003703 & 375953001 & 141985911 & 395745175 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A3-BDI-MIXED`. The matching [`bidiag_mixed.m`](../../../../examples/tiered/svd-tier-a/bidiag_mixed.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The mixed matrix has the same singular spectrum as the raw bidiagonal but dense signed entries and a different reduction path. It tests whether the public SVD handles a dense representation without confusing orthogonal equivalence with similarity. The product is a finite sum of dyadic terms and must be constructed at a declared precision. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [bidiag_mixed.m](../../../../examples/tiered/svd-tier-a/bidiag_mixed.m) selects only A3-BDI-MIXED from the fixed manifest. The matching bidiag_mixed.m constructs raw B and dense A separately, verifies the Hadamard identities, runs svd(A), and compares its spectrum with raw B and an independent MP reference. It reports the mixed input hash and keeps the raw run as a control. No measured output is replaced by the raw singular values. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness The Hadamard matrices are integer and the common denominator bound covers both product stages and division by n. Exact equality of spectra is a model theorem; measured agreement is checked separately. A binary64 plotting or display conversion is not part of construction. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes The raw and mixed source models are exact dyadic when the guard is met. Arithmetic precision controls the mixed products and SVD. Mathematical singular-value conditioning is inherited from B, while representation affects backward errors and factor geometry. More bits cannot repair an incorrectly rounded mixed input. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Read the spectrum identity, $r_{\mathrm{svd}}$, and both factor orthogonality residuals. Dense mixing can change factor vectors even when singular values agree. For repeated values compare left/right subspaces, not $H$ or $G$ columns individually. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not use $HBG^{\mathsf T}$ as an eigenvalue similarity, solve the raw $B$ in place of $A$, compare factor columns without phases, or claim a dense HRA algorithm. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [LAPACK Working Group, “DLASQ1: Compute the singular values of a real bidiagonal matrix,” LAPACK online documentation (current).](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) — The official bidiagonal singular-value reference; this case measures the public dense SVD interface and does not claim to call DLASQ1. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [bidiag_mixed.m](../../../../examples/tiered/svd-tier-a/bidiag_mixed.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/pascal_lower.md0000644000230300031750000002372215274353473025244 0ustar rafaelrafael# Lower Pascal matrix (Tier A1) ## Quick idea A1-PASCAL-LOWER is a Tier A control. The matrix is exactly representable and nonsingular, but combinatorial entries create a broad singular-value range. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=8$. Demo: $n=24$. $Q$ is lower triangular with binomial integer entries. ```math Q_{ij}= \begin{cases} \binom{i-1}{j-1}, & j\le i,\\ 0, & j>i. \end{cases} ``` $Q$ is unit lower triangular, so $\det(Q)=1$. Its entries are generated by Pascal addition, not by native factorial arithmetic. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 1 & 2 & 1 & 0 & 0 & 0 & 0 & 0 \\ 1 & 3 & 3 & 1 & 0 & 0 & 0 & 0 \\ 1 & 4 & 6 & 4 & 1 & 0 & 0 & 0 \\ 1 & 5 & 10 & 10 & 5 & 1 & 0 & 0 \\ 1 & 6 & 15 & 20 & 15 & 6 & 1 & 0 \\ 1 & 7 & 21 & 35 & 35 & 21 & 7 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A1-PASCAL-LOWER`. The matching [`pascal_lower.m`](../../../../examples/tiered/svd-tier-a/pascal_lower.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The matrix is exactly representable and nonsingular, but combinatorial entries create a broad singular-value range. Unit diagonal and determinant are algebraic rank facts; they do not guarantee relative accuracy for the smallest singular values. The lower-triangular zero pattern also means that structured nonnegative terminology must be used carefully. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [pascal_lower.m](../../../../examples/tiered/svd-tier-a/pascal_lower.m) selects only A1-PASCAL-LOWER from the fixed manifest. The matching pascal_lower.m generates Q through integer binomial recurrence, runs public svd, and checks all values, reconstruction, and factor orthogonality. It compares with a wider MP reference and records the exact source model. The run is dense SVD even though the matrix belongs to a structured family. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness Pascal addition is checked against the binomial identity for every entry. A conservative bit guard covers row sums and products. The unit diagonal gives an independent full-rank proof. No measured singular value is inserted into the reference and no determinant shortcut replaces svd. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input/source precision is exact integer Q. Arithmetic precision controls generation, dense SVD, and reference. Mathematical conditioning comes from combinatorial growth and can remain severe after residuals are small. More bits improve arithmetic accuracy but do not change Q or make factors unique. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Inspect the full sorted spectrum, especially the smallest values, together with $r_{\mathrm{svd}}$, $r_U$, and $r_V$. The determinant is not a spectral accuracy certificate. If a singular value is repeated or close, compare its subspace rather than individual factor columns. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not form $Q$ with binary64 nchoosek, infer SVD accuracy from $\det(Q)=1$, use $Q^{\mathsf T}Q$ as the solver path, or compare repeated factor columns by entry. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Pedro Alonso, Jorge Delgado, Rafael Gallego, and Juan Manuel Peña, Conditioning and accurate computations with Pascal matrices. Journal of Computational and Applied Mathematics 252 (2013), 21–26. DOI: 10.1016/j.cam.2011.12.007](https://doi.org/10.1016/j.cam.2011.12.007) — Exact Pascal constructions and conditioning context. - [Plamen Koev, Accurate Eigenvalues and SVDs of Totally Nonnegative Matrices. SIAM Journal on Matrix Analysis and Applications 27(1) (2005), 1–23. DOI: 10.1137/S0895479803438225](https://doi.org/10.1137/S0895479803438225) — The structured-factor accuracy context; this page does not claim a dense SVD implementation of that algorithm. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [pascal_lower.m](../../../../examples/tiered/svd-tier-a/pascal_lower.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/hadamard_geometric.md0000644000230300031750000002377615274353473026401 0ustar rafaelrafael# Hadamard-mixed geometric spectrum (Tier A5) ## Quick idea A5-GEO is a Tier A control. This is a dense matrix with a known geometrically decaying singular spectrum. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=8$, $a=4$. Demo: $n=16$, $a=8$. The exact diagonal values are $d_j=2^{-a(j-1)}$. ```math A=\frac{1}{n}H\mathrm{diag}(d_1,\ldots,d_n)G^{\mathsf T}, \qquad d_j=2^{-a(j-1)}. ``` Orthogonal equivalence gives singular values exactly d_1,...,d_n. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-31} \begin{bmatrix} 250671375 & 286331153 & 252645135 & 284102895 & 250679025 & 286322415 & 252637425 & 284094225 \\ 284094225 & 252645135 & 286331153 & 250679025 & 284102895 & 252637425 & 286322415 & 250671375 \\ 252637425 & 284102895 & 250679025 & 286331153 & 252645135 & 284094225 & 250671375 & 286322415 \\ 286322415 & 250679025 & 284102895 & 252645135 & 286331153 & 250671375 & 284094225 & 252637425 \\ 250679025 & 286322415 & 252637425 & 284094225 & 250671375 & 286331153 & 252645135 & 284102895 \\ 284102895 & 252637425 & 286322415 & 250671375 & 284094225 & 252645135 & 286331153 & 250679025 \\ 252645135 & 284094225 & 250671375 & 286322415 & 252637425 & 284102895 & 250679025 & 286331153 \\ 286331153 & 250671375 & 284094225 & 252637425 & 286322415 & 250679025 & 284102895 & 252645135 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A5-GEO`. The matching [`hadamard_geometric.m`](../../../../examples/tiered/svd-tier-a/hadamard_geometric.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult This is a dense matrix with a known geometrically decaying singular spectrum. The source entries are finite signed sums of dyadics, so construction precision and cancellation need an explicit guard. A global reconstruction residual can conceal a small tail value; the geometric reference makes that failure visible. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [hadamard_geometric.m](../../../../examples/tiered/svd-tier-a/hadamard_geometric.m) selects only A5-GEO from the fixed manifest. The matching hadamard_geometric.m constructs H, G, and A in MP, runs svd, and compares all values with d. It checks the exact mixed-product identity, projectors for separated groups, reconstruction, and factor orthogonality. The measured dense input is not replaced by the diagonal source. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness Hadamard orthogonality and the common denominator bound are checked independently. The exact singular values follow from two-sided unitary equivalence, while the dense factorization is still measured. The zero-free source rank is known by construction. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input/source precision is the guarded dyadic Hadamard product. Arithmetic precision controls construction and SVD. Mathematical conditioning increases across the geometric spectrum. More bits protect the tail but do not make the dense factors unique. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Use relative error across the geometric scale and $r_{\mathrm{svd}}$ together. The singular-value order is canonical mathematically, but factor signs/phases are not. A good largest value is not evidence for the smallest. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not use $HAH^{\mathsf T}$ as the inverse operation, compare one absolute tolerance for all values, form $A^{\mathsf T}A$, or treat the diagonal source as the measured dense input. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Per-Åke Wedin, Perturbation bounds in connection with singular value decomposition. BIT 12 (1972), 99–111. DOI: 10.1007/BF01932678](https://doi.org/10.1007/BF01932678) — Separates individual singular-vector claims from separated-subspace claims. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [hadamard_geometric.m](../../../../examples/tiered/svd-tier-a/hadamard_geometric.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/nro_companion.md0000644000230300031750000002401515274353473025426 0ustar rafaelrafael# NRO bounded-integer companion-like control (Tier A6) ## Quick idea A6-NRO-COMPANION is a Tier A control. This is a nonsymmetric bounded-integer construction whose singular spectrum is not supplied by a simple diagonal formula. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=8$, $\nu=16$. Demo: $n=16$, $\nu=256$. The first row is generated from an alternating sign sequence $k_i$. ```math k_i=(-1)^{i-1}\quad (k_n=1), \qquad a_1=k_1,\quad a_i=k_i-\nu k_{i-1}. ``` The matrix has first row a, subdiagonal ones, and diagonal -nu as specified by the companion-like construction. Horner recurrence preserves the target k sequence and det(A)=(-1)^(n-1). ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & -17 & 17 & -17 & 17 & -17 & 17 & -15 \\ 1 & -16 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & -16 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & -16 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & -16 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & -16 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & -16 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & -16 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A6-NRO-COMPANION`. The matching [`nro_companion.m`](../../../../examples/tiered/svd-tier-a/nro_companion.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult This is a nonsymmetric bounded-integer construction whose singular spectrum is not supplied by a simple diagonal formula. The large parameter nu creates a scale-separated dense eigen/singular problem while the exact recurrence supplies an independent construction invariant. It is a control against treating a companion-like matrix as if its eigenvalues were its singular values. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [nro_companion.m](../../../../examples/tiered/svd-tier-a/nro_companion.m) selects only A6-NRO-COMPANION from the fixed manifest. The matching nro_companion.m constructs the integer matrix in MP, runs public svd, and checks the Horner/state recurrence, determinant sign, reconstruction, and factor orthogonality. It compares the measured spectrum with an independent wider MP run; no known singular values are substituted. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness All first-row coefficients and the subdiagonal/diagonal pattern are checked by exact integer arithmetic under the declared guard. The determinant and recurrence are independent of SVD. A high-precision reference is a numerical comparator, not a proof of a hidden closed-form singular spectrum. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes The source is exact integer for the selected nu. Arithmetic precision controls construction, SVD, and reference; mathematical conditioning is driven by nu and the companion-like nonnormal pattern. More bits reduce arithmetic error but do not make singular values equal to eigenvalues. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Read the complete singular spectrum, $r_{\mathrm{svd}}$, and factor residuals. The determinant is a rank/invariant check, not a product-based accuracy certificate in finite precision. Because values may be clustered or widely scaled, use value-wise metrics appropriate to magnitude and avoid individual-vector claims without a gap. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not use eig values as singular values, build coefficients through native overflow-prone arithmetic, infer full accuracy from det, or claim a published companion experiment was reproduced. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Tetsuo Nishi, Siegfried M. Rump, and Shin'ichi Oishi, On the generation of very ill-conditioned integer matrices. Nonlinear Theory and Its Applications, IEICE 2(2) (2011), 226–245. DOI: 10.1587/nolta.2.226](https://doi.org/10.1587/nolta.2.226) — Bounded-integer companion-like construction context. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [nro_companion.m](../../../../examples/tiered/svd-tier-a/nro_companion.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/hadamard_rank5.md0000644000230300031750000002421515274353473025430 0ustar rafaelrafael# Hadamard-mixed near-rank-deficient matrix (Tier A5) ## Quick idea A5-RANK5 is a Tier A control. The fifth value sits next to a null space and can be confused with zero by a low-precision or threshold-only test. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=8$ with $\eta=2^{-32}$. Demo: $n=8$ with $\eta=2^{-100}$. Five positive source values are followed by three zeros. ```math d=[1,1/2,1/4,1/8,\eta,0,0,0], \qquad \eta=2^{-b}, \qquad \mathrm{rank}(A)=5. ``` The fifth singular value is $\eta$ exactly in the model, while the last three are exact zeros. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-35} \begin{bmatrix} 1610612735 & 8053063681 & 2684354561 & 4831838209 & 1610612737 & 8053063679 & 2684354559 & 4831838207 \\ 4831838207 & 2684354561 & 8053063681 & 1610612737 & 4831838209 & 2684354559 & 8053063679 & 1610612735 \\ 2684354559 & 4831838209 & 1610612737 & 8053063681 & 2684354561 & 4831838207 & 1610612735 & 8053063679 \\ 8053063679 & 1610612737 & 4831838209 & 2684354561 & 8053063681 & 1610612735 & 4831838207 & 2684354559 \\ 1610612737 & 8053063679 & 2684354559 & 4831838207 & 1610612735 & 8053063681 & 2684354561 & 4831838209 \\ 4831838209 & 2684354559 & 8053063679 & 1610612735 & 4831838207 & 2684354561 & 8053063681 & 1610612737 \\ 2684354561 & 4831838207 & 1610612735 & 8053063679 & 2684354559 & 4831838209 & 1610612737 & 8053063681 \\ 8053063681 & 1610612735 & 4831838207 & 2684354559 & 8053063679 & 1610612737 & 4831838209 & 2684354561 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A5-RANK5`. The matching [`hadamard_rank5.m`](../../../../examples/tiered/svd-tier-a/hadamard_rank5.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The fifth value sits next to a null space and can be confused with zero by a low-precision or threshold-only test. The five-dimensional range is the stable rank target; the individual vector associated with $\eta$ can be sensitive to the gap from zero. The exact dyadic $\eta$ must be kept separate from any native rounded input. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [hadamard_rank5.m](../../../../examples/tiered/svd-tier-a/hadamard_rank5.m) selects only A5-RANK5 from the fixed manifest. The matching hadamard_rank5.m measures the dense SVD, checks the five-dimensional positive range and three-dimensional null space, and reports $\eta$ with absolute and relative errors. It uses projectors for the grouped spaces and does not append $\eta$ or zeros to measured output. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness The diagonal source and Hadamard products are audited under a guard that includes b. The exact rank proof comes from the five nonzero d entries. Projector references are model-derived and separate from the public SVD output. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input precision preserves $\eta$ and exact zeros; arithmetic precision controls construction and SVD. Mathematical conditioning is near-rank sensitivity at the fifth value. More bits resolve $\eta$ but do not make the null-space basis unique. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Read $\eta$'s value error, the positive-range projector, and null-space projector independently. A small $r_{\mathrm{svd}}$ can coexist with loss of relative accuracy in $\eta$. If $\eta$ is rounded to zero, report changed input provenance rather than a failed exact model. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not classify $\eta$ using only a binary64 threshold, compare null columns individually, or call a rounded rank-four input the exact rank-five case. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Per-Åke Wedin, Perturbation bounds in connection with singular value decomposition. BIT 12 (1972), 99–111. DOI: 10.1007/BF01932678](https://doi.org/10.1007/BF01932678) — Separates individual singular-vector claims from separated-subspace claims. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [hadamard_rank5.m](../../../../examples/tiered/svd-tier-a/hadamard_rank5.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/hadamard_close.md0000644000230300031750000002431215274353473025513 0ustar rafaelrafael# Hadamard-mixed close singular pair (Tier A5) ## Quick idea A5-CLOSE is a Tier A control. The close pair is a forward-accuracy and subspace test. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=8$ with $\delta=2^{-32}$. Demo: $n=8$ with $\delta=2^{-100}$. The close pair is around one. ```math d=[4,2,1+\delta,1,1/2,1/4,1/8,1/16], \qquad A=\frac{1}{n}H\mathrm{diag}(d)G^{\mathsf T}. ``` The pair at indices 3 and 4 has gap delta and is otherwise separated from the remaining values. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-35} \begin{bmatrix} 7784628223 & 38386270209 & 9932111873 & 19595788287 & 9395240959 & 30333206529 & 7247757313 & 14763950079 \\ 14763950079 & 9932111873 & 38386270209 & 9395240959 & 19595788287 & 7247757313 & 30333206529 & 7784628223 \\ 7247757313 & 19595788287 & 9395240959 & 38386270209 & 9932111873 & 14763950079 & 7784628223 & 30333206529 \\ 30333206529 & 9395240959 & 19595788287 & 9932111873 & 38386270209 & 7784628223 & 14763950079 & 7247757313 \\ 9395240959 & 30333206529 & 7247757313 & 14763950079 & 7784628223 & 38386270209 & 9932111873 & 19595788287 \\ 19595788287 & 7247757313 & 30333206529 & 7784628223 & 14763950079 & 9932111873 & 38386270209 & 9395240959 \\ 9932111873 & 14763950079 & 7784628223 & 30333206529 & 7247757313 & 19595788287 & 9395240959 & 38386270209 \\ 38386270209 & 7784628223 & 14763950079 & 7247757313 & 30333206529 & 9395240959 & 19595788287 & 9932111873 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A5-CLOSE`. The matching [`hadamard_close.m`](../../../../examples/tiered/svd-tier-a/hadamard_close.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The close pair is a forward-accuracy and subspace test. When delta is small, individual singular vectors can rotate substantially under tiny perturbations even though the two-dimensional subspace is stable. A binary64 source can lose delta entirely; a high-precision run must preserve it as part of the exact dyadic model. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [hadamard_close.m](../../../../examples/tiered/svd-tier-a/hadamard_close.m) selects only A5-CLOSE from the fixed manifest. The matching hadamard_close.m builds the mixed dense matrix, measures svd, and checks the pair with a cluster-aware metric. It reports the exact d vector, pair gap, reconstruction, orthogonality, and any native rounded control. It does not replace the pair with a repeated reference. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness The dyadic close entry and Hadamard product are checked with a sufficient bit guard. The known singular values follow from orthogonal equivalence. The pair projector is generated independently and used as a subspace reference; individual H/G columns are not mandatory answers. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input precision preserves delta; arithmetic precision controls the dense SVD and pair comparison. Mathematical conditioning of individual factors scales with the inverse gap, while the pair subspace can remain well behaved. More bits resolve the pair but cannot make individual vectors canonical. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Read the pair’s value bottleneck and its two-dimensional projector/angle diagnostic separately. A small $r_{\mathrm{svd}}$ does not certify individual columns. If $\delta$ is below the work precision, the honest status is unresolved separation, not a changed parameter. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not infer distinct factors from a close value pair, use a repeated reference when delta is nonzero, or claim a native loss of delta is an MP solver error. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Per-Åke Wedin, Perturbation bounds in connection with singular value decomposition. BIT 12 (1972), 99–111. DOI: 10.1007/BF01932678](https://doi.org/10.1007/BF01932678) — Separates individual singular-vector claims from separated-subspace claims. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [hadamard_close.m](../../../../examples/tiered/svd-tier-a/hadamard_close.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/README.md0000644000230300031750000001345415274353473023527 0ustar rafaelrafael# Singular value decompositions — Tier A Tier A broadens the SVD path with Pascal and Vandermonde structure, raw versus dense bidiagonal representations, tall/wide/complex Läuchli shapes, known singular-value groups, exact rank controls, and a bounded-integer companion-like construction. The detailed pages print every small smoke or fixed control in full with exact integer or dyadic entries, including the small rectangular and complex Läuchli controls. The source matrix is kept separate from measured SVD output, and the exact generator comparison is `tools/check-smoke-matrices.sh`. ## Core equation and interpretation For $A\in\mathbb{C}^{m\times n}$: ```math A=U\Sigma V^{\mathsf H}, \qquad r_{\mathrm{svd}}= \frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` The value spectrum, reconstruction, factor orthogonality, rank, and repeated subspaces are separate diagnostics. A known spectrum does not make individual factors canonical, and a tiny measured singular value is not automatically an exact rank proof. ## Learning map | Case | Mathematical object | Main question | Start here | Detailed page | External primary context | |---|---|---|---|---|---| | A1-PASCAL-LOWER | lower binomial triangle Q | exact combinatorial input | [pascal_lower.m](../../../../examples/tiered/svd-tier-a/pascal_lower.m) | [pascal_lower.md](./pascal_lower.md) | [Alonso et al. (2013)](https://doi.org/10.1016/j.cam.2011.12.007) | | A1-PASCAL-SYM | $P=QQ^{\mathsf T}$ | dense symmetric product | [pascal_sym.m](../../../../examples/tiered/svd-tier-a/pascal_sym.m) | [pascal_sym.md](./pascal_sym.md) | [Alonso et al. (2013)](https://doi.org/10.1016/j.cam.2011.12.007) | | A2-VAND | dyadic-node Vandermonde | powers and node conditioning | [vandermonde.m](../../../../examples/tiered/svd-tier-a/vandermonde.m) | [vandermonde.md](./vandermonde.md) | [Koev (2005)](https://doi.org/10.1137/S0895479803438225) | | A3-BDI-RAW | graded upper bidiagonal | relative tail accuracy | [bidiag_raw.m](../../../../examples/tiered/svd-tier-a/bidiag_raw.m) | [bidiag_raw.md](./bidiag_raw.md) | [LAPACK DLASQ1](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) | | A3-BDI-MIXED | $HBG^{\mathsf T}/n$ | dense representation | [bidiag_mixed.m](../../../../examples/tiered/svd-tier-a/bidiag_mixed.m) | [bidiag_mixed.md](./bidiag_mixed.md) | [LAPACK DLASQ1](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) | | A4-LAU-TALL | tall Läuchli construction | repeated small group | [lauchli_tall.m](../../../../examples/tiered/svd-tier-a/lauchli_tall.m) | [lauchli_tall.md](./lauchli_tall.md) | [Läuchli (1961)](https://doi.org/10.1007/BF01386022) | | A4-LAU-WIDE | transpose of tall case | shape and side exchange | [lauchli_wide.m](../../../../examples/tiered/svd-tier-a/lauchli_wide.m) | [lauchli_wide.md](./lauchli_wide.md) | [Läuchli (1961)](https://doi.org/10.1007/BF01386022) | | A4-LAU-COMPLEX | phased complex tall case | MPC conjugation | [lauchli_complex.m](../../../../examples/tiered/svd-tier-a/lauchli_complex.m) | [lauchli_complex.md](./lauchli_complex.md) | [Läuchli (1961)](https://doi.org/10.1007/BF01386022) | | A5-GEO | Hadamard mix of geometric d | dense known spectrum | [hadamard_geometric.m](../../../../examples/tiered/svd-tier-a/hadamard_geometric.m) | [hadamard_geometric.md](./hadamard_geometric.md) | [Wedin (1972)](https://doi.org/10.1007/BF01932678) | | A5-CLOSE | close Hadamard pair | value gap versus vector gap | [hadamard_close.m](../../../../examples/tiered/svd-tier-a/hadamard_close.m) | [hadamard_close.md](./hadamard_close.md) | [Wedin (1972)](https://doi.org/10.1007/BF01932678) | | A5-REPEAT | repeated Hadamard group | subspace, not columns | [hadamard_repeat.m](../../../../examples/tiered/svd-tier-a/hadamard_repeat.m) | [hadamard_repeat.md](./hadamard_repeat.md) | [Wedin (1972)](https://doi.org/10.1007/BF01932678) | | A5-RANK4 | four nonzero d values | exact rank four | [hadamard_rank4.m](../../../../examples/tiered/svd-tier-a/hadamard_rank4.m) | [hadamard_rank4.md](./hadamard_rank4.md) | [Wedin (1972)](https://doi.org/10.1007/BF01932678) | | A5-RANK5 | $\eta$ next to exact zeros | near-rank boundary | [hadamard_rank5.m](../../../../examples/tiered/svd-tier-a/hadamard_rank5.m) | [hadamard_rank5.md](./hadamard_rank5.md) | [Wedin (1972)](https://doi.org/10.1007/BF01932678) | | A6-NRO-COMPANION | bounded-integer companion-like | recurrence and dense SVD | [nro_companion.m](../../../../examples/tiered/svd-tier-a/nro_companion.m) | [nro_companion.md](./nro_companion.md) | [Nishi–Rump–Oishi (2011)](https://doi.org/10.1587/nolta.2.226) | The references establish the external setting; these fixed parameters and measured dense SVD runs are suite-specific adaptations. ## How to run ~~~octave pkg load mplapack-interop run ("examples/tiered/svd-tier-a/hadamard_close.m"); ~~~ For counted coverage: ~~~octave pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "svd_tiers")); result = mp_svd_tiers ("demo", struct ("tier", "A", "plot", false)); ~~~ The smoke profile has 13 Tier A cases and the demo adds complex Läuchli plus the S1 scale controls. V1/V2/V3 certificates remain separate from ordinary measured SVD rows. ## Suggested order Read Pascal lower/symmetric first, then raw/mixed bidiagonal. Use tall/wide/complex Läuchli to understand shape and conjugation. Finish with geometric, close, repeated, rank-four/rank-five Hadamard cases and the companion-like matrix. At each step keep value, factor, rank, and subspace claims separate. See the [master map](../README.md), [SVT cases](../../../../docs/codex/svt/cases.json), [SVT verification limits](../../../../docs/codex/svt/VERIFICATION.md), and [SVT sources](../../../../docs/codex/svt/SOURCES.md). mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/vandermonde.md0000644000230300031750000002422515274353473025072 0ustar rafaelrafael# Dyadic Vandermonde matrix (Tier A2) ## Quick idea A2-VAND is a Tier A control. Vandermonde powers amplify small node errors and produce a rapidly changing singular spectrum even when every node is an exact dyadic. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=8$ and node denominator $2^4$. Demo: $n=16$ and node denominator $2^5$. Nodes are $x_i=i/2^d$. ```math V_{ij}=x_i^{j-1},\qquad x_i=i/2^d, \qquad \det(V)=\prod_{1\le i0. ``` The nodes are distinct because $n<2^d$ in the selected profiles. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-28} \begin{bmatrix} 268435456 & 16777216 & 1048576 & 65536 & 4096 & 256 & 16 & 1 \\ 268435456 & 33554432 & 4194304 & 524288 & 65536 & 8192 & 1024 & 128 \\ 268435456 & 50331648 & 9437184 & 1769472 & 331776 & 62208 & 11664 & 2187 \\ 268435456 & 67108864 & 16777216 & 4194304 & 1048576 & 262144 & 65536 & 16384 \\ 268435456 & 83886080 & 26214400 & 8192000 & 2560000 & 800000 & 250000 & 78125 \\ 268435456 & 100663296 & 37748736 & 14155776 & 5308416 & 1990656 & 746496 & 279936 \\ 268435456 & 117440512 & 51380224 & 22478848 & 9834496 & 4302592 & 1882384 & 823543 \\ 268435456 & 134217728 & 67108864 & 33554432 & 16777216 & 8388608 & 4194304 & 2097152 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A2-VAND`. The matching [`vandermonde.m`](../../../../examples/tiered/svd-tier-a/vandermonde.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult Vandermonde powers amplify small node errors and produce a rapidly changing singular spectrum even when every node is an exact dyadic. The determinant identity proves nonsingularity but is not a useful accuracy bound for individual singular values. Building successive powers in MP is part of the input contract; native decimal or binary64 nodes would define a different matrix. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [vandermonde.m](../../../../examples/tiered/svd-tier-a/vandermonde.m) selects only A2-VAND from the fixed manifest. The matching vandermonde.m generates nodes and powers in MP, runs public svd, and compares values and reconstruction with a wider reference. It verifies node distinctness and determinant-sign algebraically. A dense SVD result is kept separate from any structured totally-nonnegative algorithm suggested by the literature. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness The common dyadic denominator and successive-power recurrence give a sufficient exactness guard. The determinant product is independently checked for sign and nonzero status. No determinant-based threshold is used as a surrogate rank or SVD accuracy certificate. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input/source precision is the exact dyadic node/power construction. Arithmetic precision controls powers, SVD, and reference. Mathematical conditioning is driven by node spacing and exponent growth. More bits reduce arithmetic error but do not make a Vandermonde matrix well conditioned. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Use value-wise relative error where $\sigma_i$ is nonzero, plus $r_{\mathrm{svd}}$ and factor orthogonality. A stable largest singular value says little about the small tail. The node and dimension fields are essential when comparing runs; changing $d$ changes the model. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not use native powers for the MP input, infer rank from determinant magnitude, form $V^{\mathsf T}V$ as the solver, or call a structured TN result a generic dense result. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Plamen Koev, Accurate Eigenvalues and SVDs of Totally Nonnegative Matrices. SIAM Journal on Matrix Analysis and Applications 27(1) (2005), 1–23. DOI: 10.1137/S0895479803438225](https://doi.org/10.1137/S0895479803438225) — The structured-factor accuracy context; this page does not claim a dense SVD implementation of that algorithm. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [vandermonde.m](../../../../examples/tiered/svd-tier-a/vandermonde.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/hadamard_rank4.md0000644000230300031750000002272315274353473025431 0ustar rafaelrafael# Hadamard-mixed exact rank-four matrix (Tier A5) ## Quick idea A5-RANK4 is a Tier A control. This is an exact rank-deficiency control. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke and demo: $n=8$. The diagonal source has four positive values and four exact zeros. ```math d=[1,1/2,1/4,1/8,0,0,0,0], \qquad A=\frac{1}{n}H\mathrm{diag}(d)G^{\mathsf T}, \qquad \mathrm{rank}(A)=4. ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-6} \begin{bmatrix} 3 & 15 & 5 & 9 & 3 & 15 & 5 & 9 \\ 9 & 5 & 15 & 3 & 9 & 5 & 15 & 3 \\ 5 & 9 & 3 & 15 & 5 & 9 & 3 & 15 \\ 15 & 3 & 9 & 5 & 15 & 3 & 9 & 5 \\ 3 & 15 & 5 & 9 & 3 & 15 & 5 & 9 \\ 9 & 5 & 15 & 3 & 9 & 5 & 15 & 3 \\ 5 & 9 & 3 & 15 & 5 & 9 & 3 & 15 \\ 15 & 3 & 9 & 5 & 15 & 3 & 9 & 5 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A5-RANK4`. The matching [`hadamard_rank4.m`](../../../../examples/tiered/svd-tier-a/hadamard_rank4.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult This is an exact rank-deficiency control. The null singular subspace is known by construction, but individual null vectors are not unique. Thresholding tiny computed values cannot prove rank; the exact source rank and the two-sided unitary transformation provide the model proof. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [hadamard_rank4.m](../../../../examples/tiered/svd-tier-a/hadamard_rank4.m) selects only A5-RANK4 from the fixed manifest. The matching hadamard_rank4.m runs svd on the dense A, checks four positive values and a four-dimensional null subspace, and reports reconstruction and factor orthogonality. It compares the null projector rather than null columns. Measured zeros are not inserted or rounded by the example. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness The zero entries are exact, and H/G orthogonality preserves rank. The exact rank proof is independent of the SVD. A wider MP reconstruction confirms the measured factors but is not the rank proof. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input precision retains exact zeros; arithmetic precision controls dense SVD and null-subspace diagnostics. Mathematical rank is exact and unchanged by more bits, while small computed tails can shrink with precision. Do not substitute a tolerance-based rank for the model fact. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Read rank-model metadata, positive-value accuracy, and null-projector distance separately. A small numerical σ does not by itself distinguish exact zero from near-zero. Factor bases in the null group are arbitrary. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not infer exact rank from a tolerance, compare null columns entrywise, or perturb zeros into a near-rank model without changing the case ID. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Per-Åke Wedin, Perturbation bounds in connection with singular value decomposition. BIT 12 (1972), 99–111. DOI: 10.1007/BF01932678](https://doi.org/10.1007/BF01932678) — Separates individual singular-vector claims from separated-subspace claims. - [Plamen Koev, Accurate Eigenvalues and SVDs of Totally Nonnegative Matrices. SIAM Journal on Matrix Analysis and Applications 27(1) (2005), 1–23. DOI: 10.1137/S0895479803438225](https://doi.org/10.1137/S0895479803438225) — The structured-factor accuracy context; this page does not claim a dense SVD implementation of that algorithm. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [hadamard_rank4.m](../../../../examples/tiered/svd-tier-a/hadamard_rank4.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/lauchli_complex.md0000644000230300031750000002352115274353473025736 0ustar rafaelrafael# Complex phase Läuchli control (Tier A4) ## Quick idea A4-LAU-COMPLEX is a Tier A control. This is a complex SVD interface control: the value spectrum is unchanged but both factor sides become genuinely complex. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Demo only: $n=8$, $b=100$, tall $T$. Quarter-turn diagonal phases are applied on the left and right. ```math T_c=D_L T D_R, \qquad \lvert(D_L)_{ii}\rvert=\lvert(D_R)_{jj}\rvert=1. ``` Two-sided unitary phase factors preserve singular values and transform the singular subspaces by D_L and D_R. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & -1i & -1 & 1i & 1 & -1i & -1 & 1i \\ 2^{-100}i & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 2^{-100}i & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 2^{-100}i & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 2^{-100}i & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 2^{-100}i & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 2^{-100}i & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 2^{-100}i & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 2^{-100}i \end{bmatrix}. ``` This is the full concrete smoke fixture for `A4-LAU-COMPLEX`. The matching [`lauchli_complex.m`](../../../../examples/tiered/svd-tier-a/lauchli_complex.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. This fixed demo configuration is deliberately small enough to inspect in full. It is a demo-only manifest row rather than a smoke-profile row, and the displayed matrix is the exact input for that complex phase control. ## Why this problem is numerically difficult This is a complex SVD interface control: the value spectrum is unchanged but both factor sides become genuinely complex. It catches transpose-only code and binary64 complex fallback. The repeated small group remains a subspace target, so phase changes cannot be mistaken for numerical failure. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [lauchli_complex.m](../../../../examples/tiered/svd-tier-a/lauchli_complex.m) selects only A4-LAU-COMPLEX from the fixed manifest. The matching lauchli_complex.m builds the tall complex phase variant in MPC, runs public svd, and compares singular values with the real tall control. It checks complex reconstruction, $U^{\mathsf H}U$, $V^{\mathsf H}V$, and the transformed repeated projectors. The base $T$ is not substituted for the complex input. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness Quarter-turn phases are exact MPC values. The two-sided unitary identity is checked independently, and the real spectrum is used only as a mathematical control. The measured complex factors remain the public solver output. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes The source includes exact dyadic μ and exact fourth-root phases. Arithmetic precision controls MPC construction and SVD; mathematical conditioning remains the Lauchli small-tail problem. More bits improve complex residuals but do not make repeated factors unique. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Equal singular values are expected; factor entries can rotate. Read conjugate-transpose orthogonality and complex reconstruction. Compare the repeated subspace after applying D_L/D_R, not raw columns. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not use transpose instead of conjugate transpose, remove phases before calling svd, compare raw factor columns, or claim optimized complex support not validated by this case. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Peter Läuchli, Jordan-Elimination und Ausgleichung nach kleinsten Quadraten. Numerische Mathematik 3 (1961), 226–240. DOI: 10.1007/BF01386022](https://doi.org/10.1007/BF01386022) — Historical source for the Läuchli matrix convention; the exact spectrum here follows directly from its Gram matrix. - [Per-Åke Wedin, Perturbation bounds in connection with singular value decomposition. BIT 12 (1972), 99–111. DOI: 10.1007/BF01932678](https://doi.org/10.1007/BF01932678) — Separates individual singular-vector claims from separated-subspace claims. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [lauchli_complex.m](../../../../examples/tiered/svd-tier-a/lauchli_complex.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/bidiag_raw.md0000644000230300031750000002351515274353473024661 0ustar rafaelrafael# Raw graded bidiagonal matrix (Tier A3) ## Quick idea A3-BDI-RAW is a Tier A control. Bidiagonal structure is the natural setting for relative-accuracy singular-value ideas, but this page still measures the public dense SVD interface. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=8$, $a=4$. Demo: $n=16$, $a=8$. The diagonal and superdiagonal are dyadic and geometrically graded. ```math B_{ii}=2^{-a(i-1)}, \qquad B_{i,i+1}=2^{-a(i-1)-1},\quad i ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 2^{-1} & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 2^{-4} & 2^{-5} & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 2^{-8} & 2^{-9} & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 2^{-12} & 2^{-13} & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 2^{-16} & 2^{-17} & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 2^{-20} & 2^{-21} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 2^{-24} & 2^{-25} \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 2^{-28} \end{bmatrix}. ``` This is the full concrete smoke fixture for `A3-BDI-RAW`. The matching [`bidiag_raw.m`](../../../../examples/tiered/svd-tier-a/bidiag_raw.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult Bidiagonal structure is the natural setting for relative-accuracy singular-value ideas, but this page still measures the public dense SVD interface. The small tail spans several powers of two and is sensitive to input rounding. Exact dyadic construction makes it possible to separate loss in the model from loss in the decomposition. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [bidiag_raw.m](../../../../examples/tiered/svd-tier-a/bidiag_raw.m) selects only A3-BDI-RAW from the fixed manifest. The matching bidiag_raw.m builds B directly in MP, runs public svd, and compares the complete spectrum with the mixed and high-precision references. It checks reconstruction, orthogonality, and exact nonzero structure. It does not bind or silently substitute a specialized LASQ routine. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness The maximum exponent range is recorded and a common denominator bound covers the raw entries. The bidiagonal pattern and positive diagonal prove rank n. The independently computed mixed form is used for orthogonal invariance, not as a replacement input. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input precision controls retention of the dyadic graded entries. Arithmetic precision controls construction and SVD; mathematical conditioning grows with the grading exponent a and n. More bits preserve the tail but do not confer the guarantees of a specialized HRA solver. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Inspect the smallest singular values with relative and absolute metrics, then reconstruction and factor residuals. A residual near work precision does not prove relative accuracy in the tail. Compare raw and mixed spectra only after confirming identical parameters. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not assume dense svd is LASQ1, use one absolute tolerance for every scale, round the entries through binary64, or infer relative accuracy from reconstruction alone. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [LAPACK Working Group, “DLASQ1: Compute the singular values of a real bidiagonal matrix,” LAPACK online documentation (current).](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) — The official bidiagonal singular-value reference; this case measures the public dense SVD interface and does not claim to call DLASQ1. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [bidiag_raw.m](../../../../examples/tiered/svd-tier-a/bidiag_raw.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/lauchli_tall.md0000644000230300031750000002357615274353473025235 0ustar rafaelrafael# Tall Läuchli matrix (Tier A4) ## Quick idea A4-LAU-TALL is a Tier A control. The small singular group is controlled by μ while the normal-equation matrix contains μ^2, which is much easier to lose. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=4$, $b=20$, $\mu=2^{-20}$. Demo: $n=8$, $b=100$, $\mu=2^{-100}$. $T$ has shape $(n+1)$-by-$n$. ```math T=\begin{bmatrix}\mathbf{1}^{\mathsf T}\\ \mu I_n\end{bmatrix}, \qquad T^{\mathsf T}T=\mathbf{1}\mathbf{1}^{\mathsf T}+\mu^2 I_n. ``` The singular values are $\sqrt{n+\mu^2}$, followed by $n-1$ copies of $\mu$. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 1 & 1 & 1 \\ 2^{-20} & 0 & 0 & 0 \\ 0 & 2^{-20} & 0 & 0 \\ 0 & 0 & 2^{-20} & 0 \\ 0 & 0 & 0 & 2^{-20} \end{bmatrix}. ``` This is the full concrete smoke fixture for `A4-LAU-TALL`. The matching [`lauchli_tall.m`](../../../../examples/tiered/svd-tier-a/lauchli_tall.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The small singular group is controlled by μ while the normal-equation matrix contains μ^2, which is much easier to lose. This is a rank-sensitive example with a repeated small singular value; individual small singular vectors are not identifiable. The exact Gram identity is a control, not a replacement for measuring T with svd. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [lauchli_tall.m](../../../../examples/tiered/svd-tier-a/lauchli_tall.m) selects only A4-LAU-TALL from the fixed manifest. The matching lauchli_tall.m builds $T$ in MP, runs public svd, and compares the values with the analytic spectrum. It checks the repeated right subspace $I-\mathbf{1}\mathbf{1}^{\mathsf T}/n$, the left subspace, reconstruction, and factor orthogonality. A native $T^{\mathsf T}T$ calculation is logged only as a negative control. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness The row of ones and dyadic μ are exact within the selected input guard. The Gram identity is checked entrywise, and the repeated projector is generated exactly. The null direction in a full SVD is not counted as an additional economy singular value. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input precision controls μ itself; arithmetic precision controls T, svd, and analytic sqrt(n+μ^2). Mathematical sensitivity is concentrated in the small repeated group and in the squaring of μ under normal equations. More bits preserve μ but do not select a unique small basis. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Expect one large value and a repeated μ group. Read the repeated-group projector rather than individual columns, and compare σ_min to μ with an absolute metric. A reconstruction pass does not establish that a native normal-equation path retained μ. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not compute the main answer from $T^{\mathsf T}T$, take $\sqrt{\lvert\mathrm{eig}(\cdot)\rvert}$ as an oracle, compare repeated columns individually, or claim the full-SVD null direction is a listed singular value. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Peter Läuchli, Jordan-Elimination und Ausgleichung nach kleinsten Quadraten. Numerische Mathematik 3 (1961), 226–240. DOI: 10.1007/BF01386022](https://doi.org/10.1007/BF01386022) — Historical source for the Läuchli matrix convention; the exact spectrum here follows directly from its Gram matrix. - [Per-Åke Wedin, Perturbation bounds in connection with singular value decomposition. BIT 12 (1972), 99–111. DOI: 10.1007/BF01932678](https://doi.org/10.1007/BF01932678) — Separates individual singular-vector claims from separated-subspace claims. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [lauchli_tall.m](../../../../examples/tiered/svd-tier-a/lauchli_tall.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/hadamard_repeat.md0000644000230300031750000002334715274353473025675 0ustar rafaelrafael# Hadamard-mixed repeated singular group (Tier A5) ## Quick idea A5-REPEAT is a Tier A control. A repeated singular value makes individual left and right vectors nonunique. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke and demo: $n=8$. The close-pair $\delta$ is exactly zero, so $d=[4,2,1,1,1/2,1/4,1/8,1/16]$. ```math A=\frac{1}{n}H\mathrm{diag}(4,2,1,1,1/2,1/4,1/8,1/16)G^{\mathsf T}. ``` The singular value 1 has multiplicity two and its left/right model subspaces are the corresponding H/G column spans. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-7} \begin{bmatrix} 29 & 143 & 37 & 73 & 35 & 113 & 27 & 55 \\ 55 & 37 & 143 & 35 & 73 & 27 & 113 & 29 \\ 27 & 73 & 35 & 143 & 37 & 55 & 29 & 113 \\ 113 & 35 & 73 & 37 & 143 & 29 & 55 & 27 \\ 35 & 113 & 27 & 55 & 29 & 143 & 37 & 73 \\ 73 & 27 & 113 & 29 & 55 & 37 & 143 & 35 \\ 37 & 55 & 29 & 113 & 27 & 73 & 35 & 143 \\ 143 & 29 & 55 & 27 & 113 & 35 & 73 & 37 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A5-REPEAT`. The matching [`hadamard_repeat.m`](../../../../examples/tiered/svd-tier-a/hadamard_repeat.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult A repeated singular value makes individual left and right vectors nonunique. This dense construction is designed so the target is a projector or subspace, not a particular factor basis. It is a semantic test: a checker that matches columns one by one can report failure for two mathematically correct SVDs. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [hadamard_repeat.m](../../../../examples/tiered/svd-tier-a/hadamard_repeat.m) selects only A5-REPEAT from the fixed manifest. The matching hadamard_repeat.m runs public svd and compares the repeated value group through left/right projectors, while checking the complete spectrum and reconstruction. It allows arbitrary orthogonal/unitary changes within the group. The exact diagonal source remains separate from measured factors. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness The zero gap is an exact model parameter, not a rounded small delta. Hadamard orthogonality proves the singular spectrum and gives exact projectors under the declared guard. The group multiplicity is known algebraically, not inferred from a numerical disk. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input/source precision records an exact repeated group. Arithmetic precision controls dense products and SVD. Mathematical nonuniqueness remains at infinite precision; more bits reduce residuals but cannot choose one basis among infinitely many. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Expect two singular values equal to one within arithmetic error and arbitrary bases for their subspaces. Read projector/angle residuals, $r_{\mathrm{svd}}$, $r_U$, and $r_V$. Individual phase/sign or column-order comparisons are intentionally not used. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not call a rotated basis wrong, infer distinct vectors from two equal values, or use a simple-gap factor bound. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Per-Åke Wedin, Perturbation bounds in connection with singular value decomposition. BIT 12 (1972), 99–111. DOI: 10.1007/BF01932678](https://doi.org/10.1007/BF01932678) — Separates individual singular-vector claims from separated-subspace claims. - [Plamen Koev, Accurate Eigenvalues and SVDs of Totally Nonnegative Matrices. SIAM Journal on Matrix Analysis and Applications 27(1) (2005), 1–23. DOI: 10.1137/S0895479803438225](https://doi.org/10.1137/S0895479803438225) — The structured-factor accuracy context; this page does not claim a dense SVD implementation of that algorithm. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [hadamard_repeat.m](../../../../examples/tiered/svd-tier-a/hadamard_repeat.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/pascal_sym.md0000644000230300031750000002400015274353473024712 0ustar rafaelrafael# Symmetric Pascal matrix (Tier A1) ## Quick idea A1-PASCAL-SYM is a Tier A control. The dense symmetric product has exact combinatorial entries, large growth, and a clean positive-definite model. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=8$. Demo: $n=24$. $P$ is the dense symmetric product $QQ^{\mathsf T}$. ```math P=QQ^{\mathsf T}, \qquad P_{ij}=\binom{i+j-2}{i-1}, \qquad P=P^{\mathsf T}\succ0. ``` Because $Q$ is unit lower triangular, $P$ is positive definite and $\det(P)=1$. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 \\ 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 \\ 1 & 3 & 6 & 10 & 15 & 21 & 28 & 36 \\ 1 & 4 & 10 & 20 & 35 & 56 & 84 & 120 \\ 1 & 5 & 15 & 35 & 70 & 126 & 210 & 330 \\ 1 & 6 & 21 & 56 & 126 & 252 & 462 & 792 \\ 1 & 7 & 28 & 84 & 210 & 462 & 924 & 1716 \\ 1 & 8 & 36 & 120 & 330 & 792 & 1716 & 3432 \end{bmatrix}. ``` This is the full concrete smoke fixture for `A1-PASCAL-SYM`. The matching [`pascal_sym.m`](../../../../examples/tiered/svd-tier-a/pascal_sym.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The dense symmetric product has exact combinatorial entries, large growth, and a clean positive-definite model. It is a useful contrast with the nonsymmetric triangular factor: symmetry enables an orthogonal factor interpretation, but it does not remove the singular-value dynamic range. Forming P by an exact product and checking the closed form prevents a hidden source inconsistency. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [pascal_sym.m](../../../../examples/tiered/svd-tier-a/pascal_sym.m) selects only A1-PASCAL-SYM from the fixed manifest. The matching pascal_sym.m constructs $Q$ and $P$ in MP, verifies $P=QQ^{\mathsf T}$, runs public svd($P$), and compares the complete spectrum with a wider reference. It also checks the cross-family identity that singular values of $P$ equal squares of singular values of $Q$, while still using dense svd for the measured result. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness Binomial values are generated by addition, and the product identity is checked entrywise under a sufficient bit guard. Positive definiteness follows from Q being nonsingular, not from a numerical Cholesky alone. The Q reference and P measured input remain distinct objects. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes The stored P is exact integer data after the checked product. Work precision controls P, SVD, and the cross-reference. Mathematical conditioning is inherited from Pascal growth. More bits preserve small singular values but do not turn a dense run into a structured high-relative-accuracy algorithm. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Read reconstruction and orthogonality first, then compare $\sigma(P)$ with $\sigma(Q)^2$ as an independent identity. This relation is a check, not permission to form $P^{\mathsf T}P$ as a generic SVD oracle. Repeated or clustered factors remain nonunique. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not call a numerical $P=QQ^{\mathsf T}$ equality an exact proof, use normal equations as the main path, infer factor uniqueness from symmetry, or quote a published table not reproduced by this fixture. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Pedro Alonso, Jorge Delgado, Rafael Gallego, and Juan Manuel Peña, Conditioning and accurate computations with Pascal matrices. Journal of Computational and Applied Mathematics 252 (2013), 21–26. DOI: 10.1016/j.cam.2011.12.007](https://doi.org/10.1016/j.cam.2011.12.007) — Exact Pascal constructions and conditioning context. - [Plamen Koev, Accurate Eigenvalues and SVDs of Totally Nonnegative Matrices. SIAM Journal on Matrix Analysis and Applications 27(1) (2005), 1–23. DOI: 10.1137/S0895479803438225](https://doi.org/10.1137/S0895479803438225) — The structured-factor accuracy context; this page does not claim a dense SVD implementation of that algorithm. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [pascal_sym.m](../../../../examples/tiered/svd-tier-a/pascal_sym.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/svd-tier-a/lauchli_wide.md0000644000230300031750000002337615274353473025227 0ustar rafaelrafael# Wide transpose of the Läuchli matrix (Tier A4) ## Quick idea A4-LAU-WIDE is a Tier A control. The wide form checks shape-aware SVD semantics and conjugate/transposed factor orientation. It is one fixed matrix with one matching runnable example. The tier identifies the verification question, not a claim that public dense svd implements any cited structured algorithm. ## Mathematical problem Smoke: $n=4$, $b=20$. Demo: $n=8$, $b=100$. $W=T^{\mathsf T}$ has shape $n$-by-$(n+1)$. ```math W=T^{\mathsf T}=\begin{bmatrix}\mathbf{1}&\mu I_n\end{bmatrix}, \qquad WW^{\mathsf T}=\mathbf{1}\mathbf{1}^{\mathsf T}+\mu^2 I_n. ``` The nonzero singular values are the same as for T, but left and right singular subspaces exchange roles. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 2^{-20} & 0 & 0 & 0 \\ 1 & 0 & 2^{-20} & 0 & 0 \\ 1 & 0 & 0 & 2^{-20} & 0 \\ 1 & 0 & 0 & 0 & 2^{-20} \end{bmatrix}. ``` This is the full concrete smoke fixture for `A4-LAU-WIDE`. The matching [`lauchli_wide.m`](../../../../examples/tiered/svd-tier-a/lauchli_wide.m) selects the same manifest case and hands this input to the public `svd` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The wide form checks shape-aware SVD semantics and conjugate/transposed factor orientation. The repeated small group remains non-identifiable, but it lives on the opposite side from the tall formulation. A routine that assumes m≥n or compares the wrong projector can pass a scalar-value test while returning wrong factors. The exact model, any analytic or structural reference, and measured SVD output are kept separate. A convenient identity is a check on the named matrix, never a silent replacement for it. ## What the Octave example computes The matching [lauchli_wide.m](../../../../examples/tiered/svd-tier-a/lauchli_wide.m) selects only A4-LAU-WIDE from the fixed manifest. The matching lauchli_wide.m builds W directly, runs public svd, and checks the nonzero spectrum, reconstruction, and the exchanged repeated projectors. It uses the tall case only as a mathematically related reference; the measured input remains W. Economy/full output dimensions are recorded explicitly. The runner records shape, parameters, source/model identity, operation precision, and any native control while retaining MPFR/MPC arithmetic. ## Construction and exactness The transpose identity and Gram form are checked in MP. μ is a dyadic source value, and the projector formulas are evaluated without normal-equation recovery of the measured SVD. The nullspace convention is documented for the chosen output shape. Exactness is proved from the declared integer/dyadic construction and guard. Two agreeing MP computations are useful corroboration but are not an exactness proof. Binary64 conversion is allowed only at an explicitly labelled presentation boundary. ## Diagnostics For $A\in\mathbb{C}^{m\times n}$, use ```math A=U\Sigma V^{\mathsf H},\qquad r_{\mathrm{svd}}=\frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\quad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` For a repeated or rank cluster compare the associated left/right projectors or ranges; individual factors are not canonical. Also inspect the value-wise forward bottleneck, rank/cluster metric, and any model-specific identity. Keep residuals as MP values until display. A small reconstruction residual alone does not certify each singular value digit. ## Backward error versus forward error The reconstruction residual is a backward-error style measure for the factorization equation: the returned factors nearly explain the stored A. Forward singular-value error compares values with the mathematical spectrum of that exact stored model and depends on gaps, scales, and conditioning. For repeated values the forward object is a subspace; for rank-deficient data exact model rank is separate from thresholding measured values. ## What arbitrary precision changes Input/source precision preserves μ; arithmetic precision controls W, SVD, and references. Mathematical sensitivity is the same as the tall problem but appears on the transposed side. More bits reduce arithmetic error, not subspace nonuniqueness. Input/source precision identifies the stored matrix and deliberate once-rounded variants. Arithmetic/work precision is the MPFR/MPC precision used by construction, SVD, and references. Mathematical conditioning belongs to the model and can remain severe at arbitrary precision. Raising mpbits reduces arithmetic error but does not restore a tail lost in the input or make a repeated basis unique. Ambient-precision and restoration tests protect operation ownership. ## Reading the output Read dimensions before interpreting $U$ and $V$. Compare the repeated right/left subspaces on the correct side and do not expect a column-by-column match with $T$. $r_{\mathrm{svd}}$ remains the reconstruction diagnostic; singular-value equality is only one gate. A PASS line is scoped to this case and profile. Compare rows only when parameters and model identity match. If a rank, subspace, or exactness field is not claimed, do not infer it from a visually stable display. ## Common mistakes Do not assume tall output dimensions, swap U and V without conjugation/transpose, use T as the measured input, or derive values through normal equations. For diagnosis, verify case ID and shape, then model hash/input precision, then reconstruction and orthogonality, then the case-specific value or subspace metric. Do not change parameters after a failure and report the changed input as this case. ## Parameter boundary and comparison protocol The parameter in this page is part of the case identity, not a tuning knob. Record n, the dyadic exponents, the representation (raw, mixed, tall, wide, complex, repeated, or rank-deficient), and the source/model hash before comparing outputs. A reference generated from a neighboring case can be mathematically related and still be the wrong target. This is especially important for a close pair, where replacing a nonzero gap by zero changes the forward problem, and for a rank case, where replacing an exact zero by a tiny positive number changes the rank. Use a bijective matching for values and a phase-aware or subspace-aware comparison for factors. The matching is performed in MP arithmetic and is a diagnostic, not a way to hide an unmatched value. If the output shape is rectangular, state which economy/full convention is being used. If a factor is not identifiable because of a repeated singular value or a null space, report the projector or range and do not manufacture an individual-vector error. These rules make the short runner reproducible and keep its PASS result scoped to the named model. ## Scope of the claim This page explains one fixed SVD model and the precise object that the runner measures. Changing a dimension, dyadic exponent, scale, phase, gap, or zero entry changes the source matrix and requires a new case identity. That is especially important for repeated and rank-deficient examples: a zero gap is not a tiny gap, and an exact zero is not merely a small positive singular value. The analytic spectrum or projector is an independent model check. It is not inserted into the measured factorization, and the public dense SVD is not silently replaced by a structured bidiagonal or totally-nonnegative algorithm. Reconstruction, unitarity, value-wise forward error, and subspace comparisons answer different questions. The runner records all of them with the input and arithmetic precision roles. Binary64 is permitted only at an explicitly declared presentation boundary; it is never an unreported numerical fallback. ## References - [Peter Läuchli, Jordan-Elimination und Ausgleichung nach kleinsten Quadraten. Numerische Mathematik 3 (1961), 226–240. DOI: 10.1007/BF01386022](https://doi.org/10.1007/BF01386022) — Historical source for the Läuchli matrix convention; the exact spectrum here follows directly from its Gram matrix. - [Per-Åke Wedin, Perturbation bounds in connection with singular value decomposition. BIT 12 (1972), 99–111. DOI: 10.1007/BF01932678](https://doi.org/10.1007/BF01932678) — Separates individual singular-vector claims from separated-subspace claims. - [GNU MPFR project, MPFR 4.2 manual, floating-point numbers and rounding](https://www.mpfr.org/mpfr-current/mpfr.html) — Correct-rounding and exponent-range terminology for dyadic input audits. These sources establish external mathematical context. The selected dimensions, dyadic values, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated above. ## Project provenance - Runnable case: [lauchli_wide.m](../../../../examples/tiered/svd-tier-a/lauchli_wide.m). - Case manifest: [SVT cases.json](../../../../docs/codex/svt/cases.json). - Certificate scope: [SVT VERIFICATION.md](../../../../docs/codex/svt/VERIFICATION.md) and [SVT SOURCES.md](../../../../docs/codex/svt/SOURCES.md). - This page explains the model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/MIGRATION.md0000644000230300031750000004136415274353473022151 0ustar rafaelrafael# Tiered example migration and documentation map This map records the migration from the four historical numbered entry points to the 44 one-case examples. The original files remain compatibility indexes and counted profile surfaces. Each row below must keep one case ID, one runnable example, one detailed mathematical page, one explicit definition/equation review, and one external primary-context link. ## Map | Case ID | Layer | Runnable .m | Detailed .md | Definition and equations | External reference | Depth review | |---|---|---|---|---|---|---| | OO53_REAL | NEIG S1 | [oo53_real.m](../../../examples/tiered/neig-tier-s/oo53_real.m) | [oo53_real.md](./neig-tier-s/oo53_real.md) | Ozaki–Ogita $g=53$ real triple product; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/s11075-021-01186-7) | reviewed: definition, precision roles, errors, limitations | | OO53_PAIR | NEIG S1 | [oo53_pair.m](../../../examples/tiered/neig-tier-s/oo53_pair.m) | [oo53_pair.md](./neig-tier-s/oo53_pair.md) | paired 2-by-2 standard blocks and sign-copy rule; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/s11075-021-01186-7) | reviewed: definition, precision roles, errors, limitations | | OO128_CLOSE | NEIG S1 | [oo128_close.m](../../../examples/tiered/neig-tier-s/oo128_close.m) | [oo128_close.md](./neig-tier-s/oo128_close.md) | $g=128$ requested/realized close spectrum; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/s11075-021-01186-7) | reviewed: definition, precision roles, errors, limitations | | SIM_SIMPLE | NEIG S2 | [sim_simple.m](../../../examples/tiered/neig-tier-s/sim_simple.m) | [sim_simple.md](./neig-tier-s/sim_simple.md) | dense similarity with simple gap d; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/21M1451440) | reviewed: definition, precision roles, errors, limitations | | SIM_REPEAT | NEIG S2 | [sim_repeat.m](../../../examples/tiered/neig-tier-s/sim_repeat.m) | [sim_repeat.md](./neig-tier-s/sim_repeat.md) | semisimple repeated invariant subspace; rendered model and diagnostics present | [primary source](https://doi.org/10.1016/S0024-3795(00)00279-2) | reviewed: definition, precision roles, errors, limitations | | SIM_JORDAN | NEIG S2 | [sim_jordan.m](../../../examples/tiered/neig-tier-s/sim_jordan.m) | [sim_jordan.md](./neig-tier-s/sim_jordan.md) | genuine $J_2$ block and nilpotency; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/21M1451440) | reviewed: definition, precision roles, errors, limitations | | SIM_TWO_JORDAN | NEIG S2 | [sim_two_jordan.m](../../../examples/tiered/neig-tier-s/sim_two_jordan.m) | [sim_two_jordan.md](./neig-tier-s/sim_two_jordan.md) | two defective clusters and merge; rendered model and diagnostics present | [primary source](https://doi.org/10.1016/S0024-3795(00)00279-2) | reviewed: definition, precision roles, errors, limitations | | TOEPLITZ | NEIG S3 | [toeplitz.m](../../../examples/tiered/neig-tier-s/toeplitz.m) | [toeplitz.md](./neig-tier-s/toeplitz.md) | diagonal-scaled tridiagonal Toeplitz; rendered model and diagnostics present | [primary source](https://doi.org/10.1002/nla.1811) | reviewed: definition, precision roles, errors, limitations | | TOEPLITZ_SYM | NEIG S3 | [toeplitz_sym.m](../../../examples/tiered/neig-tier-s/toeplitz_sym.m) | [toeplitz_sym.md](./neig-tier-s/toeplitz_sym.md) | symmetric Toeplitz control; rendered model and diagnostics present | [primary source](https://doi.org/10.1002/nla.1811) | reviewed: definition, precision roles, errors, limitations | | FORSYTHE | NEIG S4 | [forsythe.m](../../../examples/tiered/neig-tier-s/forsythe.m) | [forsythe.md](./neig-tier-s/forsythe.md) | cyclic perturbation of Jordan block; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/1.9780898718027) | reviewed: definition, precision roles, errors, limitations | | FORSYTHE_SCALED | NEIG S4 | [forsythe_scaled.m](../../../examples/tiered/neig-tier-s/forsythe_scaled.m) | [forsythe_scaled.md](./neig-tier-s/forsythe_scaled.md) | normal cyclic control; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/1.9780898718027) | reviewed: definition, precision roles, errors, limitations | | FORSYTHE_ZERO | NEIG S4 | [forsythe_zero.m](../../../examples/tiered/neig-tier-s/forsythe_zero.m) | [forsythe_zero.md](./neig-tier-s/forsythe_zero.md) | exact Jordan zero limit; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/21M1451440) | reviewed: definition, precision roles, errors, limitations | | HAD_BIDIAG | NEIG A1 | [had_bidiag.m](../../../examples/tiered/neig-tier-a/had_bidiag.m) | [had_bidiag.md](./neig-tier-a/had_bidiag.md) | Hadamard similarity of upper bidiagonal; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/21M1451440) | reviewed: definition, precision roles, errors, limitations | | FRANK0 | NEIG A2 | [frank0.m](../../../examples/tiered/neig-tier-a/frank0.m) | [frank0.md](./neig-tier-a/frank0.md) | explicit integer Frank orientation; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/1.9780898718027) | reviewed: definition, precision roles, errors, limitations | | FRANK1 | NEIG A2 | [frank1.m](../../../examples/tiered/neig-tier-a/frank1.m) | [frank1.md](./neig-tier-a/frank1.md) | reflected Frank orientation; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/1.9780898718027) | reviewed: definition, precision roles, errors, limitations | | WILKINSON | NEIG A3 | [wilkinson.m](../../../examples/tiered/neig-tier-a/wilkinson.m) | [wilkinson.md](./neig-tier-a/wilkinson.md) | integer companion and polynomial backward error; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/17M1152802) | reviewed: definition, precision roles, errors, limitations | | GRCAR | NEIG A4 | [grcar.m](../../../examples/tiered/neig-tier-a/grcar.m) | [grcar.md](./neig-tier-a/grcar.md) | $0/\pm1$ Grcar and pseudospectrum; rendered model and diagnostics present | [primary source](https://doi.org/10.1016/j.laa.2005.06.009) | reviewed: definition, precision roles, errors, limitations | | MKS | NEIG A5 | [mks.m](../../../examples/tiered/neig-tier-a/mks.m) | [mks.md](./neig-tier-a/mks.md) | nilpotent shift plus rank one; rendered model and diagnostics present | [primary source](https://doi.org/10.1142/S2661335225500133) | reviewed: definition, precision roles, errors, limitations | | MARKOV | NEIG A6 | [markov.m](../../../examples/tiered/neig-tier-a/markov.m) | [markov.md](./neig-tier-a/markov.md) | dyadic Markov matrix and stationary vector; rendered model and diagnostics present | [primary source](https://doi.org/10.13001/ela.2021.5181) | reviewed: definition, precision roles, errors, limitations | | PERRON_POS | NEIG A6 | [perron_pos.m](../../../examples/tiered/neig-tier-a/perron_pos.m) | [perron_pos.md](./neig-tier-a/perron_pos.md) | positive diagonal Perron similarity; rendered model and diagnostics present | [primary source](https://doi.org/10.13001/ela.2021.5181) | reviewed: definition, precision roles, errors, limitations | | HAD_COMPLEX | NEIG A1 | [had_complex.m](../../../examples/tiered/neig-tier-a/had_complex.m) | [had_complex.md](./neig-tier-a/had_complex.md) | quarter-turn complex phase control; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/21M1451440) | reviewed: definition, precision roles, errors, limitations | | S1-NRO-TWO | SVD S1 | [nro_two.m](../../../examples/tiered/svd-tier-s/nro_two.m) | [nro_two.md](./svd-tier-s/nro_two.md) | NRO block reciprocal singular pairs; rendered model and diagnostics present | [primary source](https://doi.org/10.1587/nolta.2.226) | reviewed: definition, precision roles, errors, limitations | | S1-NRO-THREE | SVD S1 | [nro_three.m](../../../examples/tiered/svd-tier-s/nro_three.m) | [nro_three.md](./svd-tier-s/nro_three.md) | NRO unit plus reciprocal groups; rendered model and diagnostics present | [primary source](https://doi.org/10.1587/nolta.2.226) | reviewed: definition, precision roles, errors, limitations | | S1-NRO-GRADED | SVD S1 | [nro_graded.m](../../../examples/tiered/svd-tier-s/nro_graded.m) | [nro_graded.md](./svd-tier-s/nro_graded.md) | graded NRO singular scales; rendered model and diagnostics present | [primary source](https://doi.org/10.1587/nolta.2.226) | reviewed: definition, precision roles, errors, limitations | | S1-NRO-SCALE-UP | SVD S1 | [nro_scale_up.m](../../../examples/tiered/svd-tier-s/nro_scale_up.m) | [nro_scale_up.md](./svd-tier-s/nro_scale_up.md) | large exponent range control; rendered model and diagnostics present | [primary source](https://www.mpfr.org/mpfr-current/mpfr.html) | reviewed: definition, precision roles, errors, limitations | | S1-NRO-SCALE-DOWN | SVD S1 | [nro_scale_down.m](../../../examples/tiered/svd-tier-s/nro_scale_down.m) | [nro_scale_down.md](./svd-tier-s/nro_scale_down.md) | small exponent range control; rendered model and diagnostics present | [primary source](https://www.mpfr.org/mpfr-current/mpfr.html) | reviewed: definition, precision roles, errors, limitations | | S2-JS | SVD S2 | [jacobi_stirling.m](../../../examples/tiered/svd-tier-s/jacobi_stirling.m) | [jacobi_stirling.md](./svd-tier-s/jacobi_stirling.md) | Jacobi–Stirling integer recurrence; rendered model and diagnostics present | [primary source](https://doi.org/10.1016/j.amc.2014.03.047) | reviewed: definition, precision roles, errors, limitations | | S3-LAH | SVD S3 | [lah.m](../../../examples/tiered/svd-tier-s/lah.m) | [lah.md](./svd-tier-s/lah.md) | unsigned Lah recurrence; rendered model and diagnostics present | [primary source](https://doi.org/10.1002/nla.2217) | reviewed: definition, precision roles, errors, limitations | | S4-DD-SYM | SVD S4 | [dd_sym.m](../../../examples/tiered/svd-tier-s/dd_sym.m) | [dd_sym.md](./svd-tier-s/dd_sym.md) | symmetric shifted path and tiny sigma; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/s00211-011-0382-3) | reviewed: definition, precision roles, errors, limitations | | S4-DD-NONSYM | SVD S4 | [dd_nonsym.m](../../../examples/tiered/svd-tier-s/dd_nonsym.m) | [dd_nonsym.md](./svd-tier-s/dd_nonsym.md) | biased path; eigenvalue not $\sigma_{\min}$; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/s00211-011-0382-3) | reviewed: definition, precision roles, errors, limitations | | A1-PASCAL-LOWER | SVD A1 | [pascal_lower.m](../../../examples/tiered/svd-tier-a/pascal_lower.m) | [pascal_lower.md](./svd-tier-a/pascal_lower.md) | lower Pascal binomial recurrence; rendered model and diagnostics present | [primary source](https://doi.org/10.1016/j.cam.2011.12.007) | reviewed: definition, precision roles, errors, limitations | | A1-PASCAL-SYM | SVD A1 | [pascal_sym.m](../../../examples/tiered/svd-tier-a/pascal_sym.m) | [pascal_sym.md](./svd-tier-a/pascal_sym.md) | symmetric Pascal product; rendered model and diagnostics present | [primary source](https://doi.org/10.1016/j.cam.2011.12.007) | reviewed: definition, precision roles, errors, limitations | | A2-VAND | SVD A2 | [vandermonde.m](../../../examples/tiered/svd-tier-a/vandermonde.m) | [vandermonde.md](./svd-tier-a/vandermonde.md) | dyadic-node Vandermonde powers; rendered model and diagnostics present | [primary source](https://doi.org/10.1137/S0895479803438225) | reviewed: definition, precision roles, errors, limitations | | A3-BDI-RAW | SVD A3 | [bidiag_raw.m](../../../examples/tiered/svd-tier-a/bidiag_raw.m) | [bidiag_raw.md](./svd-tier-a/bidiag_raw.md) | graded raw bidiagonal; rendered model and diagnostics present | [primary source](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) | reviewed: definition, precision roles, errors, limitations | | A3-BDI-MIXED | SVD A3 | [bidiag_mixed.m](../../../examples/tiered/svd-tier-a/bidiag_mixed.m) | [bidiag_mixed.md](./svd-tier-a/bidiag_mixed.md) | two-sided Hadamard mix; rendered model and diagnostics present | [primary source](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) | reviewed: definition, precision roles, errors, limitations | | A4-LAU-TALL | SVD A4 | [lauchli_tall.m](../../../examples/tiered/svd-tier-a/lauchli_tall.m) | [lauchli_tall.md](./svd-tier-a/lauchli_tall.md) | tall Läuchli repeated small group; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/BF01386022) | reviewed: definition, precision roles, errors, limitations | | A4-LAU-WIDE | SVD A4 | [lauchli_wide.m](../../../examples/tiered/svd-tier-a/lauchli_wide.m) | [lauchli_wide.md](./svd-tier-a/lauchli_wide.md) | wide transpose and side exchange; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/BF01386022) | reviewed: definition, precision roles, errors, limitations | | A4-LAU-COMPLEX | SVD A4 | [lauchli_complex.m](../../../examples/tiered/svd-tier-a/lauchli_complex.m) | [lauchli_complex.md](./svd-tier-a/lauchli_complex.md) | complex phased Läuchli; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/BF01386022) | reviewed: definition, precision roles, errors, limitations | | A5-GEO | SVD A5 | [hadamard_geometric.m](../../../examples/tiered/svd-tier-a/hadamard_geometric.m) | [hadamard_geometric.md](./svd-tier-a/hadamard_geometric.md) | Hadamard-mixed geometric spectrum; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/BF01932678) | reviewed: definition, precision roles, errors, limitations | | A5-CLOSE | SVD A5 | [hadamard_close.m](../../../examples/tiered/svd-tier-a/hadamard_close.m) | [hadamard_close.md](./svd-tier-a/hadamard_close.md) | close singular pair; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/BF01932678) | reviewed: definition, precision roles, errors, limitations | | A5-REPEAT | SVD A5 | [hadamard_repeat.m](../../../examples/tiered/svd-tier-a/hadamard_repeat.m) | [hadamard_repeat.md](./svd-tier-a/hadamard_repeat.md) | repeated singular subspace; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/BF01932678) | reviewed: definition, precision roles, errors, limitations | | A5-RANK4 | SVD A5 | [hadamard_rank4.m](../../../examples/tiered/svd-tier-a/hadamard_rank4.m) | [hadamard_rank4.md](./svd-tier-a/hadamard_rank4.md) | exact rank four; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/BF01932678) | reviewed: definition, precision roles, errors, limitations | | A5-RANK5 | SVD A5 | [hadamard_rank5.m](../../../examples/tiered/svd-tier-a/hadamard_rank5.m) | [hadamard_rank5.md](./svd-tier-a/hadamard_rank5.md) | near-rank fifth value; rendered model and diagnostics present | [primary source](https://doi.org/10.1007/BF01932678) | reviewed: definition, precision roles, errors, limitations | | A6-NRO-COMPANION | SVD A6 | [nro_companion.m](../../../examples/tiered/svd-tier-a/nro_companion.m) | [nro_companion.md](./svd-tier-a/nro_companion.md) | bounded-integer companion-like matrix; rendered model and diagnostics present | [primary source](https://doi.org/10.1587/nolta.2.226) | reviewed: definition, precision roles, errors, limitations | ## Historical entry points | Historical file | New family guide | Cases | Regression authority | |---|---|---:|---| | [examples/14_neig_tier_s.m](../../../examples/14_neig_tier_s.m) | [neig-tier-s/README.md](neig-tier-s/README.md) | 12 | examples/neig_tiers/mp_neig_tiers.m | | [examples/15_neig_tier_a.m](../../../examples/15_neig_tier_a.m) | [neig-tier-a/README.md](neig-tier-a/README.md) | 9 | examples/neig_tiers/mp_neig_tiers.m | | [examples/14_svd_tier_s.m](../../../examples/14_svd_tier_s.m) | [svd-tier-s/README.md](svd-tier-s/README.md) | 9 | examples/svd_tiers/mp_svd_tiers.m | | [examples/15_svd_tier_a.m](../../../examples/15_svd_tier_a.m) | [svd-tier-a/README.md](svd-tier-a/README.md) | 14 | examples/svd_tiers/mp_svd_tiers.m | ## Review rules Definition and equations mean the page states dimensions, index ranges, parameters, construction, and the exact mathematical identity or reference used by the runner. The diagnostics section must name reconstruction/eigen residuals and the appropriate forward, subspace, rank, or cluster interpretation. References must identify authors, title, publication/year, DOI or stable URL, and relevance. Depth review also checks source precision, arithmetic precision, mathematical conditioning, common mistakes, and the exact boundary between a measured result and an independent reference. The one-case scripts intentionally remain thin. Full 120 smoke eig rows, 168 demo eig rows, the SVD profile rows, NEIG/SVT V jobs, replay/adversarial checks, and isolated package QA remain in their existing harnesses. The migration does not claim that a short page replaces those gates. See [GLOSSARY.md](GLOSSARY.md) for shared terms and [master README](README.md) for the learning order. mplapack-interop-0.5.1/docs/examples/tiered/README.md0000644000230300031750000003745415274353473021562 0ustar rafaelrafael# Tiered nonsymmetric eigensystem and SVD examples This is the complete learning map for the decomposed difficult-matrix examples. There are 44 standard cases: 21 nonsymmetric-eigensystem cases and 23 SVD cases, split into Tier S (deep stress/semantic cases) and Tier A (broad advanced controls). Every row has exactly one conceptual case, one runnable .m entry point, and one matching detailed .md explanation. The historical numbered scripts remain indexes and counted regression surfaces. ## Start with the mathematical contract For nonsymmetric eigensystems, the right and left equations are ```math A V=V D,\qquad A^{\mathsf H}W=WD^{\mathsf H}. ``` For SVD, ```math A=U\Sigma V^{\mathsf H}. ``` The residuals are backward-style equation diagnostics. Forward error additionally depends on conditioning, scale, gaps, multiplicity, and the exact model that was stored. Repeated or defective eigenspaces and repeated or null singular groups must be compared as subspaces. A high-precision reference is not silently inserted into measured output. The examples use only the public arbitrary-precision interfaces. Input/source precision, operation/work precision, and mathematical conditioning are separate fields. A displayed conversion to binary64 is a presentation boundary, never an unreported numerical fallback. Every reasonably small smoke or fixed matrix is shown in full on its detailed page using exact integer or dyadic notation. The displayed source matrix is kept separate from measured eig/SVD output, and fixed-generation precision is kept separate from any exact widening and solver precision. The matrix audit is `tools/check-smoke-matrices.sh`. ## Family guides | Family | Cases | Purpose | Guide | |---|---:|---|---| | NEIG Tier S | 12 | fixed generator, near/repeated/defective roots, Toeplitz and Forsythe representations | [neig-tier-s/README.md](neig-tier-s/README.md) | | NEIG Tier A | 9 | Hadamard, Frank, companion, Grcar, MKS, Markov/Perron, complex control | [neig-tier-a/README.md](neig-tier-a/README.md) | | SVD Tier S | 9 | NRO, combinatorial growth, exponent range, diagonally dominant paths | [svd-tier-s/README.md](svd-tier-s/README.md) | | SVD Tier A | 14 | Pascal, Vandermonde, bidiagonal, Läuchli, known groups/rank, companion-like controls | [svd-tier-a/README.md](svd-tier-a/README.md) | ## Complete learning map The External reference column is a primary or authoritative external source for the mathematical phenomenon. The selected dimensions and thresholds are project fixtures; the detailed page records the attribution boundary. | ID | Family | Mathematical definition / phenomenon | Main measured question | Runnable example | Detailed explanation | External reference | |---|---|---|---|---|---|---| | OO53_REAL | NEIG-S1 | fixed $g=53$ Ozaki–Ogita real triple product | requested versus realized spectrum | [oo53_real.m](../../../examples/tiered/neig-tier-s/oo53_real.m) | [oo53_real.md](neig-tier-s/oo53_real.md) | [Ozaki–Ogita 2022](https://doi.org/10.1007/s11075-021-01186-7) | | OO53_PAIR | NEIG-S1 | paired real 2-by-2 standard blocks | sign-copy and conjugate pairs | [oo53_pair.m](../../../examples/tiered/neig-tier-s/oo53_pair.m) | [oo53_pair.md](neig-tier-s/oo53_pair.md) | [Ozaki–Ogita 2022](https://doi.org/10.1007/s11075-021-01186-7) | | OO128_CLOSE | NEIG-S1 | fixed $g=128$ close standard form | deliberate $2^{-120}$ realization loss | [oo128_close.m](../../../examples/tiered/neig-tier-s/oo128_close.m) | [oo128_close.md](neig-tier-s/oo128_close.md) | [Ozaki–Ogita 2022](https://doi.org/10.1007/s11075-021-01186-7) | | SIM_SIMPLE | NEIG-S2 | dense similarity of a 2-by-2 near-Jordan model | simple near-defective roots | [sim_simple.m](../../../examples/tiered/neig-tier-s/sim_simple.m) | [sim_simple.md](neig-tier-s/sim_simple.md) | [Rump 2022](https://doi.org/10.1137/21M1451440) | | SIM_REPEAT | NEIG-S2 | dense similarity of $I_2$ | semisimple repeated eigenspace | [sim_repeat.m](../../../examples/tiered/neig-tier-s/sim_repeat.m) | [sim_repeat.md](neig-tier-s/sim_repeat.md) | [Rump 2001](https://doi.org/10.1016/S0024-3795(00)00279-2) | | SIM_JORDAN | NEIG-S2 | dense similarity of $J_2(1)$ | genuine defect and block relation | [sim_jordan.m](../../../examples/tiered/neig-tier-s/sim_jordan.m) | [sim_jordan.md](neig-tier-s/sim_jordan.md) | [Rump 2022](https://doi.org/10.1137/21M1451440) | | SIM_TWO_JORDAN | NEIG-S2 | two nearby defective blocks | separated versus merged clusters | [sim_two_jordan.m](../../../examples/tiered/neig-tier-s/sim_two_jordan.m) | [sim_two_jordan.md](neig-tier-s/sim_two_jordan.md) | [Rump 2001](https://doi.org/10.1016/S0024-3795(00)00279-2) | | TOEPLITZ | NEIG-S3 | diagonal scaling of tridiagonal Toeplitz | spectrum versus vector conditioning | [toeplitz.m](../../../examples/tiered/neig-tier-s/toeplitz.m) | [toeplitz.md](neig-tier-s/toeplitz.md) | [Noschese et al. 2013](https://doi.org/10.1002/nla.1811) | | TOEPLITZ_SYM | NEIG-S3 | explicit symmetric Toeplitz control | representation sensitivity | [toeplitz_sym.m](../../../examples/tiered/neig-tier-s/toeplitz_sym.m) | [toeplitz_sym.md](neig-tier-s/toeplitz_sym.md) | [Noschese et al. 2013](https://doi.org/10.1002/nla.1811) | | FORSYTHE | NEIG-S4 | $I+N$ plus $\varepsilon$ corner | tiny cyclic perturbation | [forsythe.m](../../../examples/tiered/neig-tier-s/forsythe.m) | [forsythe.md](neig-tier-s/forsythe.md) | [Higham 2002](https://doi.org/10.1137/1.9780898718027) | | FORSYTHE_SCALED | NEIG-S4 | $I+rP$ normal control | scaled versus original coordinates | [forsythe_scaled.m](../../../examples/tiered/neig-tier-s/forsythe_scaled.m) | [forsythe_scaled.md](neig-tier-s/forsythe_scaled.md) | [Higham 2002](https://doi.org/10.1137/1.9780898718027) | | FORSYTHE_ZERO | NEIG-S4 | $I+N$, true Jordan limit | no full eigenbasis claim | [forsythe_zero.m](../../../examples/tiered/neig-tier-s/forsythe_zero.m) | [forsythe_zero.md](neig-tier-s/forsythe_zero.md) | [Rump 2022](https://doi.org/10.1137/21M1451440) | | HAD_BIDIAG | NEIG-A1 | Hadamard similarity of upper bidiagonal T | separated roots, sensitive vectors | [had_bidiag.m](../../../examples/tiered/neig-tier-a/had_bidiag.m) | [had_bidiag.md](neig-tier-a/had_bidiag.md) | [Rump 2022](https://doi.org/10.1137/21M1451440) | | FRANK0 | NEIG-A2 | explicit integer Frank orientation | small reciprocal roots | [frank0.m](../../../examples/tiered/neig-tier-a/frank0.m) | [frank0.md](neig-tier-a/frank0.md) | [Higham 2002](https://doi.org/10.1137/1.9780898718027) | | FRANK1 | NEIG-A2 | $RF_0^{\mathsf T}R$ reflected orientation | left/right transformation | [frank1.m](../../../examples/tiered/neig-tier-a/frank1.m) | [frank1.md](neig-tier-a/frank1.md) | [Higham 2002](https://doi.org/10.1137/1.9780898718027) | | WILKINSON | NEIG-A3 | integer-root Frobenius companion | polynomial versus matrix backward error | [wilkinson.m](../../../examples/tiered/neig-tier-a/wilkinson.m) | [wilkinson.md](neig-tier-a/wilkinson.md) | [Aurentz et al. 2018](https://doi.org/10.1137/17M1152802) | | GRCAR | NEIG-A4 | exact $0/\pm1$ Grcar band | nonnormal pseudospectrum | [grcar.m](../../../examples/tiered/neig-tier-a/grcar.m) | [grcar.md](neig-tier-a/grcar.md) | [Rump 2006](https://doi.org/10.1016/j.laa.2005.06.009) | | MKS | NEIG-A5 | $N^m+\delta\mathbf{1}\mathbf{1}^{\mathsf T}$ | defective zero and reduced q | [mks.m](../../../examples/tiered/neig-tier-a/mks.m) | [mks.md](neig-tier-a/mks.md) | [Morimoto et al. 2025](https://doi.org/10.1142/S2661335225500133) | | MARKOV | NEIG-A6 | dyadic irreducible row-stochastic P | nonuniform stationary left vector | [markov.m](../../../examples/tiered/neig-tier-a/markov.m) | [markov.md](neig-tier-a/markov.md) | [Miyajima 2021](https://doi.org/10.13001/ela.2021.5181) | | PERRON_POS | NEIG-A6 | positive diagonal similarity of P | positive root and both vectors | [perron_pos.m](../../../examples/tiered/neig-tier-a/perron_pos.m) | [perron_pos.md](neig-tier-a/perron_pos.md) | [Miyajima 2021](https://doi.org/10.13001/ela.2021.5181) | | HAD_COMPLEX | NEIG-A1 | quarter-turn unitary phase | complex adjoint convention | [had_complex.m](../../../examples/tiered/neig-tier-a/had_complex.m) | [had_complex.md](neig-tier-a/had_complex.md) | [Rump 2022](https://doi.org/10.1137/21M1451440) | | S1-NRO-TWO | SVD-S1 | NRO block with reciprocal weights | reciprocal extreme values | [nro_two.m](../../../examples/tiered/svd-tier-s/nro_two.m) | [nro_two.md](svd-tier-s/nro_two.md) | [Nishi et al. 2011](https://doi.org/10.1587/nolta.2.226) | | S1-NRO-THREE | SVD-S1 | NRO block with zero-weight half | unit and reciprocal groups | [nro_three.m](../../../examples/tiered/svd-tier-s/nro_three.m) | [nro_three.md](svd-tier-s/nro_three.md) | [Nishi et al. 2011](https://doi.org/10.1587/nolta.2.226) | | S1-NRO-GRADED | SVD-S1 | graded powers-of-two weights | multiple singular scales | [nro_graded.m](../../../examples/tiered/svd-tier-s/nro_graded.m) | [nro_graded.md](svd-tier-s/nro_graded.md) | [Nishi et al. 2011](https://doi.org/10.1587/nolta.2.226) | | S1-NRO-SCALE-UP | SVD-S1 | $2^{600}$ NRO scale control | large exponent range | [nro_scale_up.m](../../../examples/tiered/svd-tier-s/nro_scale_up.m) | [nro_scale_up.md](svd-tier-s/nro_scale_up.md) | [MPFR manual](https://www.mpfr.org/mpfr-current/mpfr.html) | | S1-NRO-SCALE-DOWN | SVD-S1 | $2^{-600}$ NRO scale control | small exponent range | [nro_scale_down.m](../../../examples/tiered/svd-tier-s/nro_scale_down.m) | [nro_scale_down.md](svd-tier-s/nro_scale_down.md) | [MPFR manual](https://www.mpfr.org/mpfr-current/mpfr.html) | | S2-JS | SVD-S2 | Jacobi–Stirling lower triangle | combinatorial growth | [jacobi_stirling.m](../../../examples/tiered/svd-tier-s/jacobi_stirling.m) | [jacobi_stirling.md](svd-tier-s/jacobi_stirling.md) | [Delgado–Peña 2014](https://doi.org/10.1016/j.amc.2014.03.047) | | S3-LAH | SVD-S3 | unsigned Lah lower triangle | growth and small tail | [lah.m](../../../examples/tiered/svd-tier-s/lah.m) | [lah.md](svd-tier-s/lah.md) | [Delgado et al. 2019](https://doi.org/10.1002/nla.2217) | | S4-DD-SYM | SVD-S4 | symmetric shifted path | exact tiny $\sigma_{\min}$ | [dd_sym.m](../../../examples/tiered/svd-tier-s/dd_sym.m) | [dd_sym.md](svd-tier-s/dd_sym.md) | [Dopico–Koev 2011](https://doi.org/10.1007/s00211-011-0382-3) | | S4-DD-NONSYM | SVD-S4 | biased dominant path | eigenvalue is not $\sigma_{\min}$ | [dd_nonsym.m](../../../examples/tiered/svd-tier-s/dd_nonsym.m) | [dd_nonsym.md](svd-tier-s/dd_nonsym.md) | [Dopico–Koev 2011](https://doi.org/10.1007/s00211-011-0382-3) | | A1-PASCAL-LOWER | SVD-A1 | lower Pascal Q | exact combinatorial source | [pascal_lower.m](../../../examples/tiered/svd-tier-a/pascal_lower.m) | [pascal_lower.md](svd-tier-a/pascal_lower.md) | [Alonso et al. 2013](https://doi.org/10.1016/j.cam.2011.12.007) | | A1-PASCAL-SYM | SVD-A1 | $P=QQ^{\mathsf T}$ | dense symmetric product | [pascal_sym.m](../../../examples/tiered/svd-tier-a/pascal_sym.m) | [pascal_sym.md](svd-tier-a/pascal_sym.md) | [Alonso et al. 2013](https://doi.org/10.1016/j.cam.2011.12.007) | | A2-VAND | SVD-A2 | dyadic-node Vandermonde | node and power conditioning | [vandermonde.m](../../../examples/tiered/svd-tier-a/vandermonde.m) | [vandermonde.md](svd-tier-a/vandermonde.md) | [Koev 2005](https://doi.org/10.1137/S0895479803438225) | | A3-BDI-RAW | SVD-A3 | graded upper bidiagonal | small-tail accuracy | [bidiag_raw.m](../../../examples/tiered/svd-tier-a/bidiag_raw.m) | [bidiag_raw.md](svd-tier-a/bidiag_raw.md) | [LAPACK DLASQ1](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) | | A3-BDI-MIXED | SVD-A3 | $HBG^{\mathsf T}/n$ | dense representation | [bidiag_mixed.m](../../../examples/tiered/svd-tier-a/bidiag_mixed.m) | [bidiag_mixed.md](svd-tier-a/bidiag_mixed.md) | [LAPACK DLASQ1](https://www.netlib.org/lapack/explore-html/d5/dce/group__lasq1_ga5a8c1474ef61ff7c59c17412ae456ca6.html) | | A4-LAU-TALL | SVD-A4 | tall Läuchli construction | repeated small group | [lauchli_tall.m](../../../examples/tiered/svd-tier-a/lauchli_tall.m) | [lauchli_tall.md](svd-tier-a/lauchli_tall.md) | [Läuchli 1961](https://doi.org/10.1007/BF01386022) | | A4-LAU-WIDE | SVD-A4 | transpose of tall case | shape and side exchange | [lauchli_wide.m](../../../examples/tiered/svd-tier-a/lauchli_wide.m) | [lauchli_wide.md](svd-tier-a/lauchli_wide.md) | [Läuchli 1961](https://doi.org/10.1007/BF01386022) | | A4-LAU-COMPLEX | SVD-A4 | phased complex tall case | MPC conjugation | [lauchli_complex.m](../../../examples/tiered/svd-tier-a/lauchli_complex.m) | [lauchli_complex.md](svd-tier-a/lauchli_complex.md) | [Läuchli 1961](https://doi.org/10.1007/BF01386022) | | A5-GEO | SVD-A5 | Hadamard mix of geometric d | dense known spectrum | [hadamard_geometric.m](../../../examples/tiered/svd-tier-a/hadamard_geometric.m) | [hadamard_geometric.md](svd-tier-a/hadamard_geometric.md) | [Wedin 1972](https://doi.org/10.1007/BF01932678) | | A5-CLOSE | SVD-A5 | close Hadamard pair | value gap and vector gap | [hadamard_close.m](../../../examples/tiered/svd-tier-a/hadamard_close.m) | [hadamard_close.md](svd-tier-a/hadamard_close.md) | [Wedin 1972](https://doi.org/10.1007/BF01932678) | | A5-REPEAT | SVD-A5 | repeated Hadamard group | subspace, not columns | [hadamard_repeat.m](../../../examples/tiered/svd-tier-a/hadamard_repeat.m) | [hadamard_repeat.md](svd-tier-a/hadamard_repeat.md) | [Wedin 1972](https://doi.org/10.1007/BF01932678) | | A5-RANK4 | SVD-A5 | four positive d values | exact rank four | [hadamard_rank4.m](../../../examples/tiered/svd-tier-a/hadamard_rank4.m) | [hadamard_rank4.md](svd-tier-a/hadamard_rank4.md) | [Wedin 1972](https://doi.org/10.1007/BF01932678) | | A5-RANK5 | SVD-A5 | $\eta$ beside exact zeros | near-rank boundary | [hadamard_rank5.m](../../../examples/tiered/svd-tier-a/hadamard_rank5.m) | [hadamard_rank5.md](svd-tier-a/hadamard_rank5.md) | [Wedin 1972](https://doi.org/10.1007/BF01932678) | | A6-NRO-COMPANION | SVD-A6 | bounded-integer companion-like | recurrence and dense SVD | [nro_companion.m](../../../examples/tiered/svd-tier-a/nro_companion.m) | [nro_companion.md](svd-tier-a/nro_companion.md) | [Nishi et al. 2011](https://doi.org/10.1587/nolta.2.226) | ## Running the layers One-case pages are deliberately light-weight entry points: ~~~octave pkg load mplapack-interop run ("examples/tiered/neig-tier-s/sim_jordan.m"); run ("examples/tiered/svd-tier-a/hadamard_close.m"); ~~~ The counted measurement runners remain authoritative: ~~~octave pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "neig_tiers")); neig_smoke = mp_neig_tiers ("smoke", struct ("plot", false)); addpath (fullfile (pwd (), "examples", "svd_tiers")); svd_smoke = mp_svd_tiers ("smoke", struct ("plot", false)); ~~~ Use the NEIG V-S/V-A examples and SVT V verification entry points only for the certificate claims they explicitly report. Stress and plotting are opt-in and remain outside ordinary PASS unless executed. ## Historical and verification surfaces - [NEIG Tier S guide](neig-tier-s/README.md), [NEIG Tier A guide](neig-tier-a/README.md). - [SVD Tier S guide](svd-tier-s/README.md), [SVD Tier A guide](svd-tier-a/README.md). - [Migration table](MIGRATION.md). - [NEIG cases](../../../docs/codex/neigt/cases.json), [NEIG verification jobs](../../../docs/codex/neigt/verification-jobs.json), and [NEIG sources](../../../docs/codex/neigt/SOURCES.md). - [SVT cases](../../../docs/codex/svt/cases.json), [SVT verification](../../../docs/codex/svt/VERIFICATION.md), and [SVT sources](../../../docs/codex/svt/SOURCES.md). - Historical numbered indexes: [14_neig_tier_s.m](../../../examples/14_neig_tier_s.m), [15_neig_tier_a.m](../../../examples/15_neig_tier_a.m), [14_svd_tier_s.m](../../../examples/14_svd_tier_s.m), [15_svd_tier_a.m](../../../examples/15_svd_tier_a.m). - Full measured V surfaces: [16_neig_verified_vs.m](../../../examples/16_neig_verified_vs.m), [17_neig_verified_va.m](../../../examples/17_neig_verified_va.m), [16_svd_verified.m](../../../examples/16_svd_verified.m). This map is pedagogical. It does not replace the exact-count profile gates, replay/adversarial tests, or isolated clean-package QA. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/0000755000230300031750000000000015274353473022411 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/sim_repeat.md0000644000230300031750000002613215274353473025067 0ustar rafaelrafael# Dense similarity with a semisimple repeated root (Tier S2) ## Quick idea SIM_REPEAT isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: Read the root count and the subspace metric together. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=8$ and demo: $n=16$. The leading block is $I_2$, so $\lambda=1$ has algebraic and geometric multiplicity 2. With the same exact triangular inverse pair $X=LU$ and $Y=X^{-1}$ used by the neighboring similarity cases, set ```math J_{\mathrm{repeat}}=I_2\oplus\mathrm{diag}(4,5,\ldots,n),\qquad A=YJ_{\mathrm{repeat}}X. ``` The eigenvalue 1 has algebraic multiplicity two and geometric multiplicity two. Its invariant right subspace is $\mathcal{R}(Y_{:,1:2})$, while the corresponding left subspace is represented by the columns of $X^{\mathsf T}$ selected by the same coordinates. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 18 & 16 & -2 & 2 & -2 & 2 & -2 \\ 0 & -17 & -16 & 2 & -2 & 2 & -2 & 2 \\ 0 & 18 & 17 & -2 & 2 & -2 & 2 & -2 \\ 0 & -15 & -10 & 6 & -2 & 2 & -2 & 2 \\ 0 & 12 & 8 & 0 & 7 & -2 & 2 & -2 \\ 0 & -9 & -6 & 0 & 0 & 8 & -2 & 2 \\ 0 & 6 & 4 & 0 & 0 & 0 & 9 & -2 \\ 0 & -3 & -2 & 0 & 0 & 0 & 0 & 10 \end{bmatrix}. ``` This is the full concrete smoke fixture for `SIM_REPEAT`. The matching [`sim_repeat.m`](../../../../examples/tiered/neig-tier-s/sim_repeat.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult A repeated eigenvalue does not identify two individual eigenvectors. Any nonsingular change of basis inside the two-dimensional eigenspace is equally valid, so entrywise comparison with the model columns would reject correct results. The dense similarity hides the repeated subspace and gives the eigensolver freedom to return a different basis. The difficult numerical claim is therefore a cluster or subspace statement. A residual for a single computed vector is necessary but cannot certify that the whole two-dimensional eigenspace has been captured. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [sim_repeat.m](../../../../examples/tiered/neig-tier-s/sim_repeat.m) runs the public eig call and compares the matched $\lambda=1$ cluster as a two-dimensional invariant subspace. It records the algebraic/geometric model multiplicities, projector or basis-angle diagnostics, and the ordinary all-spectrum residual. It also runs the neighboring distinct and Jordan fixtures so that the report cannot silently reinterpret a repeated case as either simple or defective. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness Exact verification checks $XY=YX=I$, the intertwining equations, the characteristic polynomial $(z-1)^2$ product from 4 through $n$, and the rank of the model eigenspace. The nontrivial cluster certificate uses the range of the selected $Y$ columns; the oblique spectral projector $Y_{:,1:2}X_{1:2,:}$ is recorded separately from an orthogonal projector. The proof does not rely on two high-precision runs agreeing. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes The model is exact at the construction precision; later MP work/reference precision controls the dense eig and subspace products. Mathematical multiplicity is exact and does not become simple when mpbits increases. Higher precision should reduce residuals and stabilize the cluster representation, but it cannot select a unique basis. Ambient precision tests verify that operation precision comes from the stored inputs rather than a caller’s unrelated default. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output Read the root count and the subspace metric together. A correct result may list two nearly identical $\lambda$ values with two arbitrary vectors. The meaningful residual is $r_{\mathrm{eig}}$ for the block $A V_J-V_JD_J$, plus a principal-angle or projector comparison for the entire range. There is no unique first and second eigenvector at $\lambda=1$, and no forward error for an individual basis direction is canonical. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Do not match individual vectors by entry, claim a repeated root is defective, use an isolated-simple-root bound, or call the oblique spectral projector an orthogonal projector. Do not infer multiplicity solely from a numerical disk count. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. - [Siegfried M. Rump, “Computational error bounds for multiple or nearly multiple eigenvalues.” *Linear Algebra and its Applications* 324(1–3) (2001), 209–226. DOI: [10.1016/S0024-3795(00)00279-2](https://doi.org/10.1016/S0024-3795(00)00279-2)](https://doi.org/10.1016/S0024-3795(00)00279-2) — It is the external reference for treating clusters and defective invariant subspaces rather than individual vectors. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [sim_repeat.m](../../../../examples/tiered/neig-tier-s/sim_repeat.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/toeplitz.md0000644000230300031750000002303315274353473024606 0ustar rafaelrafael# Diagonally scaled nonsymmetric tridiagonal Toeplitz matrix (Tier S3) ## Quick idea TOEPLITZ isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: Use the sorted eigenvalue bottleneck and the explicit left/right condition estimates. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=16$, $b=4$. Demo: $n=32$, $b=4$. The original coordinates have subdiagonal 1 and superdiagonal $2^{-2b}$. Let ```math A=\mathrm{tridiag}(1,3,2^{-2b}),\qquad B=\mathrm{tridiag}(2^{-b},3,2^{-b}),\qquad D=\mathrm{diag}(2^{b(j-1)})_{j=1}^n. ``` The exact identities are ```math AD=DB,\qquad D^{-1}AD=B. ``` The eigenvalues are ```math \lambda_k=3+2^{1-b}\cos\!\left(\frac{k\pi}{n+1}\right),\quad k=1,\ldots,n. ``` Right and left eigenvectors scale oppositely: $v_{jk}=2^{b(j-1)}\sin(j\theta_k)$ and $w_{jk}=2^{-b(j-1)}\sin(j\theta_k)$, with $\theta_k=k\pi/(n+1)$. ## Why this problem is numerically difficult The symmetric-looking spectrum hides a severe coordinate scaling. $B$ is symmetric, but $A$ is not; the two matrices are similar rather than unitarily equivalent. The condition of the diagonal similarity $D$ grows like $2^{b(n-1)}$, while that number is not itself the condition number of every individual eigenvalue. Individual left/right overlaps determine eigenvalue sensitivity. This is a useful test of whether a dense eigensolver and its diagnostics preserve the original coordinates instead of silently solving the symmetric control. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [toeplitz.m](../../../../examples/tiered/neig-tier-s/toeplitz.m) builds $A$ and $B$ directly, verifies $AD=DB$, solves $A$ with public eig, and compares against the MP trigonometric reference and the independently solved symmetric $B$. It evaluates $\pi$, sine, cosine, vector norms, and overlaps in MP. The output labels original and symmetric representations separately and does not use a numerically computed inverse for $D$. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness The exactness audit checks each dyadic entry, the similarity identity, the analytic eigenvalue formula at reference precision, and the closed-form left/right vector relations. The overlap $w^{\mathsf H}v$ is evaluated before normalization; for the real formula it is $(n+1)/2$. The symmetric control is an independent coordinate calculation, not a proof that the original $A$ has symmetric eigenvectors. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes The source matrix is exact dyadic at the stated n,b. Arithmetic precision controls A, B, analytic references, and the solve. Mathematical conditioning is dominated by the left/right scale separation and grows with n and b. Increasing bits makes the original-coordinate computation more trustworthy; it does not convert A into B or reduce the true sensitivity. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output Use the sorted eigenvalue bottleneck and the explicit left/right condition estimates. A small residual against A is a backward statement; it does not erase the scaling sensitivity. Compare original-coordinate vectors only after phase/sign normalization and recognize that the eigensolver may order equal-looking values differently. The balance and nobalance rows are diagnostic controls, not promises of improvement. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Do not call $A$ symmetric, report $2^{b(n-1)}$ as every eigenvalue’s condition number, construct $A$ as a rounded inverse similarity, use native pi/sin/cos constants, or compare $A$'s vectors directly with $B$'s vectors. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Silvia Noschese, Lionello Pasquini, and Lothar Reichel, “Tridiagonal Toeplitz matrices: properties and novel applications.” *Numerical Linear Algebra with Applications* 20(2) (2013), 302–326. DOI: [10.1002/nla.1811](https://doi.org/10.1002/nla.1811)](https://doi.org/10.1002/nla.1811) — The closed-form eigenvalues and eigenvectors explain the symmetric control and the diagonal-scaling sensitivity. - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [toeplitz.m](../../../../examples/tiered/neig-tier-s/toeplitz.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/oo128_close.md0000644000230300031750000003032315274353473024771 0ustar rafaelrafael# Ozaki–Ogita 128-bit close-spectrum form (Tier S1) ## Quick idea OO128_CLOSE isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: the key reading is a three-way comparison. Requested roots contain $2^{-80}+2^{-120}$, realized roots contain only $2^{-80}$, and measured roots approximate the realized values. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=8$, generation precision $g=128$ bits. Demo: $n=16$, $g=128$ bits. The first two requested diagonal entries differ by a deliberately unrepresentable tail. The real requested standard form is upper bidiagonal. Its first diagonal entries are ```math s_1=1,\qquad s_2=1+2^{-80}+2^{-120}, ``` the remaining diagonal entries are $3,4,\ldots,n$, and every first-superdiagonal entry is 1. The fixed 128-bit generator rounds the shifted expression at $g=128$, producing $S'$ and then ```math A=\mathrm{RN}_{128}\!\left(Y\,\mathrm{RN}_{128}(S'X)\right). ``` The required realized gap is $s'_2-s'_1=2^{-80}$: the $2^{-120}$ requested increment is intentionally removed and must remain visible in the metadata. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-80} \begin{bmatrix} 10880332376531662572355577 & 25387442211907212668829682 & 10880332376531662572355577 & -2417851639229258349412352 & 2417851639229258349412352 & -2417851639229258349412352 & 2417851639229258349412352 & -1208925819614629174706176 \\ -8462480737302404222943225 & -21760664753063325144711154 & -9671406556917033397649401 & 2417851639229258349412352 & -2417851639229258349412352 & 2417851639229258349412352 & -2417851639229258349412352 & 1208925819614629174706176 \\ 7253554917687775048237050 & 21760664753063325144711156 & 12089258196146291747061754 & -1208925819614629174706176 & 2417851639229258349412352 & -2417851639229258349412352 & 2417851639229258349412352 & -1208925819614629174706176 \\ -6044629098073145873530875 & -18133887294219437620592630 & -6044629098073145873530875 & 6044629098073145873530880 & -1208925819614629174706176 & 2417851639229258349412352 & -2417851639229258349412352 & 1208925819614629174706176 \\ 4835703278458516698824700 & 14507109835375550096474104 & 4835703278458516698824700 & 0 & 7253554917687775048237056 & -1208925819614629174706176 & 2417851639229258349412352 & -1208925819614629174706176 \\ -3626777458843887524118525 & -10880332376531662572355578 & -3626777458843887524118525 & 0 & 0 & 8462480737302404222943232 & -1208925819614629174706176 & 1208925819614629174706176 \\ 2417851639229258349412350 & 7253554917687775048237052 & 2417851639229258349412350 & 0 & 0 & 0 & 9671406556917033397649408 & 0 \\ -1208925819614629174706175 & -3626777458843887524118526 & -1208925819614629174706175 & 0 & 0 & 0 & 0 & 9671406556917033397649408 \end{bmatrix}. ``` This is the full concrete smoke fixture for `OO128_CLOSE`. The matching [`oo128_close.m`](../../../../examples/tiered/neig-tier-s/oo128_close.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult This case separates source/model fidelity from eigensolver precision. The target roots are close relative to their magnitude, and the requested form includes a tail below the selected generation lattice. If a reader sees a 256-bit eig run and assumes all requested bits are present, the experiment has been misread. Conversely, if the dense products are evaluated at insufficient precision, a product error can be mistaken for the intended quantization. The test therefore has two distinct questions: did the prescribed $g=128$ generator realize exactly the documented $S'$, and can later MP arithmetic recover the spectrum of that realized dense matrix? The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [oo128_close.m](../../../../examples/tiered/neig-tier-s/oo128_close.m) runs the fixed case, checks the realized first gap, and measures eig(A) at the suite work/reference precisions. It reports both requested and realized spectra. The dense matrix is not rebuilt at each mpbits value. The balance and nobalance rows are controls for solver behavior; neither is allowed to alter the frozen input. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness Exactness is checked at the dyadic level for the shifted quantization, $S'X$, $Y(S'X)$, and the final $A$. The guard calculation records $P$, $\alpha$, $n_Y$, and $n'$ and verifies the theorem inequality. The $2^{-120}$ loss is checked by decoding the stored dyadic entries, not by decimal formatting. Repeating the generator at $g=128$ must produce identical hashes; raising the eig precision must leave those hashes unchanged. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes The input/source precision is the frozen 128-bit standard form; work precision is 128/256-bit in smoke and higher in reference rows. The mathematical gap is $2^{-80}$ after realization, while the discarded tail is not part of the model. Higher arithmetic precision improves the solve and dense products but cannot recreate the discarded tail. This is why the document names the realized matrix explicitly. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output The key reading is a three-way comparison: requested roots contain $2^{-80}+2^{-120}$, realized roots contain only $2^{-80}$, and measured roots approximate the realized values. A high residual means the eigensolver failed; a small residual with a $2^{-120}$ difference from the requested root is expected. Use absolute error for this local gap and a scaled bottleneck metric for the full spectrum. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Do not label the requested spectrum as the exact spectrum, regenerate S for each solve precision, claim that the lost tail proves MP arithmetic is inaccurate, or use a low-precision rounded product as the exact model. Do not scale the entire S and assume that the same tail behavior follows; the generator’s alpha guard scales too. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Katsuhisa Ozaki and Takeshi Ogita, “Generation of test matrices with specified eigenvalues using floating-point arithmetic.” *Numerical Algorithms* 90 (2022), 241–262. DOI: [10.1007/s11075-021-01186-7](https://doi.org/10.1007/s11075-021-01186-7)](https://doi.org/10.1007/s11075-021-01186-7) — Theorem 1 and the paired standard-form construction motivate the fixed-precision generator and the requested/realized distinction. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [oo128_close.m](../../../../examples/tiered/neig-tier-s/oo128_close.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/oo53_pair.md0000644000230300031750000002707715274353473024550 0ustar rafaelrafael# Ozaki–Ogita paired real standard form (Tier S1) ## Quick idea OO53_PAIR isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: Look for conjugate pairing in the realized spectrum and for a small left residual using conjugate transpose. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=8$, $g=53$ bits. Demo: $n=16$, $g=53$ bits. The dimension is even and $S$ is block upper triangular with 2-by-2 real blocks. For block index $j=0,\ldots,n/2-1$, define ```math a_j=2j+1+2^{-45},\qquad b_j=(2j+1)/8+2^{-45},\qquad B_j=\begin{bmatrix}a_j&b_j\\-b_j&a_j\end{bmatrix}. ``` The requested $S_{\mathrm{req}}$ places $B_j$ on the diagonal and $8I_2$ on each first block superdiagonal. The same fixed Ozaki–Ogita triple product as in OO53_REAL is then applied. The roots of the realized standard form are the exact complex pair ```math \lambda_{j,\pm}=a'_j\mathbin{\pm} i b'_j, ``` where $a'_j,b'_j$ are the realized, once-quantized entries. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-3} \begin{bmatrix} 23 & 646 & 744 & 130 & 148 & 94 & 96 & -93 \\ -14 & -572 & -615 & -66 & -148 & -94 & -96 & 93 \\ 12 & 513 & 558 & 130 & 212 & 94 & 96 & -93 \\ -10 & -430 & -450 & -100 & -145 & -30 & -96 & 93 \\ 8 & 344 & 360 & 115 & 166 & 94 & 160 & -93 \\ -6 & -258 & -270 & -90 & -102 & -44 & -91 & 157 \\ 4 & 172 & 180 & 60 & 68 & 69 & 126 & -93 \\ -2 & -86 & -90 & -30 & -34 & -38 & -42 & 99 \end{bmatrix}. ``` This is the full concrete smoke fixture for `OO53_PAIR`. The matching [`oo53_pair.m`](../../../../examples/tiered/neig-tier-s/oo53_pair.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The pair case tests a subtle representation invariant rather than merely asking for complex output. A pair block is real, but its eigenvalues are complex conjugates, and the full block upper-triangular standard form need not be normal because of the $8I_2$ couplings. Quantizing the upper $b$ and lower $-b$ independently can break the exact conjugate block structure by one ulp. The specified sign-copy rule avoids that error: quantize the shared magnitude once and form the lower entry by exact negation. The dense $A$ then inherits a nontrivial nonnormal eigenvector problem while its requested pair geometry is known. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [oo53_pair.m](../../../../examples/tiered/neig-tier-s/oo53_pair.m) selects the paired case and reports the generator audit, the realized block roots, and the measured eig output. The comparison uses a complex MP bijective matching and the left-eigenvector convention $A^{\mathsf H}w=\overline{\lambda}w$. It checks the real reconstruction of the paired blocks separately from the dense residual. The example is deliberately not a call to a complex-valued generic matrix constructor followed by a binary64 conversion. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness The paired generator checks that both diagonal positions share one quantized $a$, that the lower $b$ is exactly the negative of the quantized upper $b$, and that the same lattice and magnitude bounds used for the theorem hold. It independently verifies both matrix products and $XY=YX=I$. The realized pair is stored before any eigensolver call. A nonzero $b'$ is required for the mandatory fixture; if a future parameter made $b'=0$, its multiplicity would have to be relabeled rather than still called a complex pair. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes The source precision is $g=53$ for the generator. Later 128/256-bit arithmetic evaluates the frozen $A$ and its complex eigensystem. MPFR precision controls real components and MPC precision controls complex operations at the selected operation precision; neither changes the original quantization. Mathematical difficulty comes from nonnormal block coupling and the relation between right and left eigenvectors, not simply from the presence of imaginary parts. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output Look for conjugate pairing in the realized spectrum and for a small left residual using conjugate transpose. The order and phases of eigenvectors are not fixed. A residual for $AV-VD$ can be small even when the two members of a sensitive pair move, so compare the matched eigenvalues and the block-structure audit together. The requested values are a construction target; the realized values are the forward-error reference. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Do not quantize b and -b separately, transpose instead of conjugate-transpose the left relation, call the whole S normal because each diagonal block has a conjugate pair, or compare arbitrary eigenvector phases entrywise. Do not replace the paired form with two unrelated scalar roots. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Katsuhisa Ozaki and Takeshi Ogita, “Generation of test matrices with specified eigenvalues using floating-point arithmetic.” *Numerical Algorithms* 90 (2022), 241–262. DOI: [10.1007/s11075-021-01186-7](https://doi.org/10.1007/s11075-021-01186-7)](https://doi.org/10.1007/s11075-021-01186-7) — Theorem 1 and the paired standard-form construction motivate the fixed-precision generator and the requested/realized distinction. - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [oo53_pair.m](../../../../examples/tiered/neig-tier-s/oo53_pair.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/README.md0000644000230300031750000001401715274353473023673 0ustar rafaelrafael# Nonsymmetric eigensystems — Tier S Tier S is the study path for cases where a residual-only eigensystem check is not enough. The cases progress from a specified eigenvalue generator to exact similarities, representation-sensitive Toeplitz/Forsythe pairs, and a genuine Jordan limit. Each row below is one conceptual case, one runnable .m file, and one detailed mathematical page. The detailed pages print every small smoke matrix in full with exact integer or dyadic entries. Source/generation precision, exact widening, and measured eigensolver output remain separate; `tools/check-smoke-matrices.sh` verifies the displayed matrices against the existing constructors. ## What to know first The public result is interpreted as a right relation ```math A V = V D ``` and, when left vectors are requested, an adjoint relation ```math A^{\mathsf H} W = W D^{\mathsf H}. ``` The basic residual is ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F} {\lVert A\rVert_F\lVert V\rVert_F}. ``` It is a backward-style equation diagnostic. Forward eigenvalue accuracy also depends on separation and left/right conditioning. For repeated or defective roots the target is a cluster or invariant subspace, not a list of canonical individual vectors. The exact model, any once-rounded/generated input, the work precision, and the measured solver output are recorded separately. Raising the selected mpbits improves later arithmetic; it does not restore a bit removed by a fixed generator or make a Jordan block diagonalizable. ## Learning map | Case | Mathematical object | Main question | Start here | Detailed page | External primary context | |---|---|---|---|---|---| | OO53_REAL | Fixed $g=53$ Ozaki–Ogita real triple product | requested versus realized roots | [oo53_real.m](../../../../examples/tiered/neig-tier-s/oo53_real.m) | [oo53_real.md](./oo53_real.md) | [Ozaki–Ogita (2022)](https://doi.org/10.1007/s11075-021-01186-7) | | OO53_PAIR | Fixed $g=53$ paired 2-by-2 blocks | sign-copy and complex pairs | [oo53_pair.m](../../../../examples/tiered/neig-tier-s/oo53_pair.m) | [oo53_pair.md](./oo53_pair.md) | [Ozaki–Ogita (2022)](https://doi.org/10.1007/s11075-021-01186-7) | | OO128_CLOSE | Fixed $g=128$ close standard form | lost $2^{-120}$ tail | [oo128_close.m](../../../../examples/tiered/neig-tier-s/oo128_close.m) | [oo128_close.md](./oo128_close.md) | [Ozaki–Ogita (2022)](https://doi.org/10.1007/s11075-021-01186-7) | | SIM_SIMPLE | Dense similarity of a 2-by-2 near-Jordan model | simple but near-defective roots | [sim_simple.m](../../../../examples/tiered/neig-tier-s/sim_simple.m) | [sim_simple.md](./sim_simple.md) | [Rump (2022)](https://doi.org/10.1137/21M1451440) | | SIM_REPEAT | Dense similarity of $I_2$ | semisimple repeated eigenspace | [sim_repeat.m](../../../../examples/tiered/neig-tier-s/sim_repeat.m) | [sim_repeat.md](./sim_repeat.md) | [Rump (2001)](https://doi.org/10.1016/S0024-3795(00)00279-2) | | SIM_JORDAN | Dense similarity of $J_2(1)$ | defective block and no full basis | [sim_jordan.m](../../../../examples/tiered/neig-tier-s/sim_jordan.m) | [sim_jordan.md](./sim_jordan.md) | [Rump (2022)](https://doi.org/10.1137/21M1451440) | | SIM_TWO_JORDAN | Two nearby J_2 blocks | separate versus merged clusters | [sim_two_jordan.m](../../../../examples/tiered/neig-tier-s/sim_two_jordan.m) | [sim_two_jordan.md](./sim_two_jordan.md) | [Rump (2001)](https://doi.org/10.1016/S0024-3795(00)00279-2) | | TOEPLITZ | diagonally scaled tridiagonal Toeplitz | symmetric spectrum, nonsymmetric vectors | [toeplitz.m](../../../../examples/tiered/neig-tier-s/toeplitz.m) | [toeplitz.md](./toeplitz.md) | [Noschese–Pasquini–Reichel (2013)](https://doi.org/10.1002/nla.1811) | | TOEPLITZ_SYM | explicit symmetric Toeplitz control | representation effect | [toeplitz_sym.m](../../../../examples/tiered/neig-tier-s/toeplitz_sym.m) | [toeplitz_sym.md](./toeplitz_sym.md) | [Noschese–Pasquini–Reichel (2013)](https://doi.org/10.1002/nla.1811) | | FORSYTHE | Jordan block with $\varepsilon=r^n$ corner | tiny cyclic perturbation | [forsythe.m](../../../../examples/tiered/neig-tier-s/forsythe.m) | [forsythe.md](./forsythe.md) | [Higham (2002)](https://doi.org/10.1137/1.9780898718027) | | FORSYTHE_SCALED | $I+rP$ normal control | scaled normal comparison | [forsythe_scaled.m](../../../../examples/tiered/neig-tier-s/forsythe_scaled.m) | [forsythe_scaled.md](./forsythe_scaled.md) | [Higham (2002)](https://doi.org/10.1137/1.9780898718027) | | FORSYTHE_ZERO | $I+N$ genuine Jordan block | exact defective limit | [forsythe_zero.m](../../../../examples/tiered/neig-tier-s/forsythe_zero.m) | [forsythe_zero.md](./forsythe_zero.md) | [Rump (2022)](https://doi.org/10.1137/21M1451440) | The primary papers motivate the phenomenon and terminology. The dimensions, dyadic parameters, acceptance gates, and runnable implementation are explicit suite choices. ## How to run Run one case from the repository root: ~~~octave pkg load mplapack-interop run ("examples/tiered/neig-tier-s/oo128_close.m"); ~~~ Run the complete counted family through the existing runner: ~~~octave pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "neig_tiers")); result = mp_neig_tiers ("smoke", struct ("tier", "S", "plot", false)); ~~~ The smoke profile contains 12 Tier S cases and the demo profile uses the larger dimensions plus the demo-only complex Hadamard control in Tier A. The full runner, not a copied formula in this README, is the measurement authority. ## Suggested order 1. Start with OO53_REAL to learn the fixed generation precision and realized-spectrum record. 2. Read SIM_SIMPLE, then SIM_REPEAT and SIM_JORDAN, to separate simple, semisimple, and defective claims. 3. Compare TOEPLITZ with TOEPLITZ_SYM and FORSYTHE with FORSYTHE_SCALED. 4. Finish with SIM_TWO_JORDAN and FORSYTHE_ZERO, where cluster and block semantics matter most. See the [master tiered map](../README.md), [NEIG manifest](../../../../docs/codex/neigt/cases.json), and [NEIG certificates](../../../../docs/codex/neigt/CERTIFICATES.md) for the boundary between ordinary measured rows and conservative verification claims. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/forsythe.md0000644000230300031750000002525415274353473024606 0ustar rafaelrafael# Forsythe cyclic perturbation of a Jordan block (Tier S4) ## Quick idea FORSYTHE isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: Inspect the scaled circle error, not ordinary relative error near $\lambda=1$. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=8$, $a=4$, $r=2^{-a}$, and $\varepsilon=r^n$. Demo: $n=16$, $a=12$. The original matrix has a tiny lower-left corner. Let $N$ be the first-superdiagonal shift, $r=2^{-a}$, and $\varepsilon=r^n$. The original matrix is ```math F=I+N+\varepsilon e_n e_1^{\mathsf T}. ``` Writing $P=N+e_ne_1^{\mathsf T}$, the exact scaled control is $F_{\mathrm{scaled}}=I+rP$, and with $D=\mathrm{diag}(1,r,\ldots,r^{n-1})$, ```math FD=D F_{\mathrm{scaled}}. ``` The roots are the circle ```math \lambda_k=1+r\exp(2\pi i k/n),\qquad k=0,\ldots,n-1. ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \\ 2^{-32} & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `FORSYTHE`. The matching [`forsythe.m`](../../../../examples/tiered/neig-tier-s/forsythe.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The perturbation closes a nilpotent chain with a value as small as $r^n$. In native arithmetic the corner can be lost while the superdiagonal remains visible, turning a simple-root cyclic matrix into the zero-limit Jordan block. In the exact model the roots are distinct, but their eigenvectors inherit strong scaling from the original coordinates. The scaled control is normal and has the same roots, so it provides a representation control rather than a replacement for the original test. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [forsythe.m](../../../../examples/tiered/neig-tier-s/forsythe.m) constructs $F$ directly, constructs the scaled control separately, evaluates the unit-circle roots in MP, and runs public eig on the original matrix. It sets exact real endpoints such as the $k=0$ root where appropriate and matches $(\lambda-1)/r$ against the unit-circle reference. Native underflow, if encountered only in stress, is logged as an altered input. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness The model audit checks the cyclic identity $FD=D F_{\mathrm{scaled}}$, $P^n=I$, the characteristic relation $(\lambda-1)^n=r^n$, and the dyadic corner. It does not infer the roots from measured eig output. The circle reference is evaluated at MP precision and is not an interval proof for transcendental values; exact endpoints are inserted explicitly. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes Input/source precision includes $\varepsilon=r^n$; work precision must retain the corner and the circle displacement. Mathematical sensitivity is governed by the near-Jordan limit and coordinate scaling. More bits can preserve $\varepsilon$ and resolve the circle, but it cannot retroactively repair a native $F$ whose corner underflowed. The exact model and any changed native model are never conflated. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output Inspect the scaled circle error, not ordinary relative error near $\lambda=1$. A measured result close to 1 can have a large relative error if the small displacement is lost, so the normalized circle coordinate is informative. Compare original and scaled residuals separately. The eig residual can remain small for the wrong limiting matrix when $\varepsilon$ has disappeared. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Do not compare $\lambda$ directly with 1 using only relative error, call the original $F$ normal, use the scaled control as the original input, or treat an underflowed native corner as an MP failure. Do not apply a simple-root claim to FORSYTHE_ZERO. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. - [Nicholas J. Higham, *Accuracy and Stability of Numerical Algorithms*, 2nd ed. SIAM (2002). DOI: [10.1137/1.9780898718027](https://doi.org/10.1137/1.9780898718027)](https://doi.org/10.1137/1.9780898718027) — The general backward/forward-error vocabulary and nonnormal sensitivity interpretation used here. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [forsythe.m](../../../../examples/tiered/neig-tier-s/forsythe.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/sim_jordan.md0000644000230300031750000002561015274353473025064 0ustar rafaelrafael# Dense similarity with a genuine 2-by-2 Jordan block (Tier S2) ## Quick idea SIM_JORDAN isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: A small $r_{\mathrm{eig}}$ for two columns does not mean those columns form a diagonalization. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=8$ and demo: $n=16$. The leading block is $J_2(1)$, with algebraic multiplicity 2 and geometric multiplicity 1. Define ```math J_{\mathrm{Jordan}}= \begin{bmatrix}1&1\\0&1\end{bmatrix}\oplus\mathrm{diag}(4,5,\ldots,n), \qquad A=YJ_{\mathrm{Jordan}}X,\qquad X=LU,\;Y=U^{-1}L^{-1}. ``` The root 1 has algebraic multiplicity two but only one independent eigenvector. The nontrivial generalized relation is $J_{\mathrm{Jordan}}e_2=e_2+e_1$, which becomes ```math A(Y e_2)=Y e_2+Y e_1. ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 9 & 34 & 24 & -2 & 2 & -2 & 2 & -2 \\ -7 & -31 & -23 & 2 & -2 & 2 & -2 & 2 \\ 6 & 30 & 23 & -2 & 2 & -2 & 2 & -2 \\ -5 & -25 & -15 & 6 & -2 & 2 & -2 & 2 \\ 4 & 20 & 12 & 0 & 7 & -2 & 2 & -2 \\ -3 & -15 & -9 & 0 & 0 & 8 & -2 & 2 \\ 2 & 10 & 6 & 0 & 0 & 0 & 9 & -2 \\ -1 & -5 & -3 & 0 & 0 & 0 & 0 & 10 \end{bmatrix}. ``` This is the full concrete smoke fixture for `SIM_JORDAN`. The matching [`sim_jordan.m`](../../../../examples/tiered/neig-tier-s/sim_jordan.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The Jordan block is the explicit counterexample to the idea that a full eigenbasis always exists. Near a defective matrix, computed eigenvalues can split and computed vectors can become extremely sensitive; at the exact model, requiring two independent eigenvectors is mathematically impossible. The correct numerical object is the invariant two-dimensional subspace and, when requested, a block Schur factor. The example is also a guard against calling a nontrivial projector certificate a proof of diagonalizability. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [sim_jordan.m](../../../../examples/tiered/neig-tier-s/sim_jordan.m) runs eig(A) only as an ordinary measured output, while the case metadata records that no full diagonalizing basis target applies. It checks the root count, the dimension of the target invariant subspace, the nilpotency order of the shifted block, and the residual of the selected invariant basis. If a Schur-style diagnostic is present, the leading two-by-two block is interpreted as one block, not as two certified simple roots. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness The exact checks are $XY=YX=I$, $XA=JX$, $AY=YJ$, $(J-I)^2=0$ on the leading block, and $(J-I)\ne0$. A characteristic polynomial check confirms $(z-1)^2$, but that check alone does not establish the geometric multiplicity; the rank of $J-I$ supplies the latter. The dense certificate does not pretend to certify a Jordan chain from a rounded eig output. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes The input model is exact dyadic; work precision controls the measured dense solve. Mathematical defectiveness remains at every precision. More bits can make the invariant-subspace and generalized-vector residual smaller, but no number of bits creates a second exact eigenvector. The distinction between arithmetic error and nonexistence of a full eigenbasis is the point of the case. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output A small $r_{\mathrm{eig}}$ for two columns does not mean those columns form a diagonalization. The relevant output is a block residual $A V_J-V_JT_J$, where $T_J$ is allowed to be a nontrivial $2$-by-$2$ triangular/block factor, and a rank/subspace check. A solver may split the repeated root in its scalar $D$ output; that is a diagnostic of representation sensitivity, not a change in the exact model. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Never claim the Jordan block is diagonalizable, never certify two independent eigenvectors merely because two scalar roots were returned, and never use a disk count as an exact multiplicity proof. Do not replace the block with diag(1,1). A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. - [Siegfried M. Rump, “Computational error bounds for multiple or nearly multiple eigenvalues.” *Linear Algebra and its Applications* 324(1–3) (2001), 209–226. DOI: [10.1016/S0024-3795(00)00279-2](https://doi.org/10.1016/S0024-3795(00)00279-2)](https://doi.org/10.1016/S0024-3795(00)00279-2) — It is the external reference for treating clusters and defective invariant subspaces rather than individual vectors. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [sim_jordan.m](../../../../examples/tiered/neig-tier-s/sim_jordan.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/forsythe_scaled.md0000644000230300031750000002501615274353473026115 0ustar rafaelrafael# Scaled normal Forsythe control (Tier S4) ## Quick idea FORSYTHE_SCALED isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: The primary diagnostics are $r_{\mathrm{eig}}$, the unitary eigenvector residual, and the normalized circle bottleneck. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=8$, $a=4$, $r=2^{-a}$. Demo: $n=16$, $a=12$. The matrix is $I+rP$, where $P$ is the cyclic permutation. Let $P$ be the cyclic permutation matrix with $P_{i,i+1}=1$ and $P_{n,1}=1$. The control is ```math F_{\mathrm{scaled}}=I+rP,\qquad r=2^{-a},\qquad P^{\mathsf H}P=I. ``` Because $P$ is unitary, its eigenvalues are $\zeta_k=\exp(2\pi i k/n)$ and ```math \lambda_k=1+r\zeta_k. ``` This matrix is unitarily diagonalizable and is related to the original Forsythe form by $FD=DF_{\mathrm{scaled}}$. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 2^{-4} & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 2^{-4} & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 2^{-4} & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 2^{-4} & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 2^{-4} & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 2^{-4} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 2^{-4} \\ 2^{-4} & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `FORSYTHE_SCALED`. The matching [`forsythe_scaled.m`](../../../../examples/tiered/neig-tier-s/forsythe_scaled.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult This is the normal-coordinate control for the tiny cyclic perturbation. It asks whether the eigensolver can preserve a small but exactly representable displacement when no nonunitary diagonal scaling is present. The result should be interpreted with the original FORSYTHE case: equal spectra do not imply equal eigenvector conditioning or equal pseudospectra in the original coordinates. The control also makes the unit-circle matching metric transparent. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [forsythe_scaled.m](../../../../examples/tiered/neig-tier-s/forsythe_scaled.m) builds $P$ directly, forms $I+rP$ in MP, and measures the dense eig result. It compares normalized coordinates $(\lambda-1)/r$ with the MP roots of unity and checks the unitary similarity/control identities. It does not form $P$ through a generic exponential or through a binary64 complex fallback. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness The constructor verifies $P$'s permutation entries, $P^n=I$, and $P^{\mathsf H}P=I$. The dyadic scale $r$ is exact within the selected input precision; complex roots of unity are analytic MP references, with real endpoints fixed explicitly. The identity with FORSYTHE is checked independently from measured eigenvalues. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes The input is an exact dyadic normal control; arithmetic precision controls r, complex products, and root-of-unity evaluation. Mathematical conditioning is much milder than for the original Forsythe representation. More bits preserve the displacement from 1 and improve the normalized circle comparison; they do not change the scale r. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output The primary diagnostics are $r_{\mathrm{eig}}$, the unitary eigenvector residual, and the normalized circle bottleneck. Since the matrix is normal, a small residual has a more direct forward interpretation than in the original scaled coordinates, but it still does not certify every displayed digit. Signs, phases, and column order remain arbitrary. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Do not claim this control proves the original matrix is well conditioned, compare unnormalized $\lambda$ with a relative tolerance around 1, or use native roots of unity as the MP reference. Do not hide the diagonal scaling relationship. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. - [Nicholas J. Higham, *Accuracy and Stability of Numerical Algorithms*, 2nd ed. SIAM (2002). DOI: [10.1137/1.9780898718027](https://doi.org/10.1137/1.9780898718027)](https://doi.org/10.1137/1.9780898718027) — The general backward/forward-error vocabulary and nonnormal sensitivity interpretation used here. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [forsythe_scaled.m](../../../../examples/tiered/neig-tier-s/forsythe_scaled.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/sim_simple.md0000644000230300031750000002627415274353473025107 0ustar rafaelrafael# Dense similarity with a simple near-collision (Tier S2) ## Quick idea SIM_SIMPLE isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: for each matched root, read the eigen residual together with its distance to the exact spectrum $\{1,1+d,4,5,\ldots,n\}$. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eigensolver routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=8$ and gap $d=2^{-24}$. Demo: $n=16$ and gap $d=2^{-80}$. The leading block is simple and diagonalizable. Let $N$ be the first-superdiagonal shift, $L=I+N^{\mathsf T}$, $U=I+N$, $X=LU$, $Y=U^{-1}L^{-1}$, and ```math J_{\mathrm{simple}}= \begin{bmatrix}1&1\\0&1+d\end{bmatrix}\oplus\mathrm{diag}(4,5,\ldots,n), \qquad d=2^{-a}. ``` The dense test matrix is ```math A=YJ_{\mathrm{simple}}X,\qquad X A=J_{\mathrm{simple}}X,\quad A Y=YJ_{\mathrm{simple}}. ``` Its spectrum is simple, but the first two roots are only d apart and the leading block has a large off-diagonal relative to that gap. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 9 & 34 & 24 & -2 & 2 & -2 & 2 & -2 \\ -7 & -31 & -23 & 2 & -2 & 2 & -2 & 2 \\ 6 & 30 & 23 & -2 & 2 & -2 & 2 & -2 \\ -5 & -25 & -15 & 6 & -2 & 2 & -2 & 2 \\ 4 & 20 & 12 & 0 & 7 & -2 & 2 & -2 \\ -3 & -15 & -9 & 0 & 0 & 8 & -2 & 2 \\ 2 & 10 & 6 & 0 & 0 & 0 & 9 & -2 \\ -1 & -5 & -3 & 0 & 0 & 0 & 0 & 10 \end{bmatrix}. ``` This is the full concrete smoke fixture for `SIM_SIMPLE`. The matching [`sim_simple.m`](../../../../examples/tiered/neig-tier-s/sim_simple.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The case is diagonalizable, so it is a legitimate individual-eigenpair experiment, but it is close to the defective limit. The coordinate columns of Y are not the eigenvectors of the leading triangular block: the second coordinate eigenvector must solve a 2-by-2 triangular equation. This distinction matters in a dense similarity because a visually plausible column can have a large residual. The small gap makes forward eigenvalue error sensitive even if a backward perturbation is small. It also creates a natural balance-control question without changing the exact model. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [sim_simple.m](../../../../examples/tiered/neig-tier-s/sim_simple.m) constructs the exact dyadic model through the finite triangular inverse, runs the public eig interface, and matches the two close roots bijectively. It checks the intertwining identities and the independently formed characteristic polynomial for the leading block. The selected gap and profile are read from cases.json; they are not altered to fit an observed answer. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness The model is exact because $X$ and $Y$ are finite nilpotent series with dyadic/integer entries and the product guard is recorded. The checker independently confirms $XA=JX$ and $AY=YJ$, then checks the two-by-two characteristic factor $(z-1)(z-1-d)$. It does not use the solver’s eigenvalues to construct $J$ or to prove simplicity. The simple model is separate from SIM_REPEAT and SIM_JORDAN even when $d$ is small. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes Input/source precision is the exact dyadic construction; work precision is chosen by the smoke/demo profile, with higher reference rows. The arithmetic precision must be high enough to retain d and to evaluate the dense similarity. Mathematical conditioning worsens as a grows and as the leading block approaches a Jordan block. More mpbits reduces rounding in the computed solve but does not change the prescribed gap or turn the model into a repeated root. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output For each matched root, read the eigen residual and the distance to $\{1,1+d,4,5,\ldots,n\}$. The eigensolver may return accurate backward solutions whose forward root error is a visible fraction of $d$. The balance row can have different componentwise behavior; a pass does not require balancing to improve every row. The eigenvectors are only comparable up to independent scaling, and left vectors use the adjoint equation. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Do not call the matrix defective, claim that Y(:,2) is automatically an eigenvector, merge the two roots merely because their disks overlap at low precision, or treat balance as a required improvement. Do not use a disk count to infer exact multiplicity. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. - [Siegfried M. Rump, “Computational error bounds for multiple or nearly multiple eigenvalues.” *Linear Algebra and its Applications* 324(1–3) (2001), 209–226. DOI: [10.1016/S0024-3795(00)00279-2](https://doi.org/10.1016/S0024-3795(00)00279-2)](https://doi.org/10.1016/S0024-3795(00)00279-2) — It is the external reference for treating clusters and defective invariant subspaces rather than individual vectors. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [sim_simple.m](../../../../examples/tiered/neig-tier-s/sim_simple.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/forsythe_zero.md0000644000230300031750000002505415274353473025643 0ustar rafaelrafael# Forsythe zero-limit Jordan block (Tier S4) ## Quick idea FORSYTHE_ZERO isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: A small $r_{\mathrm{eig}}$ for a returned diagonal $D$ is not a diagonalizability result. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=8$, $a=4$ metadata retained. Demo: $n=16$, $a=12$ metadata retained. The lower-left perturbation is exactly $\varepsilon=0$. The zero-limit case is the genuine Jordan matrix ```math F_0=I+N,\qquad N_{i,i+1}=1,\qquad N^n=0,\quad N^{n-1}\ne0. ``` Its only eigenvalue is 1 with algebraic multiplicity n and geometric multiplicity 1. The shifted nilpotent part has exact order n: ```math (F_0-I)^n=0,\qquad (F_0-I)^{n-1}\ne0. ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `FORSYTHE_ZERO`. The matching [`forsythe_zero.m`](../../../../examples/tiered/neig-tier-s/forsythe_zero.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult This is not a failed version of the nonzero Forsythe test. It is a deliberate boundary case where no full eigenbasis exists and all individual eigenvectors are maximally nonunique in the defective sense. The right success condition is an invariant block or a generalized chain, not n independent vectors. Keeping this case separate prevents a certificate framework from silently converting an exact Jordan block into a diagonal matrix because a numerical eig call printed repeated roots. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [forsythe_zero.m](../../../../examples/tiered/neig-tier-s/forsythe_zero.m) runs public eig as a measured diagnostic, verifies the exact nilpotent order, and checks the full-space invariant relation. It records that individual simple-root and eigenvector-forward-error gates are not applicable. The all-spectrum count is n, but the geometric dimension is one. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness The exact constructor uses only I and N. Independent checks evaluate powers of F_0-I, the rank of the first nilpotent power, and the characteristic polynomial (z-1)^n. The whole-space projector I is a trivial identity and is not accepted as a nontrivial cluster certificate. A genuine block relation is required if a V-style invariant-subspace test is run. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes The source matrix is exact at every reasonable MP precision; the mathematical defectiveness is exact and precision-independent. Raising arithmetic precision improves residual evaluation and generalized-chain diagnostics but cannot create n eigenvectors. This case is therefore a test of semantic honesty as much as arithmetic accuracy. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output A small $r_{\mathrm{eig}}$ for a returned diagonal $D$ is not a diagonalizability result. Read the algebraic count, geometric dimension, nilpotency order, and block residual. If native or low-precision output splits the repeated root, that is expected numerical representation behavior. No individual-vector matching target is reported. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Never claim the Jordan block is diagonalizable, never use a scalar root condition number, never infer multiplicity from a disk count, and never substitute the normal scaled control. Do not mark a full-space identity projector as the required nontrivial cluster certificate. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. - [Siegfried M. Rump, “Computational error bounds for multiple or nearly multiple eigenvalues.” *Linear Algebra and its Applications* 324(1–3) (2001), 209–226. DOI: [10.1016/S0024-3795(00)00279-2](https://doi.org/10.1016/S0024-3795(00)00279-2)](https://doi.org/10.1016/S0024-3795(00)00279-2) — It is the external reference for treating clusters and defective invariant subspaces rather than individual vectors. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [forsythe_zero.m](../../../../examples/tiered/neig-tier-s/forsythe_zero.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/sim_two_jordan.md0000644000230300031750000002632215274353473025756 0ustar rafaelrafael# Two nearby defective clusters under one dense similarity (Tier S2) ## Quick idea SIM_TWO_JORDAN isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: Read the bottleneck matching, cluster counts, and block residuals as separate fields. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=8$ and $d=2^{-12}$. Demo: $n=16$ and $d=2^{-40}$. The leading blocks are $J_2(1)$ and $J_2(1+d)$. Set ```math J_{\mathrm{two}}= \begin{bmatrix}1&1\\0&1\end{bmatrix} \oplus \begin{bmatrix}1+d&1\\0&1+d\end{bmatrix} \oplus\mathrm{diag}(4,5,\ldots,n-1), \qquad d=2^{-a}, ``` and $A=YJ_{\mathrm{two}}X$ with the exact inverse pair $X=LU$, $Y=U^{-1}L^{-1}$. The two clusters each have algebraic multiplicity 2 and geometric multiplicity 1; their union has dimension four. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-12} \begin{bmatrix} 36864 & 65542 & 57351 & 98300 & 73723 & -8192 & 8192 & -8192 \\ -28672 & -53254 & -53255 & -98300 & -73723 & 8192 & -8192 & 8192 \\ 24576 & 49158 & 53255 & 98300 & 73723 & -8192 & 8192 & -8192 \\ -20480 & -40965 & -40965 & -86011 & -69627 & 8192 & -8192 & 8192 \\ 16384 & 32772 & 32772 & 81916 & 69628 & -8192 & 8192 & -8192 \\ -12288 & -24579 & -24579 & -61437 & -36861 & 24576 & -8192 & 8192 \\ 8192 & 16386 & 16386 & 40958 & 24574 & 0 & 28672 & -8192 \\ -4096 & -8193 & -8193 & -20479 & -12287 & 0 & 0 & 32768 \end{bmatrix}. ``` This is the full concrete smoke fixture for `SIM_TWO_JORDAN`. The matching [`sim_two_jordan.m`](../../../../examples/tiered/neig-tier-s/sim_two_jordan.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult This case makes cluster selection itself part of the problem. At high enough precision the two defective blocks are separated, but a lower-precision inclusion region can merge them. A simple-root solver diagnostic is invalid inside either block, while a four-dimensional invariant-subspace statement is valid for the union. The dense similarity also means that the coordinate block basis is not orthogonal, so a naive Euclidean comparison can overstate or understate the actual subspace error. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [sim_two_jordan.m](../../../../examples/tiered/neig-tier-s/sim_two_jordan.m) runs separate two-root clusters and the merged four-root cluster using the fixed gap from the manifest. It checks each block’s generalized relation, the combined invariant range, and all-spectrum coverage. The reported classification says whether the working precision resolved the internal gap; it does not retune d or turn a merged numerical enclosure into an exact multiplicity assertion. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness The model proof checks the similarity identities, the two characteristic factors $(z-1)^2$ and $(z-1-d)^2$, the rank-one nilpotent part of each Jordan block, and the direct-sum dimensions. The invariant basis is formed from the relevant columns of $Y$, and the oblique commuting projector for a union of full coordinate blocks is kept distinct from an orthogonal range projector. Exact dyadic construction is checked independently from the eig output. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes Source precision is the exact dyadic model; the gap is d; arithmetic precision varies by profile. The conditioning has two layers: defectiveness within each cluster and the separation between clusters. More bits can resolve the gap and improve subspace bounds but cannot make either Jordan block semisimple. The ambient-precision wall verifies that these conclusions are not caused by a leaked global default. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output Read the bottleneck matching, cluster counts, and block residuals as separate fields. If the two clusters merge numerically, the correct statement is a certificate for the union, not “the roots have multiplicity four.” If they separate, each two-dimensional invariant space is still defective and must not be reduced to two individual eigenvector claims. $r_{\mathrm{eig}}$ is reported for the full matrix and for selected blocks. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Do not count a merged disk as a proof of algebraic multiplicity four, do not treat the block bases as orthogonal, do not demand individual eigenvectors inside a Jordan block, and do not silently replace d by a larger gap when a run is slow. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. - [Siegfried M. Rump, “Computational error bounds for multiple or nearly multiple eigenvalues.” *Linear Algebra and its Applications* 324(1–3) (2001), 209–226. DOI: [10.1016/S0024-3795(00)00279-2](https://doi.org/10.1016/S0024-3795(00)00279-2)](https://doi.org/10.1016/S0024-3795(00)00279-2) — It is the external reference for treating clusters and defective invariant subspaces rather than individual vectors. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [sim_two_jordan.m](../../../../examples/tiered/neig-tier-s/sim_two_jordan.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/oo53_real.md0000644000230300031750000002415415274353473024531 0ustar rafaelrafael# Ozaki–Ogita real standard form (Tier S1) ## Quick idea OO53_REAL is the smallest complete example of a fixed-precision eigenvalue generator followed by a dense nonsymmetric eigensolve. Its purpose is to make a distinction visible: a requested matrix, the once-rounded standard form, the generated dense matrix, and the measured eigensolver output are four different objects. The case uses the real form of the Ozaki–Ogita construction and is intentionally deterministic. ## Mathematical problem Smoke uses $n=8$ and generation precision $g=53$ bits; demo uses $n=16$ and the same $g$. Let $N$ have ones on the first superdiagonal, let $L=I+N^{\mathsf T}$ and $U=I+N$, and define $X=LU$ and $Y=U^{-1}L^{-1}$. The requested standard form is upper bidiagonal: ```math (S_{\mathrm{req}})_{ii}=i+2^{-45},\qquad (S_{\mathrm{req}})_{i,i+1}=32. ``` The specified generator applies the two rounded shifted additions and then the two matrix products at exactly g: ```math \sigma=12\alpha P,\qquad S'_{ij}=\mathrm{RN}_{g}\left(\mathrm{RN}_{g}(\sigma+(S_{\mathrm{req}})_{ij})-\sigma\right), ``` ```math A=\mathrm{RN}_{g}\left(Y\,\mathrm{RN}_{g}(S'X)\right). ``` The roots of the realized triangular standard form are $\mathrm{diag}(S')$, not the requested diagonal. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 250 & 286 & 2 & -2 & 2 & -2 & 2 & 30 \\ -217 & -221 & 30 & 2 & -2 & 2 & -2 & -30 \\ 186 & 192 & 4 & 30 & 2 & -2 & 2 & 30 \\ -155 & -160 & 0 & 5 & 30 & 2 & -2 & -30 \\ 124 & 128 & 0 & 0 & 6 & 30 & 2 & 30 \\ -93 & -96 & 0 & 0 & 0 & 7 & 30 & -30 \\ 62 & 64 & 0 & 0 & 0 & 0 & 8 & 62 \\ -31 & -32 & 0 & 0 & 0 & 0 & 0 & -23 \end{bmatrix}. ``` This is the full concrete smoke fixture for `OO53_REAL`. The matching [`oo53_real.m`](../../../../examples/tiered/neig-tier-s/oo53_real.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The difficulty is in the construction as well as in the eigensolve. $X$ and $Y$ are triangular inverse factors with different dyadic scales. The Ozaki–Ogita theorem uses those scales, the unit roundoff $u=2^{-g}$, the nonzero-count parameters, and the exact bound $P=\beta\gamma\theta\omega$ to make the two products error-free at the selected generation precision. A generic similarity generator would not test that contract. The requested diagonal contains a small $2^{-45}$ increment. The shift expression can quantize it, and the realized matrix must preserve that fact in its metadata. A later 256-bit eig call cannot restore a bit removed at $g=53$. Conversely, if a low work precision corrupts $S'X$ or $Y(S'X)$, that is a product failure, not an intended quantization effect. Exactness and solver accuracy are therefore separate gates. ## What the Octave example computes The matching [oo53_real.m](../../../../examples/tiered/neig-tier-s/oo53_real.m) selects only OO53_REAL from the fixed NEIG manifest and invokes the public mp_neig_tiers smoke path. The family runner uses $n=8$ for smoke and $n=16$ for demo, runs both balance modes, and records generation precision, requested/realized spectra, model hashes, operation precision, measured roots, and left/right diagnostics. It sends the generated dense $A$ to eig; it does not solve the easier triangular $S'$ problem in its place. Before reading the root comparison, inspect the generator record: $X$ and $Y$ must be inverse pairs, the theorem inequality must hold, the rounded products must equal the independently evaluated exact products, and at least one requested entry must be quantized. Repeating generation at $g=53$ must be bit-identical, regardless of later eig precision. ## Construction and exactness The independent audit verifies $XY=YX=I$ using finite nilpotent series, not an unverified numerical inverse. It calculates a sufficient dyadic bit guard for both matrix-product stages and checks the Ozaki–Ogita inequality ```math 4 n_Y n' 2^{-g}P\le 1. ``` Every rounded scalar sum and every final matrix entry is compared with an exact dyadic numerator/denominator evaluation. The realized standard form and the final A are serialized separately. Agreement between two MP runs is a useful regression check but cannot replace this exactness proof. The $g=53$ generator is the explicitly allowed fixed-precision generator. It must not be silently changed to 64, 128, or the eigensolver precision. The construction is also not a license to route later dense operations through builtin binary64 complex arithmetic. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` Match measured eigenvalues bijectively with diag(S') and separately with diag(S_req). Keep a requested-versus-realized forward bottleneck, a model hash, and the generation exactness status. A real model has no mathematical imaginary parts; a displayed imaginary component is a solver/conditioning diagnostic. ## Backward error versus forward error The eigen residual is a backward-style equation defect. It says that the returned factors nearly satisfy an eigen-equation for the stored $A$. It does not say that each root is close to the requested root: forward error is affected by the realized/requested difference and by the left/right eigenvalue condition. A small residual can therefore coexist with a visible difference at the $2^{-45}$ scale, while a large residual means the measured solve itself needs investigation. ## What arbitrary precision changes The input/source precision is $g=53$ for the frozen generator output. Arithmetic/work precision is 128 or 256 bits in the smoke rows, with higher reference/evaluation rows. Mathematical conditioning is determined by the triangular factors and the eigenvector geometry. More work precision reduces rounding in the dense eigensolve and diagnostics, but it does not regenerate $S'$ or restore a discarded requested bit. The operation must still use the input-owned MPFR/MPC precision and restore the caller’s ambient precision. ## Reading the output First confirm that the case ID, $n$, $g$, and requested/realized hashes are correct. Next confirm the theorem audit and product exactness. Then read $r_{\mathrm{eig}}$ and the matched forward errors. If the measured result follows $\mathrm{diag}(S')$ rather than the requested $\mathrm{diag}(S_{\mathrm{req}})$, that is expected when the generator removed a requested increment. A PASS line is only a pass for these declared gates; it is not a claim that the requested unrounded spectrum was computed. ## Common mistakes Do not use $mp(S_{\mathrm{req}})$ as the measured $A$, compare only with the requested diagonal, regenerate the standard form for each eig precision, or call the construction a generic similarity recipe. Do not infer forward accuracy from $r_{\mathrm{eig}}$ alone. Do not use an ordinary inverse to establish $XY=I$. Do not silently change $g$ or label a native binary64 control as the MP result. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Katsuhisa Ozaki and Takeshi Ogita, “Generation of test matrices with specified eigenvalues using floating-point arithmetic.” Numerical Algorithms 90 (2022), 241–262. DOI: 10.1007/s11075-021-01186-7](https://doi.org/10.1007/s11075-021-01186-7) — Theorem 1 and the paired standard-form construction motivate the fixed-precision generator and the requested/realized distinction. - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” SIAM Journal on Matrix Analysis and Applications 43(4) (2022), 1736–1754. DOI: 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — General all-eigenvalue error-bound context; this page does not claim that the project implements that paper. The selected dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations. ## Project provenance - Runnable case: [oo53_real.m](../../../../examples/tiered/neig-tier-s/oo53_real.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Generator specification: [GENERATOR-OO.md](../../../../docs/codex/neigt/GENERATOR-OO.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-s/toeplitz_sym.md0000644000230300031750000002224015274353473025475 0ustar rafaelrafael# Symmetric Toeplitz control (Tier S3) ## Quick idea TOEPLITZ_SYM isolates one mathematical reason a dense nonsymmetric eigensystem can be misleading: Expect a small eigen residual and an orthogonality residual in the symmetric run, but do not compare signs entrywise. The case is intentionally small enough to inspect and is paired with a deterministic runner. Its tier is a statement about pedagogical difficulty and verification depth, not a claim that the public eig routine implements the cited paper's algorithm. ## Mathematical problem Smoke: $n=16$, $b=4$. Demo: $n=32$, $b=4$. This is $B$ itself, with both off-diagonals equal to $2^{-b}$. The control matrix is ```math B=\mathrm{tridiag}(2^{-b},3,2^{-b}). ``` For $\theta_k=k\pi/(n+1)$, the exact real eigenpairs are ```math \lambda_k=3+2^{1-b}\cos(\theta_k),\qquad q_{jk}=\sqrt{\frac{2}{n+1}}\sin(j\theta_k). ``` The dense nonsymmetric case satisfies $A=D B D^{-1}$ in the corresponding orientation, so B is the same spectrum in a symmetric coordinate system. ## Why this problem is numerically difficult This control isolates the effect of representation. The matrix is real symmetric, so its eigenvectors can be chosen orthonormal and its eigenvalue sensitivity is governed by separated spectral gaps rather than the nonorthogonal left/right scaling in A. Comparing it with A is meaningful only when the two inputs are generated separately and their coordinate labels are preserved. It is not a shortcut that licenses replacing the original Toeplitz test with a symmetric eig call. The matrix is never replaced by a different representation merely because a related control has a convenient spectrum. Exact model facts, generated-input facts, and measured solver output are kept in separate records. ## What the Octave example computes The matching [toeplitz_sym.m](../../../../examples/tiered/neig-tier-s/toeplitz_sym.m) solves B through the public eig path, computes the analytic spectrum in MP, and checks orthogonality of the returned eigenvectors. It records the symmetric representation as a control beside, not in place of, TOEPLITZ. The exact dimensions and b are fixed by the manifest. The example reports the selected case ID, profile, dimensions, input/model identity, and measured rows. Run it from a loaded mplapack-interop package; the package's mp values remain MPFR/MPC values throughout the numerical path. ## Construction and exactness Dyadic off-diagonal and diagonal entries are checked directly. The reference formula follows from the sine recurrence and is evaluated at MP precision; no native trigonometric constants enter the model. The normalized sine matrix is orthogonal up to the explicitly computed MP error. A repeated or nearly equal output vector basis would still be interpreted as a subspace if parameters are changed. The construction audit is intentionally independent of eig: it checks algebraic identities, dyadic serialization, and declared generation guards before using a solver result. A cross-precision match is useful evidence, but it is not an exactness proof. ## Diagnostics For a computed $A\in\mathbb{C}^{n\times n}$, right vectors $V$, diagonal or block output $D$, and left vectors $W$, the primary residuals are ```math r_{\mathrm{eig}}= \frac{\lVert AV-VD\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}}= \frac{\lVert A^{\mathsf H}W-WD^{\mathsf H}\rVert_F} {\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use $A V_J-V_JD_J$ and a range/projector or principal-angle comparison; do not turn a repeated or defective cluster into an individual-vector claim. Also inspect the normwise backward indicator against the correct input, the forward bottleneck against the exact/realized reference, and the left/right or subspace diagnostic appropriate to this case. Keep MP values until the final display. A residual is not a certificate that every eigenvalue digit is forward correct. ## Backward error versus forward error The residual ($r_{\mathrm{eig}}$) measures how nearly the returned factors satisfy an eigen-equation. It can be interpreted as a small backward perturbation of the matrix under suitable normalization, but the corresponding forward eigenvalue error is multiplied by eigenvalue and eigenvector conditioning. In a cluster, the forward object is an invariant subspace. In a defective case, a full diagonalizing basis does not exist. The report therefore never promotes a small residual to a universal accuracy claim. ## What arbitrary precision changes The source precision is exact dyadic for B; arithmetic precision controls the eigensolver and MP sine reference. The comparison is sensitive to any accidental native conversion of pi or sine. Higher precision should improve both residual and reference evaluation without changing B. Three precision roles must be distinguished. **Input/source precision** describes the stored model and any fixed generator rounding. **Arithmetic/work precision** is the one-operation MPFR/MPC precision used to construct, factor, and inspect that stored value. **Mathematical conditioning** describes sensitivity of the problem and is not repaired merely by printing more digits. The runner also tests low/high ambient defaults and restoration so an unrelated caller setting cannot silently choose the operation precision. No builtin binary64 complex fallback is part of this example. ## Reading the output Expect a small eigen residual and an orthogonality residual in the symmetric run, but do not compare signs entrywise. The difference between B’s clean eigenvectors and A’s scaled vectors is the intended observation. Compare absolute and relative eigenvalue error against the analytic reference, while remembering that a residual is a backward error indicator rather than a complete forward certificate. A PASS line means the declared case-level gates passed; it does not erase the limitations stated above. Compare rows only within the same model identity and profile. If an exactness, coverage, cluster, or precision-contract field is missing, the honest status is incomplete rather than inferred from a pretty display. ## Common mistakes Do not identify B with A, use D’s condition as B’s eigenvalue condition, use binary64 sine values as the MP reference, or require exact signs/phases from eig. A useful debugging sequence is: verify the case ID and parameters; verify the serialized input/model hash; inspect the input precision and ambient precision; inspect the residual; then inspect the conditioning-appropriate forward or subspace metric. Do not change parameters after seeing a failure and call the changed run the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Silvia Noschese, Lionello Pasquini, and Lothar Reichel, “Tridiagonal Toeplitz matrices: properties and novel applications.” *Numerical Linear Algebra with Applications* 20(2) (2013), 302–326. DOI: [10.1002/nla.1811](https://doi.org/10.1002/nla.1811)](https://doi.org/10.1002/nla.1811) — The closed-form eigenvalues and eigenvectors explain the symmetric control and the diagonal-scaling sensitivity. - [Siegfried M. Rump, “Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix.” *SIAM Journal on Matrix Analysis and Applications* 43(4) (2022), 1736–1754. DOI: [10.1137/21M1451440](https://doi.org/10.1137/21M1451440)](https://doi.org/10.1137/21M1451440) — The all-spectrum and Jordan-similarity setting motivates the counted spectrum and subspace warnings; this example remains an independent dense-eigensolver demonstration. The references motivate the mathematical phenomenon and attribution boundary. The fixed dimensions, dyadic parameters, acceptance thresholds, and executable implementation are project-specific adaptations unless explicitly stated otherwise. ## Project provenance - Runnable case: [toeplitz_sym.m](../../../../examples/tiered/neig-tier-s/toeplitz_sym.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification jobs and conservative certificate scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - The detailed page explains the model; the family runner remains the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/GLOSSARY.md0000644000230300031750000001614115274353473022056 0ustar rafaelrafael# Tiered NEIG/SVD glossary This glossary fixes the vocabulary used by the 44 one-case pages and their counted runners. A diagnostic is not promoted to a stronger claim than the equation or proof it actually checks. ## Arithmetic and model terms **Input/source precision** is the precision with which the stored matrix or generator output was formed. For a fixed Ozaki–Ogita case, it includes the generation precision and the realized standard form. For a once-rounded lower-work model, it includes the fact that the rounded matrix is the measured input. **Work/arithmetic precision** is the MPFR/MPC precision selected for the current operation. It controls construction, products, eig, SVD, references, and diagnostics according to the operation contract. It is not a replacement for source precision. **Mathematical conditioning** is sensitivity of the exact problem to perturbations. Raising arithmetic precision can reduce rounding error while leaving a large condition number, a small singular gap, or a defective Jordan structure unchanged. **Dyadic** means a rational number of the form $z/2^k$, with integer z and exponent k. A dyadic is exactly representable when the available significand and exponent range are sufficient. Decimal-looking output is not an exactness proof. **Realized model** is the exact matrix that the generator or once-rounding rule actually stores. A requested parameter, a realized parameter, a dense product, and a solver output must not be collapsed into one label. ## Eigenproblem terms For $A\in\mathbb{C}^{n\times n}$, a right eigenpair satisfies $A v=\lambda v$. A left eigenvector is represented as a column satisfying $A^{\mathsf H}w=\overline{\lambda}w$. With $V,D,W$, the measured equations are ```math A V=V D,\qquad A^{\mathsf H}W=W D^{\mathsf H}. ``` **Eigen residual** is the normalized equation defect ```math r_{\mathrm{eig}}= \frac{\lVert A V-V D\rVert_F} {\lVert A\rVert_F\lVert V\rVert_F}. ``` It is a backward-style diagnostic. It does not by itself bound forward eigenvalue error. **Backward error** asks how much the input must be perturbed for the computed output to satisfy the stated relation. **Forward error** asks how far the computed output is from the mathematical output of the stored input. A small backward error can yield a large forward error for an ill-conditioned problem. **Nonnormal** means $A^{\mathsf H}A\ne AA^{\mathsf H}$. Nonnormal eigenvectors need not be orthogonal; left/right overlaps can make eigenvalues very sensitive even when they are separated. **Simple eigenvalue** has algebraic multiplicity one. An isolated-simple-root diagnostic is not valid for a repeated cluster or a defective block. **Algebraic multiplicity** is the multiplicity in the characteristic polynomial. **Geometric multiplicity** is the dimension of the nullspace of $A-\lambda I$. A Jordan block of size two has algebraic multiplicity two and geometric multiplicity one. **Semisimple repeated eigenvalue** has equal algebraic and geometric multiplicities. Individual eigenvectors within the repeated eigenspace are not canonical. **Invariant subspace** is a range $\mathcal R(V_J)$ satisfying $A\mathcal R(V_J)\subseteq\mathcal R(V_J)$. For a cluster, the block residual $A V_J-V_JD_J$ and a range/projector comparison are meaningful even when individual roots or vectors are not. **Spectral projector** can mean an orthogonal projector onto a numerical range or an oblique algebraic projector such as $Y_{:,J}X_{J,:}$. These are different objects and must be labelled separately. **Pseudospectrum** at level $\varepsilon$ for the unstructured 2-norm is ```math \Lambda_\varepsilon(A)= \{z\in\mathbb C:\sigma_{\min}(zI-A)\le\varepsilon\}. ``` A pseudospectral point is not necessarily an eigenvalue. A plotted contour is not a verified enclosure unless outward bounds and a declared inside/outside convention support it. **Balancing** is a representation transformation intended to reduce scale disparities. It is a solver control, not a guaranteed improvement for every eigenvalue or vector. Balance and nobalance rows must retain the same input identity. ## SVD terms For $A\in\mathbb{C}^{m\times n}$, an SVD is ```math A=U\Sigma V^{\mathsf H}. ``` The reconstruction and factor orthogonality diagnostics are ```math r_{\mathrm{svd}}= \frac{\lVert A-U\Sigma V^{\mathsf H}\rVert_F}{\lVert A\rVert_F}, \qquad r_U=\lVert U^{\mathsf H}U-I\rVert_F,\qquad r_V=\lVert V^{\mathsf H}V-I\rVert_F. ``` **Singular-value forward error** compares a returned $\widehat\sigma_i$ with the mathematical singular value $\sigma_i(A)$ of the stored A. It is different from reconstruction error. **Singular gap** is the distance between a target singular value or cluster and the rest of the spectrum. A small gap makes individual singular vectors sensitive. **Repeated singular group** is a set of equal singular values. Individual columns of U or V can be rotated by any unitary basis change inside the group. Compare projectors or ranges. **Rank-deficient model** has exact zero singular values by construction or proof. Thresholding a measured small value is not an exact rank proof. **Near-rank** means a small positive singular value next to exact or effectively small zeros; it requires an explicit scale and gap statement. **Two-sided unitary equivalence** $A=Q B R^{\mathsf H}$, with Q and R unitary, preserves singular values but not eigenvalues in general. It must not be confused with similarity $A=Q B Q^{-1}$. ## Verification and reference terms **Analytic reference** is a formula evaluated independently at declared MP precision. It is not automatically an outward interval certificate. **Exactness check** proves a finite algebraic identity from integer/dyadic numerators, denominators, and a sufficient bit/range guard. Two agreeing floating computations are not enough. **Certified inclusion** is a statement supported by outward-safe bounds that enclose a mathematical object. A residual, a cross-precision match, or an empty adapter is not a certificate. **Bijection/matching** pairs computed values with reference values one-to-one in MP arithmetic. It must preserve all-spectrum counts and expose unmatched or merged values. **Model-specific oracle** is an independently proved fact about a named construction, such as a determinant identity, exact rank, or known spectrum. It cannot be generalized to an arbitrary matrix or inserted into measured solver output. ## References and boundaries - [Siegfried M. Rump, Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix (2022), DOI 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — eigenvalue, eigenvector, cluster, and Jordan-structure context. - [Per-Åke Wedin, Perturbation bounds in connection with singular value decomposition (1972), DOI 10.1007/BF01932678](https://doi.org/10.1007/BF01932678) — singular-vector and subspace perturbation context. - [GNU MPFR manual](https://www.mpfr.org/mpfr-current/mpfr.html) — correctly rounded scalar and exponent-range terminology. The project implements conservative, example-local checks described in the associated NEIG and SVT verification documents. The glossary does not claim full reproduction of the cited papers' algorithms. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/0000755000230300031750000000000015274353473022367 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/wilkinson.md0000644000230300031750000002276015274353473024735 0ustar rafaelrafael# Wilkinson integer companion matrix (Tier A3) ## Quick idea WILKINSON is a Tier A control. The roots are simple integers, but the coefficient vector contains large cancellation and the companion problem magnifies coefficient perturbations. It is small, deterministic, and intended to be read with its one-case Octave runner. Tier A identifies an advanced example; it does not claim that the public eig routine implements the cited paper's specialized algorithm. ## Mathematical problem Smoke: $n=10$. Demo: $n=20$. The target polynomial has exact roots $1,2,\ldots,n$. ```math p_n(z)=\prod_{j=1}^{n}(z-j)=z^n+c_1z^{n-1}+\cdots+c_n. ``` The Frobenius companion has first row $-(c_1,\ldots,c_n)$ and ones on the first subdiagonal. The complex coefficientwise indicator is ```math \eta_{\mathrm{poly}}(z)= \frac{\lvert p_n(z)\rvert} {\displaystyle\sum_{j=0}^{n}\lvert c_j\rvert\lvert z\rvert^{n-j}}, \qquad c_0=1. ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 55 & -1320 & 18150 & -157773 & 902055 & -3416930 & 8409500 & -12753576 & 10628640 & -3628800 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \end{bmatrix}. ``` This is the full concrete smoke fixture for `WILKINSON`. The matching [`wilkinson.m`](../../../../examples/tiered/neig-tier-a/wilkinson.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The roots are simple integers, but the coefficient vector contains large cancellation and the companion problem magnifies coefficient perturbations. A matrix residual is a backward statement for $C$, whereas $\eta_{\mathrm{poly}}$ is a coefficientwise backward statement for $p_n$; neither is the root's forward error. The example catches unsafe coefficient construction from native poly. The exact model, any transformed control, and measured solver output remain separate. A related matrix with a convenient analytic answer is never silently substituted for the matrix named by the case ID. ## What the Octave example computes The matching [wilkinson.m](../../../../examples/tiered/neig-tier-a/wilkinson.m) selects only WILKINSON from the fixed manifest and calls the public eig interface. The matching wilkinson.m constructs coefficients by exact integer recurrence, forms $C$, runs public eig, and evaluates Horner $p(z)$ and its denominator in MP. It reports exact-root bottleneck, $r_{\mathrm{eig}}$, and $\eta_{\mathrm{poly}}$ for the exact model and any separately labelled native control. The matrix is never reconstructed from measured roots. The runner records the case ID, profile, dimensions, input identity, and operation precision, and keeps MP values until presentation. ## Construction and exactness The generator records a conservative integer/intermediate guard and checks coefficients independently. Horner evaluation at known roots uses higher precision. A denominator-zero case is explicit. The companion first row and subdiagonal are checked entry by entry. Exactness means that declared integer/dyadic identities and their bit guards have been checked independently. Agreement between two MP runs is useful evidence but is not an exactness proof. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}} = \frac{\lVert A^{\mathsf H} W - W D^{\mathsf H}\rVert_F}{\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use the block residual $A V_J-V_JD_J$ and compare ranges or projectors; never turn a repeated or defective cluster into an individual-vector claim. Also inspect the case-specific forward reference, the normwise backward indicator, and any positivity, polynomial, similarity, or pseudospectrum diagnostic. A residual alone does not establish forward accuracy of every eigenvalue or vector component. ## Backward error versus forward error The eigen residual measures the equation defect and can support a backward-error interpretation after normalization. Forward eigenvalue error additionally depends on spectral separation and left/right eigenvector conditioning. For repeated or defective objects, the forward target is an invariant subspace or block relation. For a polynomial companion, coefficientwise backward error is a different perturbation model. The report keeps these meanings distinct. ## What arbitrary precision changes Source coefficients and companion entries are exact integers when the guard is met. Arithmetic precision controls coefficient generation, Horner evaluation, and eig. Mathematical root sensitivity is distinct from coefficient exactness. Native stress rounding is a different input. Input/source precision is the precision and exactness of the stored model. Arithmetic/work precision is the MPFR/MPC precision selected for this operation. Mathematical conditioning is a property of the model. Raising mpbits addresses the second item only; it does not restore bits lost in a separately rounded input or alter a defective structure. Ambient-precision and restoration rows protect this distinction. ## Reading the output A tiny $\eta_{\mathrm{poly}}$ says a nearby coefficient vector can explain $z$; it does not say $z$ is close to its intended integer. Compare $\eta_{\mathrm{poly}}$, $r_{\mathrm{eig}}$, and forward distance as three quantities. Exact roots belong only to the exact coefficient model. A PASS line is scoped to the declared case gates and profile. Compare only rows with the same parameters and model hash. If a certificate field is absent, do not infer it from a small residual or a stable display. ## Common mistakes Do not form coefficients with binary64 poly, call polynomial backward error a forward error, use poly(eig(C)) as an oracle, or claim a small residual proves all roots equal $1,\ldots,n$. For diagnosis, verify case ID and dimensions, then model hash and input precision, then residual, then the appropriate forward, cluster, or structural metric. Never change the fixture after observing a failure and report it as the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Jared L. Aurentz, Thomas Mach, Leonardo Robol, Raf Vandebril, and David S. Watkins, Fast and Backward Stable Computation of Roots of Polynomials, Part II. SIAM Journal on Matrix Analysis and Applications 39(3) (2018), 1245–1269. DOI: 10.1137/17M1152802](https://doi.org/10.1137/17M1152802) — Keeps polynomial coefficient backward error separate from dense eigenvalue forward error. - [Nicholas J. Higham, Accuracy and Stability of Numerical Algorithms, 2nd ed. SIAM (2002). DOI: 10.1137/1.9780898718027](https://doi.org/10.1137/1.9780898718027) — The backward/forward-error framework and companion/nonnormal conditioning language used here. These references establish the external mathematical context. The selected dimensions, dyadic constants, runner, and acceptance thresholds are explicit project adaptations unless this page states otherwise. ## Project provenance - Runnable case: [wilkinson.m](../../../../examples/tiered/neig-tier-a/wilkinson.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - This page explains the named model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/had_complex.md0000644000230300031750000002356115274353473025203 0ustar rafaelrafael# Complex phase of the Hadamard-bidiagonal control (Tier A1) ## Quick idea HAD_COMPLEX is a Tier A control. This is a complex API and conjugation control, not a new spectrum. It is small, deterministic, and intended to be read with its one-case Octave runner. Tier A identifies an advanced example; it does not claim that the public eig routine implements the cited paper's specialized algorithm. ## Mathematical problem Demo only: $n=16$ and $s=128$. The phase diagonal repeats $1$, $i$, $-1$, $i$ and is applied by unitary similarity. ```math Z=\mathrm{diag}(1,i,-1,-i,\ldots),\qquad A_{\mathbb C}=ZAZ^{\mathsf H}. ``` $Z^{\mathsf H}Z=I$, so $A_{\mathbb C}$ and $A$ have the same eigenvalues; right and left vectors transform with the corresponding conjugate phases. ## Concrete demo matrix For the fixed demo parameters $n=16$ and $s=128$, the exact complex input passed to `eig` is ```math A_{\mathbb C,\mathrm{demo}}=2^{-1}\begin{bmatrix} 257 & 17i & 18 & -16i & -20 & 16i & 16 & -16i & -24 & 16i & 16 & -16i & -16 & 16i & 16 & -16i \\ 15i & -223 & -16i & -14 & 16i & 12 & -16i & -16 & 16i & 8 & -16i & -16 & 16i & 16 & -16i & -16 \\ -14 & 16i & 33 & 241i & -16 & 16i & 12 & -16i & -16 & 16i & 8 & -16i & -16 & 16i & 16 & -16i \\ 16i & 18 & 239i & 1 & 16i & 16 & -16i & -20 & 16i & 16 & -16i & -24 & 16i & 16 & -16i & -16 \\ 12 & -16i & -16 & 16i & 161 & 113i & 114 & -112i & 16 & -16i & -16 & 16i & 8 & -16i & -16 & 16i \\ -16i & -20 & 16i & 16 & 111i & -127 & -112i & -110 & -16i & -16 & 16i & 16 & -16i & -24 & 16i & 16 \\ 16 & -16i & -20 & 16i & -110 & 112i & 129 & 145i & 16 & -16i & -16 & 16i & 16 & -16i & -24 & 16i \\ -16i & -16 & 16i & 12 & 112i & 114 & 143i & -95 & -16i & -16 & 16i & 16 & -16i & 16 & -16i & 8 \\ 8 & -16i & -16 & 16i & 16 & -16i & -16 & 16i & 225 & 49i & 50 & -48i & -52 & 48i & 48 & -48i \\ -16i & -24 & 16i & 16 & -16i & -16 & 16i & 16 & 47i & -191 & -48i & -46 & 48i & 44 & -48i & -48 \\ 16 & -16i & -24 & 16i & 16 & -16i & -16 & 16i & -46 & 48i & 65 & 209i & -48 & 48i & 44 & -48i \\ -16i & -16 & 16i & 8 & -16i & -16 & 16i & 16 & 48i & 50 & 207i & -31 & 48i & 48 & -48i & -52 \\ -16 & 16i & 16 & -16i & -24 & 16i & 16 & -16i & 44 & -48i & -48 & 48i & 193 & 81i & 82 & -80i \\ 16i & 16 & -16i & -16 & 16i & 8 & -16i & -16 & -48i & -52 & 48i & 48 & 79i & -159 & -80i & -78 \\ -16 & 16i & 16 & -16i & -16 & 16i & 8 & -16i & 48 & -48i & -52 & 48i & -78 & 80i & 97 & 177i \\ 16i & 16 & -16i & -16 & 16i & 16 & -16i & -24 & -48i & -48 & 48i & 44 & 80i & 82 & 175i & -63 \end{bmatrix}. ``` This is the full concrete demo fixture for `HAD_COMPLEX`. It is obtained from the exact real Hadamard-bidiagonal model by $A_{\mathbb C}=ZAZ^{\mathsf H}$ with the repeated phase pattern $(1,i,-1,-i)$. The matching [`had_complex.m`](../../../../examples/tiered/neig-tier-a/had_complex.m) selects the same manifest case and passes this exact complex input to the public `eig` path; the displayed matrix is not solver output. The common factor $2^{-1}$ applies to every displayed entry, so all source values are exact dyadic real/imaginary components. ## Why this problem is numerically difficult This is a complex API and conjugation control, not a new spectrum. It catches a transpose in place of conjugate transpose and code that routes a real-only operation through an unrelated binary64 complex fallback. The underlying dense matrix remains nonnormal, while the phase changes the coordinate appearance of vectors. The exact model, any transformed control, and measured solver output remain separate. A related matrix with a convenient analytic answer is never silently substituted for the matrix named by the case ID. ## What the Octave example computes The matching [had_complex.m](../../../../examples/tiered/neig-tier-a/had_complex.m) selects only HAD_COMPLEX from the fixed manifest and calls the public `eig` interface. The matching `had_complex.m` runs the demo case through the public complex eig path, checks the unitary similarity, and compares its spectrum with the real control. It measures $A_{\mathbb C}V-VD$ and $A_{\mathbb C}^{\mathsf H}W-WD^{\mathsf H}$, then compares transformed subspaces after phase matching. It remains a separate complex input. The runner records the case ID, profile, dimensions, input identity, and operation precision, and keeps MP values until presentation. ## Construction and exactness The constructor checks $Z^{\mathsf H}Z=I$, exact quarter-turn entries, and the similarity identity. The real model reference is reused only as a mathematical control; the complex `eig` call consumes $A_{\mathbb C}$. Exactness is checked before and after phase application. Exactness means that declared integer/dyadic identities and their bit guards have been checked independently. Agreement between two MP runs is useful evidence but is not an exactness proof. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}} = \frac{\lVert A^{\mathsf H} W - W D^{\mathsf H}\rVert_F}{\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use the block residual $A V_J-V_JD_J$ and compare ranges or projectors; never turn a repeated or defective cluster into an individual-vector claim. Also inspect the case-specific forward reference, the normwise backward indicator, and any positivity, polynomial, similarity, or pseudospectrum diagnostic. A residual alone does not establish forward accuracy of every eigenvalue or vector component. ## Backward error versus forward error The eigen residual measures the equation defect and can support a backward-error interpretation after normalization. Forward eigenvalue error additionally depends on spectral separation and left/right eigenvector conditioning. For repeated or defective objects, the forward target is an invariant subspace or block relation. For a polynomial companion, coefficientwise backward error is a different perturbation model. The report keeps these meanings distinct. ## What arbitrary precision changes The real source is exact dyadic and the phase is exact in MPC. Arithmetic precision controls complex products at the operation precision; mathematical conditioning is inherited from the nonnormal base. More bits improve residuals without changing the similarity. Input/source precision is the precision and exactness of the stored model. Arithmetic/work precision is the MPFR/MPC precision selected for this operation. Mathematical conditioning is a property of the model. Raising mpbits addresses the second item only; it does not restore bits lost in a separately rounded input or alter a defective structure. Ambient-precision and restoration rows protect this distinction. ## Reading the output Equal spectra are expected, while vector entries and phases can differ. A transpose-only left residual can look plausible for real data but is invalid here. Read the complex left residual and matching result together. A PASS line is scoped to the declared case gates and profile. Compare only rows with the same parameters and model hash. If a certificate field is absent, do not infer it from a small residual or a stable display. ## Common mistakes Do not use $A$ instead of $A_{\mathbb C}$, compare vectors without phase normalization, use a transpose-only left identity, or claim an optimized backend that was not validated. For diagnosis, verify case ID and dimensions, then model hash and input precision, then residual, then the appropriate forward, cluster, or structural metric. Never change the fixture after observing a failure and report it as the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix. SIAM Journal on Matrix Analysis and Applications 43(4) (2022), 1736–1754. DOI: 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — The all-spectrum and rigorous eigensystem context; these are independent dense controls. - [Nicholas J. Higham, Accuracy and Stability of Numerical Algorithms, 2nd ed. SIAM (2002). DOI: 10.1137/1.9780898718027](https://doi.org/10.1137/1.9780898718027) — The backward/forward-error framework and companion/nonnormal conditioning language used here. These references establish the external mathematical context. The selected dimensions, dyadic constants, runner, and acceptance thresholds are explicit project adaptations unless this page states otherwise. ## Project provenance - Runnable case: [had_complex.m](../../../../examples/tiered/neig-tier-a/had_complex.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - This page explains the named model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/frank0.md0000644000230300031750000002253315274353473024077 0ustar rafaelrafael# Frank matrix, orientation 0 (Tier A2) ## Quick idea FRANK0 is a Tier A control. Frank matrices are integer and structured, but small positive eigenvalues and reciprocal pairing make relative accuracy important. It is small, deterministic, and intended to be read with its one-case Octave runner. Tier A identifies an advanced example; it does not claim that the public eig routine implements the cited paper's specialized algorithm. ## Mathematical problem Smoke: $n=8$. Demo: $n=24$. The matrix is an exact integer upper-Hessenberg Frank orientation. ```math (F_0)_{ij} = \begin{cases} n+1-\max(i,j), & j \ge i-1,\\ 0, & j < i-1. \end{cases} ``` An independent symmetric Jacobi reference has off-diagonal entries $\sqrt{j}$. Its eigenvalue $z$ is mapped stably to $f(z)$ by ```math f(z) = \begin{cases} \left(\dfrac{z+\sqrt{z^2+4}}{2}\right)^2, & z \ge 0,\\ \left(\dfrac{2}{\sqrt{z^2+4}-z}\right)^2, & z < 0. \end{cases} ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 8 & 7 & 6 & 5 & 4 & 3 & 2 & 1 \\ 7 & 7 & 6 & 5 & 4 & 3 & 2 & 1 \\ 0 & 6 & 6 & 5 & 4 & 3 & 2 & 1 \\ 0 & 0 & 5 & 5 & 4 & 3 & 2 & 1 \\ 0 & 0 & 0 & 4 & 4 & 3 & 2 & 1 \\ 0 & 0 & 0 & 0 & 3 & 3 & 2 & 1 \\ 0 & 0 & 0 & 0 & 0 & 2 & 2 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `FRANK0`. The matching [`frank0.m`](../../../../examples/tiered/neig-tier-a/frank0.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. For `FRANK0`, the displayed array is the exact integer upper-Hessenberg orientation. Representative formula checks are $(F_0)_{11}=8$, $(F_0)_{18}=1$, $(F_0)_{43}=5$, and $(F_0)_{42}=0$. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult Frank matrices are integer and structured, but small positive eigenvalues and reciprocal pairing make relative accuracy important. The orientation convention is part of the case: a reflected gallery matrix with a different flag is not silently substituted. The Jacobi map provides an independent reference and a cancellation-safe formula for the small branch. The exact model, any transformed control, and measured solver output remain separate. A related matrix with a convenient analytic answer is never silently substituted for the matrix named by the case ID. ## What the Octave example computes The matching [frank0.m](../../../../examples/tiered/neig-tier-a/frank0.m) selects only FRANK0 from the fixed manifest and calls the public `eig` interface. The matching `frank0.m` builds $F_0$ from the explicit index rule, runs public `eig`, and compares sorted roots with the MP Jacobi-derived reference. It checks positivity, reciprocal pairing, the odd-order central root when applicable, and absolute and relative bottlenecks. FRANK1 is a separate orientation control, not a second arbitrary spectrum. The runner records the case ID, profile, dimensions, input identity, and operation precision, and keeps MP values until presentation. ## Construction and exactness The constructor checks the integer Hessenberg pattern. The Jacobi reference uses MP square roots and the branch-stable map above. Small characteristic polynomials are checked by an independent recurrence for $n=2$ through $5$. The reference is never formed from measured roots. Exactness means that declared integer/dyadic identities and their bit guards have been checked independently. Agreement between two MP runs is useful evidence but is not an exactness proof. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}} = \frac{\lVert A^{\mathsf H} W - W D^{\mathsf H}\rVert_F}{\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use the block residual $A V_J-V_JD_J$ and compare ranges or projectors; never turn a repeated or defective cluster into an individual-vector claim. Also inspect the case-specific forward reference, the normwise backward indicator, and any positivity, polynomial, similarity, or pseudospectrum diagnostic. A residual alone does not establish forward accuracy of every eigenvalue or vector component. ## Backward error versus forward error The eigen residual measures the equation defect and can support a backward-error interpretation after normalization. Forward eigenvalue error additionally depends on spectral separation and left/right eigenvector conditioning. For repeated or defective objects, the forward target is an invariant subspace or block relation. For a polynomial companion, coefficientwise backward error is a different perturbation model. The report keeps these meanings distinct. ## What arbitrary precision changes The source is exact integer MP data. Arithmetic precision controls the dense eigensolver and Jacobi reference; mathematical conditioning of small paired roots remains. Raising precision helps only if the exact integer model is preserved. Input/source precision is the precision and exactness of the stored model. Arithmetic/work precision is the MPFR/MPC precision selected for this operation. Mathematical conditioning is a property of the model. Raising mpbits addresses the second item only; it does not restore bits lost in a separately rounded input or alter a defective structure. Ambient-precision and restoration rows protect this distinction. ## Reading the output Use relative error for small nonzero roots and absolute error near zero. Reciprocal pairing is a structural check, not an eigenvector certificate. A small $r_{\mathrm{eig}}$ can coexist with a large relative error in a small root. Compare orientation labels before comparing rows. A PASS line is scoped to the declared case gates and profile. Compare only rows with the same parameters and model hash. If a certificate field is absent, do not infer it from a small residual or a stable display. ## Common mistakes Do not use a different Frank orientation, use only absolute error, calculate the reference from `eig(F_0)`, evaluate the small branch by cancellation, or infer pairing from a display-only sorted list. For diagnosis, verify case ID and dimensions, then model hash and input precision, then residual, then the appropriate forward, cluster, or structural metric. Never change the fixture after observing a failure and report it as the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Nicholas J. Higham, Accuracy and Stability of Numerical Algorithms, 2nd ed. SIAM (2002). DOI: 10.1137/1.9780898718027](https://doi.org/10.1137/1.9780898718027) — The backward/forward-error framework and companion/nonnormal conditioning language used here. - [Siegfried M. Rump, Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix. SIAM Journal on Matrix Analysis and Applications 43(4) (2022), 1736–1754. DOI: 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — The all-spectrum and rigorous eigensystem context; these are independent dense controls. These references establish the external mathematical context. The selected dimensions, dyadic constants, runner, and acceptance thresholds are explicit project adaptations unless this page states otherwise. ## Project provenance - Runnable case: [frank0.m](../../../../examples/tiered/neig-tier-a/frank0.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - This page explains the named model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/README.md0000644000230300031750000001101615274353473023645 0ustar rafaelrafael# Nonsymmetric eigensystems — Tier A Tier A is the broad advanced-example path. These cases retain exact integer/dyadic models while introducing eigenvalue conditioning, companion-polynomial diagnostics, pseudospectrum probes, stochastic/Perron structure, and a complex phase control. Each row is one conceptual case with one runnable entry point and one detailed mathematical explanation. The detailed pages print every small smoke or fixed control in full with exact integer or dyadic entries. The source matrix is not solver output, and source precision remains separate from measured eigensystem precision. ## Common diagnostic language For right eigenvectors V and left eigenvectors W: ```math A V = V D,\qquad A^{\mathsf H}W=WD^{\mathsf H},\qquad r_{\mathrm{eig}} = \frac{\lVert AV-VD\rVert_F} {\lVert A\rVert_F\lVert V\rVert_F}. ``` A forward comparison uses an independent exact, analytic, or high-precision reference appropriate to the case. A polynomial coefficient backward error, a pseudospectral shifted singular value, a Perron contraction, and an eig residual are different claims. The tables and detail pages name which one is being measured. ## Learning map | Case | Mathematical object | Main question | Start here | Detailed page | External primary context | |---|---|---|---|---|---| | HAD_BIDIAG | Hadamard similarity of upper bidiagonal T | separated roots, sensitive vectors | [had_bidiag.m](../../../../examples/tiered/neig-tier-a/had_bidiag.m) | [had_bidiag.md](./had_bidiag.md) | [Rump (2022)](https://doi.org/10.1137/21M1451440) | | FRANK0 | explicit integer Frank orientation | small positive reciprocal roots | [frank0.m](../../../../examples/tiered/neig-tier-a/frank0.m) | [frank0.md](./frank0.md) | [Higham (2002)](https://doi.org/10.1137/1.9780898718027) | | FRANK1 | $RF_0^{\mathsf T}R$ orientation | orientation and left/right exchange | [frank1.m](../../../../examples/tiered/neig-tier-a/frank1.m) | [frank1.md](./frank1.md) | [Higham (2002)](https://doi.org/10.1137/1.9780898718027) | | WILKINSON | integer-root Frobenius companion | matrix versus polynomial backward error | [wilkinson.m](../../../../examples/tiered/neig-tier-a/wilkinson.m) | [wilkinson.md](./wilkinson.md) | [Aurentz et al. (2018)](https://doi.org/10.1137/17M1152802) | | GRCAR | exact $0/\pm1$ Grcar band | nonnormal pseudospectrum | [grcar.m](../../../../examples/tiered/neig-tier-a/grcar.m) | [grcar.md](./grcar.md) | [Rump (2006)](https://doi.org/10.1016/j.laa.2005.06.009) | | MKS | $N^m+\delta\mathbf{1}\mathbf{1}^{\mathsf T}$ | defective zero part and small q | [mks.m](../../../../examples/tiered/neig-tier-a/mks.m) | [mks.md](./mks.md) | [Morimoto–Katori–Shirai (2025)](https://doi.org/10.1142/S2661335225500133) | | MARKOV | irreducible dyadic row-stochastic P | nonuniform left stationary vector | [markov.m](../../../../examples/tiered/neig-tier-a/markov.m) | [markov.md](./markov.md) | [Miyajima (2021)](https://doi.org/10.13001/ela.2021.5181) | | PERRON_POS | positive diagonal similarity of P | positive root and both vectors | [perron_pos.m](../../../../examples/tiered/neig-tier-a/perron_pos.m) | [perron_pos.md](./perron_pos.md) | [Miyajima (2021)](https://doi.org/10.13001/ela.2021.5181) | | HAD_COMPLEX | quarter-turn unitary phase | complex left-vector convention | [had_complex.m](../../../../examples/tiered/neig-tier-a/had_complex.m) | [had_complex.md](./had_complex.md) | [Rump (2022)](https://doi.org/10.1137/21M1451440) | The cited works are mathematical context, not claims that the package implements their complete algorithms. Fixed parameters and acceptance thresholds are suite-specific. ## How to run ~~~octave pkg load mplapack-interop run ("examples/tiered/neig-tier-a/grcar.m"); ~~~ For counted coverage: ~~~octave pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "neig_tiers")); result = mp_neig_tiers ("demo", struct ("tier", "A", "plot", false)); ~~~ The smoke profile includes the eight Tier A cases; the demo adds HAD_COMPLEX. Use the V-S/V-A entry points for verified targets and read their certificate status independently from ordinary eig residuals. ## Suggested order Start with HAD_BIDIAG, compare FRANK0/FRANK1, then read WILKINSON and GRCAR for backward-error and pseudospectral meaning. Finish with MKS, MARKOV, and PERRON_POS, where algebraic multiplicity, the left stationary vector, and positive-pair verification matter. HAD_COMPLEX is the final API/conjugation control. See the [master map](../README.md), [NEIG cases](../../../../docs/codex/neigt/cases.json), and [NEIG sources](../../../../docs/codex/neigt/SOURCES.md). mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/grcar.md0000644000230300031750000002141715274353473024014 0ustar rafaelrafael# Grcar nonnormal band matrix (Tier A4) ## Quick idea GRCAR is a Tier A control. Grcar shows that an eigenvalue list does not describe a nonnormal matrix. It is small, deterministic, and intended to be read with its one-case Octave runner. Tier A identifies an advanced example; it does not claim that the public eig routine implements the cited paper's specialized algorithm. ## Mathematical problem Smoke: $n=12$ and upper bandwidth 3. Demo: $n=24$ and upper bandwidth 3. Entries are exactly $0$, $+1$, or $-1$. ```math G_{ij}= \begin{cases} 1, & 0\le j-i\le 3,\\ -1, & i-j=1,\\ 0, & \text{otherwise}. \end{cases} ``` The unstructured complex 2-norm pseudospectrum is ```math \Lambda_\varepsilon(G)= \{z:\sigma_{\min}(zI-G)\le\varepsilon\}. ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ -1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & -1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & -1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & -1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & -1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & -1 & 1 & 1 & 1 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & -1 & 1 & 1 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 1 & 1 & 1 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 1 & 1 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 1 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 1 \end{bmatrix}. ``` This is the full concrete smoke fixture for `GRCAR`. The matching [`grcar.m`](../../../../examples/tiered/neig-tier-a/grcar.m) selects the same manifest case (`n=12`, upper bandwidth `3`) and hands this input to the public `eig` path; the displayed matrix is not solver output. Every entry is an exact integer, and the lower subdiagonal `-1` is distinct from the three upper diagonals of `+1`. ## Why this problem is numerically difficult Grcar shows that an eigenvalue list does not describe a nonnormal matrix. Small perturbations can move eigenvalues far from the computed spectrum, and an individual residual does not certify a pseudospectral boundary. The exact ±1 input is easy to audit, but there is no claimed analytic spectrum; the reference uses independent MP eig and shifted singular-value probes. The exact model, any transformed control, and measured solver output remain separate. A related matrix with a convenient analytic answer is never silently substituted for the matrix named by the case ID. ## What the Octave example computes The matching [grcar.m](../../../../examples/tiered/neig-tier-a/grcar.m) selects only GRCAR from the fixed manifest and calls the public `eig` interface. The matching `grcar.m` builds the exact band pattern, measures `eig` at selected precisions, and probes complex shifts through the public singular-value path. It reports $r_{\mathrm{eig}}$, shift singular values, and an explicit closed-set inside/outside convention. Optional plots are presentation only and never a certificate. The runner records the case ID, profile, dimensions, input identity, and operation precision, and keeps MP values until presentation. ## Construction and exactness The constructor checks every index rule and nonzero count. A verified point or positive-area cell is accepted only when an outward-safe bound supports its classification. Two MP reference runs are independent measurements, not an analytic oracle. A binary64 contour plot is not a proof. Exactness means that declared integer/dyadic identities and their bit guards have been checked independently. Agreement between two MP runs is useful evidence but is not an exactness proof. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}} = \frac{\lVert A^{\mathsf H} W - W D^{\mathsf H}\rVert_F}{\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use the block residual $A V_J-V_JD_J$ and compare ranges or projectors; never turn a repeated or defective cluster into an individual-vector claim. Also inspect the case-specific forward reference, the normwise backward indicator, and any positivity, polynomial, similarity, or pseudospectrum diagnostic. A residual alone does not establish forward accuracy of every eigenvalue or vector component. ## Backward error versus forward error The eigen residual measures the equation defect and can support a backward-error interpretation after normalization. Forward eigenvalue error additionally depends on spectral separation and left/right eigenvector conditioning. For repeated or defective objects, the forward target is an invariant subspace or block relation. For a polynomial companion, coefficientwise backward error is a different perturbation model. The report keeps these meanings distinct. ## What arbitrary precision changes The input is exact 0/±1 data. Arithmetic precision controls eig, shifted solves/SVD, and outward diagnostic widths. Mathematical nonnormal sensitivity remains after arithmetic error is reduced. More bits narrow a verified bound but do not shrink the true pseudospectrum. Input/source precision is the precision and exactness of the stored model. Arithmetic/work precision is the MPFR/MPC precision selected for this operation. Mathematical conditioning is a property of the model. Raising mpbits addresses the second item only; it does not restore bits lost in a separately rounded input or alter a defective structure. Ambient-precision and restoration rows protect this distinction. ## Reading the output A point with small $\sigma_{\min}(zI-G)$ is near the closed pseudospectrum; it is not necessarily an eigenvalue. Read eigen residuals and shift singular values separately. Precision-dependent contours can reflect arithmetic or unresolved boundary geometry. No balancing improvement is required. A PASS line is scoped to the declared case gates and profile. Compare only rows with the same parameters and model hash. If a certificate field is absent, do not infer it from a small residual or a stable display. ## Common mistakes Do not claim an analytic spectrum, equate a residual contour with a proof, call a structured metric the unstructured pseudospectrum, or use plotting samples as measured MP output. For diagnosis, verify case ID and dimensions, then model hash and input precision, then residual, then the appropriate forward, cluster, or structural metric. Never change the fixture after observing a failure and report it as the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, Eigenvalues, pseudospectrum and structured perturbations. Linear Algebra and its Applications 413(2–3) (2006), 567–593. DOI: 10.1016/j.laa.2005.06.009](https://doi.org/10.1016/j.laa.2005.06.009) — Separates unrestricted and structured perturbations. - [Siegfried M. Rump, Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix. SIAM Journal on Matrix Analysis and Applications 43(4) (2022), 1736–1754. DOI: 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — The all-spectrum and rigorous eigensystem context; these are independent dense controls. These references establish the external mathematical context. The selected dimensions, dyadic constants, runner, and acceptance thresholds are explicit project adaptations unless this page states otherwise. ## Project provenance - Runnable case: [grcar.m](../../../../examples/tiered/neig-tier-a/grcar.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - This page explains the named model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/markov.md0000644000230300031750000002404615274353473024216 0ustar rafaelrafael# Dyadic irreducible Markov matrix (Tier A6) ## Quick idea MARKOV is a Tier A control. The Perron root is known, but the stationary vector is a nontrivial left eigenvector. It is small, deterministic, and intended to be read with its one-case Octave runner. Tier A identifies an advanced example; it does not claim that the public eig routine implements the cited paper's specialized algorithm. ## Mathematical problem Smoke: $n=8$ and $\varepsilon=2^{-24}$. Demo: $n=16$ and $\varepsilon=2^{-80}$. The matrix is row-stochastic with a nonuniform stationary left vector. ```math h=n/2,\qquad C\in\mathbb{R}^{h\times h}. ``` ```math C_{i,i+1}=1\quad (1\leq i ```math A_{\mathrm{smoke}} = 2^{-31} \begin{bmatrix} 1610612704 & 536870912 & 16 & 8 & 4 & 2 & 1 & 1 \\ 64 & 1610612672 & 536870896 & 8 & 4 & 2 & 1 & 1 \\ 64 & 32 & 1610612656 & 536870888 & 4 & 2 & 1 & 1 \\ 536870944 & 32 & 16 & 1610612648 & 4 & 2 & 1 & 1 \\ 64 & 32 & 16 & 8 & 1879048084 & 268435442 & 1 & 1 \\ 64 & 32 & 16 & 8 & 4 & 1879048082 & 268435441 & 1 \\ 64 & 32 & 16 & 8 & 4 & 2 & 1879048081 & 268435441 \\ 64 & 32 & 16 & 8 & 268435444 & 2 & 1 & 1879048081 \end{bmatrix}. ``` This is the full concrete smoke fixture for `MARKOV`. The matching [`markov.m`](../../../../examples/tiered/neig-tier-a/markov.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The Perron root is known, but the stationary vector is a nontrivial left eigenvector. Rank-one dyadic mixing makes the chain irreducible while preserving an exact model. A row-sum check tests only the right vector and can miss a broken left convention. Non-Perron roots are outside the Perron certificate. The exact model, any transformed control, and measured solver output remain separate. A related matrix with a convenient analytic answer is never silently substituted for the matrix named by the case ID. ## What the Octave example computes The matching [markov.m](../../../../examples/tiered/neig-tier-a/markov.m) selects only MARKOV from the fixed manifest and calls the public eig interface. The underlying `net_markov_model` constructs $C$, $Q$, $r$, and $P$ in MP. The reference path evaluates the formula for $\pi$ and also solves the normalized linear system obtained from $P^{\mathsf T}\pi=\pi$. The runner compares those two independently prepared stationary rows, checks row sums, and keeps the teleportation target $r$ separate from the stationary vector $\pi$. It also runs the V-A3 Perron checker on $P$ and $P^{\mathsf T}$. The output separates root, right vector, left vector, normalization, and non-Perron diagnostics. The runner records the case ID, profile, dimensions, input identity, and operation precision, and keeps MP values until presentation. ## Construction and exactness The audit verifies nonnegative dyadic entries, $P\mathbf{1}=\mathbf{1}$, the rank-one formula, and the irreducibility assumptions. It checks both the analytic formula and the independent normalized solve for $\pi$, including $\pi^{\mathsf T}P=\pi^{\mathsf T}$ and $\pi^{\mathsf T}\mathbf{1}=1$. The stationary vector has a declared normalization and is not supplied to the eigensolver as its answer. Exactness means that declared integer/dyadic identities and their bit guards have been checked independently. Agreement between two MP runs is useful evidence but is not an exactness proof. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}} = \frac{\lVert A^{\mathsf H} W - W D^{\mathsf H}\rVert_F}{\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use the block residual $A V_J-V_JD_J$ and compare ranges or projectors; never turn a repeated or defective cluster into an individual-vector claim. Also inspect the case-specific forward reference, the normwise backward indicator, and any positivity, polynomial, similarity, or pseudospectrum diagnostic. A residual alone does not establish forward accuracy of every eigenvalue or vector component. ## Backward error versus forward error The eigen residual measures the equation defect and can support a backward-error interpretation after normalization. Forward eigenvalue error additionally depends on spectral separation and left/right eigenvector conditioning. For repeated or defective objects, the forward target is an invariant subspace or block relation. For a polynomial companion, coefficientwise backward error is a different perturbation model. The report keeps these meanings distinct. ## What arbitrary precision changes The source is exact dyadic and includes epsilon. Arithmetic precision controls positivity, eig, and normalization. Mathematical conditioning depends on mixing and Perron separation. More bits preserve a small mixing term but do not prove a spectral gap. Input/source precision is the precision and exactness of the stored model. Arithmetic/work precision is the MPFR/MPC precision selected for this operation. Mathematical conditioning is a property of the model. Raising mpbits addresses the second item only; it does not restore bits lost in a separately rounded input or alter a defective structure. Ambient-precision and restoration rows protect this distinction. ## Reading the output A valid Perron result requires a positive root enclosure, both vector residuals, and a contraction or Collatz–Wielandt uniqueness check. Row-stochasticity alone is insufficient. The second eigenvalue and a mixing-time theorem are not claimed. A PASS line is scoped to the declared case gates and profile. Compare only rows with the same parameters and model hash. If a certificate field is absent, do not infer it from a small residual or a stable display. ## Common mistakes Do not call the stationary vector uniform, verify only P*1=1, claim the Perron test certifies all eigenvalues, or use a rounded native stochastic matrix as the exact model. For diagnosis, verify case ID and dimensions, then model hash and input precision, then residual, then the appropriate forward, cluster, or structural metric. Never change the fixture after observing a failure and report it as the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Shinya Miyajima, Fast verification for the Perron pair of an irreducible nonnegative matrix. Electronic Journal of Linear Algebra 37 (2021), 402–415. DOI: 10.13001/ela.2021.5181](https://doi.org/10.13001/ela.2021.5181) — The positive Perron root/vector target; the checker here is an independent conservative baseline. - [Siegfried M. Rump, Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix. SIAM Journal on Matrix Analysis and Applications 43(4) (2022), 1736–1754. DOI: 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — The all-spectrum and rigorous eigensystem context; these are independent dense controls. These references establish the external mathematical context. The selected dimensions, dyadic constants, runner, and acceptance thresholds are explicit project adaptations unless this page states otherwise. ## Project provenance - Runnable case: [markov.m](../../../../examples/tiered/neig-tier-a/markov.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - This page explains the named model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/frank1.md0000644000230300031750000002166515274353473024105 0ustar rafaelrafael# Frank matrix, reflected orientation (Tier A2) ## Quick idea FRANK1 is a Tier A control. It is easy to turn two orientation IDs into aliases by using a library constructor with an unexamined flag. It is small, deterministic, and intended to be read with its one-case Octave runner. Tier A identifies an advanced example; it does not claim that the public eig routine implements the cited paper's specialized algorithm. ## Mathematical problem Smoke: $n=8$. Demo: $n=24$. The matrix is $F_1=RF_0^{\mathsf T}R$, with $R$ the reversal permutation. ```math F_1=R F_0^{\mathsf T}R,\qquad R^2=I. ``` Transpose and permutation similarity preserve the characteristic polynomial, so $F_1$ and $F_0$ have the same eigenvalues while their coordinate vectors and left/right roles differ. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = \begin{bmatrix} 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 \\ 1 & 2 & 2 & 2 & 2 & 2 & 2 & 2 \\ 0 & 2 & 3 & 3 & 3 & 3 & 3 & 3 \\ 0 & 0 & 3 & 4 & 4 & 4 & 4 & 4 \\ 0 & 0 & 0 & 4 & 5 & 5 & 5 & 5 \\ 0 & 0 & 0 & 0 & 5 & 6 & 6 & 6 \\ 0 & 0 & 0 & 0 & 0 & 6 & 7 & 7 \\ 0 & 0 & 0 & 0 & 0 & 0 & 7 & 8 \end{bmatrix}. ``` This is the full concrete smoke fixture for `FRANK1`. The matching [`frank1.m`](../../../../examples/tiered/neig-tier-a/frank1.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult It is easy to turn two orientation IDs into aliases by using a library constructor with an unexamined flag. The explicit reflection tests the convention and the dense path. Transposition exchanges right and left eigenvectors and reversal changes their coordinates; an equal spectrum does not imply equal eigenvectors or equal conditioning. The exact model, any transformed control, and measured solver output remain separate. A related matrix with a convenient analytic answer is never silently substituted for the matrix named by the case ID. ## What the Octave example computes The matching [frank1.m](../../../../examples/tiered/neig-tier-a/frank1.m) selects only FRANK1 from the fixed manifest and calls the public `eig` interface. The matching `frank1.m` constructs $F_0$, $R$, and $F_1$ in MP, verifies the exact relation, and calls `eig` on $F_1$. It uses the independent Jacobi reference from FRANK0, but measures $F_1$ residuals and left/right diagnostics independently. It does not reuse $F_0$'s measured vectors as an answer. The runner records the case ID, profile, dimensions, input identity, and operation precision, and keeps MP values until presentation. ## Construction and exactness The exact check verifies $R^2=I$, the reflected-transpose identity, the integer Hessenberg pattern, and small characteristic-polynomial identities. Any vector correspondence is tested through the correct transpose/reversal relation only after normalization. Exactness means that declared integer/dyadic identities and their bit guards have been checked independently. Agreement between two MP runs is useful evidence but is not an exactness proof. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}} = \frac{\lVert A^{\mathsf H} W - W D^{\mathsf H}\rVert_F}{\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use the block residual $A V_J-V_JD_J$ and compare ranges or projectors; never turn a repeated or defective cluster into an individual-vector claim. Also inspect the case-specific forward reference, the normwise backward indicator, and any positivity, polynomial, similarity, or pseudospectrum diagnostic. A residual alone does not establish forward accuracy of every eigenvalue or vector component. ## Backward error versus forward error The eigen residual measures the equation defect and can support a backward-error interpretation after normalization. Forward eigenvalue error additionally depends on spectral separation and left/right eigenvector conditioning. For repeated or defective objects, the forward target is an invariant subspace or block relation. For a polynomial companion, coefficientwise backward error is a different perturbation model. The report keeps these meanings distinct. ## What arbitrary precision changes Input values are exact integers. Work precision controls F1 construction, eig, and the independent reference. Mathematical sensitivity of the small roots remains even though there are no tiny source entries. More bits separate orientation effects from arithmetic noise. Input/source precision is the precision and exactness of the stored model. Arithmetic/work precision is the MPFR/MPC precision selected for this operation. Mathematical conditioning is a property of the model. Raising mpbits addresses the second item only; it does not restore bits lost in a separately rounded input or alter a defective structure. Ambient-precision and restoration rows protect this distinction. ## Reading the output Equal spectra are expected; equal vector entries are not. The left residual uses the adjoint equation $A^{\mathsf H}W-WD^{\mathsf H}$. Relative error remains important for small roots. This is a controlled transformation experiment, not evidence that orientation is numerically irrelevant. A PASS line is scoped to the declared case gates and profile. Compare only rows with the same parameters and model hash. If a certificate field is absent, do not infer it from a small residual or a stable display. ## Common mistakes Do not compare $F_1$ and $F_0$ without the $R/F$ transpose identity, use a transpose-only left residual, or claim that same eigenvalues imply same right eigenvectors. For diagnosis, verify case ID and dimensions, then model hash and input precision, then residual, then the appropriate forward, cluster, or structural metric. Never change the fixture after observing a failure and report it as the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Nicholas J. Higham, Accuracy and Stability of Numerical Algorithms, 2nd ed. SIAM (2002). DOI: 10.1137/1.9780898718027](https://doi.org/10.1137/1.9780898718027) — The backward/forward-error framework and companion/nonnormal conditioning language used here. - [Siegfried M. Rump, Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix. SIAM Journal on Matrix Analysis and Applications 43(4) (2022), 1736–1754. DOI: 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — The all-spectrum and rigorous eigensystem context; these are independent dense controls. These references establish the external mathematical context. The selected dimensions, dyadic constants, runner, and acceptance thresholds are explicit project adaptations unless this page states otherwise. ## Project provenance - Runnable case: [frank1.m](../../../../examples/tiered/neig-tier-a/frank1.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - This page explains the named model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/mks.md0000644000230300031750000001751315274353473023512 0ustar rafaelrafael# Nilpotent shift plus rank-one perturbation (Tier A5) ## Quick idea MKS is a Tier A control. The matrix combines a large defective zero part with a small nonzero-root problem. It is small, deterministic, and intended to be read with its one-case Octave runner. Tier A identifies an advanced example; it does not claim that the public eig routine implements the cited paper's specialized algorithm. ## Mathematical problem Smoke: $n=12$, $m=3$, $\delta=1/8$, $\ell=4$. Demo: $n=32$, $m=3$, $\delta=1/8$, $\ell=11$. ```math A=N^m+\delta\mathbf{1}\mathbf{1}^{\mathsf T}, \qquad \det(zI-A)=z^{n-\ell}q(z), \qquad q(z)=z^\ell-\delta\sum_{j=0}^{\ell-1}(n-mj)z^{\ell-1-j}. ``` The nonzero constant term of $q$ proves exact algebraic zero multiplicity $n-\ell$. ## Why this problem is numerically difficult The matrix combines a large defective zero part with a small nonzero-root problem. A rational formula with division by $z$ can be singular at the point the test needs, so the polynomial identity is the safe model. In the $m=3$ cases the zero part is defective: algebraic multiplicity and geometric multiplicity differ. Measured eig output must not be repaired by appending known zeros. The exact model, any transformed control, and measured solver output remain separate. A related matrix with a convenient analytic answer is never silently substituted for the matrix named by the case ID. ## What the Octave example computes The matching [mks.m](../../../../examples/tiered/neig-tier-a/mks.m) selects only MKS from the fixed manifest and calls the public eig interface. The matching mks.m constructs A, runs public eig, and compares nonzero roots with an independently built small companion for q at reference precision. It counts the full measured spectrum, reports the exact zero multiplicity, and checks invariant-subspace dimensions. Exact zeros are part of the reference record only; measured output is untouched. The runner records the case ID, profile, dimensions, input identity, and operation precision, and keeps MP values until presentation. ## Construction and exactness The audit verifies $N^m$, the dyadic rank-one term, $q$ coefficients, and small-$n$ determinant identities. $q$ is solved independently at two MP precisions. A rank calculation distinguishes algebraic multiplicity from geometric nullspace dimension. No exact multiplicity is inferred from a disk count. Exactness means that declared integer/dyadic identities and their bit guards have been checked independently. Agreement between two MP runs is useful evidence but is not an exactness proof. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}} = \frac{\lVert A^{\mathsf H} W - W D^{\mathsf H}\rVert_F}{\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use the block residual $A V_J-V_JD_J$ and compare ranges or projectors; never turn a repeated or defective cluster into an individual-vector claim. Also inspect the case-specific forward reference, the normwise backward indicator, and any positivity, polynomial, similarity, or pseudospectrum diagnostic. A residual alone does not establish forward accuracy of every eigenvalue or vector component. ## Backward error versus forward error The eigen residual measures the equation defect and can support a backward-error interpretation after normalization. Forward eigenvalue error additionally depends on spectral separation and left/right eigenvector conditioning. For repeated or defective objects, the forward target is an invariant subspace or block relation. For a polynomial companion, coefficientwise backward error is a different perturbation model. The report keeps these meanings distinct. ## What arbitrary precision changes Input is exact dyadic. Arithmetic precision controls the dense construction, eig, and small q reference. Mathematical difficulty is dominated by the defective zero cluster and scale separation. More bits improve separation but do not make the zero block diagonalizable. Input/source precision is the precision and exactness of the stored model. Arithmetic/work precision is the MPFR/MPC precision selected for this operation. Mathematical conditioning is a property of the model. Raising mpbits addresses the second item only; it does not restore bits lost in a separately rounded input or alter a defective structure. Ambient-precision and restoration rows protect this distinction. ## Reading the output Read zero count, nonzero-root matching, and invariant-subspace fields separately. A small residual for a near-zero vector is not a proof of exact multiplicity. The reduced companion is a reference computation, not the dense algorithm. Merged roots are reported as a cluster. A PASS line is scoped to the declared case gates and profile. Compare only rows with the same parameters and model hash. If a certificate field is absent, do not infer it from a small residual or a stable display. ## Common mistakes Do not use a singular rational formula, append known zeros to measured output, claim zero is semisimple, use the reduced companion as the dense solve, or infer $n-\ell$ from a disk count alone. For diagnosis, verify case ID and dimensions, then model hash and input precision, then residual, then the appropriate forward, cluster, or structural metric. Never change the fixture after observing a failure and report it as the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Saori Morimoto, Makoto Katori, and Tomoyuki Shirai, Eigenvalue and pseudospectrum processes generated by nonnormal Toeplitz matrices with rank 1 perturbations. International Journal of Mathematics for Industry 17(1) (2025), 2550013. DOI: 10.1142/S2661335225500133](https://doi.org/10.1142/S2661335225500133) — Model 1 motivates the nilpotent-shift plus rank-one determinant identity. - [Siegfried M. Rump, Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix. SIAM Journal on Matrix Analysis and Applications 43(4) (2022), 1736–1754. DOI: 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — The all-spectrum and rigorous eigensystem context; these are independent dense controls. These references establish the external mathematical context. The selected dimensions, dyadic constants, runner, and acceptance thresholds are explicit project adaptations unless this page states otherwise. ## Project provenance - Runnable case: [mks.m](../../../../examples/tiered/neig-tier-a/mks.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - This page explains the named model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/had_bidiag.md0000644000230300031750000002325615274353473024754 0ustar rafaelrafael# Hadamard-similar upper bidiagonal matrix (Tier A1) ## Quick idea HAD_BIDIAG is a Tier A control. The spectrum is well separated while the eigenvectors are not. It is small, deterministic, and intended to be read with its one-case Octave runner. Tier A identifies an advanced example; it does not claim that the public eig routine implements the cited paper's specialized algorithm. ## Mathematical problem Smoke: $n=8$ and $s=16$. Demo: $n=16$ and $s=128$. $n$ is a power of two and $H$ is the Sylvester Hadamard matrix. ```math T=\mathrm{diag}(1,2,\ldots,n)+sN,\qquad A=\frac{1}{n}HTH^{\mathsf T},\qquad HH^{\mathsf T}=nI. ``` The orthogonal similarity preserves the exact eigenvalues $1,2,\ldots,n$. For root $k$, the triangular reference vectors use ```math v_i=\frac{s^{k-i}}{(k-i)!}\quad (i\le k),\qquad w_i=\frac{(-s)^{i-k}}{(i-k)!}\quad (i\ge k). ``` The corresponding left/right condition reference is ```math \kappa_k= \left[\sum_{j=0}^{k-1}\frac{s^{2j}}{(j!)^2}\right]^{1/2} \left[\sum_{j=0}^{n-k}\frac{s^{2j}}{(j!)^2}\right]^{1/2}. ``` ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-1} \begin{bmatrix} 37 & -5 & -6 & -4 & -8 & -4 & -4 & -4 \\ 3 & -19 & 4 & 2 & 4 & 0 & 4 & 4 \\ 2 & 4 & 13 & -29 & 4 & 4 & 0 & 4 \\ -4 & -6 & 27 & 5 & -4 & -4 & -4 & -8 \\ 0 & 4 & 4 & 4 & 29 & -13 & -14 & -12 \\ -4 & -8 & -4 & -4 & 11 & -11 & 12 & 10 \\ -4 & -4 & -8 & -4 & 10 & 12 & 21 & -21 \\ 4 & 4 & 4 & 0 & -12 & -14 & 19 & -3 \end{bmatrix}. ``` This is the full concrete smoke fixture for `HAD_BIDIAG`. The matching [`had_bidiag.m`](../../../../examples/tiered/neig-tier-a/had_bidiag.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult The spectrum is well separated while the eigenvectors are not. A dense orthogonal similarity hides the triangular structure, so the eigensolver must work in dense coordinates. Factorial recurrences create large and small components at once, and the left/right overlap determines individual eigenvalue sensitivity. Exact integer and dyadic entries make the input auditable, but an integer spectrum does not make every computed digit forward accurate. The exact model, any transformed control, and measured solver output remain separate. A related matrix with a convenient analytic answer is never silently substituted for the matrix named by the case ID. ## What the Octave example computes The matching [had_bidiag.m](../../../../examples/tiered/neig-tier-a/had_bidiag.m) selects only HAD_BIDIAG from the fixed manifest and calls the public eig interface. The matching had_bidiag.m selects only HAD_BIDIAG from the frozen manifest, constructs $T$ and $A$ directly, checks Hadamard orthogonality, and calls the public eig path on $A$. It compares measured roots with $1:n$, reports residuals and matched forward error, and evaluates the condition reference $\kappa_k$ shown above. It never solves $T$ instead of $A$. The runner records the case ID, profile, dimensions, input identity, and operation precision, and keeps MP values until presentation. ## Construction and exactness The audit checks $HH^{\mathsf T}=nI$, both dense product stages, the dyadic bit guard, and the exact spectrum independently. Factorial terms are evaluated by MP multiplicative recurrences rather than native factorials. Vector comparisons use normalization and sign matching. Agreement between two MP runs is corroborating evidence, not an exactness proof. Exactness means that declared integer/dyadic identities and their bit guards have been checked independently. Agreement between two MP runs is useful evidence but is not an exactness proof. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}} = \frac{\lVert A^{\mathsf H} W - W D^{\mathsf H}\rVert_F}{\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use the block residual $A V_J-V_JD_J$ and compare ranges or projectors; never turn a repeated or defective cluster into an individual-vector claim. Also inspect the case-specific forward reference, the normwise backward indicator, and any positivity, polynomial, similarity, or pseudospectrum diagnostic. A residual alone does not establish forward accuracy of every eigenvalue or vector component. ## Backward error versus forward error The eigen residual measures the equation defect and can support a backward-error interpretation after normalization. Forward eigenvalue error additionally depends on spectral separation and left/right eigenvector conditioning. For repeated or defective objects, the forward target is an invariant subspace or block relation. For a polynomial companion, coefficientwise backward error is a different perturbation model. The report keeps these meanings distinct. ## What arbitrary precision changes The source model is exact at the stated n and s. Arithmetic precision controls the dense products and eig call, while mathematical conditioning is reflected by the factorial norm products and grows with s. More bits reduce arithmetic error but do not make a sensitive eigenvalue insensitive. Input precision and work precision are recorded separately. Input/source precision is the precision and exactness of the stored model. Arithmetic/work precision is the MPFR/MPC precision selected for this operation. Mathematical conditioning is a property of the model. Raising mpbits addresses the second item only; it does not restore bits lost in a separately rounded input or alter a defective structure. Ambient-precision and restoration rows protect this distinction. ## Reading the output The integer-root bottleneck is a forward diagnostic; $r_{\mathrm{eig}}$ is an eigen-equation diagnostic. A small residual with a larger root error is consistent with a large $\kappa_k$. The Hadamard transform is an orthogonal similarity, not the two-sided equivalence used by SVD cases. A PASS line is scoped to the declared case gates and profile. Compare only rows with the same parameters and model hash. If a certificate field is absent, do not infer it from a small residual or a stable display. ## Common mistakes Do not replace $A$ with $T$, compute factorials in binary64, call $\kappa_k$ a measured error, or infer good eigenvectors from separated eigenvalues. Do not confuse eigenvalue similarity with singular-value mixing. For diagnosis, verify case ID and dimensions, then model hash and input precision, then residual, then the appropriate forward, cluster, or structural metric. Never change the fixture after observing a failure and report it as the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Siegfried M. Rump, Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix. SIAM Journal on Matrix Analysis and Applications 43(4) (2022), 1736–1754. DOI: 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — The all-spectrum and rigorous eigensystem context; these are independent dense controls. - [Nicholas J. Higham, Accuracy and Stability of Numerical Algorithms, 2nd ed. SIAM (2002). DOI: 10.1137/1.9780898718027](https://doi.org/10.1137/1.9780898718027) — The backward/forward-error framework and companion/nonnormal conditioning language used here. These references establish the external mathematical context. The selected dimensions, dyadic constants, runner, and acceptance thresholds are explicit project adaptations unless this page states otherwise. ## Project provenance - Runnable case: [had_bidiag.m](../../../../examples/tiered/neig-tier-a/had_bidiag.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - This page explains the named model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/examples/tiered/neig-tier-a/perron_pos.md0000644000230300031750000002367415274353473025113 0ustar rafaelrafael# Positive diagonally similar Perron matrix (Tier A6) ## Quick idea PERRON_POS is a Tier A control. Positivity is preserved while a nonunitary diagonal similarity creates a large coordinate dynamic range. It is small, deterministic, and intended to be read with its one-case Octave runner. Tier A identifies an advanced example; it does not claim that the public eig routine implements the cited paper's specialized algorithm. ## Mathematical problem Smoke: $n=8$, $\varepsilon=2^{-24}$, and scale $\alpha=3/2$. Demo: $n=16$, $\varepsilon=2^{-80}$, and $\alpha=3/2$. ```math \alpha=\frac{3}{2},\qquad D=\mathrm{diag}(1,2,\ldots,2^{n-1}),\qquad A=\alpha D P D^{-1}. ``` Here $P$ is the MARKOV model from the companion page. It satisfies $P\mathbf{1}=\mathbf{1}$, but its stationary row is $\pi^{\mathsf T}$, not the teleportation target $r^{\mathsf T}$. Therefore ```math v=D\mathbf{1},\qquad w=D^{-1}\pi,\qquad Av=\alpha v,\qquad w^{\mathsf T}A=\alpha w^{\mathsf T},\qquad \rho(A)=\alpha. ``` Both $v$ and $w$ are positive. The runner normalizes $v$ to have unit sum and then scales $w$ so that $w^{\mathsf T}v=1$. The vectors $r$ and $\pi$ are deliberately distinct objects: $r$ defines teleportation, while $\pi$ is the left stationary vector computed from the Markov equation. ## Concrete smoke matrix ```math A_{\mathrm{smoke}} = 2^{-39} \begin{bmatrix} 618475278336 & 103079215104 & 1536 & 384 & 96 & 24 & 6 & 3 \\ 49152 & 618475266048 & 103079212032 & 768 & 192 & 48 & 12 & 6 \\ 98304 & 24576 & 618475259904 & 103079210496 & 384 & 96 & 24 & 12 \\ 1649267539968 & 49152 & 12288 & 618475256832 & 768 & 192 & 48 & 24 \\ 393216 & 98304 & 24576 & 6144 & 721554464256 & 51539604864 & 96 & 48 \\ 786432 & 196608 & 49152 & 12288 & 3072 & 721554463488 & 51539604672 & 96 \\ 1572864 & 393216 & 98304 & 24576 & 6144 & 1536 & 721554463104 & 51539604672 \\ 3145728 & 786432 & 196608 & 49152 & 824633683968 & 3072 & 768 & 721554463104 \end{bmatrix}. ``` This is the full concrete smoke fixture for `PERRON_POS`. The matching [`perron_pos.m`](../../../../examples/tiered/neig-tier-a/perron_pos.m) selects the same manifest case and hands this input to the public `eig` path; the displayed matrix is not solver output. The entries are exact integers or dyadic rationals. If a common factor such as `2^{-q}` appears before the bracket, it multiplies every bracket entry and is part of the exact matrix, not a decimal approximation. Fixed-generation cases retain the declared generator precision in their model object; any separate exact widening and solver/work precision remain distinct recorded quantities. The smoke configuration is the small, inspectable documentation and CI instance. Its matching demo is a separate manifest row that may change the dimension, parameter, or profile; it is not substituted for this input when interpreting the measured result. This separation keeps the source matrix, source precision, and solver output auditable. ## Why this problem is numerically difficult Positivity is preserved while a nonunitary diagonal similarity creates a large coordinate dynamic range. A solver can satisfy a small residual with a poorly normalized vector, and checking only the right equation misses the nontrivial left vector. The scale 3/2 also distinguishes this matrix from the stochastic model. The exact model, any transformed control, and measured solver output remain separate. A related matrix with a convenient analytic answer is never silently substituted for the matrix named by the case ID. ## What the Octave example computes The matching [perron_pos.m](../../../../examples/tiered/neig-tier-a/perron_pos.m) selects only PERRON_POS from the fixed manifest and calls the public eig interface. The underlying model builds the MARKOV matrix $P$ and the similar matrix $A$ directly in MP, verifies the diagonal-similarity identity, and runs `eig` on $A$. The independent reference uses $v=D\mathbf{1}$ and $w=D^{-1}\pi$, where $\pi$ comes from the companion Markov stationary solve; it does not use $r$ as a surrogate. V-A3 checks the appropriate transpose/ adjoint orientation. The runner records the case ID, profile, dimensions, input identity, and operation precision, and keeps MP values until presentation. ## Construction and exactness The audit checks dyadic $D$ and $D^{-1}$ scaling, positivity, the transformed Perron equations, the stationary equation for $\pi$, and the normalization overlap. It never uses a measured vector to construct the reference. MP evaluation is retained because native normalization can obscure scale-separated components. Exactness means that declared integer/dyadic identities and their bit guards have been checked independently. Agreement between two MP runs is useful evidence but is not an exactness proof. ## Diagnostics For $A\in\mathbb{C}^{n\times n}$, right vectors $V$, output $D$, and left vectors $W$, use ```math r_{\mathrm{eig}} = \frac{\lVert A V - V D\rVert_F}{\lVert A\rVert_F\lVert V\rVert_F}, \qquad r_{\mathrm{left}} = \frac{\lVert A^{\mathsf H} W - W D^{\mathsf H}\rVert_F}{\lVert A\rVert_F\lVert W\rVert_F}. ``` For a selected cluster $J$, use the block residual $A V_J-V_JD_J$ and compare ranges or projectors; never turn a repeated or defective cluster into an individual-vector claim. Also inspect the case-specific forward reference, the normwise backward indicator, and any positivity, polynomial, similarity, or pseudospectrum diagnostic. A residual alone does not establish forward accuracy of every eigenvalue or vector component. ## Backward error versus forward error The eigen residual measures the equation defect and can support a backward-error interpretation after normalization. Forward eigenvalue error additionally depends on spectral separation and left/right eigenvector conditioning. For repeated or defective objects, the forward target is an invariant subspace or block relation. For a polynomial companion, coefficientwise backward error is a different perturbation model. The report keeps these meanings distinct. ## What arbitrary precision changes The source is exact dyadic apart from rational 3/2, with range set by D. Arithmetic precision controls dense construction and Perron verification. Mathematical conditioning comes from diagonal similarity and mixing; more bits preserve components but do not remove sensitivity. Input/source precision is the precision and exactness of the stored model. Arithmetic/work precision is the MPFR/MPC precision selected for this operation. Mathematical conditioning is a property of the model. Raising mpbits addresses the second item only; it does not restore bits lost in a separately rounded input or alter a defective structure. Ambient-precision and restoration rows protect this distinction. ## Reading the output Read root error, right residual, left residual, positivity margin, and contraction fields together. A positive matrix need not have a well-conditioned eigenvector pair in these coordinates. A small $r_{\mathrm{eig}}$ does not prove that the Perron vector has all correct digits. A PASS line is scoped to the declared case gates and profile. Compare only rows with the same parameters and model hash. If a certificate field is absent, do not infer it from a small residual or a stable display. ## Common mistakes Do not assume the left vector is uniform, drop D from the equations, claim A is stochastic, verify only the Perron root, or call positivity alone a certificate. For diagnosis, verify case ID and dimensions, then model hash and input precision, then residual, then the appropriate forward, cluster, or structural metric. Never change the fixture after observing a failure and report it as the original case. ## Scope of the claim This page is a worked mathematical explanation, not a promise about every matrix that happens to resemble this family. The named case ID fixes the construction, profile, precision roles, comparison convention, and status vocabulary. A reader who changes n, an exponent, an orientation, a phase, or a representation has created a new represented input and must record it as such. That discipline matters because a harmless-looking change can alter rank, multiplicity, cluster separation, exponent range, or the left/right conditioning. The dense output is always interpreted in the coordinates of the named model. Analytic roots, transformed controls, and exact identities are used as independent checks. They are not spliced into measured output, and a high-precision reference is not treated as a formal proof unless the page names the additional proof. For nonsymmetric problems, keep right and left equations distinct and use conjugation for complex data. The family runner supplies counted coverage; this page supplies the meaning of one row. ## References - [Shinya Miyajima, Fast verification for the Perron pair of an irreducible nonnegative matrix. Electronic Journal of Linear Algebra 37 (2021), 402–415. DOI: 10.13001/ela.2021.5181](https://doi.org/10.13001/ela.2021.5181) — The positive Perron root/vector target; the checker here is an independent conservative baseline. - [Siegfried M. Rump, Verified Error Bounds for All Eigenvalues and Eigenvectors of a Matrix. SIAM Journal on Matrix Analysis and Applications 43(4) (2022), 1736–1754. DOI: 10.1137/21M1451440](https://doi.org/10.1137/21M1451440) — The all-spectrum and rigorous eigensystem context; these are independent dense controls. These references establish the external mathematical context. The selected dimensions, dyadic constants, runner, and acceptance thresholds are explicit project adaptations unless this page states otherwise. ## Project provenance - Runnable case: [perron_pos.m](../../../../examples/tiered/neig-tier-a/perron_pos.m). - Case manifest: [NEIG cases.json](../../../../docs/codex/neigt/cases.json). - Verification scope: [NEIG verification-jobs.json](../../../../docs/codex/neigt/verification-jobs.json) and [CERTIFICATES.md](../../../../docs/codex/neigt/CERTIFICATES.md). - This page explains the named model; the family runner and milestone logs remain the measurement authority. mplapack-interop-0.5.1/docs/linear-solve.md0000644000230300031750000000425015274353473020117 0ustar rafaelrafael# Dense MPFR linear solve M09 adds dense real `mp` left division through the installed MPLAPACK MPFR `Rgesv` routine. M15 added full-rank rectangular systems through `Rgels`, and M16 upgrades the public rectangular path to the rank-revealing `Rgelss` driver. Square systems remain on `Rgesv`; rectangular systems now return the minimum-norm least-squares result, including rank-deficient cases. Complex, sparse, and reusable factorization interfaces remain outside the current milestones. ## Uniform precision boundary Public operands remain immutable and may have different precisions. The operation precision is the maximum precision of participating `mp` operands (or the precision of the sole `mp` operand with a builtin real double). Native operation-owned copies of `A` and `B` are promoted to that precision. The caller enters `MplapackMpfrPrecisionScope` at the same precision before calling `Rgesv`; mixed-precision MPLAPACK calls are never issued. `Rgesv` overwrites both arrays during LU factorization and solve, so public payloads are never passed to the backend. The returned operation-owned `B` buffer is the solution and a 1x1 result is normalized to the scalar payload. For a rectangular solve, `Rgelss` receives operation-owned `A` and a `max(m,n) x nrhs` padded RHS, plus `p_op`-precision `RCOND`, singular values, and workspace. Its query and solve run under the same uniform operation-precision scope, and the first `n` RHS rows form the public `n x nrhs` minimum-norm solution. The default rank threshold is `Rlamch_mpfr("E")` at `p_op`; rank deficiency is supported for rectangular matrices. The M15 `Rgels` bridge remains available for full-rank regression/reference tests. ## Status and empty systems `info == 0` returns the solution. Positive `info` is reported as a deterministic singular-matrix error; negative `info` is reported as an internal `Rgesv` argument error. A `0x0` coefficient matrix with a compatible empty right-hand side returns an empty result without calling `Rgesv`. Scalar left division uses native MPFR division/scaling rather than LAPACK. The current `mpbits()` setting is restored after every operation and does not select the precision of existing operands. mplapack-interop-0.5.1/docs/backend-map.md0000644000230300031750000001622415274353473017665 0ustar rafaelrafael# Public API backend map This map connects the user-facing Octave API to its native bridge and the tested numerical backend. It is a DOC00 handoff artifact and must be kept in step with [`docs/public-api-inventory.md`](public-api-inventory.md) and the compatibility documents. `p_op` means the single operation precision selected from the stored operands; all destructive backend calls use operation-owned copies. | Public API | Native entry | Real path | Complex path | Copy/precision rule | |---|---|---|---|---| | `mtimes` | `__mplapack_core__("mtimes",...)` | `Rgemm` | `Cgemm` | uniform `p_op`; backend buffers are owned by the operation | | `mldivide` | `__mplapack_core__("mldivide",...)` | `Rgesv`/`Rgelss` | `Cgesv`/`Cgelsy` | factorization input is copied at `p_op` | | `mrdivide` | `__mplapack_core__("mrdivide",...)` | transpose solve | conjugate-transpose solve | transpose/promote once at `p_op` | | `chol` | `__mplapack_core__("chol",...)` | `Rpotrf` | `Cpotrf` | selected triangle is copied before destructive call | | `qr` | `__mplapack_core__("qr",...)` | `Rgeqrf`/`Rorgqr` | `Cgeqrf`/`Cungqr` | reflector and workspace buffers own `p_op` | | pivoted `qr` | `__mplapack_core__("qr_pivoted",...)` | `Rgeqp3`/`Rorgqr` | `Cgeqp3`/`Cungqr` | permutation is a structural builtin output | | `lu` | `__mplapack_core__("lu",...)` | `Rgetrf` | `Cgetrf` | public input is never mutated; partial singular factors are preserved | | `norm` | `__mplapack_core__("norm",...)` | `Rlange`/`Rnrm2`/`Rgesvd` | `Clange`/`RCnrm2`/`Cgesvd` | singular-value-only calls use an owned copy | | `svd` | `__mplapack_core__("svd",...)` | `Rgesvd` | `Cgesvd` | `U,S,V` are returned as owned uniform-precision values | | `det`/`inv` | `__mplapack_core__("det",...)`, `("inv",...)` | `Rgetrf`/`Rgetri` | `Cgetrf`/`Cgetri` | factor and inverse buffers are operation-owned | | `rank` | `__mplapack_core__("rank",...)` | MPFR singular values | MPC singular values | stored-precision default tolerance | | `cond`/`rcond` | `__mplapack_core__("cond",...)` | singular values/`Rgecon` | singular values/`Cgecon` | estimates are native real MPFR results | | structured `eig` | `__mplapack_core__("eig",...)` | `Rsyevd` | `Cheevd` | exact represented symmetry/Hermiticity selects path | | general `eig` | `__mplapack_core__("eig",...)` | `Rgeevx` | `Cgeevx` | balance mode and left vectors are native | | generalized `eig` | `__mplapack_core__("geig",...)` | `Rsygvd`/`Rggev` | `Chegvd`/`Cggev` | definite or QZ path; alpha/beta retained | | `log2` | `__mplapack_core__("script_elementary",...)` | MPFR `log2` | gmpfrxx `mpfrxx::log2` over MPC | stored `p_op`; principal branch; no direct `mpc_log2` dependency | | `hess` | `__mplapack_core__("hess",...)` | `GEHRD`/`ORGHR` | `GEHRD`/`UNGHR` | Householder data and factors own `p_op` | | `schur` | `__mplapack_core__("schur",...)` | `GEES` | `GEES` | Schur vectors are non-unique; source is copied | | `qz` | `__mplapack_core__("qz",...)` | `GGES` | `GGES` | generalized factors use owned A/B buffers | | `expm`/`logm`/`sqrtm` | package matrix-function bridge | MPFR matrix algorithm | MPC matrix algorithm | guarded working precision is function-owned | | `polyval`/`polyvalm` | package polynomial helpers | MPFR Horner | MPC Horner | coefficients and argument select one `p_op` | | `roots`/`compan` | package polynomial bridge | native eig | native eig | clustered roots are sensitivity-limited | | `interp1`/`interp2` | `mp_interp_*` helpers | MPFR interpolation | MPC interpolation | grids, queries, and coefficients retain source precision | | `fzero`/`fsolve` | `mp_solver_*` helpers | MPFR safeguarded solver | deferred | callback values must be `mp`; tolerances are p-aware | | `integral`/`quadgk` | `mp_quad_*` helpers | MPFR tanh-sinh | MPC scalar callback | nodes, weights, and error estimates are `mp` | | `fminbnd`/`fminsearch` | `mp_opt_*` helpers | MPFR golden/Nelder--Mead | deferred | objective and stopping values are `mp` | | `mprand*`/`mprng` | `mp_rng_*` helpers | direct p-bit MPFR | not a complex API | state is explicit and serializable | | `saveobj`/`loadobj` | serialization bridge | MPFR text schema | MPC component text schema | stored precision, shape, and special values preserved | | graphics wrappers | `mp_graphics_args` | final `double` boundary | final `double` boundary | the only documented numerical conversion boundary | ## Value and lifetime invariants `mp` storage is a native RAII payload owned by the Octave value. Public values are not passed as writable LAPACK buffers. Each bridge establishes the matching current-thread MPFR/MPC context for the call, constructs operation temporaries at `p_op`, and restores that context on return or exception. New worker threads do not inherit a parent thread's precision automatically; worker entry must establish its own scope when a worker exists. ## Package-owned algorithms Polynomial, interpolation, solver, quadrature, optimization, statistics, sequence, and graphics-adaptation helpers are package-owned code. They must use MPFR/MPC values directly. The graphics helper is explicitly different: it converts only final display data to builtin `double`, after numerical calculation has completed. ## Difficult nonsymmetric eigensystem example boundary `examples/nonsymmetric_eig/` is a repository-local QA/example harness, not a new public package entry. It calls the existing general `eig` path in MPFR/MPC mode, compares both `balance` and `nobalance`, and reevaluates the actual returned eigentriples at a high MP precision. Its references and deterministic matching are described in `docs/nonsymmetric-eig-suite.md`; the optional plot is the only display-only `double` boundary. ## NEIGT example and certificate boundary The numbered NEIGT examples under `examples/14_neig_tier_s.m` through `examples/17_neig_verified_va.m` are repository-local QA surfaces. Their ordinary rows call the existing general `eig` path; the verification layer uses the existing MPFR/MPC `mp` arithmetic, `svd`, `qr`, and solve interfaces plus example-local outward interval/checker helpers. It does not introduce a new package-level backend or route real-only work through a complex kernel. The short one-case examples are listed in `docs/examples/tiered/README.md` and use the same `mp_neig_tiers`/`mp_svd_tiers` runners; they introduce no backend or installed API. | NEIGT surface | Existing public numerical source | Certificate boundary | |---|---|---| | Tier-S/Tier-A ordinary rows | `mp_neig_tiers` -> `eig` | exact model/frozen input/work precision and native control are recorded separately | | V-S1 all-spectrum | `eig` candidate, MPFR/MPC residual and inverse checks | counted disks/singletons require the recorded similarity and nonsingularity proof | | V-S2/V-S3 | `qr`, solves, `svd`, MPFR/MPC outward primitives | invariant graph/projector and polar/Weyl point/cell bounds are finite-matrix proofs | | V-A1/V-A2 | `qr`, solves, and explicit finite-pencil reduction | compatible factors, Schur/block-Schur, and proved `B` inverse enclosure | | V-A3 | MPFR/MPC arithmetic and solve | Collatz--Wielandt plus positive normalized left/right pair existence | | exact output/replay | MP text serialization | content hash binds inputs, methods, targets, and proof fields; replay does not call `eig` | mplapack-interop-0.5.1/docs/random.md0000644000230300031750000000075515274353473017005 0ustar rafaelrafael# Arbitrary-precision random generation The closed random-generation API is documented in [`rng.md`](rng.md): `mprand`, `mprandn`, `mprandi`, and `mprng`. It uses the fixed native `xorshift128plus-v1` engine, exact MPFR generation, and a versioned state schema. It is separate from Octave's builtin `rand` and `randn` state. The implementation is deterministic for a fixed state and precision, but it is not a cryptographic source. No random numerical path uses builtin binary64 generation. mplapack-interop-0.5.1/docs/cholesky.md0000644000230300031750000000305615274353473017343 0ustar rafaelrafael# Dense `mp` Cholesky factorization M17 provides dense real Cholesky factorization through the MPLAPACK MPFR `Rpotrf` routine: ```octave R = chol (A); R = chol (A, "upper"); L = chol (A, "lower"); [R, p] = chol (A); [L, p] = chol (A, "lower"); ``` The default is `"upper"`. Dense `chol` uses only the selected triangle of the input; the ignored triangle is not checked for symmetry. Thus the upper form satisfies `R.' * R` for the symmetric matrix described by the upper triangle, and the lower form satisfies `L * L.'` for the matrix described by the lower triangle. `Rpotrf` overwrites its input, so the native bridge factors an operation-owned deep copy. Public `mp` values remain immutable and the returned factor owns independent storage. A successful factor has the stored precision of `A`; the current `mpbits()` setting is only a construction default and is irrelevant to an existing factorization. The bridge enters the MPLAPACK uniform-precision scope at that source precision and restores the prior thread default on every exit path. With one output, a non-positive-definite input raises an Octave-facing error. With two outputs, the factor/status form returns the positive failure index in `p` and the partial factor shape/content observed from dense Octave. A successful call returns `p == 0`. The status is a builtin numeric scalar, not an `mp` value. M17 is real dense only. Sparse and complex Cholesky, the dense three-output permutation form, `cholupdate`-family operations, `cholinv`, and automatic SPD optimization of `mldivide` remain future work. mplapack-interop-0.5.1/docs/special-functions-backend-matrix.md0000644000230300031750000001347515274353473024045 0ustar rafaelrafael# Special-function backend matrix This audit records the special-function boundary for the T-series. The authoritative numerical backend is the frozen gmpfrxx_mkII 1.4.1 tree at `32a7fb797202cdf92312ed9d133f96fdbcda590a` (`v1.4.1`). A backend primitive is not by itself a public `@mp` implementation: Octave's argument order, normalization, tails, output count, domain behavior, and complex policy must also be specified and tested before a wrapper is added. | Family | Octave-facing API | gmpfrxx / MPFR evidence | Classification | T-series decision and TODO | |---|---|---|---|---| | Gamma | `gamma`, `gammaln`, `lgamma` | `gamma`, `lngamma`, `lgamma` | DIRECT-BACKEND | Implemented in T05 through the native precision-scoped bridge. | | Error function | `erf`, `erfc` | `erf`, `erfc` | DIRECT-BACKEND | Implemented in T05; complex inputs remain explicitly rejected. | | Digamma | `psi` | `digamma` | DIRECT-BACKEND | Primitive is available, but Octave's `psi` signature and floating-point input contract require a separate public mapping. See [`TODO-T06-PSI`](todo/T06-special-functions.md#psi--todo-t06-psi). | | Polygamma | `polygamma` (where available) | No MPFR/gmpfrxx primitive | DEFERRED-BACKEND | No package wrapper and no binary64 fallback. See [`TODO-T06-POLYGAMMA`](todo/T06-special-functions.md#polygamma--todo-t06-polygamma). | | Beta | `beta` | `beta` wrapping `mpfr_beta` | DIRECT-BACKEND | Primitive is available; public domain and pole semantics are not yet frozen. See [`TODO-T06-BETA`](todo/T06-special-functions.md#beta--todo-t06-beta). | | Log beta | `betaln` | No direct wrapper; can be formed from log-gamma | IMPLEMENTABLE-IN-PACKAGE | Feasible using precision-matched log-gamma identities, but requires a dedicated cancellation/domain test. See [`TODO-T06-BETALN`](todo/T06-special-functions.md#betaln--todo-t06-betaln). | | Incomplete gamma | `gammainc` | `gamma_inc` wrapping `mpfr_gamma_inc` | DIRECT-BACKEND | The primitive is not an automatic implementation: Octave's normalized lower/upper definitions and `tail` behavior must be matched exactly. See [`TODO-T06-GAMMAINC`](todo/T06-special-functions.md#gammainc--todo-t06-gammainc). | | Incomplete beta | `betainc` | No MPFR/gmpfrxx primitive | DEFERRED-BACKEND | Do not substitute complete beta or a double implementation. See [`TODO-T06-BETAINC`](todo/T06-special-functions.md#betainc--todo-t06-betainc). | | Inverse error family | `erfinv`, `erfcinv` | No direct MPFR/gmpfrxx wrapper | IMPLEMENTABLE-IN-PACKAGE | A published arbitrary-precision inverse-error algorithm could be added, with endpoint and signed-domain tests. See [`TODO-T06-INV-ERF`](todo/T06-special-functions.md#erfinverfcinv--todo-t06-inv-erf). | | Scaled error family | `erfcx` and related scaled variants | No direct MPFR/gmpfrxx wrapper | DEFERRED-BACKEND | Requires a region-partitioned arbitrary-precision algorithm; no fallback is permitted. See [`TODO-T06-ERFCX`](todo/T06-special-functions.md#erfcx--todo-t06-erfcx). | | Exponential integral | `expint` | `eint` | DIRECT-BACKEND | MPFR's `eint` primitive is present, but Octave's `expint` argument and branch/domain semantics need a separate mapping. See [`TODO-T06-EXPINT`](todo/T06-special-functions.md#expint--todo-t06-expint). | | Zeta | no standard Octave `@mp` mapping in this package | `zeta`, plus `zeta_ui` | DIRECT-BACKEND | Backend capability recorded; no public wrapper is added until an Octave API and domain contract exists. See [`TODO-T06-ZETA`](todo/T06-special-functions.md#zeta--todo-t06-zeta). | | Bessel J | `besselj` | `j0`, `j1` only | DIRECT-BACKEND (partial) | Only orders 0 and 1 exist in the backend surface; general order mapping is deferred. See [`TODO-T06-BESSEL-J`](todo/T06-special-functions.md#bessel-jy--todo-t06-bessel-j-todo-t06-bessel-y). | | Bessel Y | `bessely` | `y0`, `y1` only | DIRECT-BACKEND (partial) | Only orders 0 and 1 exist in the backend surface; general order mapping is deferred. See [`TODO-T06-BESSEL-Y`](todo/T06-special-functions.md#bessel-jy--todo-t06-bessel-j-todo-t06-bessel-y). | | Bessel I | `besseli` | No direct wrapper | DEFERRED-BACKEND | No arbitrary-precision backend primitive is available in the frozen dependency. See [`TODO-T06-BESSEL-I`](todo/T06-special-functions.md#bessel-ik--todo-t06-bessel-i-todo-t06-bessel-k). | | Bessel K | `besselk` | No direct wrapper | DEFERRED-BACKEND | No arbitrary-precision backend primitive is available in the frozen dependency. See [`TODO-T06-BESSEL-K`](todo/T06-special-functions.md#bessel-ik--todo-t06-bessel-i-todo-t06-bessel-k). | | Hankel | `besselh` | No direct wrapper | DEFERRED-BACKEND | Requires both a general J/Y implementation and a complex branch-cut contract. See [`TODO-T06-HANKEL`](todo/T06-special-functions.md#hankel--todo-t06-hankel). | | Airy | `airy` | `ai` only | DIRECT-BACKEND (partial) | The backend exposes Ai only, while Octave's API includes multiple outputs and Bi. No partial public wrapper is added. See [`TODO-T06-AIRY`](todo/T06-special-functions.md#airy--todo-t06-airy). | ## Closed boundary The package currently exposes only the T05 gamma/error-function family from this matrix. Calls to deferred or not-yet-mapped special-function APIs with `mp` operands are rejected by the compatibility firewall; they do not pass through Octave's binary64 implementation. T06 therefore closes the audit and does not add numerical production code. The direct-backend entries are capability findings, not release claims. Each TODO names the semantic audit required before exposing that family through the package. In particular, `gamma_inc` is not treated as an implementation of Octave `gammainc` merely because their names are similar. ## Provenance The direct-wrapper inventory was audited in: ```text /home/docker/work/gmpfrxx_mkII/include/gmpfrxx_mkII/detail/mpfr_impl.hpp ``` No raw MPFR call, builtin binary64 fallback, or change to the frozen gmpfrxx_mkII dependency was made for T06. mplapack-interop-0.5.1/docs/native-value-design.md0000644000230300031750000002214315274353473021367 0ustar rafaelrafael# Native value design ## Purpose M02 establishes an internal GNU Octave value that owns one MPLAPACK MPFR scalar. It is lifecycle infrastructure for later milestones, not the public `mp` class. No constructor, conversion, display, indexing, matrix, or arithmetic API is provided here. ## Octave 11.1 API audit The target API was inspected in the headers installed with GNU Octave 11.1.0 under `/usr/include/octave-11.1.0/octave`. The extension include directory was obtained from both `mkoctfile -p OCTINCLUDEDIR` and `octave-config -p OCTINCLUDEDIR`; the reported API directory is `api-v61`. The selected base class is `octave_base_dld_value`, the installed DLD-aware subclass of `octave_base_value`. It owns an `octave::auto_shlib` reference to the containing dynamic library and schedules library release safely from its destructor. The internal value overrides `clone()`, `empty_clone()`, `dims()`, `is_defined()`, and the minimum scalar introspection needed by M02. Numeric conversion and operator hooks are not overridden. The installed `DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA` and `DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA` macros provide a distinct type ID, type name, class name, and registration function. An instance is placed in an `octave_value` with the public `octave_value(octave_base_value *)` constructor. The checked recovery path first compares `octave_value::type_id()` with the registered static ID and then uses `dynamic_cast` on `octave_value::internal_rep()`. `octave_value` owns the representation through Octave's built-in reference count. Normal assignment therefore shares an immutable representation, while `clone()` constructs an independent representation and storage payload. The dynamic function uses `DEFMETHOD_DLD` to receive an `octave::interpreter&`. Octave 11.1 exposes the executing function through `tree_evaluator::current_function()`. The implementation verifies that this object is a DLD function and calls `octave_function::lock()` on that exact object, avoiding a second name-based symbol-table lookup. Type registration is performed once before an internal value can be constructed, while the lock is reasserted on each module entry after a package reload. Installed headers used by the implementation are: - `defun-dld.h` - `interpreter.h` - `auto-shlib.h` - `oct-shlib.h` - `ov.h` - `ov-base.h` - `ov-fcn.h` - `ov-typeinfo.h` - `pt-eval.h` These are installed oct-file development headers, and no Octave source or private header is copied into the package. The important compatibility risk is that the installed registration macro calls `octave::__get_type_info__()`, whose header comment describes it as an internal interface that remains available for user-defined `octave_value` objects. Evaluator current-function lookup and direct function locking are also compatibility-sensitive. The subclass and registration code is therefore isolated in `mp_value.*` and the bridge initialization code, targeting Octave 11.1 specifically. ## Selected native base class The internal value derives from `octave_base_dld_value`. It represents exactly one scalar and reports dimensions `1 x 1`. It does not derive from a built-in numeric container and does not advertise implicit numeric conversions. The DLD-aware base is essential: every native representation holds a reference to its containing shared library. ## Type registration The registered type name is `mplapack_mpfr_scalar_internal`, deliberately not `mp`. Registration uses Octave's installed type-ID macros and is guarded by a C++ `std::once_flag` so repeated calls cannot allocate new type identities. ## Scalar storage representation MPLAPACK's installed `mplapack_mpfr.h` declares real routines in terms of `mpfrxx::mpfr_class`, and `mplapack_arithmetic_params_mpfr.h` defines `REAL` as the same type. The project-owned scalar storage class therefore contains one `mpfrxx::mpfr_class` initialized at an explicit MPFR precision. M03 sets decimal text with `mpfr_set_str` and binary64 input with `mpfr_set_d`, both using explicit `MPFR_RNDN` rounding. The wrapper is kept free of Octave headers. This lets ownership and container behavior be tested independently under sanitizers and keeps the Octave ABI boundary localized. ## RAII ownership `mpfrxx::mpfr_class` initializes its `mpfr_t` with `mpfr_init2`, clears it in its destructor, and uses an initialization guard on throwing constructors. The project wrapper preserves those RAII guarantees. It does not expose a raw pointer or use an external object registry. ## Copy and clone semantics Copy construction creates an independent MPFR value with the source object's precision. Project-level copy assignment uses copy-and-swap so it also adopts the source precision; the underlying wrapper's ordinary assignment would otherwise retain the destination precision. Move construction and assignment transfer ownership safely. Octave `clone()` deep-copies the project storage. ## Immutability Native payloads are immutable at the Octave boundary. Assignment may safely share Octave's representation, and operations in future milestones must produce new values. Destructive LAPACK calls must operate on operation-owned input copies or result storage rather than mutate shared public values. ## Precision ownership Every constructed M02 scalar receives an explicit precision in bits, validated against `MPFR_PREC_MIN` and `MPFR_PREC_MAX`. The effective precision is read from the stored MPFR value. M02 introduces no public or process-global default precision. ## Module lifetime and locking The type's vtable, destructor, clone implementation, and registered metadata reside in `__mplapack_core__.oct`. Unloading that module while values or the type registry remain alive would be unsafe. Each representation therefore inherits `octave_base_dld_value`, whose `octave::auto_shlib` member retains the containing DSO and whose destructor calls `delete_later()`. The registration prototype also uses this base and remains in Octave's type registry, so type metadata cannot outlive the module. Initialization additionally locks the executing DLD function object. The internal `module_test_locked` QA command reports that exact object's `islocked()` state. Ordinary `clear __mplapack_core__` leaves the DSO resident, the value queryable, and destruction safe even if a name-based lookup no longer shows the function lock. Octave 11.1's name-based `mislocked("__mplapack_core__")` is true for the direct source module but can return false after an architecture-specific installed package function has been resolved more than once, even while the executing DLD object's `islocked()` is true. Installed-package QA therefore uses the exact function-object state rather than treating the cache-sensitive name lookup as authoritative. Octave 11.1 `pkg unload mplapack-interop` forcibly removes package function names and the visible lock flag, but the DLD-aware native values and registration prototype retain the module. In an isolated subprocess with a native value alive, the value retained its type identity, its virtual print method executed, its destructor ran safely, and the process exited zero after package unload. A subsequent `pkg load` resolves the same registered type and reasserts the function lock. Thus package unload removes access to the private command until reload, but does not invalidate live registered values. M02 never calls `munlock`. ## Error handling The bridge validates command arity, string arguments, integral precision, and internal type identity before access. Storage and clone exceptions are translated to Octave errors at the extension boundary. Failed parsing initializes temporary native storage and remains RAII-safe. ## MPLAPACK type compatibility The stored native scalar is the same `mpfrxx::mpfr_class` type accepted by the MPLAPACK MPFR interface, so later numerical code will not require a scalar format conversion. M02 does not invoke arithmetic with stored values. ## Matrix-storage implications The selected native type is moveable, copyable, and safe in contiguous C++ containers. Its installed implementation asserts the same size and alignment as `mpfr_t` for dense-array stride. M07 still owns the matrix representation; it will need column-major contiguous native scalar storage, leading dimensions, and efficient MPLAPACK pointer access. M02 does not choose or implement that container. ## Octave compatibility boundary Only the Octave-facing value and registration files depend on custom-value APIs. The pure scalar storage does not include Octave headers. The type-ID macros, `internal_rep()` checked access, `DEFMETHOD_DLD`, evaluator current- function lookup, and function locking are the compatibility-sensitive APIs to re-audit before supporting an Octave release other than 11.1. ## Known limitations - M03 wraps one native scalar in a private classdef property; this document continues to describe the underlying M02 value mechanics. - User-visible conversion and display are not implemented. - Matrix storage, indexing, arithmetic, and operator registration are not implemented. - `pkg unload` removes package function names until the package is loaded again; safe destruction of already-created native values is supported. mplapack-interop-0.5.1/docs/interpolation-2d.md0000644000230300031750000000176615274353473020722 0ustar rafaelrafael# Two-dimensional interpolation `interp2` supports the 2-D MP grid boundary for vector grids, mesh-style matrix grids, MP query points, real or complex data, and `nearest`, `linear`, `pchip`, and `spline` methods. The three-argument `interp2(z,xi,yi)` form uses exact MP integer coordinates. Numeric inputs are promoted to MP at the selected precision; MP coordinates and queries never pass through binary64. The data matrix has rows corresponding to the y axis and columns corresponding to the x axis. Descending axes are normalized together with the data matrix, and repeated grid coordinates are rejected. Linear interpolation uses an MP bilinear formula. The pchip and spline modes apply the T10 scalar PP engine first along x for each row and then along y, preserving complex values through MPC operations. Default out-of-range results are MP NaNs. A numeric extrapolation value or the `"extrap"` option is accepted; with `"extrap"`, the selected interpolation formula is evaluated outside the grid. mplapack-interop-0.5.1/docs/doxygen/0000755000230300031750000000000015274353473016651 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/doxygen/native-contracts.dox0000644000230300031750000000120615274353473022650 0ustar rafaelrafael/** * \file native-contracts.dox * \brief Cross-cutting native implementation contracts. * * The core headers are included in the generated reference with their * classes and functions. This page records invariants that span several * files: explicit precision, RAII lifetime, operation-owned destructive-call * buffers, MPLAPACK scope restoration, and the real/complex boundary. * The nonsymmetric eigensystem example also documents the left-vector * convention W'*A = D*W', actual-output high-precision reevaluation, and * deterministic one-to-one eigenvalue matching without assuming LAPACK * ordering or vector normalization. */ mplapack-interop-0.5.1/docs/doxygen/Doxyfile0000644000230300031750000000214215274353473020356 0ustar rafaelrafaelPROJECT_NAME = "mplapack-interop" PROJECT_NUMBER = "0.5.1" OUTPUT_DIRECTORY = docs/.build/doxygen CREATE_SUBDIRS = NO INPUT = src docs/doxygen FILE_PATTERNS = *.h *.cc *.dox RECURSIVE = NO EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = YES SOURCE_BROWSER = YES INLINE_SOURCES = NO REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES GENERATE_HTML = YES HTML_OUTPUT = html GENERATE_LATEX = NO GENERATE_XML = NO GENERATE_MAN = NO GENERATE_RTF = NO GENERATE_TREEVIEW = YES FULL_PATH_NAMES = NO STRIP_FROM_PATH = src WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES QUIET = YES JAVADOC_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = YES CLANG_ASSISTED_PARSING = NO PREDEFINED = OCTAVE_API HAVE_DOT = NO CLASS_GRAPH = NO COLLABORATION_GRAPH = NO INCLUDE_GRAPH = NO INCLUDED_BY_GRAPH = NO CALL_GRAPH = NO CALLER_GRAPH = NO mplapack-interop-0.5.1/docs/doxygen/mainpage.dox0000644000230300031750000000775115274353473021160 0ustar rafaelrafael/** * \mainpage mplapack-interop developer reference * * \section architecture Architecture * * The public GNU Octave layer is in inst/ and the mp method directory. It implements the * normal Octave syntax and owns compatibility boundaries. The native bridge * is in src/octave_bridge.cc and dispatches to storage, precision, arithmetic, * MPLAPACK, serialization, RNG, interpolation, solver, quadrature, * optimization, and graphics helpers. * * \section storage Storage and value semantics * * An mp value contains one native RAII payload: MPFR for real data or MPC for * complex data, together with shape and stored precision. Public values are * immutable. Dense matrices are contiguous column-major storage and are not * arrays of scalar wrapper objects. Native code must copy a public value * before a destructive LAPACK call. * * \section precision Precision policy * * There is one project-owned process-local default used for newly constructed * values. Existing values retain their stored precision when mpbits changes. * An operation selects one p_op from its operands, enters the corresponding * MPFR/MPC execution scope, normalizes temporaries to p_op, and restores the * caller's backend context on all exits. A new worker thread does not inherit * a parent thread's precision automatically; worker entry must establish its * own scope. * * \section backends MPLAPACK and MPFR/MPC * * Dense BLAS/LAPACK operations dispatch to the reference MPLAPACK MPFR/MPC * backend through pkg-config. Real-only operations remain on real R* paths. * Complex operations promote once to MPC at p_op. No supported numerical * path is allowed to use an implicit builtin binary64 fallback. The only * ordinary double boundary is final data conversion for graphics. * * \section ownership Ownership and errors * * Helpers return operation-owned values or copies. Octave callbacks are * checked at their boundary; nonlinear, quadrature, and optimization * callbacks must return mp values. Serialization records a versioned text * schema rather than native addresses or MPFR limb bytes. * * \section tests Tests * * Focused tests live under test/ and are grouped by M, C, N, S, and T * milestones. The documentation example runner executes the files under * examples/; * test/t00_schur_qz.tst contains the Grcar and QZ reconstruction contract. * See docs/backend-map.md and docs/public-api-inventory.md for the public * entry-to-backend map. * * \section neig Difficult nonsymmetric eigensystem example * * examples/13_nonsymmetric_eig_suite.m and the helpers under * examples/nonsymmetric_eig/ form a repository-local QA harness on top of * the existing public mp/eig API. It constructs exact or independently * referenced nonnormal matrices, runs balance and nobalance, and measures * the returned right and left relations at high MP precision. The harness * preserves stored precision and ambient-default restoration; its native * double rows are explicit rounded-input controls. Result serialization * retains MP text, while the optional PNG is a display-only boundary. * * \section neigt_tiers NEIGT verified tiers * * The numbered examples examples/14_neig_tier_s.m through * examples/17_neig_verified_va.m form the manifest-driven NEIGT Tier-S, * Tier-A, V-S, and V-A QA surface. They use the existing public mp/eig/svd/ * qr/solve interfaces and example-local audited outward checkers; they do not * add an installed numerical API. Generation precision, frozen inputs, * candidates, and certificates are separate records. V proofs require their * explicit preconditions, count all roots, preserve nontrivial defective * clusters/block Schur claims, and never use residuals or precision agreement * as a substitute for an enclosure. Exact proof bundles are written by * mp_neig_write_outputs and replayed by mp_neig_replay without calling eig or * reconstructing an ideal matrix. All MP arithmetic follows the operation * precision and no implicit binary64 fallback is permitted. */ mplapack-interop-0.5.1/docs/dense-matrix-design.md0000644000230300031750000002254315274353473021373 0ustar rafaelrafael# Native dense matrix design ## Scope M07 introduced storage and public construction for real, two-dimensional MPFR matrices. M10 adds read-only indexing, matrix `double`, and matrix display formatting without changing the storage representation. M11 extends the same storage with direct MPFR element-wise arithmetic and two-dimensional singleton expansion; M12 adds precision-preserving transpose and reshape; M13 adds native horizontal and vertical concatenation. Ownership and layout remain unchanged. ## Installed MPLAPACK ABI audit The authoritative installed MPLAPACK 3.0.1 headers are `mpblas_mpfr.h`, `mplapack_mpfr.h`, and `mplapack_config.h`, discovered through `pkg-config mplapack_mpfr`. Their public declarations establish: - MPFR real dense elements are `mpfr_class`, which is `mpfrxx::mpfr_class`; - `Rgemm` accepts its dense arrays as `mpfr_class *` and dimensions and leading dimensions as `mplapackint`; - `Rgesv` accepts its coefficient and right-hand-side arrays as `mpfr_class *`, pivots as `mplapackint *`, and dimensions as `mplapackint`; and - this installation defines `mplapackint` as `int64_t`. M07 verifies these types at compile time. It does not call either routine. ## Public representation One public classdef `mp` object owns one private native payload. A public dense matrix is never an Octave object array, a cell array of scalar wrappers, or a vector of `octave_value` objects. ## Internal native type The private matrix payload has the registered name `mplapack_mpfr_matrix_internal`. It follows the same DLD-aware Octave 11.1 registration and module-retention design as the scalar payload. The normal public class remains exactly `mp`. ## Scalar vs matrix payload All public `1 x 1` values use the established scalar payload. The matrix payload represents every supported shape whose element count is not one, including empty shapes. This gives public scalars one canonical native representation. ## Canonical 1x1 representation Scalar double, scalar text, a `1 x 1` double array, and a `1 x 1` text cell all normalize to `mplapack_mpfr_scalar_internal`. A matrix payload is never used merely because the constructor input was a container. ## Matrix precision One matrix has one immutable bit precision. Every native element is created explicitly with that precision; MPFR's mutable global default is not used. Changing the project default affects only later construction. ## Element scalar type `MpfrMatrixStorage::NativeScalar` is `mpfrxx::mpfr_class`, exactly the scalar type in the installed MPLAPACK MPFR dense-array declarations. ## Column-major storage Storage is column-major. Zero-based `(row, column)` maps to `row + column * leading_dimension`. A logical matrix ```text [11 12 13 21 22 23] ``` therefore has native order `11, 21, 12, 22, 13, 23`. ## Leading dimension For a positive row count the leading dimension equals the row count. For a zero-row matrix it is one, satisfying the Fortran BLAS/LAPACK minimum without requiring storage for an empty matrix. ## Dimension types Octave dimensions enter the bridge as `octave_idx_type`, allocations use `std::size_t`, and MPLAPACK calls use `mplapackint`. Each boundary is checked. Element-count multiplication is checked before allocation. ## Contiguous buffer The project-owned `MpfrMatrixStorage` owns a `std::vector`. The vector is reserved and populated once with explicit-precision elements. Its `data()` type is directly compatible with the installed MPLAPACK `mpfr_class *` interface; packing and `reinterpret_cast` are unnecessary. ## Construction from double matrices Every real binary64 input is transferred directly with `mpfr_set_d` and `MPFR_RNDN` at the matrix precision. Decimal formatting is not involved. ## Construction from decimal text cells Every text cell is parsed directly with `mpfr_set_str`, base ten, and `MPFR_RNDN` at the matrix precision. Construction is transactional through RAII: invalid text cannot publish a partially built payload. ## Empty matrices `0 x 0`, `0 x N`, and `N x 0` shapes retain their dimensions, precision, and leading-dimension metadata. Their element vector is empty and is never dereferenced. ## Copy and move semantics Native copy construction deep-copies the contiguous vector. Move operations transfer ownership without copying MPFR limbs. Standalone sanitizer tests prove independent buffers and safe copy, move, and destruction. ## Deep-copy work buffers The pure storage class supplies mutable access only to native operation-owned code. A deep copy may be changed by a future destructive LAPACK call without changing the immutable public input. No mutable pointer is exposed to Octave. ## Immutability Public matrix shape, precision, and elements are immutable. Public indexing and indexed assignment are rejected in M07. ## Module lifetime The matrix native value derives from the same DLD-aware base used by the scalar native value. Both types register once, and the DLD function lock is reasserted whenever the module entry point loads. Live values therefore keep their vtables, destructors, and type metadata resident across ordinary clear and package unload/reload behavior. ## Indexing boundary `size`, `rows`, `columns`, `numel`, `ndims`, and `isempty` query native shape. M10 parenthesis indexing copies selected native values directly, preserves source precision, and normalizes `1x1` selections to scalar storage. Brace indexing and indexed assignment fail explicitly; they must not treat the one-wrapper representation as an Octave object array. ## M10 inspection Read-only `A(i,j)`, `A(:,j)`, `A(i,:)`, `A(I,J)`, `A(k)`, `A(:)`, and `end` forms use checked indices and deep-copy slices. `double(A)` uses direct MPFR-to-binary64 conversion with `MPFR_RNDN`, while `disp(A)` reuses the canonical scalar formatter for every entry. Neither operation consults or mutates the current precision default. Matrix `char` remains deferred. ## M08 Rgemm implementation The dense buffer is uniform-precision, contiguous, column-major, and directly typed as the installed `Rgemm` array argument. Dimensions and leading dimensions have checked `mplapackint` conversions. M08 allocates operation-owned promoted buffers and passes them without packing. The operation precision is the maximum precision of the participating `mp` operands, and `MplapackMpfrPrecisionScope` establishes that precision on the calling thread for the duration of the reference MPFR `Rgemm` call. A strict native checker rejects any mismatch before entering MPLAPACK. Scalar and real-double scaling use direct MPFR operations. M11 element-wise arithmetic likewise operates directly on MPFR values in destination storage; it does not call MPLAPACK and does not use the current default precision. ## M09 Rgesv implementation Deep copies provide operation-owned mutable coefficient and right-hand-side buffers. Native mutation of such work copies leaves public immutable inputs unchanged. M09 uses the same checked dimensions, column-major layout, and leading dimensions for `Rgesv`; square solves return the operation-owned solution buffer and preserve public input values. ## M12 structural operations Transpose and reshape allocate independent `MpfrMatrixStorage` at the source matrix precision and copy native MPFR values directly. Transpose swaps the two-dimensional coordinates; reshape preserves the contiguous column-major linear order. Scalar results remain the canonical scalar payload, while all other shapes—including empty matrices—remain matrix payloads. These operations do not use MPLAPACK or change the current precision default. ## M13 concatenation M13 assembles arbitrary-arity horizontal and vertical concatenations directly into one new `MpfrMatrixStorage`. The complete argument list is validated with Octave's two-dimensional `hvcat` shape rules before allocation. Scalars are `1x1`; no singleton broadcasting is performed. Empty matrices retain their shape semantics and empty `mp` operands still contribute their explicit precision to `p_cat`, the maximum participating `mp` precision. MPFR values are copied exactly into uniformly `p_cat`-precision storage, while real double elements are transferred directly from binary64 with `mpfr_set_d`. The operation is structural: it does not call MPLAPACK, enter a precision scope, or read or mutate either precision default. Inputs remain immutable and the result owns independent storage. Public bracket syntax therefore returns one `mp` value rather than an array of scalar wrapper objects. ## M14 indexed assignment M14 keeps public matrix values immutable while adding limited in-bounds parenthesis assignment. `subsasgn` validates indices and RHS shape, determines `p_assign`, deep-copies the entire lhs into uniformly `p_assign` storage, and updates only the selected positions. An aliased lhs and an RHS derived from that lhs therefore remain safe. Matrix growth and deletion remain rejected; logical assignment and general vector linear assignment are implemented by S03 through native index lists. ## Non-goals Matrix `char` remains deferred. S03 adds logical indexing, general vector linear indexing, and comparisons/logicals. Powers, reductions, and complex storage remain deferred in this historical M14 section. M08 adds `mtimes`/`Rgemm`, M09 adds square `mldivide`/`Rgesv`, M10 adds read-only matrix inspection, M12 adds transpose and reshape, M13 adds horizontal/vertical concatenation, and M14 adds value-semantic indexed assignment. mplapack-interop-0.5.1/docs/pivoted-qr.md0000644000230300031750000000251715274353473017615 0ustar rafaelrafael# Dense real `mp` pivoted QR M19 adds dense real column-pivoted QR through the installed MPLAPACK MPFR `Rgeqp3` and `Rorgqr` routines. The existing one- and two-output M18 forms remain non-pivoted; a permutation output requests pivoting: ```octave [Q, R, P] = qr (A); [Q, R, P] = qr (A, "matrix"); [Q, R, p] = qr (A, "vector"); [Q, R, P] = qr (A, "econ"); [Q, R, p] = qr (A, 0); % deprecated compatibility form ``` `Q` and `R` are immutable `mp` values. `P` is a builtin double permutation matrix and `p` is a builtin double, one-based row vector. Their defining relationships are: ```text Q * R = A * P Q * R = A(:,p) ``` For an `m`-by-`n` input, `P` is `n`-by-`n`. Full QR has `Q` `m`-by-`m` and `R` `m`-by-`n`; economy QR uses `Q` `m`-by-`n` and `R` `n`-by-`n` when `m>n`, and the same shapes as full QR when `m<=n`. The permutation is produced by MPLAPACK's `Rgeqp3`; fixed-column JPVT control, `qr(A,B)`, sparse, complex, N-D, and QR update operations are not implemented. Pivoted operations use the stored precision of `A`, with all operation-owned MPFR arrays and the `Rorgqr` call inside the corresponding precision scope. The current `mpbits()` value does not affect an existing matrix or its pivot selection. `Rgeqrf` remains the backend for non-pivoted one- and two-output QR, and one-output `qr(A)` returns `R` without generating `Q`. mplapack-interop-0.5.1/docs/nonsymmetric-eig-suite.md0000644000230300031750000001135615274353473022144 0ustar rafaelrafael# Difficult nonsymmetric eigensystem suite The repository includes a reproducible experiment suite for dense general eigenproblems. It is an example and QA harness built on the existing public `mp`, `mpbits`, `eig`, `norm`, `real`, `imag`, `conj`, and `char` interfaces; it does not add a package-level numerical API. Run the compact smoke wall from a checkout with the installed MPLAPACK stack: ```sh PKG_CONFIG_PATH=/home/docker/opt/octave-mplapack-stack/lib/pkgconfig \ LD_LIBRARY_PATH=/home/docker/opt/octave-mplapack-stack/lib \ CPATH=/home/docker/opt/octave-mplapack-stack/include \ tools/run-nonsymmetric-eig-suite.sh smoke ``` Use `demo` for the 40-row wall, or pass a second argument to write a new result bundle: ```sh tools/run-nonsymmetric-eig-suite.sh demo /path/to/new-results ``` An output directory must be empty. The writer refuses to overwrite an existing result file. It creates `summary.tsv`, `eigenvalues.tsv`, `environment.txt`, and `report.md`; `options.plot = true` additionally creates `spectrum.png`. The TSV eigenvalues and metrics retain MP text via `char(mp)`. The optional plot is only a display conversion and is not numerical evidence. ## Five difficult input representations The default suite runs five representations, with `eig (A, "balance")` and `eig (A, "nobalance")`: 1. A Hadamard orthogonal similarity of an upper-bidiagonal matrix. Its exact eigenvalues are `1:n`, while large superdiagonal coupling exposes the difference between a small residual and a well-conditioned eigenvalue. 2. The Frank matrix, whose positive eigenvalues include reciprocal pairs and whose independent reference is obtained from a symmetric tridiagonal problem. 3. The companion matrix of the exact Wilkinson polynomial `prod(x-(1:n))`. Coefficients are generated by an MP recurrence rather than by a rounded builtin polynomial helper. 4. The original Forsythe form `I + N + 2^(-a*n) e_n e_1^T`. 5. The explicitly scaled Forsythe form `I + 2^(-a) P`, with `P` the cyclic shift. The two Forsythe forms are diagonally similar, but the small coupling is represented differently in native binary64. The default smoke cases produce 30 rows: ```text 5 representations × 2 eig modes × (native + 128-bit + 256-bit MP) ``` The default demo cases produce 40 rows: ```text 5 representations × 2 eig modes × (native + 128-bit + 256-bit + 512-bit MP) ``` The native rows are an explicit binary64 input control. They are not used to construct or validate the MP model. For every MP row, the actual solver output is promoted to an evaluation precision and the following are measured there: ```text A*V - V*D W'*A - D*W' column right/left residuals eigenvalue absolute and relative bottleneck matches left/right eigenvector condition estimates ``` The left-vector convention is `W'*A = D*W'`, so the corresponding column residual uses `A'*w - conj(lambda)*w`. Eigenvalue order is not assumed: the suite uses a deterministic minimum-bottleneck one-to-one matching. A reference match is marked unresolved when its independent low/high precision agreement does not meet its declared limit. ## Precision and input construction Each MP constructor temporarily establishes its requested `mpbits()` value, constructs the complete matrix, and restores the caller's ambient default. Existing MP objects are not reconstructed when the default changes. The solver receives an MP matrix at the selected work precision; no MP path calls builtin binary64 `eig`, and no native row is substituted for an MP row. The suite's self-test includes 1024-bit `2^-700` and 2048-bit `2^-1500` tail canaries. The Forsythe stress constructor also checks that a 2048-bit `2^-1600` MP coupling remains nonzero while the deliberately rounded native control underflows. This is input provenance evidence, not a claim that the native control is accurate. Use `mp_eig_suite_selftest` for constructor, reference, matching, precision, and lifetime-oriented focused checks. The full focused test is `test/test_nonsymmetric_eig_suite.m`. The top-level runnable example is `examples/13_nonsymmetric_eig_suite.m`. ## Interpretation A small backward or eigenvector residual does not by itself prove a small forward eigenvalue error for a nonnormal matrix. Report the condition estimate, the matched forward error, and the actual-input residual together. Balancing is a solver option to compare, not an assumption about the mathematical model. The reference paths are structured MP checks; they are independent of the general solver call but still use the package's MP arithmetic/backend and must not be described as an external-library oracle. The stress profile is available for extended local runs. The mandatory acceptance wall is the deterministic smoke/demo pair above; stress cases are not silently substituted for those rows. mplapack-interop-0.5.1/docs/advanced-numerics-compatibility.md0000644000230300031750000001274015274353473023761 0ustar rafaelrafael# Advanced numerical compatibility This document is the T00–T14 handoff for the arbitrary-precision numerical surface of `mplapack-interop`. The tested runtime is GNU Octave 11.1.0 with the installed MPLAPACK MPFR/MPC backend and gmpfrxx_mkII 1.4.1. ## Supported T-series surface The following public calls are implemented for dense, two-dimensional `mp` values and are covered by focused tests plus the required real-regression wall: ```text hess balance schur qz pinv null orth rref kron expm logm sqrtm polyval polyvalm roots poly conv deconv polyder polyint compan unique union intersect setdiff setxor ismember gamma gammaln lgamma erf erfc saveobj loadobj plot3 scatter3 mesh surf contour3 meshc surfc waterfall mprand mprandn mprandi mprng interp1 pchip spline ppval mkpp unmkpp ppder ppint interp2 fzero fsolve integral quadgk fminbnd fminsearch ``` The repository-local difficult nonsymmetric eigensystem harness is documented in `docs/nonsymmetric-eig-suite.md` and exercised by `examples/13_nonsymmetric_eig_suite.m`. It is built only from the existing public `mp`/`eig` API and does not add a new package-level call. The harness covers Hadamard-similar, Frank, companion, and two Forsythe representations, both balance modes, actual-output residuals, left/right conditioning, and deterministic eigenvalue matching. Native rows are explicit rounded-input controls; MP rows retain the one-operation/one-precision contract. The T-series preserves the one-operation/one-precision MPFR/MPC contract, uses operation-owned copies for destructive backend calls, and never silently routes numerical work through builtin binary64 or routes a real-only call through a complex kernel. ## NEIGT Tier-S/Tier-A and verified V-S/V-A examples The NEIGT suite is a repository-local example and QA harness layered on the existing public `mp`, `mpbits`, `eig`, `svd`, `qr`, and solve interfaces. It does not add package-level numeric methods. The numbered entry points are `examples/14_neig_tier_s.m`, `examples/15_neig_tier_a.m`, `examples/16_neig_verified_vs.m`, and `examples/17_neig_verified_va.m`. Tier-S/Tier-A keeps generation precision, exact model, frozen input, work precision, native control, reference, and measured solver output distinct. The Tier-S Ozaki--Ogita generator is the specified paired-block construction, not a generic similarity surrogate. The V layer uses audited MPFR/MPC outward primitives and conservative proof checkers for all 26 manifest jobs: all-spectrum counts, invariant clusters, pseudospectrum points/cells, compatible factors and Schur/block-Schur, finite pencils, and normalized Perron pairs. Defective models remain cluster/block claims, never scalar diagonalization claims. Candidate-only solves and graph/Newton auxiliaries are separately labeled and cannot replace measured eig outputs. `mp_neig_tiers` returns `NUMERICS_ONLY_COMPLETE` for an unfiltered `all` ordinary run because V jobs are separate. `mp_neig_verify_examples` reports all selected verification jobs and proof status. `mp_neig_write_outputs` creates a new-only result directory with TSV rows, environment metadata, and an exact MP proof record; `mp_neig_replay` rechecks the hash-bound V-S1 proof in a fresh process without calling `eig` or reconstructing an ideal model. MP values retain stored precision and every public operation restores ambient `mpbits()`. Optional plots are display-only and are not numerical evidence. The smoke profile contains 120 measured eig rows and the demo profile 168; each also contains 26 verification jobs. Stress is opt-in and does not count toward mandatory coverage. The complete manifest and theorem preconditions are in `docs/codex/neigt/ACCEPTANCE.md` and `docs/codex/neigt/CASES.md`. The pedagogical one-case files and their detailed explanations are indexed by `docs/examples/tiered/README.md`; they select existing manifest cases and do not replace the counted profile or V verification surfaces. ## Boundary and deferred surface The public type remains dense and two-dimensional. The following are explicitly deferred and have a re-entry document under `docs/todo/`: | Surface | Re-entry document | |---|---| | optional T00 Schur/QZ ordering helpers | `docs/todo/T00-schur-optional-ordering.md` | | `funm` | `docs/todo/T02-funm.md` | | `polyfit`, `polyeig` | `docs/todo/T03-polyfit-polyeig.md` | | `ismembertol` | `docs/todo/T04-ismembertol.md` | | remaining special functions | `docs/todo/T06-special-functions.md` | | `meshgrid` gap and volume graphics | `docs/todo/T08-meshgrid.md`, `docs/todo/T08-volume-graphics-after-ND.md` | | matrix-valued PP output | `docs/todo/T10-matrix-valued-pp.md` | | `interp3`, `interpn`, N-D interpolation | `docs/todo/T11-ND-interpolation.md` | | complex nonlinear callbacks | `docs/todo/T12-complex-nonlinear-solvers.md` | | `ArrayValued` quadrature | `docs/todo/T13-array-valued-quadrature.md` | | `fminunc` | `docs/todo/T14-fminunc.md` | Unsupported calls are rejected by the compatibility firewall when an `mp` operand is involved. They are not delegated to a builtin binary64 implementation. ## Precision and regression evidence The T-series uses source-precision and ambient-precision tests, including 1024-bit `2^-700` and 2048-bit `2^-1500` canaries where the relevant API is applicable. The final controller wall passed M00–M23, C00–C12 including the mandatory C11L complex LU path, N00–N08, S00–S08, T00–T14, the firewall, serialization, graphics, and package lifecycle. Native ASan, UBSan, and LSan completed successfully. Complete evidence is in `reports/T00-T14-report.md`. mplapack-interop-0.5.1/docs/generalized-eig.md0000644000230300031750000000310715274353473020552 0ustar rafaelrafael# Generalized eigenproblems N06 adds dense arbitrary-precision generalized eigenproblems: ```octave lambda = eig (A, B) [V, D] = eig (A, B) [V, d] = eig (A, B, "vector") [V, D, W] = eig (A, B) [V, D] = eig (A, B, "chol") [V, D] = eig (A, B, "qz") ``` The operation solves `A*V = B*V*D`. Three-output forms additionally return left eigenvectors satisfying `W'*A = D*W'*B`. The default one-output form returns an eigenvalue column; an explicit `"matrix"` one-output form returns the diagonal eigenvalue matrix. `"vector"` selects a column for two-output and three-output forms. Exactly represented symmetric real or Hermitian complex pairs use the positive-definite `Rsygvd`/`Chegvd` drivers when possible. `"chol"` requires that structured pair and a positive-definite `B`; the default falls back to QZ when `B` is singular or not positive definite. `"qz"` forces the general `Rggev`/`Cggev` drivers. Generalized `"balance"` and `"nobalance"` options are not accepted, matching the audited Octave interface. Real QZ results are returned as complex `mp` values so real conjugate pairs retain their imaginary components. The backend's `alpha/beta` representation is divided at the stored operation precision; `beta = 0` therefore retains an infinite eigenvalue rather than rejecting the problem. Mixed real/complex pairs are promoted once to MPC at the maximum input precision. All LAPACK calls operate on owned copies. The selected precision is uniform through each MPFR/MPC scope and is independent of the ambient construction default. No generalized path converts through builtin binary64 arithmetic. mplapack-interop-0.5.1/docs/matrix-concatenation.md0000644000230300031750000000323615274353473021651 0ustar rafaelrafael# Dense matrix concatenation M13 adds `horzcat` and `vertcat` for the dense real `mp` type, so ordinary Octave bracket expressions produce one native `mp` value: ```octave C = [A, B, C2]; D = [A; B; C2]; ``` The implementation validates all operands and the complete result shape before allocating one column-major `MpfrMatrixStorage`. Scalar operands are treated as `1x1` values, while dense double operands are converted directly from their incoming binary64 values. No broadcasting or numerical arithmetic is used. ## Precision The result precision is the greatest stored precision of all participating `mp` operands. Empty `mp` matrices participate in this maximum even when they contribute no elements. A double operand does not increase the result precision. Lower-precision `mp` values are copied directly into the result at the selected precision; this embeds the represented value but does not recover information that was rounded away in the source. Concatenation is structural. It does not call MPLAPACK, enter an MPFR precision scope, or read or modify `mpbits()` / the current-thread MPFR default. Public inputs remain immutable and the result owns independent storage. ## Supported forms and limitations Horizontal and vertical concatenation accept arbitrary argument counts and real `mp` scalars/matrices or real dense double scalars/matrices. Empty-shape behavior follows Octave's two-dimensional concatenation rules. General `cat(dim, ...)`, N-D values, complex or sparse operands, and indexed assignment remain outside M13; M14 adds limited value-semantic indexed assignment. Matrix concatenation never creates an Octave object array of scalar `mp` wrappers. mplapack-interop-0.5.1/docs/nonlinear-solvers.md0000644000230300031750000000221215274353473021173 0ustar rafaelrafael# Nonlinear solvers `fzero` and `fsolve` accept MP starting values and call user callbacks with MP values. A callback that returns builtin double data is rejected; there is no hidden call to the builtin binary64 solver. `fzero` accepts a scalar starting point or a two-point bracket. Scalar starts are expanded with MP steps until a sign-changing bracket is found. The solve uses a safeguarded secant proposal inside a sign-changing bracket and falls back to the MP midpoint when the proposal is unsafe. Default `TolX` and the iteration budget are derived from the active MP precision; `TolX`, `TolFun`, and `MaxIter` can be supplied in a scalar options struct. `fsolve` accepts real MP scalar/vector/matrix starts and uses MP Newton steps. Without `Jacobian="on"`, forward differences use MP perturbations based on the active precision. With `Jacobian="on"`, the callback must return `[residual,jacobian]`, both as real MP values. A short MP backtracking line search is applied to rejected full Newton steps. The implementation is intentionally limited to real systems in this milestone; complex nonlinear callback semantics are not silently guessed. mplapack-interop-0.5.1/docs/scalar-arithmetic.md0000644000230300031750000001052615274353473021116 0ustar rafaelrafael# Scalar arithmetic design ## Scope M06 implements real scalar `+`, `-`, `.*`, `./`, unary `+`, and unary `-`. Dense values, broadcasting, comparisons, powers, transcendental functions, and complex arithmetic are outside M06. ## Octave 11.1 dispatch audit The installed Octave 11.1 runtime was tested before implementation. For a classdef `mp` operand it dispatches `mp + mp`, `mp + double`, and `double + mp` to `@mp/plus.m`; the corresponding binary method behavior applies to the other M06 operators. Built-in operands arrive without automatic promotion: in particular, `single + mp` reaches the method as `single`, so the binding can reject it deliberately. Unary operators require distinct `uplus` and `uminus` methods. The external methods in `inst/@mp` are class methods and can replace the private hidden `payload_` property on a result prototype. M06 uses this only after the native bridge has returned a validated internal value. It avoids the public constructor, text conversion, and the current default precision. This classdef behavior is a compatibility-sensitive Octave boundary. ## Supported operators The public operators are scalar `+`, `-`, `.*`, `./`, unary `+`, and unary `-`. The native implementation uses direct `mpfr_add`, `mpfr_sub`, `mpfr_mul`, `mpfr_div`, and `mpfr_neg` calls. ## Operand types Binary operations accept two scalar `mp` operands or one scalar `mp` and one real scalar Octave `double`. Complex, nonscalar, `single`, integer, logical, cell, and other operands are rejected. No scalar expansion or public object array is created. ## Result precision For `mp`/`mp`, the result precision is the maximum of the two stored operand precisions. For `mp`/`double`, the stored `mp` precision is the result precision. The current project default never participates in arithmetic precision selection and is not modified by an operation. ## Mixed `mp` precision Operands retain their original values and precisions. A new independent native result is allocated at `max(lhs precision, rhs precision)` before the operation is evaluated. ## Double promotion A binary64 operand is converted directly with `mpfr_set_d` into a temporary RAII value at the `mp` operand precision. The conversion does not use decimal text, the public `mp` constructor, or the current default. It deliberately does not raise operation precision to 53 bits. ## Rounding mode All M06 native operations explicitly use `MPFR_RNDN` (round to nearest, ties to even). The MPFR global default rounding mode is neither read as semantics nor modified. ## Immutability Octave-facing payloads remain immutable. Binary operations and unary minus return newly owned native storage. Unary plus may share the existing public value safely because no operation mutates its payload. ## Special values NaN, infinities, and signed zeros follow the results produced by the direct MPFR operation under `MPFR_RNDN`. M06 adds no alternative exception or normalization policy. ## Division by zero Scalar `./` follows MPFR semantics. Signed nonzero values divided by signed zero produce signed infinities, while zero divided by zero produces NaN. It does not raise a project-specific divide-by-zero exception. ## Dense matrix extension M11 extends the same precision and rounding rules to dense two-dimensional matrices. Native element-wise `+`, `-`, `.*`, and `./` use direct MPFR operations into a destination allocated at the maximum stored operand precision (or the `mp` precision for mixed binary64 input). Scalar expansion and two-dimensional singleton expansion follow Octave shape rules without promoting or mutating public operands. These kernels do not call MPLAPACK or depend on the current MPFR default. ## Unsupported matrix operators The scalar-only M06 path does not implement `*`, `/`, or `\`; public matrix dispatch for those operators is owned by M08/M09. Powers use the S01 native path and comparisons use the S03 native MPFR/MPC path; neither falls back through `double(mp)`. ## Relationship to M07/M08/M09/M10/M11 M07 owns native dense storage, matrix constructors, and shape. M08 owns `*` through MPLAPACK MPFR GEMM. M09 owns `\` through MPLAPACK MPFR LAPACK. M10 adds read-only inspection, and M11 adds the dense element-wise extension described above. The scalar storage operations introduced here are reusable primitives but do not constrain dense storage to arrays of scalar wrappers. mplapack-interop-0.5.1/docs/graphics-bridge.md0000644000230300031750000000337015274353473020553 0ustar rafaelrafael# Graphics boundary bridge S07 provides class-specific wrappers for the common line graphics functions `plot`, `semilogx`, `semilogy`, `loglog`, `scatter`, `stem`, and `stairs`. The wrappers call a private helper that maps only `mp` values through the public `double` conversion immediately before the host graphics call. Axes handles, line-style strings, property/value pairs, and ordinary builtin values are passed through unchanged. Multiple data series and mixed double/`mp` arguments therefore retain the normal Octave calling convention. This is the only S07 binary64 conversion. It is a visualization boundary, not a numerical implementation path. Converting arbitrary-precision values to graphics doubles can map very small values to zero and very large values to infinity. Compute any range-sensitive transform first in `mp`, for example: ```octave plot (bits, double (log10 (residual_mp))) ``` For a single complex vector, the wrapper passes a builtin complex vector to Octave, which plots its real component against its imaginary component: ```octave z = mp ([1 + 2i; 2 + 1i; 3 + 3i]); plot (z, "o"); ``` ## Grcar eigenvalue example ```octave A = mp (gallery ("grcar", 32)); e = eig (A); plot (real (e), imag (e), "o"); axis equal; grid on; ``` Balance and no-balance results can be overlaid through the same bridge: ```octave eb = eig (A, "balance"); en = eig (A, "nobalance"); plot (real (eb), imag (eb), "o"); hold on; plot (real (en), imag (en), "x"); ``` S07/S08 intentionally do not add wrappers for surface or matrix graphics. Those forms remain outside the supported dense script surface; for example, `mesh (mp_matrix)` is an explicit compatibility-firewall stop. A future graphics extension must preserve the same final-boundary-only conversion rule. mplapack-interop-0.5.1/docs/binary-distribution.md0000644000230300031750000001277415274353473021532 0ustar rafaelrafael# Binary-distribution architecture D01R1 freezes the architecture and handoff contract for future prebuilt Octave packages. D03 freezes the current source input as `mplapack-interop 0.4.0`; it does not build or publish B01–B05 artifacts. The exact D03 freeze commit, source archive SHA256, and size are recorded in `reports/D03-report.md` and must be consumed by B01–B05 without substitution. ## Package boundary The source package and a platform binary package are separate release classes: ```text source: mplapack-interop-0.4.0.tar.gz binary: mplapack-interop-0.4.0-octave--.tar.gz ``` The internal DESCRIPTION of both forms remains: ```text Name: mplapack-interop Version: 0.4.0 ``` Normal users install a binary with `pkg install` and load it with `pkg load mplapack-interop`; they do not need a compiler, `PKG_CONFIG_PATH`, or a developer-specific library path. ## ABI key The binary compatibility key is the tuple: ```text Octave major/minor version + Octave API version + OS + architecture ``` The first audited host reports: ```text Octave: 11.1.0 Octave API: api-v61 host: x86_64-pc-linux-gnu mkoctfile: 11.1.0 compiler: GNU C++ 15.2.0 ``` The package must not promise that an `.oct` built for another Octave API version is compatible. Each binary artifact embeds this key in its filename and manifest. ## Package layout The planned installed layout is: ```text mplapack-interop-0.4.0/ ├── DESCRIPTION ├── COPYING ├── LICENSE ├── INDEX ├── inst/ ├── src/__mplapack_core__.oct ├── runtime/ # private native runtime closure └── docs/binary-manifest.json ``` The exact `runtime/` contents are target-specific and are recorded in the binary manifest. Runtime files remain inside the Octave package directory; no binary package copies private libraries into `/usr/lib`, `/usr/local/lib`, or another global directory. `pkg uninstall` therefore removes the package and its private runtime together. The current Octave 11.1 `pkg build` audit produced a binary archive, put the `.oct` under `src/`, and preserved DESCRIPTION identity. It also showed that raw `pkg build` archives whatever the build leaves in the source tree; the release build must therefore run from a clean extraction and exclude QA probes/build products before publication. ## Runtime closure The audited native module has direct runtime references to: ```text libmplapack_mpfr.so.3 libmpc.so.3 libmpfr.so.6 libgmp.so.10 libstdc++.so.6 libgcc_s.so.1 libc.so.6 ``` `libmplapack_mpfr.so.3` is the MPLAPACK runtime SONAME. The gmpfrxx wrapper is primarily header-only for the value types; any dynamically required default-context provider is treated as an explicit manifest/runtime item, not as an invisible developer dependency. Octave and the platform's base C runtime are never bundled as part of this package. ## Loader strategies ### Linux B01/B02 place private shared libraries beside the package's `.oct` or in the declared `runtime/` subdirectory. The `.oct` and any bundled libraries use relative ELF `DT_RUNPATH` entries based on `$ORIGIN` (for example, `$ORIGIN/../runtime`) and are checked with `readelf -d`, `ldd`, and `ldd -r`. No `LD_LIBRARY_PATH` is required at runtime. `DT_RPATH` and `LD_PRELOAD` are not the architecture. The current development proof was intentionally run with an isolated `LD_LIBRARY_PATH` because the existing module has no relative runpath. That is a bounded B01/B02 relocation step, not an accepted final binary artifact. ### macOS B03/B04 use package-local `.dylib` files and install names based on `@loader_path`/`@rpath`. `otool -L` and `install_name_tool` (where needed) verify both direct and transitive closure. The final build also records codesigning/notarization inputs if distribution policy requires them. No `DYLD_LIBRARY_PATH` is required at runtime. ### Windows B05 places the required MinGW-compatible DLL closure in the package-local `runtime/` directory next to the `.oct` or in the documented DLL search directory. The build verifies the exact Octave/MinGW C++ ABI and uses a dependency inspection tool such as `objdump -p`/`ntldd`. No system-wide DLL installation is performed. ## Manifest Every binary artifact includes `docs/binary-manifest.json` (or the equivalent package-preserved path) containing: ```text package name/version source commit and source archive SHA256 gmpfrxx version/tag/SHA256 MPLAPACK version/tag/SHA256 Octave version/API OS/architecture/compiler/toolchain runtime file list and SONAME/install-name/DLL identities license and notices paths build provenance ``` The manifest is data, not a replacement for the corresponding source archive. It must identify the exact source URL and checksum from `docs/dependency-release-stack-r1.md`. ## Naming matrix | Target | Artifact pattern | Loader check | |---|---|---| | B01 Linux x86_64 | `mplapack-interop-0.4.0-octave11-linux-x86_64.tar.gz` | `$ORIGIN`/`DT_RUNPATH`, `readelf`, `ldd -r` | | B02 Linux arm64 | `mplapack-interop-0.4.0-octave11-linux-aarch64.tar.gz` | `$ORIGIN`/`DT_RUNPATH`, target `readelf`, `ldd -r` | | B03 macOS arm64 | `mplapack-interop-0.4.0-octave11-macos-arm64.tar.gz` | `@loader_path`/`@rpath`, `otool -L` | | B04 macOS x86_64 | `mplapack-interop-0.4.0-octave11-macos-x86_64.tar.gz` | `@loader_path`/`@rpath`, `otool -L` | | B05 Windows x86_64 | `mplapack-interop-0.4.0-octave11-windows-x86_64.tar.gz` | package-local DLL search, `objdump -p` | The `octave11` label is shorthand for the audited Octave 11/API-v61 family; the manifest remains authoritative and contains the full API key. mplapack-interop-0.5.1/docs/math-rendering-migration.md0000644000230300031750000000736615274353473022425 0ustar rafaelrafael# GitHub math-rendering migration Status: DOCMATH01 migration record. This document records the repository-wide audit for fragile piecewise definitions in GitHub Markdown. The rendering target is GitHub's MathJax Markdown support, documented at https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/writing-mathematical-expressions. ## Permanent rule In live Markdown mathematics, an ordinary piecewise definition uses the standard cases environment. A piecewise brace must not be emulated with an aligned or array environment between a left brace and a right invisible delimiter. The forbidden and replacement forms are shown below as non-math documentation examples. They are intentionally not parsed as live equations by the checker. ```text FORBID: \left\{ ... \begin{aligned} ... \end{aligned} ... \right. REPLACE WITH: \begin{cases} ... \end{cases} ``` The aligned environment remains valid for genuinely aligned systems of equations. This migration does not impose a blanket ban on aligned. ## Scan The audit command walks every .md and .markdown file outside .git. The live enforcement scanner excludes docs/goals, release/logs, and generated docs/.build so historical goal text, immutable release evidence, and generated output are not rewritten or treated as current documentation. Non-math fenced code blocks are ignored; fenced math blocks and standalone $$ displays are checked. At the pre-migration audit, the only live fragile piecewise candidates were the two displays in docs/examples/tiered/neig-tier-a/frank0.md: 1. the Frank matrix-entry definition; 2. the cancellation-safe scalar map used for the independent Jacobi reference. No live alignedat, array, leftlbrace, or other brace variant required migration. Existing aligned systems that are not piecewise definitions remain unchanged. ## Migration Both Frank displays were rewritten to cases in the same fenced math blocks. Branch order, branch conditions, numerical constants, and mathematical meaning are unchanged. The scalar display uses dfrac for the visually larger fractions, and the optional row-spacing command was removed because the repository's raw-delimiter check treats that spelling as a fragile delimiter; this affects layout only. The Tiered NEIG and SVD pages were audited explicitly. No Tier S or Tier A SVD page contained a live fragile piecewise construction. The top README, documentation outside docs/examples/tiered, current reports, and the user-facing Markdown inventory contain no live fragile construction after the migration. ## Immutable and non-live occurrences No docs/goals or release/logs file was modified. A policy example in AGENTS.md and the examples in this document use inline code or a non-math text fence; they describe the forbidden form and are not live mathematical displays. Generated docs/.build output was not modified. ## Enforcement tools/check-github-math.sh now performs a deterministic repository-wide fragile-piecewise scan in addition to the existing Tiered Markdown structure checks. It rejects left brace or leftlbrace followed by aligned, alignedat, or array and a right invisible delimiter when that sequence occurs in live math. It ignores non-math code fences and the historical/immutable paths above. tools/check-docs.sh already invokes tools/check-github-math.sh, so future documentation changes are covered by the normal consistency gate. ## Validation method The nearest available rendering validation is the repository's GitHub-math structural checker, together with the official GitHub MathJax Markdown syntax for fenced math blocks. The actual GitHub web UI was not automated in this container. Representative coverage includes the Frank matrix-entry case, the Frank scalar mapping, and the Tiered NEIG/SVD documentation trees. mplapack-interop-0.5.1/docs/mplapack-interop.md0000644000230300031750000011622615274353473020774 0ustar rafaelrafael# mplapack-interop This Markdown manual is generated from [doc/mplapack-interop.texi](../doc/mplapack-interop.texi) via GNU Texinfo DocBook output and Pandoc. Edit the Texinfo source, then regenerate this file with `tools/build-manual-markdown.sh`. ## Introduction `mp` is a user-facing Octave class. An object owns its represented MPFR/MPC value, shape, and stored precision. Public values are immutable at the native boundary; destructive MPLAPACK calls receive operation-owned copies. The package does not silently route supported numerical work through builtin binary64 arithmetic. Use this package when the input data, intermediate values, or requested tolerances require more precision than binary64 provides. Use ordinary Octave values when binary64 is sufficient or when a deferred API is needed. ## Installation and package loading Install the source package with Octave’s package manager: pkg install mplapack-interop-0.5.1.tar.gz pkg load mplapack-interop For a local dependency installation, the repository helper selects the official gmpfrxx_mkII `1.5.0` archive by default and repairs installed MPLAPACK `.pc` metadata on Ubuntu systems whose `libmpc-dev` package does not provide `mpc.pc`. The published 0.5.1 package is the installer default; set `OCTAVE_VERSION=0.5.0` to use the immutable previous release. After starting the configured Octave session, load the package with: pkg load mplapack-interop The package requires GNU Octave 11.1 or newer and an installed MPLAPACK MPFR interface discoverable through `pkg-config`. The package does not vendor MPLAPACK or search a developer-specific source path. Check the active stack with `mplapack_version ()`. ## Creating `mp` values Decimal text is parsed directly at the current default precision: mpbits (256); x = mp ("0.1"); A = mp ({"1.0", "2.0"; "3.0", "4.0"}); A builtin double has already been rounded before `mp` receives it: binary64_value = mp (0.1); decimal_value = mp ("0.1"); These values intentionally preserve different source information. A complex scalar can be made directly from two decimal strings: z = mp ("1.25", "-0.5"); Dense matrices are two-dimensional and have one uniform stored precision. Use `char`, `disp`, and explicit `double` when inspecting or converting values. Only the last of these is an intentional binary64 conversion. ## Precision model `mpbits ()` reports the project default; `mpbits (p)` changes it for subsequently constructed values. `mpdigits (d)` requests `ceil(d*log2(10))` bits. A fresh process starts at 512 bits. Changing the default does not recreate information already lost: mpbits (128); low = mp ("0.1"); mpbits (1024); high = mp ("0.1"); % low remains a 128-bit value; high is newly constructed at 1024 bits. Existing operands determine the operation precision. For two `mp` operands it is the maximum stored precision; a builtin double is converted at the `mp` operand precision. The ambient default does not retroactively change operands or select an arithmetic result precision. Linear-algebra and other native calls enter one operation-owned precision scope, normalize temporaries to that precision, and restore the caller’s thread-local backend context. Real-to-complex promotion happens once at the selected precision. Guard precision is used only where the function-specific documentation says so; it is not a hidden binary64 fallback. ## Real and complex values Real and complex values share the public `mp` class but have different native payload kinds. `real`, `imag`, `conj`, `isreal`, `abs`, `arg`, and `angle` inspect or transform those payloads using MPFR/MPC operations. A real input is kept on a real path when the operation permits it. A result is promoted to complex `mp` when the mathematical branch requires a complex value, for example a negative real square root or a general real matrix with complex eigenvalues. A builtin complex double may be an input, but it is converted into the operation precision. A raw builtin-double-only operation remains an Octave operation outside this package’s contract. ## Arithmetic and comparisons The element-wise arithmetic functions and operators are `plus`, `minus`, `times`, `rdivide`, `uplus`, `uminus`, `power`, and `mpower`. Dense multiplication uses `mtimes` and MPLAPACK `Rgemm` or `Cgemm`. Mixed real/complex inputs promote to MPC at one operation precision. Comparisons use native MPFR/MPC equality and the documented complex magnitude/phase ordering for supported extrema and sorting operations. Ordered comparisons on complex values remain rejected. mpbits (512); a = mp ("0.1"); b = mp ("0.2"); c = a + b; d = a .* b; e = c ^ 2; ## Dense matrices and indexing The dense public type is two-dimensional, column-major, and contiguous at the native boundary. `size`, `rows`, `columns`, `numel`, `ndims`, `length`, and `isempty` inspect shape without changing stored precision. `subsref`, `subsasgn`, and `end` provide normal dense indexing and value-semantic in-bounds assignment. `reshape`, `transpose`, `ctranspose`, `horzcat`, `vertcat`, and `cat` preserve native values. `diag`, `triu`, `tril`, `repmat`, `flip`, `fliplr`, `flipud`, and `rot90` are supported for the dense two-dimensional forms. `zeros`, `ones`, `eye`, `NaN`, and `Inf` support `"like"` construction with an `mp` template. Sparse, N-dimensional, deletion, growth assignment, and packed triangular forms are not part of the public dense contract. ## Matrix factorizations and linear solves Use `A \ b` or `A / B` instead of explicitly forming an inverse for a solve. Square left division uses `Rgesv` or `Cgesv`; rectangular and rank-revealing forms use `Rgelss` or `Cgelsy`. Right division uses the conjugate-transpose solve identity and preserves complex conjugation. `chol` uses `Rpotrf`/`Cpotrf`; `qr` uses `Rgeqrf`/`Rorgqr` or `Cgeqrf`/`Cungqr`; pivoted QR uses `Rgeqp3`/`Cgeqp3`; and `lu` uses `Rgetrf`/`Cgetrf`. Every destructive call receives an operation-owned copy. A = mp ({"4", "2"; "2", "10"}); b = mp ({"1"; "2"}); x = A \ b; [Q, R] = qr (A); [L, U, P] = lu (A); Result tolerances should be based on the stored operation precision and the conditioning of the problem, not on a fixed binary64 epsilon. ## Eigenvalues, SVD, Schur and QZ This chapter covers the dense eigenvalue, singular-value, Schur, Hessenberg, and generalized Schur interfaces. These routines are useful for analysing conditioning and invariant subspaces, but their factors are not unique. A successful call therefore must be checked with a residual, an orthogonality or unitarity relation, and a precision-aware tolerance rather than by comparing vectors element by element. ### Standard eigenproblems The standard dense interface accepts a square `mp` matrix `A`: lambda = eig (A) [V, D] = eig (A) [V, d] = eig (A, "vector") [V, D, W] = eig (A) [V, D] = eig (A, "balance") [V, D] = eig (A, "nobalance") The default one-output form returns a column vector of eigenvalues. The explicit `"matrix"` form returns a diagonal eigenvalue matrix, while `"vector"` returns a column. The two-output forms return right eigenvectors and eigenvalues; the three-output form additionally returns left eigenvectors. For the matrix form the identities are `A*V = V*D` and `W'*A = D*W'`. For the vector form replace `D` by `diag(d)`. An exactly represented real symmetric matrix uses the structured MPFR `Rsyevd` path. An exactly represented complex Hermitian matrix uses `Cheevd`. Structured real eigenvalues and eigenvectors are real `mp`; a Hermitian problem has real eigenvalues but generally complex eigenvectors. The structured path does not need balancing. All other square real matrices use MPLAPACK `Rgeevx`, and all other complex matrices use `Cgeevx`. General real results are returned as complex `mp` values even when every eigenvalue happens to be real. This keeps the imaginary parts of conjugate pairs and gives one output type for the general driver. `"balance"` and `"nobalance"` select the expert-driver mode explicitly; balancing can improve the scaling of a badly scaled problem but changes the returned vectors. The structured/general decision is based on the represented values, not on a floating-point closeness test. A nearly symmetric matrix, a non-Hermitian complex matrix, a defective or nearly defective matrix, and a badly scaled matrix therefore exercise the general path. Sparse, non-square, and N-dimensional eigenproblems are outside the dense `mp` contract. This example deliberately uses a nonnormal Grcar matrix. It checks the right-eigenvector residual without assuming a particular eigenvalue order, vector scale, or complex phase: mpbits (1024); G = mp (gallery ("grcar", 32)); [V, D] = eig (G, "nobalance"); right_residual = norm (G*V - V*D, "fro") / norm (G, "fro"); disp (right_residual); For a three-output call also check the left relation. Near repeated eigenvalues can have very sensitive eigenvectors even when the residual is small, so report the residual and inspect the eigenvalue separation before interpreting the vectors. ### Difficult nonsymmetric eigensystem suite The repository includes a runnable difficult-eigensystem experiment based on the existing public `mp`, `mpbits`, `eig`, `norm`, and MP inspection functions. It is a QA/example harness, not an additional package-level API. Run it from a checkout with: tools/run-nonsymmetric-eig-suite.sh smoke tools/run-nonsymmetric-eig-suite.sh demo The smoke profile has 30 rows and the demo profile has 40 rows. Each row is one of five representations (Hadamard-similar, Frank, companion, Forsythe original, or explicitly scaled Forsythe), one of `balance` and `nobalance`, and one explicit native-binary64 or MP work precision. Native rows are rounded-input controls; they are never substituted for MP rows. The harness constructs MP input matrices at the requested work precision, restores the ambient `mpbits ()` default, and evaluates the actual solver outputs at a separate high precision. It checks `A*V = V*D`, `W'*A = D*W'`, column residuals, one-to-one eigenvalue matches, and left/right eigenvector condition estimates. It does not assume solver output ordering or vector normalization. For a high-quality example, the Hadamard-similar model has exact integer eigenvalues but can be highly nonnormal, while the Forsythe pair separates a small coupling from a native underflow control. The result writer accepts an `output_dir` option and creates `summary.tsv`, `eigenvalues.tsv`, `environment.txt`, and `report.md`. Existing result files are rejected rather than overwritten. MP numerical fields are serialized with `char(mp)`. An optional `plot = true` output is a display-only conversion to a PNG and is not numerical evidence. Full construction details and limitations are in `docs/nonsymmetric-eig-suite.md`; the runnable package example is `examples/13_nonsymmetric_eig_suite.m`. ### NEIGT verified eigensystem tiers The repository also contains a larger, manifest-driven nonsymmetric eigensystem example and verification suite. It is a repository-local example/QA surface, not an additional package-level numerical API. The four numbered entry points are: run examples/14_neig_tier_s.m run examples/15_neig_tier_a.m run examples/16_neig_verified_vs.m run examples/17_neig_verified_va.m The first two run the ordinary Tier-S and Tier-A model families. They use the existing public `mp`, `mpbits`, and `eig` interfaces and keep the exact generation model, frozen solver input, work precision, native control, reference values, and returned eigentriples separate. Tier-S includes the specified Ozaki–Ogita paired-block generator, exact simple, repeated, defective, and merged similarity models, Toeplitz/Forsythe controls, and the complex Hadamard control. Tier-A includes Hadamard-bidiagonal, Frank, Wilkinson, Grcar, MKS, and positive stochastic/Perron models. The latter two run the verified V-S and V-A jobs. They are conservative outward-safe finite-matrix proof baselines: counted Gershgorin coverage, invariant graph/projector bounds, pseudospectrum point/cell enclosures, compatible eigenfactor and Schur/block-Schur factors, finite-pencil reduction, and normalized positive Perron pairs. A broad residual or a numerical agreement between precisions is not a certificate. Defective cases are reported as clusters or block Schur factors; they are never labeled as a diagonalizable eigenbasis. The manifest profiles are `smoke` and `demo`. The mandatory ordinary profiles contain respectively 120 and 168 measured native/MP `eig` rows, and each profile has 26 separately counted verification jobs. Stress is opt-in and has no authority over the mandatory results. A direct API call is useful for selecting a tier: S = mp_neig_tiers ("smoke", struct ("tier", "S", "plot", false)); A = mp_neig_tiers ("demo", struct ("tier", "A", "plot", false)); VS = mp_neig_verify_examples ("smoke", struct ("tier", "V-S", "plot", false)); VA = mp_neig_verify_examples ("smoke", struct ("tier", "V-A", "plot", false)); These helpers preserve the one-operation/one-precision contract. MP model construction and all certificate arithmetic use MPFR/MPC values; no supported proof path falls through builtin binary64 complex arithmetic. Each operation restores the caller’s `mpbits ()` default. Candidate solves are auxiliary and are recorded with their own precision and source; known roots, generator columns, and higher-precision replacements are not silently substituted into measured outputs. For a durable result bundle, use a new output directory: bundle = mp_neig_write_outputs ("smoke", "/tmp/neigt-results", ... struct ("tier", "all", "plot", false)); replay = mp_neig_replay ("/tmp/neigt-results/proof-vs1-01.json"); The writer refuses an existing output path. It records measured rows, environment/provenance, a schema-versioned exact MP proof record, and a report. Replay verifies the content hash, decodes the recorded MP values at the stored precision, and reruns the recorded certificate without calling `eig` or reconstructing an ideal matrix. Plotting, when requested, is display-only; it cannot alter numerical rows or proof status. The detailed manifests, preconditions, limitations, and source attribution are in `docs/codex/neigt/NEIGT-LUNA-XHIGH.md` and `docs/codex/neigt/ACCEPTANCE.md`. ### Tiered worked examples The difficult NEIGT and SVD fixtures have one short runnable example and one matching explanation per conceptual case. The master index is `docs/examples/tiered/README.md`; its four family pages are `docs/examples/tiered/neig-tier-s/README.md`, `docs/examples/tiered/neig-tier-a/README.md`, `docs/examples/tiered/svd-tier-s/README.md`, and `docs/examples/tiered/svd-tier-a/README.md`. The short files select one case from the existing manifest and call the existing public `mp_neig_tiers` or `mp_svd_tiers` runner with its `case_id`. For example: run examples/tiered/neig-tier-s/sim_simple.m run examples/tiered/svd-tier-a/hadamard_rank5.m The detailed Markdown files explain the matrix formula, provenance, intended difficulty, residual and conditioning diagnostics, precision behavior, and common interpretation mistakes. Tier S and Tier A are project-specific QA labels defined by the existing manifests; they are not universal numerical classifications. The split is deliberately explicit: NEIG has 12 Tier S and 9 Tier A cases, while SVD has 9 Tier S and 14 Tier A cases. Tier S contains the fixed-precision generator, near/repeated/defective eigensystem cases, non-normal reciprocal singular groups, combinatorial growth, exponent-range controls, and diagonal-dominance cases. Tier A broadens coverage with Hadamard, Frank, companion, Grcar, MKS, Markov/Perron, Pascal, Vandermonde, bidiagonal, Läuchli, known-rank, and complex controls. The common equations should be read before any individual page. For a nonsymmetric eigensystem, $`V`$ and $`W`$ are right and left factors: $`A V = V D`$,  $`A^H W = W D^H`$ For an SVD, the measured factorization is: $`A = U \Sigma V^H`$ The corresponding normalized equation diagnostics are: $`r_e = ||A V - V D||_F/(||A||_F ||V||_F)`$,  $`r_s = ||A-U \Sigma V^H||_F/||A||_F`$ These are backward-error-style diagnostics. Forward error also depends on conditioning, scale, separation, multiplicity, and the exact represented input. Repeated or defective eigenspaces and repeated or null singular groups must be interpreted as subspaces, not as canonical individual vectors. Complex cases use the conjugate-transpose convention. The mathematical background includes Higham’s [Accuracy and Stability of Numerical Algorithms](https://doi.org/10.1137/1.9780898718027), Rump’s [verified all-spectrum eigenvalue and eigenvector bounds](https://doi.org/10.1137/21M1451440), and Wedin’s [SVD perturbation bounds](https://doi.org/10.1007/BF01932678); the case-specific attributions and adaptation boundaries are recorded in each Markdown page. The master Markdown page is a learning map rather than a second measurement implementation. Its table names every case ID, its one runnable file, its one detailed explanation, the defining equation or phenomenon, and an external reference. Use `docs/examples/tiered/GLOSSARY.md` for the symbols and diagnostics, and `docs/examples/tiered/MIGRATION.md` to audit the one-case/one-example/one-document correspondence. This separation keeps the explanatory material detailed without changing the existing counted QA runners. The historical numbered entry points remain deterministic family indexes: `examples/14_neig_tier_s.m`, `examples/15_neig_tier_a.m`, `examples/14_svd_tier_s.m`, and `examples/15_svd_tier_a.m`. They do not replace the complete measured profile walls. Those walls remain in `examples/neig_tiers/` and `examples/svd_tiers/`, and the migration map is `docs/examples/tiered/MIGRATION.md`. ### Generalized eigenproblems The generalized interface solves the pencil `A - lambda*B`: lambda = eig (A, B) [V, D] = eig (A, B) [V, d] = eig (A, B, "vector") [V, D, W] = eig (A, B) [V, D] = eig (A, B, "chol") [V, D] = eig (A, B, "qz") Right and left eigenvectors satisfy `A*V = B*V*D` and `W'*A = D*W'*B`. The default one-output form is a column vector; an explicit `"matrix"` option returns a diagonal matrix. `"vector"` selects the column layout for two- and three-output forms. The output and algorithm options can be supplied together, for example `eig (A, B, "chol", "vector")`; duplicate or contradictory options are rejected. The `"chol"` algorithm is valid only for an exactly symmetric real or Hermitian complex `A`, with a positive-definite `B`. It uses `Rsygvd` or `Chegvd`. The default chooses this definite path when the represented pair satisfies those conditions. `"qz"` forces the generalized Schur path, using `Rggev` for real input and `Cggev` for complex or promoted input. If `B` is singular or not positive definite, the default falls back to QZ; an explicit `"chol"` request reports the invalid pair instead. Generalized `"balance"` and `"nobalance"` options are not supported. The QZ backend represents an eigenvalue as `alpha/beta`. Division is performed at the operation precision. When `beta` is zero, the result is an infinite eigenvalue rather than a binary64 overflow or a rejected problem. Real QZ conjugate pairs are returned as complex `mp` values so their imaginary components are not discarded. Mixed real/complex pencils are promoted once to MPC at the maximum stored operand precision. For a singular or ill-conditioned pencil, use the residual relations and inspect the `beta == 0` cases. Do not compare eigenvalue vectors by position: QZ ordering and eigenvector normalization are not canonical. The detailed compatibility and reconstruction notes are in `docs/generalized-eig.md`. ### Singular value decomposition The dense SVD interface is: s = svd (A) [U, S, V] = svd (A) [U, S, V] = svd (A, "econ") [U, S, V] = svd (A, 0) The numeric `0` form is accepted as the deprecated economy spelling. Two-output SVD calls are rejected; request either the singular values or all three factors. If `A` is `m` by `n`, let `k = min (m, n)`. The one-output result is a real `mp` column of `k` nonnegative singular values in descending order. The full factors have shapes `U`: `m` by `m`, `S`: `m` by `n`, and `V`: `n` by `n`. Economy factors have shapes `m` by `k`, `k` by `k`, and `n` by `k`. For real input the factors are real and the reconstruction is `A = U*S*transpose(V)`. For complex input `U` and `V` are complex `mp`, `S` remains real, and the reconstruction is `A = U*S*ctranspose(V)`. Full factors are orthogonal or unitary; economy factors have orthonormal columns. Singular vectors can change sign or complex phase, especially for repeated or clustered singular values. Check reconstruction and orthogonality rather than individual factor entries. SVD uses MPLAPACK `Rgesvd` for real input and `Cgesvd` for complex input. The input buffer, factors, singular values, and workspaces are operation-owned storage at one uniform precision. The input is not modified. The operation precision comes from the stored input precision, not from the ambient default at the time of the call. No SVD path calls builtin Octave `svd` or reduces through binary64. The following Hilbert example is more informative than a diagonal test: the matrix is dense, non-diagonal, and ill-conditioned. Its entries are created from decimal `mp` values, so the Hilbert matrix is not first created by the builtin binary64 `hilb` function: mpbits (512); n = 8; H = mp (zeros (n, n)); for i = 1:n for j = 1:n H(i,j) = mp (1) / mp (i + j - 1); endfor endfor [U, S, V] = svd (H); reconstruction = norm (H - U*S*V', "fro") / norm (H, "fro"); left_orthogonality = norm (U'*U - mp (eye (n)), "fro"); right_orthogonality = norm (V'*V - mp (eye (n)), "fro"); disp (diag (S)); disp (reconstruction); disp (left_orthogonality); disp (right_orthogonality); ### Tier S/A/V SVD example suite The repository contains an example-local suite for difficult dense singular value problems in `examples/svd_tiers/`. It is a measurement and verification harness around the public `mp`/`svd` path, not a second SVD implementation and not an installed package API. The suite keeps the stored SVD precision, model-construction precision, reference precision, and interval-evaluation precision separate. The smoke profile has 20 cases and exactly 120 measured SVD rows. The demo profile has 23 cases and exactly 184 measured rows. References, inverse solves, and Tier V jobs are counted separately. The demo adds a complex Lauchli control and global-scale NRO controls; the optional stress profile is not part of the default acceptance wall. Run the complete profile from a configured checkout as follows: pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "svd_tiers")); smoke = mp_svd_tiers ("smoke"); demo = mp_svd_tiers ("demo", struct ("tier", "all", ... "output_dir", fullfile (pwd (), "svt-demo"), "plot", false)); assert (demo.ok); The numbered top-level files are family indexes and full smoke aggregators; the one-case worked examples are listed in `docs/examples/tiered/README.md`: - `examples/14_svd_tier_s.m` lists and runs the Tier-S smoke family. - `examples/15_svd_tier_a.m` lists and runs the Tier-A smoke family. - `examples/16_svd_verified.m` certifies singular values and an inverse using the Tier V baselines. The complete construction inventory and measured-output schema are in `docs/svd-tiers.md`. The finite-arithmetic claim boundary, exact dyadic replay format, and failure classifications are in `docs/svd-verification.md`. The normative source and attribution ledger is `docs/codex/svt/SOURCES.md`. Tier V uses conservative baseline method IDs `svt_polar_weyl_v1`, `svt_dilation_projector_v1`, `svt_dilation_factor_boxes_v1`, and `svt_neumann_inverse_v1`. Certificates bind to the actual represented target and factors. They use exact MPFR/MPC dyadic snapshots, not decimal round trips, and record `paper_algorithm_reproduction=false`. A broad valid interval is distinct from a narrow accuracy target; `INCONCLUSIVE` is not a singularity proof. The examples preserve the one-operation/one-precision MPFR/MPC contract and never route numerical evidence through builtin binary64 arithmetic. Optional plots are presentation-only. Existing SVD and nonsymmetric-eigenproblem tests remain in the standard test runner; the SVT tests extend that runner rather than replacing earlier coverage. For a high-condition-number problem, increase `mpbits` before creating the input and choose tolerances from the requested precision and problem conditioning. A later change to `mpbits` does not change an existing matrix or the precision of an already-created SVD result. `pinv`, `null`, `orth`, and `rref` use singular values or related rank decisions and therefore require the same tolerance discipline. ### Schur Hessenberg and QZ decompositions The Hessenberg and Schur interfaces provide useful intermediate forms: H = hess (A) [P, H] = hess (A) S = schur (A) [U, S] = schur (A) [U, S] = schur (A, "complex") [AA, BB, Q, Z] = qz (A, B) [AA, BB, Q, Z] = qz (A, B, "real") The two-output Hessenberg form satisfies `P*H*P' = A`; `H` is upper Hessenberg and `P` is orthogonal or unitary. The default Schur type is `"real"` for real input and `"complex"` for complex input. The two-output Schur form satisfies `S = U'*A*U`. A real Schur form can contain 2-by-2 blocks for conjugate pairs; a complex Schur form is triangular. The factors and their ordering are not unique, and Schur reordering selectors are not part of this public interface. The generalized Schur (QZ) interface returns the orientation used by this package: `Q*A*Z = AA` and `Q*B*Z = BB`. The default QZ type is complex; `"real"` requests the real generalized Schur form for a real pencil. The diagonal or 2-by-2 blocks encode the generalized eigenvalues; the `alpha`/`beta` interpretation and infinite-eigenvalue rule are the same as for generalized `eig`. QZ is a decomposition of a pencil, not an inverse of `B`, so it remains usable when `B` is singular. For all of these routines use the exact reconstruction orientation above. Do not substitute a transpose for a conjugate transpose in a complex test, and do not assume that two valid runs return the same signs, phases, or block ordering. The optional Schur/QZ ordering helpers remain intentionally deferred. ### Precision and validation Every eig, SVD, Hessenberg, Schur, and QZ call selects one operation precision from its stored input operands. For a generalized problem this is the maximum stored precision of `A` and `B`. The native wrapper enters the matching MPFR/MPC precision scope, converts real values to complex values once when promotion is required, and restores the caller’s ambient precision on return. A new worker thread does not inherit a parent thread’s precision automatically; a worker must establish its own scope at entry. The LAPACK drivers destructively overwrite their input buffers. The public `mp` payload is immutable, so the wrapper always passes an operation-owned copy and leaves the input unchanged. Workspace queries and driver status values are checked before results are returned. The complex paths use MPC-native storage throughout and never silently fall back to builtin binary64 complex arithmetic. For a normal validation, compute a relative residual such as `norm (A*V - V*D, "fro") / norm (A, "fro")`, an orthogonality or unitarity residual such as `norm (U'*U - eye (n), "fro")`, and the appropriate generalized relation. Keep the residual as an `mp` value until the final display or an explicitly justified pass/fail conversion. At 1024 bits, test a `2^-700` tail; at 2048 bits, test a `2^-1500` tail. Also test with a low ambient default, a high ambient default, and a restored default to ensure that the operation precision belongs to the input and not to unrelated global state. The focused API and backend notes are maintained in `docs/eig.md`, `docs/generalized-eig.md`, and `docs/svd.md`; the runnable examples are `examples/06_grcar_eig.m`, `examples/07_svd_hilbert.m`, `examples/08_advanced_dense.m`, and the Tier S/A/V examples `examples/14_svd_tier_s.m`, `examples/15_svd_tier_a.m`, and `examples/16_svd_verified.m`. ## Matrix functions `expm`, `logm`, and `sqrtm` use package-owned arbitrary- precision matrix algorithms with MPFR/MPC working values. Principal branches and branch cuts can promote a real input to complex. Validate matrix identities and inspect conditioning near a branch cut. `mpower` for integer square matrices uses exponentiation by squaring; noninteger matrix powers are deferred. `polyvalm` evaluates a polynomial at a dense matrix. ## Elementary and special functions The supported scalar/element-wise elementary family includes `sqrt`, `cbrt`, `exp`, `expm1`, `log`, `log1p`, `log10`, `log2`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`, `hypot`, and `atan2`. Real domain crossings use the documented MPC promotion rules. Real `log2` uses MPFR directly; complex `log2` uses the gmpfrxx `mpfrxx::log2` MPC compatibility wrapper at the stored operation precision and does not require a direct `mpc_log2` symbol. The supported MPFR-backed special family is `gamma`, `gammaln`, `lgamma`, `erf`, and `erfc`. Poles, signed zeros, infinities, NaNs, and domain branches are tested explicitly. Other special-function families are deferred and rejected cleanly. ## Polynomial operations `poly`, `polyval`, `polyvalm`, `roots`, `conv`, `deconv`, `polyder`, `polyint`, and `compan` operate on arbitrary-precision coefficient or root data. Polynomial roots are conditioning-sensitive; clustered roots can move materially when precision changes. Use residuals such as `polyval (p, roots (p))` and not only elementwise root matching. p = mp ({"1", "-3", "2"}); r = roots (p); residual = norm (polyval (p, r)); disp (residual); `polyfit` and `polyeig` remain deferred. ## Set operations `unique`, `union`, `intersect`, `setdiff`, `setxor`, and `ismember` support the documented dense real/complex forms, including stable and row options where implemented. Equality and ordering use native values; NaN membership follows the documented Octave compatibility rule. `ismembertol` is deferred. ## Serialization and save/load The `saveobj` and `loadobj` hooks use schema `octave-mplapack-mp`, version 1. The schema records kind, shape, stored precision, and canonical text elements in column-major order. It preserves finite values, signed zero, infinity, NaN classification, and complex components without raw pointers or MPFR limb dumps. mpbits (1024); A = mp ({"1.234567890123456789", "-0"; "Inf", "NaN"}); save ("/tmp/mp-example.mat", "A"); clear A; load ("/tmp/mp-example.mat"); disp (A); The package must be loaded before loading an `mp` object. Malformed or newer schemas are rejected rather than guessed. ## Graphics `plot`, `plot3`, `loglog`, `semilogx`, `semilogy`, `scatter`, `scatter3`, `stem`, `stairs`, `mesh`, `surf`, `contour3`, `meshc`, `surfc`, and `waterfall` are boundary wrappers. They explicitly convert only final visualization data to builtin `double`; all numerical calculation before plotting remains MPFR/MPC. This is the documented exception to the no-binary64-fallback rule. t = linspace (mp ("0"), mp ("6.283185307179586476925286766559"), 32); y = sin (t); plot (double (t), double (y)); For a package `mp` graphics call, the wrapper performs the conversion. For values outside the binary64 range, transform or scale in `mp` before the graphics boundary. N-D and volume graphics, and `meshgrid` for `mp`, are deferred. ## Arbitrary-precision random numbers `mprand`, `mprandn`, and `mprandi` use the package’s `xorshift128plus-v1` engine and generate p-bit values directly. They are not cryptographic. `mprng` controls the seed and serializable state. Fixed seed/state is required for reproducibility. mprng ("seed", uint64 (7)); u1 = mprand (2, 1); mprng ("seed", uint64 (7)); u2 = mprand (2, 1); assert (isequal (u1, u2)); ## Interpolation `interp1` and `interp2` use MPFR/MPC grids, query points, and piecewise-polynomial values. `pchip`, `spline`, `mkpp`, `unmkpp`, `ppval`, `ppder`, and `ppint` operate on the supported scalar/vector piecewise-polynomial contract. Query-grid precision matters: a query that collapses to a double grid point may remain distinct at MPFR precision. Extrapolation is explicit. `interp3`, `interpn`, and matrix-valued PP output are deferred. ## Nonlinear equations `fzero` accepts a scalar start or sign-changing bracket; `fsolve` accepts real scalar/vector starts. Callbacks receive `mp` values and must return `mp` values. `TolX`, `TolFun`, finite-difference steps, and stopping checks are precision-aware. Complex nonlinear callbacks are deferred. mpbits (512); target = mp ("1.25"); [root, fval, info] = fzero (@(x) x*x - target*target, mp ({"0", "2"})); assert (info == 1); assert (abs (root - target) < mp ("1e-40")); ## Numerical integration `integral` and `quadgk` use MP nodes, weights, transforms, and error estimates. Scalar callbacks may return real or complex `mp`; builtin double and array-valued callback results are rejected. Finite and infinite intervals, waypoints, and precision-aware absolute/relative tolerances are supported. `ArrayValued` remains deferred. options = struct ("AbsTol", mp ("1e-40"), "RelTol", mp ("1e-40")); [value, err] = integral (@(x) x*x, mp ("0"), mp ("1"), options); assert (abs (value - mp ("1")/mp ("3")) < mp ("1e-35")); ## Optimization `fminbnd` uses an MPFR safeguarded golden-section search and `fminsearch` uses an MPFR Nelder–Mead simplex. Objective callbacks must return finite real `mp` scalars. `TolX`, `TolFun`, iteration limits, and evaluation limits are precision-aware. `fminunc` remains deferred. ## Performance notes Higher precision increases scalar arithmetic cost and can increase workspace and serialization size. Dense algorithm dimension scaling remains that of the selected algorithm. MPLAPACK-backed calls and package-owned MPFR/MPC algorithms have different constant factors. RNG generation cost grows with requested precision. Graphics deliberately loses arbitrary precision at the final display boundary. ## Octave compatibility The supported surface follows ordinary Octave syntax where the dense two-dimensional `mp` contract permits it. The authoritative compatibility boundaries are `docs/octave-script-compatibility.md` and `docs/advanced-numerics-compatibility.md`. Unsupported calls involving `mp` fail through package-owned diagnostics rather than silently delegating to builtin binary64 implementations. For exact supported forms, consult `docs/public-api-inventory.md`. The public package name is `mplapack-interop`; the public numeric class is `mp`. Native `__mplapack_core__` operations are implementation details and are not user API. ## Deferred and unsupported functionality The following are intentionally deferred: optional Schur/QZ ordering helpers, `funm`, `polyfit`, `polyeig`, `ismembertol`, remaining special-function families, `meshgrid` for `mp`, volume/N-D graphics, matrix-valued PP output, `interp3`, `interpn`, complex nonlinear callbacks, `ArrayValued` quadrature, and `fminunc`. Sparse, symbolic, N-D, and unrelated ODE/PDE surfaces are also outside the current contract. Each deferred item has a re-entry record under `docs/todo/`; a missing form must not be implemented by a builtin-double fallback. These limitations are part of the release documentation, not hidden omissions. ## Troubleshooting `pkg load` fails Confirm the package is installed, the package name is `mplapack-interop`, and Octave’s package directory is on its path. MPLAPACK runtime is not found Check `pkg-config --modversion mplapack_mpfr`, the installed library search path, and the runtime environment used to start Octave. Do not add a developer source directory as a workaround. Precision unexpectedly looks low Construct from decimal text, set `mpbits` before construction, and remember that changing the default cannot restore information lost by a previous binary64 constructor. Version or dependency mismatch Use `mplapack_version ()` and `pkg-config`. The 0.5.1 maintenance stack records MPLAPACK 3.0.1 and gmpfrxx_mkII 1.5.0. If `pkg-config --cflags --libs mplapack_mpfr` fails because the host lacks `mpc.pc`, use the local installer or apply its downstream metadata normalization; do not add a fake `mpc.pc`. Graphics overflow or underflow Perform scaling or logarithms in `mp`, then explicitly convert the final display data. Callback or serialization error Return `mp` from nonlinear/integration/optimization callbacks and load the package before restoring an `mp` object. Check schema version and stored precision. ## API quick reference The following entries make every public name searchable. Related functions share a short example in the preceding task chapter and have individual help text in the corresponding Octave method/function file. The inventory is the machine-auditable coverage matrix. **Construction and inspection** `mp`, `mpbits`, `mpdigits`, `mplapack_version`, `properties`, `char`, `disp`, `double`, `real`, `imag`, `conj`, `isreal`, `isnumeric`, `isnan`, `isinf`, `isfinite`, `isequal`, `isequaln`. **Arithmetic** `plus`, `minus`, `times`, `rdivide`, `uplus`, `uminus`, `mtimes`, `mldivide`, `mrdivide`, `power`, `mpower`, `abs`, `arg`, `angle`, `sign`. **Dense structure and indexing** `size`, `rows`, `columns`, `numel`, `ndims`, `length`, `isempty`, `subsref`, `subsasgn`, `end`, `reshape`, `transpose`, `ctranspose`, `horzcat`, `vertcat`, `cat`, `diag`, `triu`, `tril`, `repmat`, `flip`, `fliplr`, `flipud`, `rot90`, `zeros`, `ones`, `eye`, `nan`, `NaN`, `inf`, `Inf`. **Logical operations and reductions** `eq`, `ne`, `lt`, `le`, `gt`, `ge`, `logical`, `and`, `or`, `xor`, `not`, `any`, `all`, `find`, `sum`, `prod`, `cumsum`, `cumprod`, `sumsq`, `min`, `max`, `mean`, `median`, `var`, `std`, `range`, `bounds`, `sort`, `diff`, `signbit`, `floor`, `ceil`, `fix`, `round`, `rem`, `mod`, `hypot`, `atan2`, `eps`, `colon`, `linspace`, `logspace`. **Factorizations and conditioning** `chol`, `qr`, `lu`, `norm`, `det`, `inv`, `rank`, `cond`, `rcond`, `svd`, `pinv`, `null`, `orth`, `rref`. **Eigenproblems and matrix functions** `eig`, `hess`, `balance`, `schur`, `qz`, `kron`, `expm`, `logm`, `sqrtm`. **Elementary and special functions** `sqrt`, `cbrt`, `exp`, `expm1`, `log`, `log1p`, `log10`, `log2`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`, `gamma`, `gammaln`, `lgamma`, `erf`, `erfc`. **Polynomials and sets** `poly`, `polyval`, `polyvalm`, `roots`, `conv`, `deconv`, `polyder`, `polyint`, `compan`, `unique`, `union`, `intersect`, `setdiff`, `setxor`, `ismember`. **Serialization, random numbers, interpolation, solvers, and optimization** `saveobj`, `loadobj`, `mprand`, `mprandn`, `mprandi`, `mprng`, `interp1`, `interp2`, `pchip`, `spline`, `ppval`, `mkpp`, `unmkpp`, `ppder`, `ppint`, `fzero`, `fsolve`, `integral`, `quadgk`, `fminbnd`, `fminsearch`. **Graphics boundary** `plot`, `plot3`, `loglog`, `semilogx`, `semilogy`, `scatter`, `scatter3`, `stem`, `stairs`, `mesh`, `surf`, `contour3`, `meshc`, `surfc`, `waterfall`. **See also** `docs/public-api-inventory.md`, `docs/advanced-numerics-compatibility.md`, `docs/precision-semantics.md`, and the per-topic documents in `docs/`. mplapack-interop-0.5.1/docs/rng.md0000644000230300031750000000474015274353473016311 0ustar rafaelrafael# Arbitrary-precision random generation The package exposes `mprand`, `mprandn`, `mprandi`, and `mprng`. These are numerical pseudo-random generators, not cryptographic random sources, and do not replace Octave's builtin `rand`/`randn` state. ## Engine and state The engine identifier is `xorshift128plus-v1`. Its state is two unsigned 64-bit words and its transition is the explicitly specified xorshift128+ transition: ```text x = s0; y = s1 s0 = y x = x xor (x << 23) s1 = x xor y xor (x >> 17) xor (y >> 26) output = s1 + y ``` All operations are modulo 2^64. A seed is expanded into the two-word state with the fixed SplitMix64 expansion used by the native implementation. The all-zero state is rejected. The public state schema is: ```octave struct ("algorithm", "xorshift128plus-v1", ... "version", uint64 (1), ... "state", uint64 ([s0, s1])) ``` `mprng("state")` reads the state, `mprng("state", s)` restores a validated state, `mprng("seed", seed)` selects a deterministic seed, and `mprng("reset")` selects seed zero. The state is ordinary serializable Octave data, so T07 save/load can persist it without embedding native addresses or implementation-specific object data. ## Distribution contracts `mprand` consumes raw engine words to form a p-bit integer `k` and returns the exact MPFR value `k / 2^p`. Therefore the endpoint is `[0,1)`, zero is allowed, one is impossible, and no binary64 value is used in generation. The output precision is the current `mpbits()` default at the operation boundary. `mprandi` uses rejection sampling for the inclusive integer interval `[imin, imax]`; it never uses biased modulo reduction. Bounds are finite exact integer `mp` scalars (ordinary integer scalars are converted to `mp` at the current default precision), and results are exact MPFR integers. The supported dimension forms are scalar, one dimension, a two-element dimension vector, or two dimensions as documented by the function help. `mprandn` uses the Box–Muller transform. Uniform samples, logarithm, square root, π, trigonometric evaluation, and the result are all computed with MPFR at the operation precision. A zero first uniform sample is discarded and a new raw sample is consumed. No builtin `randn` or floating distribution is used. The implementation defines deterministic numerical sequences, not a security property. The fixed-seed sequence is tested in `test/t09_random.tst`; broad mean/second-moment and small-range frequency checks are sanity checks only. mplapack-interop-0.5.1/docs/complex-api.md0000644000230300031750000001352615274353473017743 0ustar rafaelrafael# Complex `mp` API This is the C00–C12 implementation inventory carried by the 0.3.1 package; the N00-N08 additions complete the current release surface. Release identity and dependency provenance are maintained in `docs/dependency-release-stack-r1.md` and the D02 freeze report. ## Values and construction `mp` has one public class with separate real MPFR and complex MPC payload kinds. Complex scalars and dense two-dimensional matrices are supported. - `mp (complex_double_scalar_or_matrix)` transfers the already-rounded binary64 real and imaginary components into MPFR/MPC storage; - `mp (real_text, imag_text)` constructs one complex scalar directly from two decimal strings, without a binary64 intermediate; - `mp ("(real,imag)")` accepts the canonical single-string complex scalar form; - `mp (existing_mp)` preserves the existing value and stored precision; - complex values are immutable at the public boundary and retain their two-dimensional shape; - `char`, `double`, and `disp` are explicit conversions/inspection, with `double` being the only intentional binary64 conversion. Real and complex payloads use the stored precision of their source. Every complex numerical operation chooses one `p_op`, promotes real MP values to MPC at that precision when needed, enters one MPFR/MPC scope, and returns uniform-precision operation-owned storage. Ambient precision does not change an existing value or override `p_op`. ## Supported forms | Area | Supported complex forms | Result/backend | |---|---|---| | inspection | `size`, `rows`, `columns`, `numel`, `ndims`, `isempty`, scalar `char`, `disp` | native metadata/text | | structure | `real`, `imag`, `conj`, transpose, ctranspose, 2-D `reshape` | MPC/native MPFR | | indexing | scalar, row/column, linear, two-dimensional dense indexing | operation-owned MPC | | logical/indexing | `==`, `~=`, `logical`, `&`, `|`, `xor`, `~`, `any`, `all`, `find`, logical masks | native MPC truth/equality; builtin logical/index outputs | | assignment | in-bounds dense assignment from complex/real `mp` or double, including logical masks | value-semantic MPC promotion | | arithmetic | `+`, `-`, `.*`, `./`, unary signs | MPC element-wise path | | multiplication | `*` for scalar/matrix and mixed real/complex dense operands | MPLAPACK `Cgemm` | | square solve | `A \ B` | MPLAPACK `Cgesv` | | rectangular solve | full-rank/rank-revealing `A \ B` | MPLAPACK `Cgelsy` | | right division | dense `A / B`, including rank-deficient `B` | conjugate-transpose `Cgelsy`/`Cgesv` path | | Cholesky | `chol(A)`, `chol(A,"upper"/"lower")`, optional status | MPLAPACK `Cpotrf` | | QR | one/two-output full/economy `qr` | `Cgeqrf`/`Cungqr` | | pivoted QR | three-output matrix/vector/deprecated economy forms | `Cgeqp3`/`Cungqr` | | LU | packed, two-output, matrix/vector permutation forms | MPLAPACK `Cgetrf` | | norms | vector 0/1/2/Inf/-Inf/Fro and positive finite p; matrix 1/2/Inf/Fro | MPFR/MPC native norms and `Cgesvd` | | determinant | dense real/complex one-output `det(A)` | `Rgetrf`/`Cgetrf` and MPFR/MPC diagonal product | | inverse | dense real/complex `inv(A)` | `Rgetrf`/`Rgetri` or `Cgetrf`/`Cgetri` | | SVD | one-output values and full/economy `[U,S,V]=svd(A)` | `Rgesvd`/`Cgesvd` | | rank | `rank(A)` and `rank(A,tol)` | MPFR/MPC singular values | | condition | `cond(A)`, `cond(A,1)`, `cond(A,2)`, `cond(A,Inf)`, `cond(A,"fro")` | `Rgecon`/`Cgecon` or singular values | | reciprocal condition | `rcond(A)` | `Rgecon`/`Cgecon` 1-norm estimator | | structured eig | `eig(A)` for real symmetric or complex Hermitian input; matrix/vector outputs | `Rsyevd`/`Cheevd` | | general eig | standard real/complex `eig`, matrix/vector/balance/nobalance forms, and `[V,D,W]` | `Rgeevx`/`Cgeevx` | | generalized eig | `eig(A,B)` with `matrix`/`vector`, `chol`/`qz`, and `[V,D,W]` forms | `Rsygvd`/`Chegvd` or `Rggev`/`Cggev` | | elementary | `log2(mp_complex)` and the audited scalar/element-wise family | gmpfrxx `mpfrxx::log2` over MPC; stored `p_op` | | mixed structural | horizontal/vertical concat; real/complex assignment | MPC destination at max stored precision | For LU, one output is the packed factor. Two outputs return `A=L*U`; three outputs return builtin real `P` with `P*A=L*U`; `lu(A,"vector")` returns a builtin real column `p` with `A(p,:)=L*U`. Square, rectangular, empty, and singular factors are supported. Singular `Cgetrf INFO` is retained by the native result and partial factors are returned, matching real M21 public behavior; the public wrapper has no separate LU status output. Permutation matrices, permutation vectors, and other structural outputs are builtin real values. Real-only operands remain on the real MPFR `R*` paths; they are never routed through complex kernels. ## Precision and ownership contract The complex backend accepts `mpc_class` arrays only when both components have the same operation precision. Destructive `Cgesv`, `Cpotrf`, QR, and `Cgetrf` calls receive operation-owned copies. There is no silent builtin binary64 complex fallback. Explicit `double(...)` conversion is outside this numerical contract. N05 adds general standard `eig`. Real nonsymmetric inputs and complex non-Hermitian inputs return complex `mp` eigenvalues and eigenvectors through `Rgeevx`/`Cgeevx`; `eig(A,"balance")` and `eig(A,"nobalance")` select the expert-driver balance mode. Three outputs return right vectors, a complex diagonal matrix, and left vectors satisfying `W'*A = D*W'`. Generalized `eig(A,B)` is added by N06: exactly symmetric/Hermitian pairs use the definite `Rsygvd`/`Chegvd` path unless `"qz"` is forced, while other pairs use `Rggev`/`Cggev`. The returned values satisfy `A*V = B*V*D` and `W'*A = D*W'*B`; singular `B` preserves infinite eigenvalues. Real generalized QZ results remain complex `mp` values so conjugate pairs and the `alpha/beta` representation are not lost. Mixed real/complex pairs are promoted once to MPC at the maximum stored precision. mplapack-interop-0.5.1/docs/v0.1-api.md0000644000230300031750000002044215274353473016753 0ustar rafaelrafael# octave-mplapack v0.1.0 real API This is the authoritative inventory for the frozen `0.1.0` release candidate. The tested baseline is GNU Octave 11.1.0 and the numerical backend is the installed MPLAPACK MPFR library. The public class is `mp`; v0.1 is dense and real only. ## Construction and precision `mp(x)` accepts real scalars and dense two-dimensional real matrices. Decimal text is parsed directly by MPFR (`mp("0.1")`), while a real double is converted from its already-rounded binary64 value (`mp(0.1)`). Cell arrays of decimal strings are supported for matrix construction. A fresh process starts at 512 bits. `mpbits()` gets the project default, `mpbits(p)` sets it for future construction, and `mpdigits()`/`mpdigits(n)` provide the decimal-digit view. Existing values never change precision when the default changes. For supported arithmetic, two `mp` operands use `max(precision(lhs), precision(rhs))`; a mixed real double uses the `mp` operand precision. Every MPLAPACK invocation uses one uniform operation precision derived from its operands. No public operation consults `mpbits()` to widen an existing value. ## Supported operations | Area | Syntax | Result and backend | |---|---|---| | Inspection | `size`, `rows`, `columns`, `numel`, `ndims`, `isempty`, `end` | Builtin structural values | | Conversion | `char` (scalar), `double`, `disp` | Explicit MPFR conversion/formatting | | Indexing | `A(i,j)`, `A(:,j)`, `A(i,:)`, `A(I,J)`, `A(k)`, `A(:)` | Read-only dense indexing; general vector-linear indexing remains limited | | Assignment | Supported in-bounds scalar, row, column, submatrix and colon assignments | Immutable value-semantic deep copy | | Unary arithmetic | `+A`, `-A` | Direct MPFR | | Element-wise arithmetic | `A+B`, `A-B`, `A.*B`, `A./B` | Direct MPFR with supported singleton expansion | | Matrix multiplication | `A*B` | MPLAPACK MPFR `Rgemm` | | Left division | `A\B` | `Rgesv` for square; `Rgelss` for rectangular minimum-norm least squares | | Structure | `A.'`, `A'`, `reshape` | Precision-preserving native copies | | Concatenation | `[A,B]`, `[A;B]` | One contiguous dense `mp` value | | Cholesky | `chol(A)`, `chol(A,"upper")`, `chol(A,"lower")`, optional status | MPLAPACK `Rpotrf`; selected-triangle semantics | | QR | `qr(A)`, two-output full/economy forms, `"econ"`, numeric `0` alias | `Rgeqrf`/`Rorgqr`; one output is `R` | | Pivoted QR | Three-output forms, `"matrix"`, `"vector"`, `"econ"`, numeric `0` vector form | `Rgeqp3`/`Rorgqr`; P/p are builtin structural doubles | | LU | `lu(A)`, two/three-output forms, `[L,U,p]=lu(A,"vector")` | MPLAPACK `Rgetrf`, including rectangular and singular factors | The factorization pages explain exact shapes, status behavior, and reconstruction relations: [`cholesky.md`](cholesky.md), [`qr.md`](qr.md), [`pivoted-qr.md`](pivoted-qr.md), and [`lu.md`](lu.md). ## Feature matrix | Feature | Real scalar | Real matrix | Mixed double | Precision-preserving | Backend | Status | |---|---:|---:|---:|---:|---|---| | `+ - .* ./` | yes | yes | yes | yes | MPFR | supported | | `*` | yes | yes | yes | yes | `Rgemm` | supported | | `\` | yes | yes | yes | yes | `Rgesv`/`Rgelss` | supported | | `chol` | yes | yes | n/a | yes | `Rpotrf` | supported | | non-pivoted `qr` | yes | yes | n/a | yes | `Rgeqrf`/`Rorgqr` | supported | | pivoted `qr` | yes | yes | n/a | yes | `Rgeqp3`/`Rorgqr` | supported | | `lu` | yes | yes | n/a | yes | `Rgetrf` | supported | | complex | no | no | no | n/a | future complex series | deferred | | sparse | no | no | no | n/a | future | unsupported | ## Unsupported v0.1 surface Complex values, sparse values, N-D arrays, matrix `char`, comparisons and logical operators, matrix power, reductions, and general transcendental functions are not implemented. Matrix growth, deletion assignment, logical assignment, and the still-limited forms of vector-linear indexing are intentional boundaries. `det`, `inv`, `rank`, `cond`, `norm`, `eig`, and `svd` are not public APIs. `qr(A,B)`, QR update functions, LU updates, automatic SPD solve optimization, sparse LU/QR/Cholesky forms, and complex factorizations are deferred. Unsupported operations fail rather than silently converting an `mp` value to binary64. ## Public-to-native map The public wrappers in `inst/@mp` dispatch to the private native module `__mplapack_core__.oct`. Major mappings are: | Public method | Native command/backend | |---|---| | `mp`, `mpbits`, `mpdigits` | scalar/matrix constructors and precision commands | | `+`, `-`, `.*`, `./`, unary signs | native MPFR scalar/matrix arithmetic | | `*` | `mtimes` -> `Rgemm` | | `\` | `mldivide` -> `Rgesv`/`Rgelss` | | `chol` | `chol` -> `Rpotrf` | | `qr` | `qr` -> `Rgeqrf`/`Rorgqr`; `qr_pivoted` -> `Rgeqp3`/`Rorgqr` | | `lu` | `lu` -> `Rgetrf` | | indexing/assignment/reshape/transpose/concat | corresponding private native structural commands | Commands named `scalar_test_*`, `matrix_test_*`, and `module_test_locked` are test-only and are not public APIs. ## Wrapper audit Every file in `inst/@mp` is accounted for below. The method wrappers are supported public entry points unless marked as an intentional guard. | Wrapper | Classification | |---|---| | `mp.m`, `mpbits.m`, `mpdigits.m` | supported construction/precision | | `char.m`, `double.m`, `disp.m` | supported scalar conversion/display (`char` matrix is guarded) | | `size.m`, `rows.m`, `columns.m`, `numel.m`, `ndims.m`, `isempty.m`, `end.m` | supported structural queries | | `subsref.m` | supported dense indexing with documented limits | | `subsasgn.m` | supported in-bounds value-semantic assignment with documented limits | | `plus.m`, `minus.m`, `times.m`, `rdivide.m`, `uplus.m`, `uminus.m` | supported arithmetic | | `mtimes.m`, `mldivide.m` | supported `Rgemm`/`Rgesv`/`Rgelss` paths | | `mrdivide.m` | intentional stable unsupported guard | | `transpose.m`, `ctranspose.m`, `reshape.m` | supported structure | | `horzcat.m`, `vertcat.m` | supported dense concatenation | | `chol.m`, `qr.m`, `lu.m` | supported real factorization APIs | The native bridge also contains explicitly test-only commands (the `*_test_*` family and `module_test_locked`) and diagnostics used by `mplapack_version`; these are not accidentally public functions. ## Error namespace New stable public guards use `mplapack:mp:` (for example `DimensionMismatch`, `NonSquareMatrix`, `InvalidOption`, `OutputCount`, and `NotPositiveDefinite`). Legacy `mplapack:NotImplemented` remains for the accepted right-division guard for compatibility with the existing test suite; it is not a recommendation for new code. Native bridge errors are internal diagnostics and are not part of the v0.1 programming interface. | Identifier | Public condition | v0.1 status | |---|---|---| | `mplapack:mp:InvalidInput` | wrong constructor or method arguments | stable | | `mplapack:mp:DimensionMismatch` | incompatible arithmetic/assignment dimensions | stable | | `mplapack:mp:InvalidDimension` | invalid `size`/`reshape` dimension | stable | | `mplapack:mp:IndexingUnsupported` | unsupported indexing or growth/deletion | stable | | `mplapack:mp:AssignmentUnsupported` | unsupported assignment form | stable | | `mplapack:mp:InvalidOption` | invalid factorization option | stable | | `mplapack:mp:OutputCount` | unsupported number of outputs | stable | | `mplapack:mp:NonSquareMatrix` | square-only operation receives rectangular input | stable | | `mplapack:mp:NotPositiveDefinite` | one-output Cholesky failure | stable | | `mplapack:mp:ComplexUnsupported` / `MatrixUnsupported` | outside real dense scope | stable | | `mplapack:NotImplemented` | legacy `mrdivide` guard | compatibility exception | Low-level `mplapack:InvalidNativeValue`, `NativeError`, and conversion diagnostics remain internal bridge failures. `mpbits:*` and `mpdigits:*` are the established precision-command validation namespace. ## Release scope `0.1.0` is the frozen upstream version for the release candidate identified in the repository-only `v0.1-release-manifest.md`; M23 does not create the final Git tag or publish a PPA. The package is built against the installed MPLAPACK MPFR dependency discovered with `pkg-config`, including the uniform-precision scope interface described in [`precision-semantics.md`](precision-semantics.md). See [`octave-compatibility.md`](octave-compatibility.md) for tested intentional differences and [`ppa-plan.md`](ppa-plan.md) for the planned Ubuntu delivery. mplapack-interop-0.5.1/docs/determinant-inverse.md0000644000230300031750000000273215274353473021505 0ustar rafaelrafael# Determinant and inverse `mplapack-interop` N01 provides dense arbitrary-precision `det` and `inv` for real and complex `mp` values. ## Determinant Real determinants use MPLAPACK `Rgetrf`; complex determinants use `Cgetrf`. The operation owns the LU copy, counts the row-swap parity, and multiplies the diagonal of U at the stored operand precision. A singular factorization returns an exact MPFR/MPC zero. The empty 0-by-0 determinant is one, while nonsquare inputs are rejected. Only the one-output form is implemented in N01. A possible reciprocal condition output is intentionally deferred until the N03 condition-number machinery is complete. ## Inverse Real inverses use `Rgetrf` followed by an `Rgetri` workspace query and the final `Rgetri` call. Complex inverses use the corresponding `Cgetrf` and `Cgetri` path. Query and execution use the operation-owned factor copy, uniform MPFR/MPC precision scopes, checked workspace sizes, and explicit INFO validation. Singular and nonsquare inputs produce package diagnostics. No path converts an input to binary64, and `inv` does not replace the existing `A\b` solve operation with an explicit inverse. ## Precision and value semantics The operation precision is the stored operand precision. Ambient `mpbits` changes do not change an existing matrix's precision. Inputs remain unchanged after determinant, inverse, singular, and workspace-query paths. Real inputs remain on real MPLAPACK kernels; complex inputs remain on MPC kernels. mplapack-interop-0.5.1/docs/octave-compatibility.md0000644000230300031750000000435615274353473021656 0ustar rafaelrafael# Octave compatibility The public package identity is `mplapack-interop`. The repository remains `octave-mplapack`, and the numeric class/API names remain `mp`, `mpbits`, and `mpdigits`. C12 validates the real and complex public surface with GNU Octave 11.1.0. The normal Octave syntax is used for supported operations and the `mp` class keeps immutable native storage. Existing values retain their stored precision; `mpbits` is a construction default, not an operation-wide override. The historical v0.1 real-only release notes remain in `v0.1-api.md`. Supported syntax includes scalar and dense two-dimensional real or complex construction, indexing and in-bounds assignment, arithmetic, mixed real/ complex `*`, `\`, and `/`, `chol`, full/economy QR (including documented pivoted three-output forms), LU, `norm`, `det`, `inv`, `svd`, `rank`, `cond`, `rcond`, structured/general standard `eig` (including balance controls and three-output left eigenvectors), dense generalized `eig(A,B)` with `chol`/`qz` and `matrix`/`vector` forms, transpose, reshape, and concatenation. Factorization and norm methods use the selected MPLAPACK MPFR/MPC backend and copy destructive inputs. S02 adds native reductions and extrema: `sum`, `prod`, `sumsq`, `cumsum`, `cumprod`, `min`, and `max`, including dimensions, `"all"` where applicable, NaN flags, cumulative direction, first-value indices, and supported complex comparison methods. Intentional differences are no sparse or N-D values, no matrix `char`, limited vector-linear indexing, no growth or deletion assignment, no comparisons/logical operators, no generalized balance options, or update APIs. Three-output sparse permutation forms and `qr(A,B)` are not provided. Unsupported matrix functions are expected to fail cleanly. M22's compatibility firewall checks comparison calls for the absence of implicit binary64 fallback, crashes, and recursion. S01 closes dense element-wise power and the native MPFR/MPC elementary function family. Domain crossings are represented as complex `mp` values at the operation precision. The package does not promise identical error text to builtin Octave. It does promise matching error-versus-success behavior for audited forms and stable project-owned identifiers for public validation guards. mplapack-interop-0.5.1/docs/complex-architecture.md0000644000230300031750000003315515274353473021654 0ustar rafaelrafael# Complex MPFR architecture freeze M20 is an audit and design freeze, not a complex implementation. The public `mp` class remains real-only through M19. This document records the boundary that future C00--C12 work must preserve. ## Evidence from the pinned MPLAPACK installation The controlled installation was discovered with `pkg-config mplapack_mpfr` and corresponds to MPLAPACK commit `1cf03d1a1aa2afecde5f1840fbe9663ecfc31e57` (version 3.0.1). With `MPLAPACK_BUILD_WITH_MPFR`, `mplapack.h` defines: ```cpp using REAL = mpfrxx::mpfr_class; using COMPLEX = mpfrxx::mpc_class; ``` The exact complex type is `mpfrxx::mpc_class`, declared by the installed `gmpfrxx_mkII/detail/mpc_impl.hpp` and included by `mpcxx_mkII.h`. It owns an MPC `mpc_t value_`; the real and imaginary components are MPFR values. The class supplies `with_precision(p)`, `with_precision(real_p, imag_p)`, `real_precision()`, `imag_precision()`, `precision()`, `real()`, `imag()`, and `mpc_data()`. Copy construction preserves both component precisions; move construction swaps initialized MPC values. The installed header also asserts that `sizeof(mpc_class) == sizeof(mpc_t)` and that their alignments match, making a contiguous `std::vector` ABI-compatible with an MPLAPACK `mpc_class *` argument. The test-only `test/m20_complex_probe.cc` compiled against the installed headers and controlled library. It passed 1024-bit and 2048-bit complex GEMM identity cases with `2^-700` and `2^-1500` component tails, one-by-one Cgesv, Cpotrf, Cgeqrf, and Cungqr calls, component-precision checks, and a worker thread isolation check. The special-value probe preserves signed zero, Inf, and NaN component state through an `mpc_class` copy. The probe uses MPFR's documented negative-sign argument for negative zero. `ldd -r` resolved the controlled `libmplapack_mpfr.so.3`, `libmpc.so.3`, `libmpfr.so.6`, and `libgmp.so.10`; `libmplapack_mpfr_opt` was not linked. ## Frozen storage and precision model One future complex scalar has exactly one project precision `p`: ```text real precision = p imag precision = p ``` Although `mpc_class::with_precision(real_p, imag_p)` can construct a mixed backend value, mixed component precision is forbidden in a public `mp` object. A future `MpfrComplexMatrixStorage` will be one contiguous, column-major `std::vector` with one immutable precision field. Allocation will use explicit equal component precision (or a scoped default only where the backend requires it), and its data pointer will be passed directly as MPLAPACK `COMPLEX *`. Real matrices remain the existing `MpfrMatrixStorage` of `REAL` values; they are never widened to complex storage just because complex support exists. Every complex numerical invocation has one `p_op`. All COMPLEX arrays, REAL work arrays, tolerances, norms, singular values, and temporary values at the MPLAPACK boundary use `p_op`, and the executing worker establishes that precision. The project policy is round-to-nearest for both components. A future complex precision scope must compose the existing MPFR scope with the MPC default context, or use explicit `with_precision(p)` allocation throughout. The installed wrapper has thread-local MPC precision and rounding override state; when no override is active, defaults inherit the MPFR default. An explicit MPC override must therefore be controlled or rejected by future complex code so it cannot violate the one-precision contract. ## Public payload architecture There remains one public class, `mp`, with four checked native payload kinds: | Payload kind | Storage | Public result | |---|---|---| | real scalar | `MpfrScalarStorage` | real `mp` scalar | | real dense matrix | `MpfrMatrixStorage` | real `mp` matrix | | complex scalar | future MPC storage | complex `mp` scalar | | complex dense matrix | future `MpfrComplexMatrixStorage` | complex `mp` matrix | Native dispatch will use a small checked payload-kind/category enum and native type identity, never class-name strings or raw pointer handles. Public values remain immutable; destructive GEMM, solves, factorizations, and transformations always receive operation-owned deep copies. Clearing an input or an alias must never invalidate a result. For binary operations, any complex participant makes the result complex and `p_op` is the maximum stored precision of all `mp` participants. Real values promote by exact copy into the real component and an exact `+0` imaginary component at `p_op`. A complex builtin double promotes each incoming binary64 real and imaginary component directly with MPFR/MPC round-to-nearest; decimal text conversion is forbidden. There is no implicit complex-to-real demotion, even when all imaginary components happen to be zero. Explicit `real(z)`, `imag(z)`, and `abs(z)` are real-returning APIs and preserve the source precision; `conj(z)` is complex and preserves precision. ## Constructor, formatting, and structural design Future constructor work must distinguish real doubles, complex doubles, and arbitrary-precision text. The preferred unambiguous text API is an explicit pair of real and imaginary components (or a documented canonical grammar), not a loose parser that conflates `1e2i` and ordinary text. A future complex scalar `char` format must be locale-independent, round-trip-safe at source precision, and preserve signed zero, infinities, NaNs, and exponent spelling unambiguously. Matrix `char` remains a separate later decision. `A.'` is transpose only; `A'` is transpose plus conjugation. Real values retain the M12 behavior. Real/complex concatenation and assignment promote the complete result to complex storage at the maximum precision, while M14 value semantics still require a new result payload. Complex indexing returns complex scalars or matrices at source precision. Structural metadata and permutation/status outputs remain builtin Octave values, not complex `mp`. ## Backend inventory The installed MPFR library exports real and complex routines from the same `libmplapack_mpfr.so.3`. Exact declarations audited in `mplapack_mpfr.h` include: | Future operation | Installed MPFR routine/signature family | |---|---| | GEMM | `Cgemm(const char*, const char*, mplapackint, mplapackint, mplapackint, mpc_class, mpc_class*, mplapackint, mpc_class*, mplapackint, mpc_class, mpc_class*, mplapackint)` | | square solve | `Cgesv(mplapackint, mplapackint, mpc_class*, mplapackint, mplapackint*, mpc_class*, mplapackint, mplapackint&)` | | Cholesky | `Cpotrf(const char*, mplapackint, mpc_class*, mplapackint, mplapackint&)` | | QR | `Cgeqrf(...)` and `Cungqr(...)` with `mpc_class` work arrays | | pivoted QR | `Cgeqp3(...)` with `mplapackint* JPVT` and real `mpfr_class* RWORK` | | rectangular least squares | `Cgelss(...)`, `Cgelsy(...)`, and `Cgelsd(...)` with real singular-value/RWORK arrays | The exact full declarations remain the installed-header authority. The probe exercised Cgemm, Cgesv, Cpotrf, Cgeqrf, and Cungqr; future milestones must add numerical canaries for the remaining drivers before using them. At the pinned source, Cgemm is the reference loop implementation. Cgesv calls Cgetrf/Cgetrs; Cpotrf uses Cherk/Cpotrf2/Cgemm/Ctrsm; Cgeqrf and Cungqr use their blocked/unblocked reflector helpers; Cgeqp3 uses Cgeqrf, Cunmqr, Claqps/Claqp2, and RCnrm2; Cgelss/Cgelsy/Cgelsd use the corresponding QR/LQ, bidiagonal, SVD, and orthogonal-transform routines. A source search found no OpenMP, pthread, or `std::thread` regions in the pinned reference tree, and the controlled probe did not link the optimized MPLAPACK library. If a future optimized or worker path is enabled, every arithmetic worker must establish `p_op`; an unscoped path blocks complex release until upstream is audited. ## Future operation rules | Operation | Design rule | Future milestone | |---|---|---| | element-wise arithmetic | direct MPC operations into explicit `p_op` destinations | C04 | | GEMM | direct complex MPLAPACK `Cgemm`, never four real GEMMs | C05 | | square solve | operation-owned complex copies and `Cgesv` | C06 | | rectangular solve | rank-revealing complex candidate audit, minimum norm | C07 | | Hermitian Cholesky | selected triangle and conjugate-transpose semantics through `Cpotrf` | C08 | | QR | complex factor/generator routines identified from installed headers | C09 | | pivoted QR | complex `Cgeqp3`-equivalent after exact JPVT audit | C10 | Complex rank thresholds will derive from the real machine epsilon at `p_op`, never binary64 epsilon or a decimal constant. Permutation matrices/vectors remain builtin double structural outputs. Ordered complex comparisons are not assumed; equality/inequality and explicit real-valued reductions need a separate API decision. ## Packaging and licensing inventory The audited complex symbols are in the existing `libmplapack_mpfr.so.3`, so the current `octave-mplapack` package can gain complex support in a normal update without a package rename. The runtime closure already includes MPC, MPFR, and GMP; development packaging must continue to discover these through the MPLAPACK `pkg-config` metadata rather than copying libraries. The controlled installation linked no optimized MPLAPACK DSO. Project and MPLAPACK sources carry BSD-2-Clause-compatible terms (MPLAPACK's COPYING also records the upstream BLAS/LAPACK notices). The audited system dependencies are MPC under LGPL-3-or-later, MPFR under LGPL-3-or-later, and GMP under its GPL-2-or-later/LGPL-3-or-later dual terms. Their copyright and license metadata must be carried by Debian packaging rather than bundled by this repository. No ABI or SONAME split was found that would require `octave-mplapack-complex`. ## Decisions and rejected alternatives | Decision | Selected approach | Rejected alternatives | Reason | Evidence | Future milestone | |---|---|---|---|---|---| | complex scalar type | `mpfrxx::mpc_class` | project-local pair wrapper | direct installed backend type and ABI | installed header, static size/alignment assertions, probe | C00 | | complex matrix storage | contiguous `vector`, uniform `p` | scalar-wrapper arrays; split per-component public matrices | direct `COMPLEX*`, one matrix precision, immutable payload | type layout and vector probe | C00/C02 | | public class | one `mp` with four payload kinds | `cmp`/`mpc` public class | preserves Octave syntax and real compatibility | M02--M19 type architecture | C00 | | precision contract | one equal component precision and one `p_op` | mixed component precision; ambient default | uniform MPLAPACK contract | `with_precision` audit and probe | C01 | | real/complex promotion | complex result at max precision, exact zero imaginary part | implicit demotion or binary64 round trip | preserves represented values and type stability | M08--M16 policy plus backend API | C03/C11 | | binary64 complex conversion | direct component MPFR conversion | decimal text conversion | preserves incoming IEEE values | `mpc_class` constructors and real policy | C01 | | transpose | `.'` transpose, `'` conjugate transpose | treating both as transpose | Octave complex semantics | M12 dispatch and Octave contract | C03 | | complex GEMM | direct `Cgemm` | four real GEMMs; binary64 fallback | uses validated complex backend and keeps precision | installed symbol and Cgemm probe | C05 | | complex solve | direct `Cgesv` for square | normal equations or real decomposition | destructive operation-owned complex backend | installed symbol and Cgesv probe | C06 | | complex Cholesky | Hermitian selected-triangle `Cpotrf` | full symmetry precheck | follows dense `chol` selected-triangle semantics | installed symbol and M17 design | C08 | | complex QR | installed complex QR factor/generator pair | manual Householder loop | preserves MPLAPACK ownership of algorithms | Cgeqrf/Cungqr probe | C09 | | packaging | same `octave-mplapack` package update | separate complex package | same SONAME/dependency closure | `pkg-config`, `ldd`, `readelf` audit | PPA series | ## Open issues | Issue | Severity | Blocks PPA v0.1? | Blocks complex v0.2? | Proposed investigation | |---|---|---|---|---| | MPC thread-local override can diverge from MPFR scope | medium | no | yes | C00/C01 scope probe; explicitly set or reject overrides | | Exact complex text grammar and pretty display | medium | no | yes | C01/C02 Octave constructor/display audit | | Complex worker behavior in optimized MPLAPACK | high | no | yes | audit each enabled optimized DSO before C05 | | Complex rank-revealing driver precision/workspace | high | no | yes | C07 candidate comparison (`Cgelsy/Cgelss/Cgelsd`) | | Debian license metadata for system MPC/MPFR/GMP | low | no | no | P01 packaging review | | Complex special-value and ordered-comparison policy | medium | no | yes | C03/C04 Octave differential tests | ## Release decision and roadmap The complex audit found no representation, ABI, or dependency issue that blocks the real-only package. The explicit release decision is: ```text REAL-PPA-GO ``` Real-only PPA work can proceed independently; complex remains future work. ### Real/PPA sequence ```text M21 real LU factorization M22 real API/release closure M23 v0.1 feature freeze PPA1 MPLAPACK Debian packaging PPA2 octave-mplapack Debian packaging PPA3 Launchpad staging build PPA4 public real-only v0.1 PPA ``` ### Complex sequence ```text C00 complex scaffold / native storage C01 complex scalar constructor and conversion C02 complex dense matrix storage/indexing/display C03 real/imag/conj/transpose/ctranspose C04 complex element-wise arithmetic C05 complex GEMM C06 complex square solve C07 complex rank-revealing rectangular solve C08 Hermitian Cholesky C09 non-pivoted complex QR C10 pivoted complex QR C11 mixed real/complex closure C12 complex package/regression release ``` M20 deliberately does not begin either sequence. mplapack-interop-0.5.1/docs/milestones/0000755000230300031750000000000015274353473017356 5ustar rafaelrafaelmplapack-interop-0.5.1/docs/milestones/M20-complex-architecture.md0000644000230300031750000000516615274353473024373 0ustar rafaelrafael# Goal Audit and freeze the architecture for a future complex MPFR/MPLAPACK backend without adding public complex `mp` values. M20 is a design-only milestone; the accepted M00--M19 real implementation remains the production surface. # Scope - Inspect the pinned MPLAPACK MPFR complex scalar and routine interfaces. - Probe installed complex GEMM, solve, Cholesky, and QR entry points. - Define storage, precision, promotion, dispatch, and packaging decisions for a later complex implementation series. - Record open backend, ABI, threading, and packaging issues. # Non-goals - No public complex constructors, operators, matrices, or indexing. - No changes to real MPLAPACK calls or real public semantics. - No MPLAPACK source changes and no PPA build or publication. - No complex SVD, rank, solve, factorization, or display implementation. # Design constraints - Keep one public `mp` class with separate real and complex payload kinds. - Use the installed MPLAPACK MPFR complex scalar directly where its ABI is safe, with one explicit precision for both components of each object. - Preserve immutable public values and operation-owned destructive buffers. - Keep real storage and real backend calls unchanged; complex support must not route existing real operations through complex kernels. - Discover dependencies through `pkg-config`; do not hard-code install paths. - Any future numerical call will normalize every REAL and COMPLEX participant to one operation precision and establish that precision in every worker. # Implementation tasks - Add the test-only installed complex backend probe. - Audit headers, pinned source call chains, TLS/MPC state, and runtime linkage. - Add `docs/complex-architecture.md`, update the architecture/packaging and milestone indexes, and record the real-only release decision. - Run the M00--M19 regression and repository checks. # Required tests - Compile and run the installed complex probe at 1024 and 2048 bits, including GEMM tails, Cgesv, Cpotrf, Cgeqrf/Cungqr, component precision, and TLS scope restoration. - Verify independent worker-thread default precision. - Verify `ldd -r` resolves the controlled MPLAPACK MPFR dependency and that no optimized MPLAPACK DSO is accidentally linked. - Run `tools/check-tree.sh`, `tools/check-format.sh`, and the full local CI M00--M19 real regression. # Gate M20 passes only when G20-TYPE, G20-PRECISION, G20-PUBLIC, G20-BACKEND, G20-PACKAGING, G20-REAL-REGRESSION, and G20-RELEASE all pass. The expected release conclusion is `M20 PASS — REAL-PPA-GO`; public complex support remains future work. # Expected commit `M20: freeze complex architecture design` mplapack-interop-0.5.1/docs/milestones/C02-complex-matrix.md0000644000230300031750000000307415274353473023177 0ustar rafaelrafael# Goal Make dense complex matrices first-class public `mp` values. # Scope Support direct construction from builtin complex double matrices, contiguous uniform-precision native storage inspection, accepted one/two-dimensional indexing, value-semantic complex assignment, explicit complex-double matrix conversion, direct display, and empty matrix shapes. # Non-goals Complex arithmetic, transpose/conjugation, and complex LAPACK operations are deferred to C03-C11L. Exact complex text-cell construction is not introduced. # Design constraints Each dense matrix owns one native contiguous column-major payload. Indexing and assignment copy native MPC values directly at the source/result precision; they do not round-trip through text or binary64. Destructive mutation is performed on a new operation-owned matrix. # Implementation tasks - Add complex matrix constructors and native metadata. - Add complex matrix selection and scalar normalization. - Add complex matrix assignment with scalar/exact-shape/vector RHS rules. - Add complex matrix display and explicit `double` conversion. # Required tests Complex construction, column-major layout, precision preservation and promotion, scalar/slice/linear indexing, empty 0x0/0xN/Mx0 shapes, complex-to-complex assignment, deep value semantics, display, and the full real regression wall. # Gate `C02 PASS` requires G-C02-CONSTRUCT, G-C02-STORAGE, G-C02-INDEX, G-C02-ASSIGN, G-C02-DOUBLE, G-C02-DISP, G-C02-EMPTY, G-C02-LIFETIME, and G-C02-REAL-REGRESSION. # Expected commit `C02: add dense complex matrix inspection and assignment` mplapack-interop-0.5.1/docs/milestones/M16-rank-deficient-lstsq.md0000644000230300031750000000442115274353473024271 0ustar rafaelrafael# M16 — Rank-deficient rectangular `mp` solve # Goal Extend rectangular dense real `A \ B` to rank-deficient minimum-norm least-squares solutions through a validated rank-revealing MPLAPACK MPFR driver. # Scope Scalar and square dispatch remain unchanged. Every non-square 2-D dense real matrix uses `Rgelss` and supports overdetermined and underdetermined systems, multiple right-hand sides, mixed `mp`/double operands, precision-sensitive rank, and operation-owned LAPACK buffers. # Non-goals - Changing square `Rgesv` singular behavior - Public `rank`, singular-value, condition, or tolerance APIs - Normal equations, pseudoinverse, custom rank estimation, or home-grown QR/SVD - Complex, sparse, N-D, or other MPLAPACK backends # Design constraints The candidate audit selected `Rgelss`: the pinned `Rgelsy` implementation misclassified an exact rank-one 512-bit fixture, while `Rgelss` and `Rgelsd` passed. `Rgelss` receives uniformly `p_op`-precision operation-owned `A`, padded `B`, `RCOND`, singular values, and `WORK` under `MplapackMpfrPrecisionScope`. `RCOND` is `Rlamch_mpfr("E")` at `p_op`. Public inputs and all driver state remain immutable/private. # Implementation tasks - Audit installed `Rgelsy`, `Rgelss`, and `Rgelsd` signatures, source call chains, workspace, rank semantics, and threading. - Add checked `Rgelss` query/solve integration while retaining the M15 `Rgels` bridge for regression/reference tests. - Route only non-square public `mldivide` through `Rgelss`; preserve scalar and square `Rgesv` dispatch. - Add precision, rank, minimum-norm, mixed-input, lifecycle, sanitizer, and installed-package QA. # Required tests Run the controlled installed-driver comparison probe, exact rank-zero and rank-one minimum-norm fixtures, full-rank M15 parity, multiple RHS, the precision-dependent rank canary at 512/1024 bits, 1024/2048-bit tails, high ambient defaults, workspace checks, binary64 semantics, empty cases, and the complete M00–M15 regression suite. # Gate `G16-DRIVER-AUDIT`, `G16-UPSTREAM`, `G16-RANK`, `G16-MINNORM`, `G16-PRECISION`, `G16-WORKSPACE`, `G16-M15-PARITY`, `G16-PUBLIC`, `G16-IMMUTABILITY`, `G16-BINARY64`, `G16-INTEROP`, and `G16-ROBUSTNESS` all pass for M16. # Expected commit `M16: add rank-deficient rectangular mp least-squares solve` mplapack-interop-0.5.1/docs/milestones/C11L-complex-lu.md0000644000230300031750000000517615274353473022434 0ustar rafaelrafael# C11L — Mandatory Complex LU via `Cgetrf` ## Mission Implement the required complex LU milestone through MPLAPACK MPFR `Cgetrf`, with the same public semantics as real M21 and no incidental use of complex arithmetic for real-only inputs. ## Dependency audit The controlled MPLAPACK installation exposes: ```text void Cgetrf(mplapackint const m, mplapackint const n, mpc_class *a, mplapackint const lda, mplapackint *ipiv, mplapackint &info) ``` The declaration is in `mplapack_mpfr.h`; the tested reference implementation is `mplapack/reference/Cgetrf.cpp` at MPLAPACK commit `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d`. No new upstream fix was required by C11L. The MPFR precision-scope-header fix from the MPLAPACK development branch remains required. ## Semantics - one output returns the operation-owned packed `Cgetrf` factor; - two outputs return `L,U` with `A=L*U` after absorbing row swaps into `L`; - three outputs return builtin real `P` with `P*A=L*U`; - `"vector"` returns the builtin real column vector `p` with `A(p,:)=L*U`; - tall and wide matrices use `m×min(m,n)` and `min(m,n)×n` factors; - singular matrices return partial factors through the native gate and retain `INFO` without mutating the public input; - pivots are selected from the stored source precision, independent of the ambient default precision; - empty inputs normalize to the same empty `0×0` public factors as real M21. The implementation copies the public MPC matrix at `p_op`, enters one `MpfrMpcPrecisionScope`, validates the MPFR/MPC precision contract at the `Cgetrf` boundary, uses `mplapackint` pivots, and never routes the complex operation through builtin binary64 complex arithmetic. ## Gates `G-C11L-UPSTREAM`, `G-C11L-PACKED`, `G-C11L-TWO-OUTPUT`, `G-C11L-MATRIX-P`, `G-C11L-VECTOR-P`, `G-C11L-RECTANGULAR`, `G-C11L-SINGULAR`, `G-C11L-PIVOT-PRECISION`, `G-C11L-PRECISION`, `G-C11L-IMMUTABILITY`, `G-C11L-LIFETIME`, and `G-C11L-REAL-RGETRF-PARITY`: PASS. ## QA - native complex `Cgetrf` gate under ASan/UBSan/LSan: PASS; - square packed factors, canonical two-output factors, matrix/vector permutations, tall/wide shapes, singular partial factors, and empty shapes: PASS; - 1024-bit/`2^-700` and 2048-bit/`2^-1500` tails: PASS; - 512-bit versus 1024-bit precision-dependent pivot order: PASS; - ambient precision restoration, public-input immutability, and output lifetime: PASS; - complete native real+complex sanitizer wall: PASS; - complete public M01–M23 plus C01–C11L wall: PASS; - real M21 `Rgetrf` regression and permutation conventions: PASS. ## Result `C11L PASS` Implementation commit: `3bad050af108a6ca8739c97b91120e3053800ecc`. mplapack-interop-0.5.1/docs/milestones/P05-ppa-stable.md0000644000230300031750000000247415274353473022301 0ustar rafaelrafael# P05 — PPA stable # Goal Promote only staging packages that passed all required gates to the stable PPA. # Scope Publish to a confirmed archive conceptually named `ppa:/mplapack` while preserving source/build provenance. # Non-goals - Publishing an untested package - Rebuilding silently from different source for stable promotion - Assuming an unconfirmed Launchpad identity # Design constraints Stable publication must correspond exactly to reviewed source and staging gate evidence. Any required rebuild must be explicit, reproducible, and versioned; private signing-key management remains a user responsibility. # Implementation tasks - Verify all staging build and autopkgtest results. - Confirm the stable archive identity and permissions. - Copy or upload the exact approved source through a provenance-preserving Launchpad workflow. - Verify the published binaries and record promotion evidence. # Required tests Install from the stable archive, repeat package load and M10 functional smoke tests, and compare source versions and checksums with the approved provenance. # Gate `GP05` passes when stable publication is complete, functional, and provably derived from the approved source. This gate is planned and is not passed by M00. # Expected commit `P05: record stable PPA promotion` mplapack-interop-0.5.1/docs/milestones/P00-packaging-design.md0000644000230300031750000000275715274353473023443 0ustar rafaelrafael# P00 — Packaging design # Goal Define the Debian and Ubuntu package architecture for `octave-mplapack`. # Scope Separate MPLAPACK runtime/development packages from the `octave-mplapack` source and binary packages. Define Ubuntu 26.04 LTS as the first target and Ubuntu 24.04 LTS as the secondary target. # Non-goals - Creating Debian metadata or building packages - Creating a Launchpad archive - Uploading prebuilt local `.deb` files as a PPA workflow # Design constraints Prefer system GMP, MPFR, MPC, QD, and other dependencies where technically appropriate; do not bundle arbitrary copies into `octave-mplapack`. The initial numerical product remains MPFR-only. Launchpad PPAs build from source packages, and Ubuntu 24.04 compatibility must not block the initial Octave 11 design. # Implementation tasks - Map source, binary, runtime, development, and Octave package responsibilities. - Research available dependency packages for each target series. - Define source-package provenance and staging-to-stable flow. - Record versioning, transitions, and unsupported combinations. # Required tests Review the design against both target series, confirm that it starts from source packages, and validate that it neither vendors MPLAPACK nor assumes developer-specific installation paths. # Gate `GP00` passes when the package architecture and target policy are reviewed and actionable. This gate is planned and is not passed by M00. # Expected commit `P00: document Debian and Ubuntu packaging design` mplapack-interop-0.5.1/docs/milestones/C04-complex-elementwise.md0000644000230300031750000000213115274353473024207 0ustar rafaelrafael# C04 — Complex element-wise arithmetic ## Mission Add complex `+`, `-`, `.*`, `./`, unary `+`, and unary `-` with the accepted real M11 singleton-expansion model. ## Semantics - real/real results remain real; - any complex operand produces a complex result; - the operation precision is the maximum precision of participating `mp` operands; - builtin real and complex doubles are converted directly at the operation precision; - special values and division by zero are deterministic and non-crashing. The complex kernel uses direct MPC operations under an operation-local precision scope. Real-only operands remain on the existing MPFR path. ## Gate `G-C04-SCALAR`, `G-C04-MATRIX`, `G-C04-MIXED-KIND`, `G-C04-MIXED-PRECISION`, `G-C04-BROADCAST`, `G-C04-SPECIAL`, and `G-C04-REAL-REGRESSION`. ## Required QA Native ASan/UBSan/LSan coverage and public tests cover 128/512/1024/2048-bit precision, ambient precision, scalar and matrix broadcast, builtin complex mixing, special values, empty shapes, and the complete M01-M23 real wall. ## Expected commit `C04: add complex element-wise arithmetic` mplapack-interop-0.5.1/docs/milestones/N03-rank-condition.md0000644000230300031750000000267415274353473023166 0ustar rafaelrafael# N03 — rank / cond / rcond N03 completes dense arbitrary-precision numerical rank and condition-number inspection for real and complex `mp` matrices. ## Contract The public API is: ```octave rank(A) rank(A,tol) cond(A) cond(A,1) cond(A,2) cond(A,Inf) cond(A,"fro") rcond(A) [d,c] = det(A) ``` Rank uses MPFR/MPC singular values and a default threshold formed from `max(size(A))`, the largest singular value, and `Rlamch_mpfr("E")` at the operation precision. An explicit real MPFR tolerance is promoted as part of the same one-operation precision contract. `cond(A)` and `cond(A,2)` use `Rgesvd`/`Cgesvd`; `cond(A,"fro")` uses the singular values; and `cond(A,1)`, `cond(A,Inf)`, and `rcond(A)` use `Rgetrf`/`Rgecon` or `Cgetrf`/`Cgecon` on operation-owned copies. The determinant second output is the 1-norm reciprocal estimate. No explicit inverse or binary64 complex fallback is used. ## Gates ```text G-N03-RANK G-N03-RANK-PRECISION G-N03-COND2 G-N03-COND1 G-N03-CONDINF G-N03-CONDFRO G-N03-RCOND G-N03-SINGULAR G-N03-REAL G-N03-COMPLEX G-N03-PRECISION G-N03-REGRESSION ``` The native sanitizer test covers real and complex rank, all condition paths, singular and empty edges, and the 512/1024/2048-bit precision transition. The public wall covers the same API, determinant metadata, rectangular rank and 2-norm condition, input immutability, ambient precision, the complete M00–M23 real wall, C00–C12 including C11L, and clean archive/package QA. mplapack-interop-0.5.1/docs/milestones/P04-ppa-autopkgtest.md0000644000230300031750000000251615274353473023375 0ustar rafaelrafael# P04 — PPA autopkgtest # Goal Test the package actually installed from the staging PPA. # Scope Add package-level automated tests that load the installed Octave package, set 100 decimal digits, construct a system, and solve it with `A \ b`. # Non-goals - Running tests against the source checkout instead of the installed package - Stable promotion before all tests pass - Expanding the numerical API beyond M10 # Design constraints The minimum installed-package test is: ```octave pkg load mplapack mpdigits(100); A = mp({"1", "2"; "3", "4"}); b = mp({"1"; "2"}); x = A \ b; ``` Tests must resolve files from the installed binary package and exercise its native MPLAPACK MPFR path. # Implementation tasks - Add appropriate Debian autopkgtest metadata and installed-package commands. - Verify package origin and installed paths during the test. - Run the minimum solve and relevant regression checks. - Collect results for each staging series and architecture. # Required tests Run the minimum workflow from the installed package and verify a correct result, MPFR precision behavior, native linkage, and no source-tree contamination. # Gate `GP04` passes when installed staging packages pass autopkgtest on every required target. This gate is planned and is not passed by M00. # Expected commit `P04: add installed-package autopkgtests` mplapack-interop-0.5.1/docs/milestones/M22-real-release-closure.md0000644000230300031750000000272115274353473024253 0ustar rafaelrafael# Goal Close the documented real-only v0.1 API and prepare reproducible package and PPA handoff metadata without adding a numerical feature. # Scope API inventory, help and error audits, compatibility firewall, examples, developer workflow, dependency feature detection, package/archive QA, and release/PPA documentation. # Non-goals No new BLAS/LAPACK algorithm, complex support, sparse support, public `det`, `inv`, `rank`, `cond`, `norm`, `eig`, or `svd`, and no release tag or upload. # Design constraints The accepted M00-M21 real paths remain unchanged. Installed dependencies are discovered with `pkg-config`; unsupported operations must not fall back to binary64. M22 ends with a root-level `m22-report.md`. # Implementation tasks Publish the v0.1 API/limitations and compatibility pages, audit wrappers and native commands, add examples and a developer entrypoint, add an MPLAPACK interface probe, and write the PPA/release handoff checklist. # Required tests Run the dependency probe, release-closure smoke/firewall tests, clean build and package lifecycle, installed help/examples, full local CI, sanitizers, and the complete M00-M21 regression suite. # Gate M22 passes only when all G22 API, documentation, errors, package, dependency, developer UX, PPA handoff, metadata, firewall, and regression gates pass. # Expected commit Use reviewable commits for dependency audit, API/docs, examples/QA, and the final report. Do not begin M23 or complex implementation. mplapack-interop-0.5.1/docs/milestones/M03-constructors.md0000644000230300031750000000504615274353473023012 0ustar rafaelrafael# M03 — Public scalar constructor and wrapper # Goal Expose the M02 native scalar as a public `mp` value and support construction from scalar decimal text, scalar real double, and an existing scalar `mp`: ```octave mp("1.25") mp(1.25) mp(mp("1.25")) ``` # Scope Public class encapsulation, direct decimal parsing, exact preservation of incoming binary64 values, deterministic internal 128-bit default precision, scalar `1 x 1` dimensions, signed zero and special values, and clear rejection of invalid, complex, matrix, cell, empty, and concatenation inputs. # Non-goals - Arithmetic operations - Complex or MPC-valued construction - Treating double and decimal text inputs as equivalent - Public precision control - Conversion or numeric display - Dense, cell, numeric, or empty matrix construction # Design constraints String input must reach MPFR without an intermediate binary64 value. Double input must preserve the binary64 value Octave supplies. Construction must use the current project-owned default precision without mutating existing objects. The internal native type remains private. Dense `mp` matrices must not be represented as arrays or cells of scalar wrapper objects. M02 established that the dense representation is an M07 decision. The early roadmap's matrix constructor work is therefore deliberately moved to M07 rather than forcing a container design in M03. # Implementation tasks - Add a public classdef scalar wrapper with private native payload ownership. - Add separate scalar text and binary64 native construction paths. - Establish the reusable internal 128-bit default precision component. - Preserve signed zero, infinity, and NaN through supported constructor paths. - Reject complex, matrix, cell, empty, and concatenation inputs. - Keep conversion, arithmetic, indexing, and matrix representation absent. # Required tests Cover public class identity, private payload encapsulation, scalar dimensions, copy/container/function lifetime, invalid inputs, decimal parsing, exact binary64 conversion, signed zero, finite extremes, infinity, NaN, and package unload/shutdown safety. Demonstrate that `mp("0.1")` and `mp(0.1)` differ, while `mp("0.125")` and `mp(0.125)` agree. Prove concatenation does not create an object-array matrix. # Gate `G03` passes when the public scalar wrapper preserves M02 ownership, the two constructor paths obey the normative precision contract, scalar identity and dimensions are correct, matrix behavior remains absent, and installed-package QA passes. # Expected commit `M03: add public scalar mp constructors` mplapack-interop-0.5.1/docs/milestones/P03-ppa-staging.md0000644000230300031750000000253215274353473022454 0ustar rafaelrafael# P03 — PPA staging # Goal Publish a verified source package only to a staging PPA first. # Scope Define and execute publication to a confirmed archive conceptually named `ppa:/mplapack-staging`. # Non-goals - Stable PPA publication - Hard-coding an unconfirmed Launchpad identity - Automatically creating, replacing, exporting, or manipulating private GPG keys # Design constraints Launchpad builds from an uploaded signed source package. The process must document confirmed Launchpad account/team, PPA, signing-key registration, `dput` configuration, and required authorization without automating private-key management. # Implementation tasks - Confirm Launchpad identity, staging archive, permissions, and signing setup. - Prepare and sign the reviewed source upload using user-managed keys. - Upload to staging and monitor all requested builds. - Preserve source and build logs for later gates. # Required tests Confirm source acceptance, successful staging builds for requested targets, correct dependency resolution, installability, and traceability to the reviewed source package. # Gate `GP03` passes when the confirmed staging PPA contains successful, traceable builds from the approved source upload. This gate is planned and is not passed by M00. # Expected commit `P03: document staging PPA publication evidence` mplapack-interop-0.5.1/docs/milestones/P06-ubuntu-series-matrix.md0000644000230300031750000000261215274353473024360 0ustar rafaelrafael# P06 — Ubuntu series and architecture matrix # Goal Validate and maintain the explicitly approved Ubuntu series and architecture matrix. # Scope The initial desired matrix is: ```text Ubuntu 26.04 LTS amd64 arm64 Ubuntu 24.04 LTS amd64 arm64 ``` # Non-goals - Adding architectures merely because Launchpad can build them - Adding older Ubuntu releases without explicit review - Allowing the secondary target to compromise the Octave 11 design # Design constraints Ubuntu 26.04 LTS is primary and Ubuntu 24.04 LTS is secondary. Every matrix entry requires usable dependencies, successful source builds, installed-package tests, and an explicitly maintained support decision. # Implementation tasks - Confirm dependency availability for each matrix entry. - Enable only the reviewed Launchpad builds. - Collect build, install, and autopkgtest evidence for each entry. - Document exclusions and future series changes explicitly. # Required tests For every enabled series/architecture pair, verify source build, dependency resolution, package installation, native module loading, and the P04 functional test against the installed package. # Gate `GP06` passes when all four approved matrix entries have complete successful evidence or an explicitly reviewed scope revision. This gate is planned and is not passed by M00. # Expected commit `P06: validate Ubuntu series and architecture matrix` mplapack-interop-0.5.1/docs/milestones/M06-elementwise.md0000644000230300031750000000353615274353473022570 0ustar rafaelrafael# M06 — Element-wise arithmetic # Goal Implement `A + B`, `A - B`, `A .* B`, and `A ./ B` for real `mp` values. # Scope Scalar/scalar operation infrastructure, mixed precision, and deliberate division-by-zero behavior. Dense element-wise matrix operations are extended after M07 establishes matrix storage and shape. # Non-goals - Matrix operations, broadcasting, or scalar expansion - Matrix multiplication or linear solves - Complex arithmetic or another MPLAPACK backend # Design constraints Never calculate through ordinary Octave doubles. The initial mixed-precision rule is `max(lhs precision, rhs precision)`. M06 must not add matrix shape, broadcasting, or scalar-expansion behavior before M07. # Implementation tasks - Native real addition, subtraction, multiplication, division, and negation use direct MPFR operations with `MPFR_RNDN`. - `mp`/`mp` results use the greater operand precision. Mixed scalar binary64 operands are converted directly at the `mp` operand precision. - Division by zero, signed zeros, infinities, and NaNs follow verified MPFR behavior rather than project-specific exceptions. - Public results wrap independently owned internal payloads without invoking the public constructor or current default precision. # Required tests Automated Octave and standalone sanitizer tests cover exact scalar arithmetic, mixed precision, both mixed-binary64 operand orders, low-precision rounding, division by zero, signed zero, special values, lifetime, unsupported types and operators, and the matrix firewall. A standalone direct-MPFR reference test checks all production storage operations. # Gate `G06` passed when all four binary scalar operators and both unary signs obeyed documented native MPFR, precision, lifetime, and error semantics without creating a matrix representation. # Expected commit `M06: add scalar MPFR arithmetic` mplapack-interop-0.5.1/docs/milestones/N00-norm.md0000644000230300031750000000245315274353473021212 0ustar rafaelrafael# N00 — arbitrary-precision `norm` N00 completes the first reduction in the dense real+complex numerical API. It adds a public `@mp/norm` method while retaining the accepted MPFR/MPC one-operation/one-precision contract. ## Gate result ```text G-N00-API: PASS G-N00-REAL: PASS G-N00-COMPLEX: PASS G-N00-MATRIX: PASS G-N00-VECTOR: PASS G-N00-2NORM: PASS G-N00-PRECISION: PASS G-N00-SPECIAL: PASS G-N00-REGRESSION: PASS ``` Native tests cover real and complex vectors/matrices, standard norms, finite-vector p values, empty shapes, NaN/infinity, operation-owned SVD copies, 1024-bit/`2^-700` and 2048-bit/`2^-1500` values, and ambient precision independence. Public tests cover the same forms plus rejected matrix options and package-owned errors. Full real and C00-C12/C11L regression is rerun after the milestone. ## Backend `Rlange`/`Clange` provide standard matrix norms, `Rnrm2`/`RCnrm2` provide native vector 2-norms, and `Rgesvd`/`Cgesvd` provide singular-values-only matrix 2-norms. Complex absolute values use MPC/MPFR-native operations. ## Deferrals Induced matrix norms other than 1, 2, infinity, and Frobenius, matrix zero or negative finite p forms, row/column norm options, sparse inputs, and N-D inputs remain deferred. N02 reuses the private singular-value helper for the public SVD implementation. mplapack-interop-0.5.1/docs/milestones/N05-eig-general.md0000644000230300031750000000415215274353473022421 0ustar rafaelrafael# Goal Complete dense standard `eig` for general real and complex `mp` matrices and retain the structured symmetric/Hermitian dispatch from N04. # Scope Use MPLAPACK `Rgeevx` for general real input and `Cgeevx` for general complex input. Provide eigenvalue-only, matrix, vector, balance, nobalance, and three-output right/diagonal/left eigenvector forms. Keep generalized eig deferred to N06. # Non-goals Generalized eigenproblems, sparse or N-dimensional eig, binary64 fallback, new public arithmetic, and optimized complex worker support are outside N05. # Design constraints The input is never modified: every destructive `Rgeevx`/`Cgeevx` call receives an operation-owned copy. Each call establishes one MPFR or MPFR/MPC scope at the stored input precision, checks workspace queries and `INFO`, and returns uniform operation-owned `mp` storage. Real general eigenpairs are explicitly converted from LAPACK's conjugate-pair representation to complex `mp` columns; no builtin binary64 complex kernel is permitted. # Implementation tasks Add native real/complex general eig backends, exact structured-shape dispatch, public output and balance forms, permanent Grcar coverage, native/public precision and immutability tests, compatibility-firewall updates, release closure updates, and archive/sanitizer gates. # Required tests Cover real rotation and nonsymmetric matrices, complex non-Hermitian matrices, right and left residuals, matrix/vector/three-output forms, balance and nobalance, Grcar matrices, nearly repeated and nearly defective cases, badly scaled cases, input immutability, ambient precision, 1024-bit `2^-700`, 2048-bit `2^-1500`, generalized-eig rejection, native sanitizers, and the complete real/complex regression walls including C11L. # Gate ```text G-N05-BACKEND G-N05-REAL-GENERAL G-N05-COMPLEX-GENERAL G-N05-BALANCE G-N05-NOBALANCE G-N05-RIGHT-EIGENVECTORS G-N05-LEFT-EIGENVECTORS G-N05-GRCAR G-N05-NEAR-DEFECTIVE G-N05-PRECISION G-N05-REGRESSION ``` # Expected commit The implementation, tests, documentation, report, status, and regression gates are committed and pushed only after the complete N05 wall passes. mplapack-interop-0.5.1/docs/milestones/C06-complex-square-solve.md0000644000230300031750000000333115274353473024321 0ustar rafaelrafael# C06 — Complex square solve via `Cgesv` ## Mission Extend dense square `A \ B` to complex participation while preserving the real `Rgesv` path. ## Dispatch and precision - real square `mp` systems continue to use `Rgesv`; - any complex coefficient or right-hand side uses `Cgesv`; - all participating `mp` values are normalized to `p_op = max(precisions)`; - real values are converted to MPC with exact `+0i`, and builtin complex doubles are converted directly from binary64 components; - A, B, and every destructive working copy have uniform `p_op` precision; - the pivot array is `std::vector`, using the installed MPLAPACK integer type; - multiple right-hand sides are supported. `Cgesv` overwrites both arguments, so the binding copies coefficient and RHS matrices into operation-owned storage. Singular `info > 0` is mapped to the established `mplapack:mp:SingularMatrix` error. ## Backend audit The controlled MPLAPACK MPFR header declares `Cgesv` with `mpc_class` A/B arrays and `mplapackint *ipiv`. The tested implementation is `mplapack/reference/Cgesv.cpp` at commit `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d`; it calls the reference `Cgetrf` and `Cgetrs` routines. The controlled build disables optimized workers. ## Gates `G-C06-UPSTREAM`, `G-C06-CGESV`, `G-C06-MIXED`, `G-C06-PIVOT`, `G-C06-SINGULAR`, `G-C06-MULTIRHS`, `G-C06-PRECISION`, `G-C06-IMMUTABILITY`, and `G-C06-REAL-RGESV-PARITY` all pass. ## Required QA Native ASan/UBSan/LSan and public tests cover complex multiple-RHS solves, mixed real/complex and builtin complex operands, pivot typing, singular and non-square errors, ambient precision, operation lifetime/immutability, and 1024-bit `2^-700` / 2048-bit `2^-1500` real and imaginary tails. mplapack-interop-0.5.1/docs/milestones/C05-complex-gemm.md0000644000230300031750000000407515274353473022625 0ustar rafaelrafael# C05 — Complex matrix multiplication via `Cgemm` ## Mission Add dense complex matrix multiplication while retaining the real-only `Rgemm` path for real operands. ## Dispatch and precision - real × real remains the existing MPFR `Rgemm` implementation; - real × complex, complex × real, and complex × complex use MPLAPACK `Cgemm`; - scalar scaling uses native MPC arithmetic within the same complex boundary; - every participating `mp` operand is promoted to `p_op = max(precisions)`, while builtin real/complex doubles are converted directly from their binary64 components; - all MPC matrix elements, `alpha`, `beta`, result storage, and the active MPFR/MPC context at the Cgemm call use `p_op`. The destructive Cgemm output is operation-owned. Inputs are copied into uniform-precision temporaries before the call, so public `mp` values retain value semantics. ## Backend audit The controlled MPLAPACK build exposes the installed MPFR declaration: ```cpp void Cgemm(const char *, const char *, mplapackint, mplapackint, mplapackint, mpc_class, mpc_class *, mplapackint, mpc_class *, mplapackint, mpc_class, mpc_class *, mplapackint); ``` The tested source is `mpblas/reference/Cgemm.cpp` at MPLAPACK commit `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d`. The controlled build disables optimized workers (`MPLAPACK_ENABLE_OPT=OFF`), and the reference implementation executes on the calling thread. The project scope therefore establishes the MPFR/MPC precision contract immediately around the invocation. ## Gates `G-C05-UPSTREAM`, `G-C05-DISPATCH`, `G-C05-CGEMM`, `G-C05-PRECISION`, `G-C05-MIXED`, `G-C05-SHAPES`, `G-C05-IMMUTABILITY`, and `G-C05-REAL-RGEMM-PARITY` all pass when the native and public C05 suites and the complete real regression wall pass. ## Required QA Native ASan/UBSan/LSan coverage and public tests cover complex products, mixed real/complex operands, builtin complex matrices, scalar scaling, dimension errors, empty shapes, lifetime/immutability, ambient precision, and the 1024-bit `2^-700` and 2048-bit `2^-1500` real and imaginary tails. mplapack-interop-0.5.1/docs/milestones/README.md0000644000230300031750000000437115274353473020642 0ustar rafaelrafael# Milestone index Work proceeds one milestone at a time. A milestone is complete only when its documented gate passes. | Milestone | Purpose | Status | |-----------|---------|--------| | M00 | Repository bootstrap | Passed | | M01 | Native build probe | Passed | | M02 | Internal native MPFR scalar storage | Passed | | M03 | Public scalar constructor and wrapper | Passed | | M04 | Precision API | Passed | | M05 | Conversion/display | Passed | | M06 | Scalar element-wise arithmetic | Passed | | M07 | Native dense matrix storage | Passed | | M08 | Matrix multiplication | Passed | | M09 | Linear solve | Passed | | M10 | Dense matrix inspection | Passed | | M11 | Dense element-wise arithmetic | Passed | | M12 | Dense transpose and reshape | Passed | | M13 | Dense horizontal and vertical concatenation | Passed | | M14 | Dense indexed assignment with value semantics | Passed | | M15 | Full-rank rectangular dense solve | Passed | | M16 | Rank-deficient rectangular minimum-norm solve | Passed | | M17 | Dense real Cholesky factorization | Passed | | M18 | Dense real non-pivoted QR factorization | Passed | | M19 | Dense real pivoted QR factorization | Passed | | M20 | Complex architecture audit and design freeze | Passed (design-only) | | M21 | Dense real LU factorization | Passed | | M22 | Real API and release closure for v0.1 | Passed | | M23 | v0.1.0 feature freeze and release candidate | Passed | | C00 | Complex storage and precision scaffold | Passed | | C01 | Complex scalar construction | Passed | | C02 | Complex dense matrix values | Passed | | C03 | Complex structural operations | Passed | | C04 | Complex element-wise arithmetic | Passed | | C05 | Complex GEMM | Passed | | C06 | Complex square solve | Passed | | C07 | Complex rank-revealing solve | Passed | | C08 | Complex Cholesky | Passed | | C09 | Complex QR | Passed | | C10 | Complex pivoted QR | Passed | | C11 | Mixed real/complex closure | Passed | | C11L | Mandatory complex LU | Passed | | C12 | Real+complex release closure | Passed | | P00 | Packaging design | Planned | | P01 | Debian source package | Planned | | P02 | Local Debian build | Planned | | P03 | PPA staging | Planned | | P04 | PPA autopkgtest | Planned | | P05 | PPA stable | Planned | | P06 | Ubuntu series/architecture matrix | Planned | mplapack-interop-0.5.1/docs/milestones/N02-svd.md0000644000230300031750000000360715274353473021037 0ustar rafaelrafael# Goal Implement the dense real and complex arbitrary-precision `svd` API for the 0.3.0 development line. # Scope Support one-output singular values and three-output full/economy factors, including the deprecated numeric `0` economy option, scalar values, empty shapes, 1024/2048-bit precision, and native real/complex reconstruction and orthogonality tests. # Non-goals Do not implement `rank`, `cond`, `rcond`, eigenvalue APIs, sparse SVD, generalized SVD, binary64 fallback, or any new real-only algorithm outside the SVD surface. # Design constraints Use MPLAPACK `Rgesvd` for real input and `Cgesvd` for complex input. Keep the one-operation/one-precision MPFR/MPC contract, copy destructive operands into operation-owned buffers, check workspace queries and INFO, return real `mp` singular values for complex input, and preserve the real/complex backend boundary. # Implementation tasks - Reuse the N00 singular-values-only helpers for one-output calls. - Implement full and economy U/S/V output with Octave-compatible shapes. - Convert LAPACK VT to public V using a native transpose or conjugate transpose as appropriate. - Add public wrappers, native/public tests, compatibility updates, tree gates, archive checks, and the milestone report. # Required tests Run native sanitized SVD tests, public real/complex shape and reconstruction tests, full/economy/0 forms, scalar and empty values, orthogonality/unitarity, input immutability, ambient precision restoration, 1024-bit `2^-700`, 2048-bit `2^-1500`, the M00-M23 wall, C00-C12 including C11L, and the ASan, UBSan, and LSan gates. # Gate ```text G-N02-BACKEND G-N02-ONE-OUTPUT G-N02-FULL G-N02-ECON G-N02-REAL G-N02-COMPLEX G-N02-RECONSTRUCTION G-N02-ORTHOGONALITY G-N02-WORKSPACE G-N02-PRECISION G-N02-REGRESSION ``` # Expected commit Implement the native Rgesvd/Cgesvd backend and public `@mp/svd` API with a complete N02 regression and report. mplapack-interop-0.5.1/docs/milestones/M19-pivoted-qr.md0000644000230300031750000000364615274353473022347 0ustar rafaelrafael# M19 — Dense real `mp` pivoted QR # Goal Add Octave-compatible dense real column-pivoted QR through MPLAPACK MPFR `Rgeqp3`, reusing M18 `Rorgqr` Q generation and returning either a permutation matrix or a one-based permutation vector. # Scope Three-output full/economy pivoted QR, matrix/vector permutation forms, deprecated numeric-zero economy/vector compatibility, precision-safe operation-owned buffers, and MPFR-native reconstruction and orthogonality QA. # Non-goals - `qr(A,B)`, fixed-column JPVT control, QR updates, rank, or condition APIs - Sparse, complex, or N-D QR # Design constraints `Rgeqp3` overwrites its input and returns integer JPVT state, so all numerical storage is operation-owned. JPVT is initialized to zero, validated, and converted to a 1-based Octave permutation before constructing `P`. Every REAL array uses the stored input precision inside `MplapackMpfrPrecisionScope`. M18's non-pivoted `Rgeqrf` path remains selected for one/two-output calls. # Implementation tasks - Audit the installed `Rgeqp3` signature, JPVT mapping, call chain, threading, workspace query, and runtime linkage. - Add a native pivoted factorization bridge with shared R extraction and `Rorgqr` generation, plus public `qr` output dispatch. - Add deterministic permutation, precision, immutability, interoperability, sanitizer, and installed-package QA. # Required tests Run the controlled external pivoted-QR probe, native Rgeqp3 tests, matrix and vector permutation reconstruction, full/economy tall and wide fixtures, precision-dependent pivot canaries, 1024/2048-bit tails, scalar/empty cases, M18 parity, and the complete M00–M18 regression suite. # Gate `G19-UPSTREAM`, `G19-PERMUTATION`, `G19-PIVOT`, `G19-ECON`, `G19-PRECISION`, `G19-WORKSPACE`, `G19-PUBLIC`, `G19-M18-PARITY`, `G19-IMMUTABILITY`, `G19-INTEROP`, and `G19-ROBUSTNESS` must all pass. # Expected commit `M19: add dense mp pivoted QR via MPLAPACK Rgeqp3` mplapack-interop-0.5.1/docs/milestones/C10-complex-pivoted-qr.md0000644000230300031750000000445215274353473023765 0ustar rafaelrafael# C10 — Pivoted Complex QR via `Cgeqp3` ## Mission Extend dense complex `mp` QR to the pivoted three-output forms while keeping the existing real `Rgeqp3` implementation for real values: ```text [Q,R,P] = qr(A) [Q,R,P] = qr(A,"econ") [Q,R,p] = qr(A,"vector") [Q,R,P] = qr(A,"matrix") [Q,R,p] = qr(A,0) ``` The complex factorization satisfies `Q*R = A*P` for matrix permutations and `Q*R = A(:,p)` for vector permutations. `P` and `p` remain builtin real structural outputs. ## Backend and implementation The installed MPFR declaration of `Cgeqp3` uses `mpc_class` A, reflector, and complex workspace arrays, an installed `mplapackint*` `JPVT`, and MPFR real workspace. The binding initializes `JPVT` to zero, performs the workspace query and actual call inside `MpfrMpcPrecisionScope(p_op)`, validates the returned permutation, and forms Q through the existing `Cungqr` path. R is extracted from the operation-owned factorization storage with exact strict lower zeros. The bridge maps `JPVT` as source-column-to-destination-column matrix P, or as the one-based vector p, matching the real API. Complex inputs dispatch only to the MPC path; real inputs continue to use `Rgeqp3`/`Rorgqr`. ## Precision and ownership `p_op` is the stored input precision. A, tau, complex work, real work, Q, and R are all allocated at `p_op`; contract checks verify the active MPFR/MPC scope, default precision, storage precision, and uniform element precision at each LAPACK boundary. Destructive LAPACK calls receive operation-owned copies, and ambient precision is restored after return. ## Gates `G-C10-UPSTREAM`, `G-C10-PERMUTATION`, `G-C10-MATRIX-P`, `G-C10-VECTOR-P`, `G-C10-ECON`, `G-C10-PIVOT-PRECISION`, `G-C10-RECONSTRUCTION`, `G-C10-ORTHOGONALITY`, and `G-C10-REAL-RGEQP3-PARITY`: PASS. ## Required QA Native ASan/UBSan/LSan coverage checks full, economy, and wide shapes, matrix/vector permutation mapping, exact JPVT validation, reconstruction, unitarity, operation-owned input safety, empty shapes, ambient precision, and 1024/2048-bit pivot-order canaries. Public tests cover all required `qr` forms, complex structural outputs, real parity, lifetime, and the same precision canary. The full native real wall and complete public M01–M23 plus C01–C10 wall pass. ## Result C10 PASS. Proceed to C11: mixed real/complex API closure. mplapack-interop-0.5.1/docs/milestones/M21-lu.md0000644000230300031750000000417415274353473020663 0ustar rafaelrafael# Goal Add dense real arbitrary-precision LU factorization with MPLAPACK MPFR `Rgetrf`, including Octave-compatible packed, two-output, permutation-matrix, and permutation-vector forms for rectangular and singular matrices. # Scope M21 adds `lu(A)`, `[L,U]=lu(A)`, `[L,U,P]=lu(A)`, and `[L,U,p]=lu(A,"vector")` for dense real `mp` scalars and two-dimensional matrices. It preserves the stored operand precision and existing M00-M20 numerical paths. # Non-goals Sparse LU/UMFPACK interfaces, complex LU, complete or threshold pivoting, `luupdate`, determinant/inverse/rank/condition APIs, and triangular solve optimizations are deferred. # Design constraints `Rgetrf` is the production backend and receives only an operation-owned, column-major MPFR copy. `IPIV` is replayed into a final 1-based row permutation; it is never exposed directly as `p`. One operation uses one `p_op = precision(A)` under `MplapackMpfrPrecisionScope`, and all factors and structural values are independent native storage. # Implementation tasks Audit the installed `Rgetrf` signature, pinned call chain, IPIV and INFO semantics, and runtime linkage. Add the native factor bridge, public `@mp/lu` dispatch, packed/canonical factor extraction, permutation outputs, precision probes, and installed-package QA. # Required tests Run the installed Rgetrf probe and native sanitized LU tests. Exercise square, tall, wide, multi-pivot, singular, scalar, and empty inputs; all output modes; 1024/2048-bit tails; precision-dependent and high-ambient pivot canaries; immutability; reconstruction (`P*A=L*U`, `A(p,:)=L*U`, `A=L*U`); interoperability; package lifecycle; and the complete M00-M20 regression suite. # Gate M21 passes only when the upstream, packed, two-output, three-output, vector, pivot-precision, precision, singular, Octave-compatibility, immutability, reconstruction, interoperability, and robustness gates all pass. The final root-level `m21-report.md` records the evidence and exact gate result. # Expected commit Prefer separate reviewable commits for the Rgetrf audit/probe, native bridge, public API, and QA/documentation. Do not modify MPLAPACK or begin M22. mplapack-interop-0.5.1/docs/milestones/C11-mixed-real-complex-closure.md0000644000230300031750000000521615274353473025374 0ustar rafaelrafael# C11 — Mixed Real/Complex API Closure ## Mission Close the first-generation mixed public surface for real and complex `mp` values while retaining real result kinds for real-only operations. ## Promotion and operations Binary `+`, `-`, `.*`, `./`, `*`, and `\` now promote any complex participant to the MPC path. The result precision is the maximum stored precision of the participating `mp` values. Real-only operands remain on the existing MPFR paths, and a complex result is never demoted merely because its imaginary components are zero. Builtin real and complex doubles are converted directly from their binary64 components at the operation precision. ## Concatenation Mixed horizontal and vertical concatenation accepts real and complex `mp` operands in either order, plus builtin real/complex double operands when an `mp` operand supplies the arbitrary precision. The result is a single MPC matrix at the maximum participating `mp` precision. Structural copying uses operation-owned destination storage and does not consult ambient precision. ## Assignment and structure Indexed assignment of a complex scalar/matrix or builtin complex value into a real `mp` matrix promotes the copied result to complex. Assignment into a complex matrix accepts real `mp` and builtin real RHS values without demotion. Source values remain unchanged, and a higher-precision RHS widens the copied result only when the selection is nonempty. Complex reshape was added alongside the existing transpose, conjugate-transpose, indexing, display, and component operations. ## Precision and ownership All mixed arithmetic and structural paths derive `p_op` from stored operands, allocate destination storage explicitly at that precision, and preserve ambient MPFR/MPC state. No mixed complex path falls through builtin binary64 complex arithmetic for the numerical result, and no real-only operation is routed through a complex kernel. ## Gates `G-C11-PROMOTION`, `G-C11-PRECISION`, `G-C11-ARITHMETIC`, `G-C11-MTIMES`, `G-C11-MLDIVIDE`, `G-C11-CONCAT`, `G-C11-ASSIGN`, `G-C11-STRUCTURAL`, `G-C11-BUILTIN-DOUBLE`, `G-C11-NO-DEMOTION`, and `G-C11-REAL-REGRESSION`: PASS. ## Required QA Native ASan/UBSan/LSan coverage includes mixed complex concatenation and the existing real regression wall. Public tests cover mixed precision and kind promotion, builtin complex participation, Cgemm/Cgesv/Cgelsy mixed paths, concat in both directions, real-to-complex assignment, structural interoperability, ambient precision, output lifetime, and no-demotion. Complete public M01–M23 plus C01–C11 and full native real+complex walls pass. ## Result C11 PASS. Proceed to mandatory C11L: complex LU via `Cgetrf`. mplapack-interop-0.5.1/docs/milestones/C07-complex-rank.md0000644000230300031750000000547015274353473022635 0ustar rafaelrafael# C07 — Complex rank-revealing rectangular solve ## Mission Provide complex rectangular `A \\ B` through an audited MPLAPACK rank-revealing backend, with minimum-norm solutions, rank-deficient support, and precision derived from the participating stored values. ## Backend candidate audit The controlled MPLAPACK MPFR headers and reference sources were audited for `Cgelsy`, `Cgelss`, and `Cgelsd`. `Cgelsy` uses QR with column pivoting, a complex work array, and `2*n` real workspace; its `rcond` controls rank. The SVD alternatives `Cgelss` and `Cgelsd` were directly exercised as audit candidates. `Cgelsd` additionally requires real workspace and integer `iwork` whose sizes are substantially larger; `Cgelss` uses the real workspace in its singular-value path. The selected production backend is `Cgelsy` because its rank-revealing QR path meets the required semantics with the smallest audited workspace contract. The tested declarations are from MPLAPACK commit `a59e5a0a429b05e8f07cf7a8feab1f48aef7431d` and use `mpc_class` complex arrays, `mpfr_class` singular-value/rcond and real workspace, and installed `mplapackint` pivot/work-index types. ## Semantics and implementation - `p_op = max` of all participating stored precisions; - `rcond = Rlamch_mpfr("E")` evaluated inside the `p_op` scope; - A, B, complex workspace, real workspace, and all destructive work copies use exactly `p_op` precision; - real and builtin complex operands are promoted without routing through binary64 complex arithmetic; - A and B are copied before `Cgelsy`, which overwrites its arguments; - full-column-rank, full-row-rank, rank-one, rank-zero, inconsistent rank-deficient, and multiple-RHS cases are supported; - the returned solution has `n` rows and preserves the complex result type; - real-only `A \\ B` dispatch remains on the established real rank-revealing path. The inherited C06 public test was updated so a supported 2×1 complex system is checked as a least-squares solve rather than as the former non-square error. ## Gates `G-C07-CANDIDATE-AUDIT`, `G-C07-UPSTREAM`, `G-C07-FULL-RANK`, `G-C07-RANK-DEF`, `G-C07-MIN-NORM`, `G-C07-RANK-PRECISION`, `G-C07-WORKSPACE`, `G-C07-MIXED`, `G-C07-IMMUTABILITY`, and `G-C07-REAL-RGELSS-PARITY`: PASS. ## Required QA The native ASan/UBSan/LSan probe directly exercises all three candidates and the selected `Cgelsy` wrapper. Public tests cover full-column-rank and underdetermined minimum-norm systems, rank-deficient and zero-rank systems, mixed real/complex and builtin operands, precision-sensitive rank, 1024-bit `2^-700` and 2048-bit `2^-1500` real/imaginary tails, ambient precision, operation-owned immutability, lifetime, and dimension diagnostics. The full native real regression wall and complete public M01–M23 plus C01–C07 wall pass. ## Result C07 PASS. Proceed to C08: complex Cholesky. mplapack-interop-0.5.1/docs/milestones/M07-matrix-storage.md0000644000230300031750000000421415274353473023210 0ustar rafaelrafael# M07 — Native dense matrix storage # Goal Implement and harden dense real matrix storage before MPLAPACK BLAS/LAPACK kernels are used. # Scope Native dense storage, numeric-matrix and textual-cell matrix constructors, empty matrix representation, matrix shape, column-major ordering, leading dimensions, ownership, copy/move semantics, indexing firewalls, and direct type compatibility with future MPLAPACK array arguments. # Non-goals - GEMM or GESV itself - Matrix element access or assignment - Matrix arithmetic, conversion, or final display - Transpose or reshape - Sparse or complex matrices # Design constraints Prefer a layout that avoids unnecessary transposition or repacking for MPLAPACK. Every MPFR element has deterministic lifetime management, matrix dimensions are explicit, and copies and resizing cannot leak or double-free. Dense matrices must not be Octave arrays or cells of independent scalar `mp` wrapper objects. M07 extends the operand-derived precision and immutable-result infrastructure proven for scalars in M06 to one native dense representation. It owns matrix element-wise operations and scalar expansion decisions; M06 introduces none. # Implementation tasks - Select and document storage order, indexing, and leading dimensions. - Implement numeric matrix, textual cell matrix, and deliberate empty matrix construction on the selected native representation. - Harden allocation, copy/move, destruction, and checked dimension behavior. - Reject indexing and indexed assignment until their public semantics exist. - Prove direct compatibility with intended MPLAPACK array arguments. # Required tests Test rectangular, square, scalar-normalized, and empty dimensions; internal layout access; copies; moves; repeated allocation and destruction; public indexing firewalls; and MPLAPACK-compatible layout assumptions under memory QA. # Gate `G07` passes when dense real storage is documented, memory-safe, dimensionally correct, directly compatible with MPLAPACK MPFR dense pointers, and protected from premature indexing or matrix operators. This gate passed on 2026-09-01. # Expected commit `M07: add native dense MPFR matrix storage` mplapack-interop-0.5.1/docs/milestones/M13-concatenation.md0000644000230300031750000000354015274353473023065 0ustar rafaelrafael# Goal Implement dense real `mp` horizontal and vertical concatenation through the native immutable matrix representation. # Scope Support `[A, B, ...]`, `[A; B; ...]`, direct `horzcat`/`vertcat`, mixed real double operands, mixed stored precisions, scalar operands, and valid empty two-dimensional shapes. # Non-goals - Indexed assignment or general `cat(dim, ...)` - N-D, sparse, complex, or object-array concatenation - New arithmetic, transpose, reshape, or MPLAPACK calls # Design constraints Validate the complete argument list and result dimensions before allocation. Choose `p_cat` as the maximum precision of every `mp` operand, including empty operands, and copy values directly into one column-major destination at that precision. Do not broadcast, mutate inputs, use a precision scope, or change the current precision state. # Implementation tasks - Add a reusable native concatenation descriptor and horizontal/vertical copy kernel. - Add public `horzcat` and `vertcat` dispatch for arbitrary operand counts. - Preserve scalar normalization, empty shapes, binary64 semantics, and deep result ownership. - Add native, public, differential, precision, lifecycle, and sanitizer QA. - Update architecture, precision, package, and local-CI documentation. # Required tests Test ordinary and three-way concatenation, scalar/row/column cases, empty shapes, mixed `mp` precision, 1024/2048-bit tails, mixed double `0.1` and `0.125`, operand immutability, nested concatenation, and M00–M12 regressions. Compare supported shape and error behavior with builtin Octave matrices. # Gate M13 passes only when the public bracket syntax returns one `mp` value and the concatenation, shape, precision, binary64, immutability, interoperability, robustness, installed-package, and M00–M12 regression gates pass. # Expected commit `M13: add dense mp matrix concatenation` mplapack-interop-0.5.1/docs/milestones/M15-rgels.md0000644000230300031750000000345515274353473021363 0ustar rafaelrafael# M15 — Full-rank rectangular `mp` solve # Goal Add dense real rectangular `A \ B` through MPLAPACK MPFR `Rgels` while preserving the M08/M09 uniform-precision and immutable-value contracts. # Scope Full-column-rank overdetermined and full-row-rank underdetermined 2-D dense systems, including multiple right-hand sides and mixed `mp`/double operands. # Non-goals - Rank-deficient or rank-revealing least-squares solving - Normal equations, pseudoinverses, SVD, or condition estimation - Complex, sparse, or N-D systems - Reusable QR/LQ factorization objects # Design constraints Square systems remain on M09 `Rgesv`; scalar left division remains native MPFR arithmetic. Rectangular `Rgels` calls use operation-owned uniformly `p_op`-precision `A_work`, padded `B_work`, and `WORK` buffers under a temporary `MplapackMpfrPrecisionScope`. Public operands are immutable and no MPLAPACK mixed-precision call is possible. # Implementation tasks - Audit the installed `Rgels` signature, call chains, workspace query, and threading behavior. - Add a checked native `Rgels` bridge and rectangular `mldivide` dispatch. - Add QR/LQ, mixed-precision, workspace, empty-shape, and lifecycle QA. - Document full-rank semantics and the deferred rank-revealing milestone. # Required tests Run installed-library QR/LQ precision canaries at 1024 and 2048 bits, public single- and multiple-RHS rectangular solves, mixed `mp`/double conversion, workspace-query validation, square/scalar parity, rank/error mapping, empty cases, and the complete M00–M14 regression suite. # Gate `G15-UPSTREAM`, `G15-QR`, `G15-LQ`, `G15-WORKSPACE`, `G15-PRECISION`, `G15-PUBLIC`, `G15-LIMITS`, `G15-IMMUTABILITY`, `G15-INTEROP`, and `G15-ROBUSTNESS` must all pass for M15. # Expected commit `M15: add full-rank rectangular mp solve via MPLAPACK Rgels` mplapack-interop-0.5.1/docs/milestones/N08-mrdivide.md0000644000230300031750000000174015274353473022050 0ustar rafaelrafael# N08 — Dense real and complex mrdivide N08 implements the public dense A / B and mrdivide (A, B) operations for real and complex mp values. The matrix implementation is the conjugate-transpose reduction (B' \ A')'; scalar denominators remain on the native element-wise division path. The existing square mldivide path still uses Rgesv/Cgesv and preserves its singular-matrix error. Right division catches that error only and uses the rank-revealing Rgelss/Cgelsy path, which provides Octave-compatible minimum-norm results for singular square and rank-deficient rectangular denominators. All converted operands, workspaces, and LAPACK arguments obey the one-operation/one-precision MPFR/MPC contract. The N08 regression covers scalar, matrix/scalar, matrix/matrix, real, complex, mixed, square, rectangular, rank-deficient, singular, empty, special-value, conjugate-transpose, immutability, 1024/2048-bit, ambient precision, explicit-function, and permanent Grcar right-division cases. mplapack-interop-0.5.1/docs/milestones/M18-qr.md0000644000230300031750000000350015274353473020663 0ustar rafaelrafael# M18 — Dense real `mp` QR factorization # Goal Add non-pivoted dense real `qr` through MPLAPACK MPFR `Rgeqrf` and `Rorgqr`, with Octave-compatible single/two-output and full/economy forms. # Scope Scalar and two-dimensional dense real `mp` values, full and economy QR, deprecated numeric-zero economy compatibility, precision-preserving immutable operation-owned buffers, and MPFR-native reconstruction/orthogonality QA. # Non-goals - Pivoted QR and third-output permutation semantics - `qr(A,B)`, QR updates, rank, or condition APIs - Sparse, complex, or N-D QR # Design constraints `Rgeqrf` overwrites its input, so the public matrix is copied into a uniformly stored-precision operation-owned buffer. `Rorgqr` is called only when `Q` is requested. Workspace queries and calls run inside `MplapackMpfrPrecisionScope(precision(A))`, with all REAL storage at that precision; no ambient default or binary64 conversion participates. # Implementation tasks - Audit installed signatures, source call chains, threading, and runtime linkage for `Rgeqrf` and `Rorgqr`. - Add native QR factorization, R extraction, Q generation, checked workspace handling, and public `qr` dispatch. - Add full/economy shape, precision, numerical invariant, immutability, interoperability, sanitizer, and installed-package QA. # Required tests Run the controlled external QR probe, native QR tests, full/economy tall and wide fixtures, scalar/empty cases, one-output R semantics, 1024/2048-bit precision canaries, ambient-default independence, and the complete M00–M17 regression suite. # Gate `G18-UPSTREAM`, `G18-FULL`, `G18-ECON`, `G18-PRECISION`, `G18-WORKSPACE`, `G18-PUBLIC`, `G18-IMMUTABILITY`, `G18-NUMERICAL`, `G18-INTEROP`, and `G18-ROBUSTNESS` must all pass. # Expected commit `M18: add dense mp QR factorization via MPLAPACK Rgeqrf/Rorgqr` mplapack-interop-0.5.1/docs/milestones/P01-debian-source-package.md0000644000230300031750000000261415274353473024352 0ustar rafaelrafael# P01 — Debian source package # Goal Create correct Debian packaging for source and binary package `octave-mplapack`. # Scope Create the appropriate `debian/control`, `debian/rules`, `debian/changelog`, `debian/copyright`, `debian/source/format`, and `debian/tests/` content based on the approved P00 design. # Non-goals - Publishing to Launchpad - Guessing installation directories manually - Bundling MPLAPACK or unrelated dependency sources # Design constraints Use current `dh-octave` conventions where applicable and rely on Debian's Octave packaging infrastructure instead of manually guessing installation paths. Build dependencies must reflect actual probes and the MPFR backend baseline. # Implementation tasks - Research current Debian and `dh-octave` policy for the targets. - Add source metadata, build rules, copyright, changelog, and tests. - Declare verified build and runtime dependencies. - Ensure the source package is reproducible and policy-aligned. # Required tests Validate Debian metadata and source-package generation with supported tooling. Verify that install paths come from packaging infrastructure and that all license and dependency declarations match the source. # Gate `GP01` passes when a policy-valid Debian source package can be generated from the repository. This gate is planned and is not passed by M00. # Expected commit `P01: add Debian source package metadata` mplapack-interop-0.5.1/docs/milestones/C08-complex-cholesky.md0000644000230300031750000000442215274353473023520 0ustar rafaelrafael# C08 — Hermitian Cholesky via `Cpotrf` ## Mission Extend dense `mp` `chol`, `chol(A,"upper")`, `chol(A,"lower")`, and the two-output status form to complex matrices while preserving the real `Rpotrf` path and M17 status semantics. ## Semantics - `upper` makes only the upper triangle authoritative and factors `H = R' * R`; - `lower` makes only the lower triangle authoritative and factors `H = L * L'`; - the ignored triangle is not checked for agreement or read as input; - diagonal imaginary components are ignored by the Hermitian Cholesky contract and the returned diagonal is real; - non-positive-definite input returns the same partial factor and positive status for two-output callers; one-output callers retain the established `mplapack:mp:NotPositiveDefinite` error; - real-only `chol` remains on the existing `Rpotrf` implementation. ## Backend and precision The installed MPFR declaration of `Cpotrf` uses `mpc_class` storage and `mplapackint` dimensions/status. The controlled reference source is `mplapack/reference/Cpotrf.cpp`, which calls the reference complex Hermitian BLAS and recursive factor routines. The operation copies the input before the destructive call, establishes `MpfrMpcPrecisionScope(p_op)`, checks the MPFR/MPC precision contract before and after the call, and clears the non-selected output triangle. For this single-input operation, `p_op` is the stored input precision. All matrix elements and the factor use that precision; ambient `mpbits` does not control the calculation. ## Gates `G-C08-UPSTREAM`, `G-C08-HERMITIAN`, `G-C08-SELECTED-TRIANGLE`, `G-C08-UPPER`, `G-C08-LOWER`, `G-C08-NONPD`, `G-C08-STATUS`, `G-C08-PRECISION`, `G-C08-IMMUTABILITY`, and `G-C08-REAL-CHOL-PARITY`: PASS. ## Required QA Native ASan/UBSan/LSan coverage checks upper/lower factor values, arbitrary ignored triangles, diagonal imaginary behavior, partial factors and status, non-square rejection, operation-owned input safety, empty shapes, ambient scope restoration, and 1024-bit `2^-700` / 2048-bit `2^-1500` positive-definite tails. Public tests cover the same behavior plus one-/two-output semantics and real Cholesky regression parity. The full native real and complete public M01–M23 plus C01–C08 walls pass. ## Result C08 PASS. Proceed to C09: non-pivoted complex QR. mplapack-interop-0.5.1/docs/milestones/M00-bootstrap.md0000644000230300031750000000336215274353473022253 0ustar rafaelrafael# M00 — Bootstrap # Goal Establish the public repository and project contracts without implementing numerical functionality. # Scope - GitHub repository and initial branch workflow - Required repository tree and BSD-2-Clause license - Octave package metadata - Architecture and normative precision contracts - Contributor and agent rules - M00-M10 and P00-P06 milestone definitions - Structural QA and lightweight baseline CI # Non-goals - Native MPFR storage or a working `mp` value - Matrix arithmetic, GEMM, or GESV - Debian packages or Launchpad publication # Design constraints MPLAPACK remains an installed dependency discovered through `pkg-config` and must not be vendored or modified. The only planned backend through M10 is real MPFR. Octave's system BLAS/LAPACK remain untouched, and every callable M00 stub must fail explicitly. # Implementation tasks - Validate all mandatory environment prerequisites. - Create the public repository, `main`, and `topic/m00-bootstrap` safely. - Add all required package, source-placeholder, test-placeholder, documentation, QA, CI, and packaging-placeholder files. - Commit and push the reviewed scaffold. # Required tests Run `tools/check-tree.sh`, `tools/check-format.sh`, `tools/local-ci.sh`, and `git diff --check`. Inspect the complete diff, generated artifacts, repository status, remote, and pushed branch. # Gate `G00` passes only when all mandatory prerequisites pass, the public repository and correct remote exist, `topic/m00-bootstrap` exists, required files exist, all M00 QA passes, no unexplained artifacts remain, a commit exists, and a normal push succeeds. A mandatory dependency or command cannot be skipped. Result: `G00 PASS`. # Expected commit `M00: bootstrap octave-mplapack repository` mplapack-interop-0.5.1/docs/milestones/N01-det-inv.md0000644000230300031750000000313515274353473021604 0ustar rafaelrafael# Goal Implement dense arbitrary-precision real and complex `det` and `inv`. # Scope Add public `@mp/det` and `@mp/inv` methods, native MPFR/MPC backend paths, Rgetrf/Cgetrf pivot handling, Rgetri/Cgetri workspace-query handling, precision-aware tests, documentation, and regression integration. # Non-goals Do not implement `det` reciprocal-condition output, SVD, rank, condition numbers, eigenvalue APIs, binary distribution, Debian packaging, PPA work, or final 0.3.0 release tagging. # Design constraints Use stored operand precision and operation-owned destructive copies. Keep real and complex kernels separate. Never use builtin binary64 arithmetic as a fallback. Preserve the historical 0.2.1 tag and release archive. # Implementation tasks - Add precision-scoped Rgetrf/Rgetri and Cgetrf/Cgetri determinant/inverse paths. - Check workspace queries and all LAPACK INFO values. - Add public wrappers, native tests, Octave tests, and release-wall checks. - Document supported behavior and the N03 second-output deferral. # Required tests Test pivot parity, exact singular determinant zero, inverse values, empty and nonsquare shapes, real and complex inputs, immutability, ambient precision, 1024-bit/`2^-700`, 2048-bit/`2^-1500`, workspace queries, sanitizer behavior, and the complete M00-M23/C00-C12/C11L regression wall. # Gate ```text G-N01-DET G-N01-DET-PIVOT G-N01-INV G-N01-WORKSPACE G-N01-SINGULAR G-N01-PRECISION G-N01-IMMUTABILITY G-N01-REAL-COMPLEX G-N01-REGRESSION ``` # Expected commit One implementation/report/status commit on `topic/d01r1-mplapack-interop`, pushed after all N01 gates pass. mplapack-interop-0.5.1/docs/milestones/C03-complex-structural.md0000644000230300031750000000200215274353473024072 0ustar rafaelrafael# C03 — Complex structural operations ## Mission Implement the first complex structural and component operations while retaining the accepted real M12 behavior. ## Semantics - `real(Z)` and `imag(Z)` return real `mp` values with the source shape and precision; - `conj(Z)` returns a complex value with the source shape and precision; - `Z.'` transposes without conjugation; - `Z'` transposes and conjugates; - conjugation flips the sign of an imaginary signed zero. All complex operations copy native MPFR/MPC values under an operation-local precision scope. Real values continue through their existing real-only paths. ## Gate `G-C03-REAL`, `G-C03-IMAG`, `G-C03-CONJ`, `G-C03-TRANSPOSE`, `G-C03-CTRANSPOSE`, `G-C03-SIGNED-ZERO`, and `G-C03-REAL-PARITY`. ## Required QA Native sanitizer coverage and public tests cover 128/512/1024/2048-bit precision, shape and value invariants, signed zero, and the complete M01-M23 real wall. ## Expected commit `C03: add complex real-imag-conjugate and transpose semantics` mplapack-interop-0.5.1/docs/milestones/C01-complex-scalar.md0000644000230300031750000000260515274353473023136 0ustar rafaelrafael# Goal Make complex scalar `mp` values first-class while preserving the real native payload kind. # Scope Add direct builtin complex-double construction, exact two-component text construction, deterministic canonical text, explicit complex-double conversion, display, and special-value coverage. # Non-goals Complex dense indexing, structural operations, arithmetic, and LAPACK paths are deferred to C02-C11L. # Design constraints Builtin complex doubles are converted component-by-component directly into the stored `mpc_class` at the current project precision. Two text arguments are parsed directly at that precision. Canonical text uses `(real,imag)` with locale-independent MPFR component text and is accepted by the constructor. # Implementation tasks - Add `mp(complex_double)` and `mp(real_text, imag_text)`. - Accept canonical complex scalar text for round trips. - Return builtin `Complex` from explicit `double` conversion. - Preserve real constructor payloads and expose `isreal(mp)`. # Required tests The C01 public scalar test, 1024/2048-bit precision canaries, signed-zero, Inf/NaN, canonical round trips, direct component conversion, and the complete real regression wall. # Gate `C01 PASS` requires G-C01-CONSTRUCT, G-C01-DOUBLE, G-C01-CHAR, G-C01-DISP, G-C01-PRECISION, G-C01-SPECIAL, and G-C01-REAL-PARITY. # Expected commit `C01: add complex scalar construction and conversion` mplapack-interop-0.5.1/docs/milestones/N04-eig-structured.md0000644000230300031750000000273715274353473023216 0ustar rafaelrafael# Goal Implement the structured standard eigenproblem for dense real symmetric and complex Hermitian `mp` matrices. # Scope Provide `eig(A)`, `[V,D]=eig(A)`, the explicit `"matrix"` form, and the explicit `"vector"` form. Use MPLAPACK `Rsyevd` for real input and `Cheevd` for complex input. # Non-goals General nonsymmetric eig, generalized eig(A,B), balancing, sparse eig, and binary64 fallback remain deferred to later milestones. # Design constraints Symmetry/Hermiticity is checked by exact represented MPFR/MPC values. Every destructive LAPACK invocation receives an operation-owned copy inside the one-operation precision scope. Eigenvalues remain real `mp` values. # Implementation tasks Add the structured eigenvalue backend, native and public tests, dispatch, documentation, archive manifests, and regression gates. # Required tests Test exact detection, real symmetric and complex Hermitian residuals, orthogonality, matrix/vector output forms, repeated and nearly repeated eigenvalues, input immutability, ambient precision, and 1024/2048-bit high-dynamic-range canaries. Run the complete real and complex regression walls plus all sanitizer gates. # Gate ```text G-N04-DETECTION G-N04-REAL-SYMMETRIC G-N04-COMPLEX-HERMITIAN G-N04-VECTOR G-N04-MATRIX G-N04-RESIDUAL G-N04-ORTHOGONALITY G-N04-DEGENERATE G-N04-PRECISION G-N04-REGRESSION ``` # Expected commit The implementation, report, status, and gate updates are committed and pushed only after the complete N04 wall passes. mplapack-interop-0.5.1/docs/milestones/C00-complex-scaffold.md0000644000230300031750000000313715274353473023452 0ustar rafaelrafael# Goal Establish the native arbitrary-precision complex foundation used by the subsequent complex milestones. # Scope This milestone adds MPFR/MPC-owned scalar and dense column-major matrix storage, complex native Octave payload types, and a composed per-thread MPFR/MPC precision scope. It does not add public complex arithmetic. # Non-goals Public complex constructors, indexing, arithmetic, and LAPACK dispatch belong to C01 and later milestones. # Design constraints Every complex element is an `mpfrxx::mpc_class` with equal explicit real and imaginary precision. Dense storage is one contiguous `std::vector` and is ABI-compatible with MPLAPACK's MPFR complex entry points. Native payloads are immutable from Octave; copies are deep and ownership is RAII-based. # Implementation tasks - Add scalar and matrix complex storage with checked shape and leading dimension metadata. - Add native complex scalar and matrix payload registration. - Add `MpfrMpcPrecisionScope` with nested and exception-safe restoration of MPFR precision/rounding and MPC component precision/rounding. - Add precision, lifetime, signed-zero, Inf/NaN, and TLS probes. # Required tests `make -C src check-deps`, `make -C src check-complex-storage`, the existing M00-M23 real native test wall, and the existing public real regression suite. The complex storage gate exercises 128, 256, 512, 1024, and 2048 bits. # Gate `C00 PASS` when G-C00-TYPE, G-C00-STORAGE, G-C00-PRECISION, G-C00-TLS, G-C00-LIFETIME, G-C00-SPECIAL, and G-C00-REAL-REGRESSION pass. # Expected commit `C00: add complex native scaffold and MPFR/MPC precision scope` mplapack-interop-0.5.1/docs/milestones/M12-transpose-reshape.md0000644000230300031750000000304415274353473023701 0ustar rafaelrafael# M12 — Dense transpose and reshape # Goal Provide precision-preserving read-only `transpose`, `ctranspose`, and two-dimensional `reshape` for dense real `mp` values. # Scope Implement `A.'`, `A'`, `reshape(A,m,n)`, `reshape(A,[m n])`, and one inferred `[]` dimension using independent native MPFR matrix storage. # Non-goals - Concatenation, indexed assignment, matrix power, or comparisons - N-D reshape, permutation, squeeze, or views - Complex, sparse, or other numerical backends # Design constraints Structural operations copy existing MPFR values directly at the source precision, preserve column-major order, and do not call MPLAPACK or consult or modify the project/current-thread precision defaults. A `1x1` result uses the canonical scalar payload. # Implementation tasks - Add native transpose and reshape copy helpers with checked dimensions. - Add public `transpose`, `ctranspose`, and `reshape` dispatch. - Add precision, empty-shape, differential, lifecycle, and sanitizer QA. - Document structural semantics and deferred features. # Required tests Verify scalar, matrix, vector, empty, special-value, and 1024/2048-bit precision cases; column-major reshape order; valid and invalid dimensions; `[]` inference; M10/M11/M08/M09 interoperability; installed-package and M00–M11 regressions. # Gate `M12` passes when transpose, reshape, Octave differential, precision, interoperability, robustness, installed-package, and M00–M11 regression gates pass from a clean source tree. # Expected commit `M12: add dense mp transpose and reshape` mplapack-interop-0.5.1/docs/milestones/M10-first-functional-baseline.md0000644000230300031750000000317615274353473025311 0ustar rafaelrafael# M10 — Dense matrix inspection # Goal Make dense `mp` results inspectable through normal read-only Octave syntax: ```octave pkg install . pkg load mplapack mpdigits(100); A = mp({"1", "2"; "3", "4"}); B = mp({"5", "6"; "7", "8"}); C = A * B; b = mp({"1"; "2"}); x = A \ b; A(2, 1); double(A); disp(A); ``` # Scope Add precision-preserving read-only indexing, `end`, matrix `double`, and matrix `disp` to the M09 package while preserving the native dense payload. # Non-goals - Matrix assignment or logical indexing - SVD or eigenvalue routines - Complex arithmetic or non-MPFR backends - Debian packages or PPA publication # Design constraints The package must have no hard-coded MPLAPACK prefix, no dependency on the MPLAPACK source/build tree, and no accidental binary64 implementation of multiprecision operations. Keep the first baseline intentionally narrow. # Implementation tasks - Implement native index selection and deep-copy slices. - Add `end`, precision-preserving matrix `double`, and canonical matrix display. - Run the full M00-M09 regression suite and installed-package QA. - Document supported inspection operations and known limits. # Required tests Verify element, slice, linear, repeated, reordered, empty, and `end` indexing; invalid-index errors; source-precision preservation; matrix double/display; sanitizers; clean package installation; lifecycle behavior; and all M00-M09 regressions. # Gate `G10` passes when all read-only inspection gates and M00-M09 regressions pass from a clean source tree and installed package. Matrix assignment remains unsupported. # Expected commit `M10: add dense matrix inspection` mplapack-interop-0.5.1/docs/milestones/M08-mtimes.md0000644000230300031750000000374615274353473021552 0ustar rafaelrafael# M08 — Matrix multiplication # Goal Implement `C = A * B` using MPLAPACK's MPFR real GEMM path. # Scope Dense real `mp` matrix multiplication, dimension validation, mixed precision, and backend-path evidence. # Non-goals - High-level Octave-loop matrix multiplication - Silent conversion to double - Other BLAS operations or numerical backends # Design constraints Use the intended MPLAPACK MPFR GEMM routine directly on native storage. The result follows documented mixed-precision semantics, and tests must distinguish the backend path from an ordinary double implementation. M08 extends the scalar native multiplication path to `mtimes` and adds dense matrix products. Matrix products use the uniform MPLAPACK MPFR calling contract and the installed reference `Rgemm` implementation. M07 supplies a uniform-precision contiguous `mpfr_class *` buffer in column-major order, checked `mplapackint` dimensions and leading dimensions, and operation-owned result allocation primitives. M08 must use that contract without packing or changing public inputs. # Implementation tasks - Bind the appropriate MPLAPACK MPFR real GEMM entry point privately. - Validate dimensions and arrange leading dimensions correctly. - Allocate the result at `max(lhs precision, rhs precision)` and establish a temporary current-thread MPLAPACK MPFR precision scope at that value. - Add reproducible evidence that the intended backend routine executes. # Required tests At minimum run: ```octave A = mp({"1", "2"; "3", "4"}); B = mp({"5", "6"; "7", "8"}); C = A * B; ``` Also cover exact small matrices, high-precision nontrivial values, dimension errors, mixed precision, input preservation, and evidence that the MPLAPACK MPFR GEMM routine is exercised. # Gate `G08` passes when `mtimes` is correct at multiprecision, invokes MPLAPACK MPFR GEMM, and passes all dimensional and mixed-precision tests. This gate is planned and is not passed by M00. # Expected commit `M08: implement MPLAPACK MPFR matrix multiplication` mplapack-interop-0.5.1/docs/milestones/M17-cholesky.md0000644000230300031750000000422015274353473022061 0ustar rafaelrafael# M17 — Dense real `mp` Cholesky factorization # Goal Add dense real `chol` and `chol(A, "upper"|"lower")` through the installed MPLAPACK MPFR `Rpotrf` routine, with Octave-compatible status output and precision-preserving immutable values. # Scope Scalar and square dense matrices are supported, including one- and two-output forms, selected-triangle semantics, empty `0x0` values, and operation-owned factor storage at the source precision. # Non-goals - Sparse, complex, or N-D Cholesky - The dense three-output permutation form - `cholupdate`, `cholinsert`, `choldelete`, `cholshift`, `cholinv`, or `chol2inv` - SPD-specialized `mldivide`, determinant, inverse, rank, or condition APIs # Design constraints `Rpotrf` is destructive, so the public matrix is copied into a uniformly source-precision operation-owned buffer. The selected `UPLO` triangle is passed directly without a symmetry pre-check or arithmetic pre-symmetrization. The call runs under `MplapackMpfrPrecisionScope(precision(A))`; all public values remain immutable and all strict unused-triangle output entries are deterministic `+0` on success. # Implementation tasks - Audit the installed `Rpotrf` signature, source call chain, threading, and runtime linkage. - Add the native factorization bridge and public `chol` dispatch, including one-/two-output and partial-factor status behavior. - Add precision, selected-triangle, immutability, interoperability, sanitizer, and installed-package QA. - Keep scalar/square/rectangular solve dispatch unchanged. # Required tests Run the controlled external `Rpotrf` probe, exact upper/lower fixtures, non-square and invalid-option errors, one-/two-output non-PD behavior, 0x0/scalar cases, ignored-triangle special values, 1024/2048-bit precision canaries, ambient-default independence, reconstruction through `Rgemm`, the complete M00–M16 regression suite, and installed-package QA. # Gate `G17-UPSTREAM`, `G17-PRECISION`, `G17-TRIANGLE`, `G17-PD`, `G17-PUBLIC`, `G17-PARTIAL`, `G17-IMMUTABILITY`, `G17-RECONSTRUCT`, `G17-INTEROP`, and `G17-ROBUSTNESS` all pass for M17. # Expected commit `M17: add dense mp Cholesky factorization via MPLAPACK Rpotrf` mplapack-interop-0.5.1/docs/milestones/M09-mldivide.md0000644000230300031750000000347315274353473022047 0ustar rafaelrafael# M09 — Linear solve # Goal Implement `x = A \ b` for dense square real systems through MPLAPACK MPFR LAPACK. # Scope Dense square real `A`, one right-hand side, and multiple right-hand sides are supported through the MPLAPACK real MPFR `Rgesv` routine. # Non-goals - A replacement Gaussian-elimination implementation in the binding - Sparse, rectangular least-squares, or complex systems - Arbitrary LAPACK routine wrappers # Design constraints The solver must operate on native MPFR storage without binary64 conversion. Input mutation or preservation must be deliberate and documented, and singular status must become a clear Octave-level result or diagnostic. Scalar left division uses the existing native MPFR arithmetic path, while matrix solves use operation-owned copies and the MPLAPACK MPFR backend. M07 supplies deep native copies with independent contiguous buffers, checked `mplapackint` dimensions, column-major layout, and verified leading dimensions. M09 must mutate only those operation-owned work copies so public inputs remain immutable. # Implementation tasks - Bind the selected MPLAPACK MPFR solve routine privately. - Validate square matrices and right-hand-side dimensions. - Manage solver work copies and pivot storage safely. - Translate singular and argument statuses accurately. - Record evidence that the backend solver executes. # Required tests Cover exact small systems, high-precision systems, multiple precision settings, dimension errors, singular matrices, input preservation unless documented otherwise, optional multiple right-hand sides, and backend invocation evidence. # Gate `G09` passes when `mldivide` correctly solves the supported systems through the MPLAPACK MPFR LAPACK path with documented status and ownership behavior. # Expected commit `M09: implement MPLAPACK MPFR linear solve` mplapack-interop-0.5.1/docs/milestones/M04-precision.md0000644000230300031750000000505215274353473022233 0ustar rafaelrafael# M04 — Precision API # Goal Implement `mpbits()`, `mpbits(n)`, `mpdigits()`, and `mpdigits(n)`. # Scope Querying and changing the default precision, applying it to new values, and a documented, certified decimal-digit-to-bit conversion. The fresh-session initial default is 512 bits. # Non-goals - Retrospectively changing existing objects - An undocumented guard-bit policy - Making decimal digits the canonical internal unit # Design constraints Bits are canonical. There is exactly one process-local project state in `mp_precision`; neither the `.m` wrappers nor MPFR's global default hold a second value. Existing values retain their precision after the default changes. `mpdigits(n)` maps to `ceil(n * log2(10))` bits, while `mpdigits()` reports `floor(bits * log10(2))` complete digits. M04 uses no guard bits. The native implementation uses directed MPFR lower and upper bounds and accepts a conversion only when both bounds prove the same integer result. Setters validate and convert before atomically committing state, so failure is transactional. State survives clear and package unload/reload within a process but is not persisted to another process. # Implementation tasks - Expose the M03 precision component through public `mpbits` and `mpdigits` wrappers backed by private native commands. - Change the fresh-session project default from 128 to 512 bits. - Return public precision counts as exact Octave `uint64` scalars. - Accept real scalar integer-valued floating and Octave integer inputs within their exact ranges; reject invalid and overflowing requests without mutation. - Certify bit/digit conversions using directed MPFR interval arithmetic. - Keep state process-local, atomically accessed, and persistent across the module's safe unload/reload lifecycle. - Ensure new values capture the current default and old/copy values retain their stored per-object precision. # Required tests Test the fresh 512-bit/154-digit state; 128/256/512-bit simultaneous values; copy stability; required 1/10/38/100/1000 digit mappings; 128/332/333-bit getter mappings; all invalid input classes; overflow rollback; constructor semantics at multiple precisions; 10,000 state operations; clear; unload/reload persistence; fresh-process reset; sanitizers; clean rebuilds; and isolated source-package install/reinstall. # Gate `G04` passes when both APIs, certified conversions, transactional validation, session lifetime, installed-package behavior, and immutable per-object precision match the normative contract. # Expected commit `M04: add public precision controls` mplapack-interop-0.5.1/docs/milestones/M11-elementwise-arithmetic.md0000644000230300031750000000276115274353473024712 0ustar rafaelrafael# M11 — Dense element-wise arithmetic # Goal Extend dense real `mp` matrices with native MPFR `+`, `-`, `.*`, `./`, unary `+`, and unary `-`, including two-dimensional singleton expansion. # Scope Use explicitly precisioned native MPFR destination elements and preserve the M07 one-payload column-major matrix representation. Existing M06 scalar semantics remain authoritative. # Non-goals - Matrix power, transpose, concatenation, assignment, and comparison - Logical operations, reductions, complex, sparse, or N-D arrays - MPLAPACK calls for element-wise arithmetic # Design constraints MPLAPACK is not used by the element-wise kernel. Result precision is derived from operands, current defaults do not participate, and public operands remain immutable. # Implementation tasks - Add one native MPFR element-wise kernel with checked broadcasting. - Extend public arithmetic dispatch for scalar and dense matrix operands. - Add mixed binary64, special-value, precision, lifecycle, and sanitizer QA. # Required tests Verify same-shape, scalar, row, column, outer singleton, and compatible empty shapes against builtin Octave semantics. Verify mixed precision, binary64 source semantics, signed zero, Inf, NaN, division by zero, and M00-M10 regressions from source and installed packages. # Gate `M11` passes when arithmetic, broadcasting, precision, binary64, special-value, robustness, installed-package, and M00-M10 regression gates pass. # Expected commit `M11: add dense mp element-wise arithmetic` mplapack-interop-0.5.1/docs/milestones/M05-conversion.md0000644000230300031750000000364115274353473022430 0ustar rafaelrafael# M05 — Conversion and display # Goal Implement scalar `char(A)`, `double(A)`, and `disp(A)` without implicit precision loss. # Scope Deterministic multiprecision textual output, explicit conversion to binary64, and normal interactive display for the real `mp` scalars available before M07. Matrix conversion/display is extended after dense storage exists. # Non-goals - Implicit conversion of operations to binary64 - Complex formatting - A guarantee that `double(A)` retains multiprecision information # Design constraints Display formats native multiprecision values without converting through binary64. Canonical text uses normalized scientific notation, special forms `0`, `-0`, `Inf`, `-Inf`, and `NaN`, and enough base-10 digits for exact source-precision reconstruction. `double(A)` is explicit and uses MPFR RNDN. # Implementation tasks - Define a stable normalized scalar textual form. - Use `mpfr_get_str` and `mpfr_free_str` through project RAII. - Implement `char` directly from immutable native values. - Implement explicit scalar `double` with `mpfr_get_d` and `MPFR_RNDN`. - Implement `disp` using the canonical text independently of Octave format. # Required tests Test exact native round-trip at 128, 256, 333, 512, and 1024 bits; signed zero and special values; locale and default-precision independence; binary64 bit patterns, subnormal/overflow/underflow, and a tie-to-even midpoint; bare and explicit display; sanitizer ownership; implicit-conversion and matrix firewalls; and isolated installed-package lifecycle. # Gate `G05` passes when scalar conversion and display behavior is documented, source-precision round-trip and binary64 rounding tests pass, no unsupported operation silently substitutes binary64, and M01-M04 plus installed-package QA remain passing. G05 passed on the configured Octave 11.1 / MPFR 4.2.2 / MPLAPACK 3.0.1 environment. # Expected commit `M05: add scalar conversion and display` mplapack-interop-0.5.1/docs/milestones/N06-eig-generalized.md0000644000230300031750000000236015274353473023275 0ustar rafaelrafael# N06 — generalized `eig(A,B)` N06 completes dense generalized eigenproblems for real and complex `mp` matrices on the 0.3.0-dev development line. The public wrapper accepts Octave-compatible `matrix`/`vector` output forms, three-output left eigenvectors, and `chol`/`qz` algorithm selection. It uses `Rsygvd`/`Chegvd` for exactly symmetric/Hermitian definite pairs and falls back to, or can force, `Rggev`/`Cggev` QZ. Generalized balance options are rejected because Octave rejects them for this interface. The implementation preserves the generalized identities `A*V = B*V*D` and `W'*A = D*W'*B`, converts real conjugate pairs to complex MP values, divides `alpha/beta` at the operation precision, and preserves infinite eigenvalues for singular `B`. Mixed real/complex inputs are promoted once to MPC at the maximum operand precision. Destructive backend calls use operation-owned copies, with independent MPFR/MPC precision scopes. Required QA covers real and complex definite and QZ pairs, singular `B`, infinite eigenvalues, option validation, matrix/vector layouts, left and right residuals, immutability, mixed inputs, ambient precision, and 1024/2048-bit canaries. The complete previous real/complex regression and sanitizer walls remain mandatory. mplapack-interop-0.5.1/docs/milestones/M01-build-probe.md0000644000230300031750000000577215274353473022452 0ustar rafaelrafael# M01 — Build and dependency probe # Goal Build the smallest native `.oct` module and prove that Octave can load a module linked to MPLAPACK's MPFR backend. The target public function is `mplapack_version()` after `pkg load mplapack`. M01 implements the private module as `__mplapack_core__.oct`. Its `version` command calls `Rlamch_mpfr("E")`, verifies that the returned machine epsilon is positive and finite, and reports the Octave, MPLAPACK, backend, and MPFR versions through `mplapack_version()`. # Scope Report, where reliably obtainable, the Octave version, MPLAPACK version, `backend = mpfr`, and MPFR version. Establish the minimal package native build. The build uses `pkg-config` module `mplapack_mpfr`, requires MPLAPACK 3.0.0 or newer without fixing a patch version, and passes the detected version into the native module at compile time. `src/Makefile` honors the package manager's `MKOCTFILE` value, including values with options. # Non-goals - Native `mp` storage or constructors - Numerical matrix operations - A general MPLAPACK wrapper layer # Design constraints Use `mkoctfile` through package tooling, honor `MKOCTFILE`, and discover `mplapack_mpfr` through `pkg-config`. Do not hard-code a prefix or depend on an MPLAPACK source/build tree. Keep `__mplapack_core__.oct` private. The first M01 attempt exposed an underlinked installed MPLAPACK MPFR shared library through the unresolved `mpc_set_z` relocation. M01 resumed only after the defect was corrected upstream and the installed library passed a clean SONAME load, `ldd -r`, and DT_NEEDED inspection. No downstream preload, RPATH, or manually appended backend libraries compensate for that former defect. # Implementation tasks - Record the `pkg-config` version, flags, libraries, and resolved installation. - Implement the non-fabricated `Rlamch_mpfr("E")` version/runtime probe. - Build and load the module directly and through Octave package installation. - Inspect the MPLAPACK and native-module linker dependencies and symbols. - Generate `dist/mplapack-.tar.gz` deterministically from an explicit source set with `tools/build-package.sh`. - Install, load, uninstall, and reinstall that archive under a temporary HOME from a neutral working directory. # Required tests Prove that `mkoctfile` produces the module, Octave loads it, runtime linker dependencies resolve, and the MPLAPACK MPFR backend is actually linked without access to an MPLAPACK build tree. `tools/local-ci.sh` verifies the standalone MPLAPACK load and relocations, native DT_NEEDED and `Rlamch_mpfr` reference, direct native/public probes, missing-dependency failure, clean rebuild, deterministic archive contents, Octave 11.1 metadata parsing, and isolated installed-package paths and runtime. # Gate `G01 PASS`: the build, load, linkage, dependency, source-package, installed-package, clean-rebuild, negative-dependency, and version-reporting evidence succeeded with the installed MPLAPACK MPFR consumer interface. # Expected commit `M01: add native MPLAPACK MPFR build probe` mplapack-interop-0.5.1/docs/milestones/M02-native-value.md0000644000230300031750000000616015274353473022637 0ustar rafaelrafael# M02 — Native MPFR scalar value storage # Goal Introduce the smallest safe internal native representation for one multiprecision scalar and prove its ownership and module-lifetime behavior. The M02 value is not the public `mp` class. # Scope - Deterministic RAII ownership - Explicit value precision - Safe copy, destruction, assignment, temporaries, and moves if used - A supported Octave 11.1 custom-value integration - Immutable native payloads and deep clone support - Module lock, clear, package-unload, and interpreter-shutdown safety - Standalone sanitizer and installed-package lifecycle QA # Non-goals - Complete matrix construction or arithmetic - User-visible pointer handles or a global handle registry - Premature Octave 8 implementation throughout numerical code - Public `mp()` construction, conversion, display, arithmetic, or matrices # Design constraints The implementation uses the installed Octave 11.1 `octave_base_dld_value`, type-ID macros, `octave_value(octave_base_value *)`, checked type ID plus `dynamic_cast`, and explicit DLD function locking. The DLD-aware base retains the containing shared library for every value and the registered prototype. The registered internal type is `mplapack_mpfr_scalar_internal`; it is never exposed as public `mp`. `MpfrScalarStorage` owns `mpfrxx::mpfr_class`, the installed MPLAPACK MPFR `REAL` type. Each object is constructed with explicit precision, and project copy assignment uses copy-and-swap so value and precision move together. The Octave payload is immutable. No raw pointer handle or global object registry is used. # Implementation tasks - Document the inspected Octave API and selected native-value mechanism in `docs/native-value-design.md`. - Implement Octave-independent `MpfrScalarStorage` and the internal custom scalar representation. - Add private creation, inspection, equality, deep-clone, and exact module-lock commands for M02 QA without enabling the M03 constructor. - Lock the native module, register the type once, and verify ordinary clear, package unload/reload, and interpreter shutdown. - Keep matrix storage responsibilities assigned to M07. # Required tests `make -C src check-storage-sanitized` runs 10,000 deterministic ownership and contiguous-container iterations with GCC AddressSanitizer, LeakSanitizer, and UndefinedBehaviorSanitizer. `test/native_value.tst` covers assignment, deep clone, cells, temporaries, simultaneous 128/256/512-bit values, direct `0.1` parsing, wrong types, invalid input, stable type identity, and repeated initialization. `tools/local-ci.sh` additionally covers locked ordinary clear, live values across package unload, reload/relock, shutdown destruction, M01 regression, two clean builds, negative dependency handling, deterministic source packaging, and lifecycle tests against an isolated installed package. The public `mp()` constructor is checked to remain the M03 stub. # Gate `G02 PASS`: native storage and the custom Octave value pass sanitizer, lifecycle, module-lock, package-install, regression, and clean-rebuild QA with no known ownership defects. # Expected commit `M02: add native MPFR scalar value storage` mplapack-interop-0.5.1/docs/milestones/M14-indexed-assignment.md0000644000230300031750000000434215274353473024030 0ustar rafaelrafael# M14 — Dense `mp` indexed assignment # Goal M14 adds value-semantic, in-bounds indexed assignment for dense real `mp` matrices. The implementation always creates an independent native payload, so assignment through an alias cannot mutate the original object. The complete result remains a uniformly precisioned `MpfrMatrixStorage`. Supported forms include two-subscript scalar/vector/matrix assignment, single scalar linear assignment, and colon-linear assignment. Matrix growth, deletion, logical assignment, general vector linear assignment, complex, sparse, and N-D values remain outside the milestone. The result precision is `max(lhs, rhs)` for two `mp` values and the lhs precision for a builtin double rhs. Structural copies use direct MPFR value transfer and never consult or mutate the current precision default. The M14 gate requires value-semantic alias safety, verified Octave index and shape behavior, precision widening/preservation, binary64 and special-value handling, interoperability with M10–M13, sanitizer/lifecycle QA, and the full M00–M13 regression suite. # Scope The supported surface is `A(i,j)=x`, row/column and submatrix assignment, single scalar linear assignment, and `A(:)=scalar_or_compatible_rhs` for real dense `mp` and builtin double values. # Non-goals Matrix growth, deletion, logical/general-vector assignment, complex, sparse, N-D, and chained/cell/field assignment are deferred. # Design constraints Public payloads remain immutable. The native bridge always deep-copies the lhs and performs direct MPFR copies/conversions without MPLAPACK or a precision scope. # Implementation tasks Use shared M10 index validation, M13 exact promotion semantics, checked storage arithmetic, and one native assignment kernel for two-subscript and linear forms. # Required tests Cover alias/value semantics, scalar expansion, row/column/submatrix and linear assignment, `end`, precision widening/preservation, binary64 and special values, unsupported growth/deletion, lifecycle, sanitizers, and M00–M13 regressions. # Gate The milestone passes only when the G14 value, index, shape, precision, binary64, limits, interoperability, and robustness gates all pass. # Expected commit `M14: add dense mp indexed assignment` mplapack-interop-0.5.1/docs/milestones/C09-complex-qr.md0000644000230300031750000000355615274353473022331 0ustar rafaelrafael# C09 — Non-pivoted complex QR via `Cgeqrf` / `Cungqr` ## Mission Extend dense `mp` QR to complex input for full and economy forms, including one-output R-only calls and the deprecated `qr(A,0)` economy spelling, while leaving real QR on `Rgeqrf`/`Rorgqr`. ## Semantics - one output returns R and does not construct Q; - full tall QR returns Q `m×m` and R `m×n`; - economy tall QR returns Q `m×n` and R `n×n`; - wide matrices retain the full `m×m` Q and `m×n` R shapes; - R's strict lower triangle is exact complex zero; - complex orthogonality is `Q' * Q = I`, using conjugate transpose; - `Q * R` reconstructs the input within the operation precision. ## Backend and precision The installed MPFR declarations of `Cgeqrf` and `Cungqr` use `mpc_class` factor, reflector, and workspace arrays with `mplapackint` dimensions. The wrapper performs a workspace query and actual call for `Cgeqrf`, then queries and calls `Cungqr` only when Q is requested. All destructive factor and generator inputs are operation-owned copies. Every query/work array is allocated at `p_op`, and the MPFR/MPC scope and post-call contract checks ensure that active defaults and stored components agree. ## Gates `G-C09-UPSTREAM`, `G-C09-FULL`, `G-C09-ECON`, `G-C09-ONE-OUTPUT`, `G-C09-WORKSPACE`, `G-C09-ORTHOGONALITY`, `G-C09-RECONSTRUCTION`, `G-C09-PRECISION`, and `G-C09-REAL-QR-PARITY`: PASS. ## Required QA Native ASan/UBSan/LSan coverage checks full/economy/wide shapes, R-only dispatch, workspace queries, exact R zeros, unitary Q, reconstruction, operation-owned input safety, empty shapes, ambient precision restoration, and 1024-bit `2^-700` / 2048-bit `2^-1500` complex tails. Public tests cover the same forms plus `qr(A,0)` and real QR regression parity. The full native real wall and complete public M01–M23 plus C01–C09 wall pass. ## Result C09 PASS. Proceed to C10: pivoted complex QR. mplapack-interop-0.5.1/docs/milestones/P02-local-deb-build.md0000644000230300031750000000253415274353473023162 0ustar rafaelrafael# P02 — Local Debian build # Goal Build and exercise `octave-mplapack` in a clean Ubuntu environment before PPA publication. # Scope Use the appropriate supported subset of tools such as `debuild`, `dpkg-buildpackage`, `lintian`, `sbuild`, or `pbuilder` to build source and binary packages and verify lifecycle behavior. # Non-goals - Requiring every possible Debian build tool blindly - PPA upload or Launchpad publication - Testing only from the source checkout # Design constraints The clean environment must use declared dependencies. Tests must exercise the installed package, and build results must remain traceable to the generated source package. # Implementation tasks - Select and document the supported clean-build toolchain. - Build source and binary packages in the clean environment. - Install, load, remove, and reinstall the binary package. - Run package-level Octave functionality and dependency diagnostics. # Required tests Verify source-package creation, clean build, lint results as applicable, installation, `pkg load mplapack`, removal, reinstall, functional operation, and correct dependency declarations. # Gate `GP02` passes when clean local packages complete the documented build and installed-package lifecycle. This gate is planned and is not passed by M00. # Expected commit `P02: validate clean local Debian package build` mplapack-interop-0.5.1/docs/milestones/M23-v0.1-freeze.md0000644000230300031750000000372415274353473022207 0ustar rafaelrafael# Goal Freeze the accepted real-only source tree as the upstream `0.1.0` release candidate used by the later Debian/PPA packaging milestones. # Scope M23 changes only release metadata, documentation, QA, and packaging handoff records. It verifies the existing M00--M22 implementation without adding a numerical API. # Non-goals No new BLAS/LAPACK operation, factorization, solver, complex support, sparse support, public release tag, Debian package, or PPA upload is part of M23. # Design constraints `DESCRIPTION` is the single version source and is frozen at `0.1.0`. The release candidate is identified by one full Git SHA. Archives are generated from clean trees with the package builder and must be byte-for-byte reproducible. The MPLAPACK dependency is identified by its required feature probe and validated source revision, not by a version string alone. # Implementation tasks - Freeze user-facing version, NEWS, README, API, compatibility, and limitation text. - Build and compare two independent candidate archives. - Record the source SHA, archive checksum, dependency provenance, and PPA handoff in `docs/v0.1-release-manifest.md`. - Run fresh-clone, extracted-archive, lifecycle, sanitizer, and full local CI checks. # Required tests - `tools/local-ci.sh` and the complete M00--M22 regression suite. - Dependency feature probe and runtime linkage audit. - Two clean archive builds with identical SHA256 and file lists. - Extracted archive install/help/example/smoke/uninstall/reinstall lifecycle. - Compatibility firewall and secret/absolute-path leakage audits. - `git diff --check` and a clean working tree apart from pre-existing unrelated legacy deletions. # Gate M23 passes only as `M23 PASS — V0.1.0-RC-FROZEN` when the source-freeze, version, reproducibility, archive, QA, package, linkage, documentation, and PPA-handoff gates all pass. M23 does not create the final Git tag or upload a PPA. # Expected commit `M23: record v0.1.0 release-candidate evidence` mplapack-interop-0.5.1/docs/complex-release-checklist.md0000644000230300031750000000301215274353473022546 0ustar rafaelrafael# C12 complex release-closure checklist This checklist records the development closure for C00–C12. It does not freeze MPLAPACK 3.0.1 or begin D00, Debian, PPA, or Launchpad work. - [x] `G-C12-API`: supported complex API inventory and constructor grammar recorded in `complex-api.md`. - [x] `G-C12-DOCS`: API, compatibility, backend, and release-closure docs agree with the tested implementation. - [x] `G-C12-FIREWALL`: complex unsupported functions reject cleanly with no binary64 fallback, crash, or recursion. - [x] `G-C12-REAL-REGRESSION`: complete M01–M23 public and native real wall. - [x] `G-C12-COMPLEX-REGRESSION`: complete C01–C11L public and native wall. - [x] `G-C12-PRECISION`: 1024/2048-bit tails, source-precision pivots, mixed promotion, and all earlier real canaries. - [x] `G-C12-TLS`: low/high ambient precision, thread-local scope, and lifetime probes. - [x] `G-C12-SANITIZERS`: ASan/UBSan/LSan native gates. - [x] `G-C12-PACKAGE-LIFECYCLE`: source archive build, install/load, unload, reinstall, and real+complex smoke. - [x] `G-C12-UPSTREAM-PROVENANCE`: exact tested dependency commits and the required MPLAPACK precision-scope-header fix recorded. ## Development identity - package identity: `mplapack-interop`; - package version: `0.2.1`; - MPLAPACK pkg-config identity: `mplapack_mpfr 3.0.1`; - final release commit/tag/archive: not frozen here; - Debian package, Launchpad upload, and PPA work: not started; - next separate goal: `D00 — Dependency Release Freeze`. mplapack-interop-0.5.1/docs/norm.md0000644000230300031750000000355615274353473016502 0ustar rafaelrafael# Arbitrary-precision `norm` N00 adds dense real and complex `mp` norm support to the 0.3.0 development line. Every result is an `mp` scalar at the stored operand precision; the ambient `mpbits` default does not change an existing operand or result precision. ## Vectors The following forms are supported for real and complex vectors, including `1x1` values: ```octave norm (x) norm (x, 1) norm (x, 2) norm (x, Inf) norm (x, -Inf) norm (x, "fro") norm (x, 0) norm (x, p) % positive finite p ``` The default and Frobenius vector forms use the MPLAPACK MPFR/MPC native 2-norm kernels. One-norm and infinity forms use arbitrary-precision absolute values. Finite positive `p` values are evaluated directly with MPFR powers; zero counts nonzero absolute values and `-Inf` selects the minimum absolute value. ## Dense matrices Real and complex two-dimensional dense matrices support: ```octave norm (A) norm (A, 1) norm (A, 2) norm (A, Inf) norm (A, "fro") ``` The standard matrix forms use MPLAPACK `Rlange`/`Clange`. The matrix 2-norm uses an operation-owned copy and an MPLAPACK `Rgesvd`/`Cgesvd` singular-values- only path. The Frobenius form is the native `Rlange`/`Clange` result. Matrix `p=0`, negative finite `p`, and other induced matrix p norms are not implemented in N00 and fail with a package-owned error. Row/column options, sparse values, and N-dimensional values remain outside the current dense 2-D API. Empty dense matrices return zero for the supported forms. MPFR/MPC NaN and infinity values remain NaN/infinity; no builtin binary64 numerical fallback is used. Inputs are copied before destructive SVD calls and remain unchanged. The public method is `inst/@mp/norm.m`; native implementation and the singular-values-only helper are in `src/mp_norm.cc` and `src/mp_norm.h`. The helper is intentionally private to the package backend and is designed for reuse by N02 SVD. mplapack-interop-0.5.1/docs/public-mp-design.md0000644000230300031750000001270015274353473020655 0ustar rafaelrafael# Public `mp` design ## Purpose M03 exposes the immutable M02 native scalar through a normal GNU Octave class. It deliberately establishes only scalar construction and `1 x 1` shape. Dense storage, matrix construction, indexing, conversion, precision control, and arithmetic remain later milestones. ## Octave 11.1 class audit The selected mechanism is an Octave 11.1 `classdef` value class stored in `inst/@mp/mp.m`. Octave 11.1 supports class definitions in `@` directories, private and hidden properties, value-class copy semantics, ordinary method dispatch, and explicit `horzcat`/`vertcat` methods. These capabilities support the public operators while allowing the early scalar milestones to reject object-array concatenation before native dense storage was introduced in M07. The installed extension headers provide `octave_value::is_classdef_object()`, `octave_value::class_name()`, `octave_value::classdef_object_value()`, and `octave_classdef::get_property()`. The private native bridge can therefore verify a scalar `mp` object and retrieve its private payload without exposing a public accessor. The compatibility-sensitive header is `octave/ov-classdef.h`; this use is localized to the bridge and targets Octave 11.1. An old-style `class(struct, "mp")` wrapper was not selected because its backing fields do not provide the same property-level encapsulation. A `handle` subclass was also rejected: public values are immutable value objects, and M02 already provides safe reference-counted ownership of the native representation. ## Public wrapper The public class name is `mp`. Each object contains one private, hidden property holding either the canonical `mplapack_mpfr_scalar_internal` value or, from M07, one `mplapack_mpfr_matrix_internal` value. Users receive neither a raw pointer nor an integer handle, and ordinary property access is denied. The native bridge performs checked class, shape, property, and native type validation for internal QA. The class is a value class. Ordinary assignment and `mp(existing_mp)` may share the immutable Octave and native representations. This is safe because M02 payloads cannot be mutated at the Octave boundary; explicit native clones remain available for lifecycle QA. The private property directly retains the DLD-aware M02 value, so public assignment, cells, structs, function passage, ordinary clear, and interpreter shutdown preserve the same module-lifetime guarantees. Installed-package QA keeps a public object alive across `pkg unload`, reloads the package, verifies the payload, and also destroys a public object while the package is unloaded. ## Construction and precision The production native bridge has separate text and binary64 construction paths. Text reaches `mpfr_set_str` in base 10 directly. A `double` reaches `mpfr_set_d` directly and is never formatted as decimal text. Both paths use the explicit round-to-nearest mode `MPFR_RNDN`, so constructor semantics do not depend on the mutable MPFR process default rounding mode. M03 established the project-owned default precision component at 128 bits. M04 changes its fresh-session initial value to 512 bits and exposes the same component through `mpbits` and `mpdigits`. Every new native scalar receives the current bit precision explicitly; changing the default never mutates an existing value and never changes MPFR's process-global default. The component is process-local and uses atomic access, not thread-local precision policy. Its state survives ordinary clear and package unload/reload within one Octave process, while a new process starts at 512 bits. ## Encapsulation and display The property is private and hidden. M05 `char` returns a canonical decimal representation produced directly from the native MPFR value, and `disp` uses the same text without revealing the property or internal type. Explicit `double` conversion calls MPFR's binary64 conversion directly. Internal test commands may inspect precision, exact equality, signed zero, infinity, and NaN after checked extraction of the private payload; they are not listed in `INDEX`. ## Scalar and matrix boundary M03 objects always have scalar payloads and report `1 x 1`. M07 deliberately lifts the numeric-array, text-cell, and empty-matrix constructor firewalls. The classdef wrapper remains one object; public shape methods query the private native payload rather than relying on a classdef object array. Public dense `mp` matrices are not represented as Octave arrays or cells of independent scalar `mp` wrapper objects. M07 provides one uniform-precision, column-major, contiguous native payload and shape-preserving empty matrices. All `1 x 1` input normalizes to the established scalar payload. Concatenation and cell-of-`mp` assembly remain firewalls, as do indexing and indexed assignment. ## Special values Binary64 positive and negative infinity, NaN, and signed zero are preserved by direct MPFR construction. The decimal text syntax is locale-independent, uses `.` as the decimal point, and is passed to the backend in base 10. Text special values `Inf`, `-Inf`, and `NaN` are accepted by the installed backend parser and covered by tests. Empty text, malformed decimals, and comma decimal separators are rejected. ## Known limitations - Public precision applies to subsequent construction only; per-object public precision mutation is not provided. - Matrix indexing, conversion, arithmetic, transpose, multiplication, and linear solve are not implemented in M07. - Comparisons remain unimplemented. mplapack-interop-0.5.1/docs/rectangular-solve.md0000644000230300031750000000266015274353473021157 0ustar rafaelrafael# Dense MPFR rectangular solve M15 extends `mp` left division to full-rank rectangular dense real systems through MPLAPACK MPFR `Rgels`. For an `m x n` coefficient matrix and an `m x nrhs` right-hand side, the result is an `n x nrhs` matrix. When `m > n` the result is the full-column-rank least-squares solution; when `m < n` it is the full-row-rank minimum-norm solution. Square systems continue to use M09 `Rgesv`, and scalar left division continues to use native MPFR arithmetic. Rectangular inputs are required to be full rank. Rank-revealing drivers, pseudoinverses, normal equations, and complex or sparse inputs are outside this milestone. Before `Rgels`, the binding creates operation-owned copies of `A` and a `max(m,n) x nrhs` padded `B` buffer. The workspace query and solve run inside `MplapackMpfrPrecisionScope(p_op)`; `A_work`, `B_work`, and `WORK` all have uniform `p_op` precision. No mixed-precision MPLAPACK call is issued and the public operands are never overwritten. The workspace recommendation is converted with finite, integral, range-checked validation. On success the first `n` rows of the padded RHS form the public solution. A positive `info` is reported as a deterministic rank-deficient error; a negative `info` is reported as an internal `Rgels` argument error. Empty rectangular systems use compatible Octave shapes without unsafe zero-size LAPACK calls. The current `mpbits()` setting is a construction default only. mplapack-interop-0.5.1/docs/eig.md0000644000230300031750000000506615274353473016271 0ustar rafaelrafael# Dense eigenproblems The 0.3.0 development line supports dense standard and generalized eigenproblems for real and complex two-dimensional `mp` matrices. ```octave lambda = eig (A) [V, D] = eig (A) [V, d] = eig (A, "vector") [V, D, W] = eig (A) [V, D] = eig (A, "balance") [V, D] = eig (A, "nobalance") [lambda] = eig (A, "vector") [V, D] = eig (A, B) [V, d] = eig (A, B, "vector") [V, D, W] = eig (A, B) [V, D] = eig (A, B, "chol") [V, D] = eig (A, B, "qz") ``` Exactly represented real symmetric and complex Hermitian inputs use MPLAPACK MPFR `Rsyevd` and MPC/MPFR `Cheevd`. General real inputs use `Rgeevx`; general complex inputs use `Cgeevx`. Every destructive driver call receives an operation-owned copy inside one scope matching the stored input precision. No path converts a complex problem to builtin binary64 arithmetic. Structured eigenvalues and diagonal matrices are real `mp` values. General eigenvalues, right eigenvectors, left eigenvectors, and diagonal matrices are complex `mp` values, including when the real general problem happens to have only real eigenvalues. The standard identities are `A*V = V*D` and `W'*A = D*W'`, where `'` is the complex-conjugate transpose. For `[V,d]`, `d` is the complex eigenvalue column vector. The optional `"balance"` and `"nobalance"` flags select the `Rgeevx`/`Cgeevx` expert-driver path. `"matrix"` and `"vector"` select the matrix or column eigenvalue layout; a one-output `eig(A,"matrix")` returns the diagonal eigenvalue matrix, while the default one-output and `"vector"` forms return a column. Three-output `"vector"` returns `[V,d,W]`. Structured `Rsyevd`/`Cheevd` inputs have no balancing stage, so a balance flag has no numerical effect on that path. The structured/general choice is based on an exact represented-value check: real off-diagonal pairs must compare exactly, while complex Hermitian pairs must have equal real parts, opposite imaginary parts, and zero imaginary diagonal entries. Nearly symmetric, non-Hermitian, Grcar, nearly defective, and badly scaled matrices therefore exercise the general backend explicitly. For `eig(A,B)`, `"chol"` selects the symmetric/Hermitian-definite `Rsygvd`/`Chegvd` path and `"qz"` selects `Rggev`/`Cggev`; the default chooses the definite path only for exactly symmetric/Hermitian pairs and falls back to QZ when `B` is not positive definite. Generalized standard options such as `"balance"` are rejected, and sparse eig, N-dimensional eig, and nonsymmetric `"chol"` requests remain unsupported with package-owned diagnostics. The generalized identities are `A*V = B*V*D` and `W'*A = D*W'*B`. mplapack-interop-0.5.1/docs/octave-script-compatibility.md0000644000230300031750000003466615274353473023167 0ustar rafaelrafael# Ordinary Octave script compatibility This document records the compatibility audit for `mplapack-interop`. The tested runtime is GNU Octave 11.1.0 with the native MPFR/MPC `mp` type. A function is marked `SUPPORTED` only after an actual public call and a native precision/value test have passed. ## Classification | Area | Classification | Evidence / current boundary | |---|---|---| | dense arithmetic, solve, factorization, eig, SVD, norm | SUPPORTED | Existing M00-M23, C00-C12/C11L, N00-N08 walls | | `abs`, `arg`, `angle`, `sign` | SUPPORTED | S00 public scalar/matrix and complex tests | | `isnan`, `isinf`, `isfinite`, `isreal` | SUPPORTED | S00 real/complex special-value tests | | `isequal`, `isequaln` | SUPPORTED | S00 exact-value, shape, and NaN tests | | `isscalar`, `isvector`, `ismatrix`, `isempty`, `isnumeric` | SUPPORTED | S00 generic predicate audit on mp values | | `power`, elementary functions | SUPPORTED | S01 native MPFR/MPC power and elementary-function tests | | reductions and extrema | SUPPORTED | S02 native MPFR/MPC reductions, NaN flags, dimensions, and min/max | | comparisons, logicals, logical indexing, `find` | SUPPORTED | S03 native MPFR/MPC comparison, truth, indexing, and find tests | | matrix utilities and constructors | SUPPORTED | S04 native MPFR/MPC `diag`, `triu`/`tril`, `repmat`, flips, `rot90`, `cat(1/2)`, and `like` constructors | | ranges, rounding, utility arithmetic | SUPPORTED | S05 native MPFR/MPC range, spacing, rounding, and utility tests | | descriptive statistics | SUPPORTED | S06 native MPFR/MPC mean, median, variance, standard deviation, range, and bounds | | graphics boundary wrappers | SUPPORTED | S07 private final-boundary conversion for common line graphics | | ordinary script corpus closure | SUPPORTED | S08 six-script corpus, structural audit, and intentional-stop firewall | | difficult nonsymmetric eigensystem example | SUPPORTED | `examples/13_nonsymmetric_eig_suite.m`; 30-row smoke and 40-row demo walls | | NEIGT Tier-S/Tier-A and verified V-S/V-A examples | SUPPORTED | `docs/examples/tiered/README.md`, `examples/14_neig_tier_s.m` through `examples/17_neig_verified_va.m`; 120/168 ordinary rows and 26 verification jobs per profile | | T00–T14 advanced dense numerics | SUPPORTED | T00–T14 focused walls and final controller wall; see `docs/advanced-numerics-compatibility.md` | | `fminbnd`, `fminsearch` | SUPPORTED | T14 MPFR bounded/simplex optimization tests | | `fminunc` | INTENTIONALLY-DEFERRED | `docs/todo/T14-fminunc.md` | | scalar `integral`, `quadgk` | SUPPORTED | T13 MPFR/MPC adaptive quadrature tests | | `ArrayValued` quadrature | INTENTIONALLY-DEFERRED | `docs/todo/T13-array-valued-quadrature.md` | | 1-D/2-D interpolation | SUPPORTED | T10/T11 native MPFR/MPC interpolation tests | | N-D interpolation | INTENTIONALLY-DEFERRED | `docs/todo/T11-ND-interpolation.md` | | `meshgrid` with MP arguments and volume graphics | INTENTIONALLY-DEFERRED | `docs/todo/T08-meshgrid.md`, `docs/todo/T08-volume-graphics-after-ND.md` | | sparse, symbolic, signal/image-specialized, ODE/PDE APIs | INTENTIONALLY-DEFERRED | Outside the dense ordinary-script and advanced-numerics targets | | general N-D support | INTENTIONALLY-DEFERRED | Current public mp contract is two-dimensional | ## S00 semantics `abs` returns real MPFR magnitudes. `angle` and `arg` return real MPFR arguments; complex inputs use MPC argument semantics and real signed-zero inputs use the same quadrant behavior as Octave. `sign` uses native MPFR signs for real values and native MPC `x/abs(x)` for nonzero complex values; complex zero returns positive complex zero as in Octave. The predicate methods return builtin logical scalars or matrices. A complex value is NaN or infinite when either component has that property, and finite only when both components are finite. `isequal` compares exact native values and shape while treating NaNs as unequal; `isequaln` treats corresponding NaNs as equal. No S00 mathematical path converts through binary64. Generic structural predicates were audited rather than duplicated where Octave already handles the `mp` class. `isnumeric` required the small public `@mp/isnumeric` wrapper because Octave otherwise reports a classdef `mp` object as nonnumeric. ## S01 semantics Element-wise `.^` and `power` support real/complex `mp` operands, mixed builtin real/complex operands, and existing 2-D singleton expansion. Scalar `^` uses the same native principal-power path. Integer powers of square matrices use exponentiation by squaring; negative powers use the existing native inverse path before multiplication. Noninteger matrix powers remain outside the supported surface. The elementary wrappers use MPFR for real-domain values and MPC for complex values. When a real input crosses a complex domain boundary, the complete result is promoted to MPC at the stored operation precision. The positive real-axis asin/acos branch fixtures are adjusted to match Octave's signed-zero principal-branch convention. `expm1` and `log1p` use guarded MPC working precision and never call builtin binary64 arithmetic. ## S02 semantics `sum`, `prod`, `sumsq`, `cumsum`, and `cumprod` retain native MPFR/MPC accumulators and default to the first non-singleton dimension. Explicit dimensions, `"all"` reductions, `omitnan`/`includenan`, `native`/`default`, and explicit `double` output are supported. Cumulative operations also accept `forward` and `reverse`; `"all"` is rejected for cumulative forms. Complex `sumsq` returns a real MPFR result formed from native MPC magnitudes. `min` and `max` support dimension/all reductions, first-value indices, pairwise scalar/matrix operands with two-dimensional singleton expansion, and the practical NaN flags. Complex ordering uses the native magnitude/phase comparison path by default; `ComparisonMethod` accepts `auto`, `real`, and `abs` for the supported dense forms. Pairwise extrema do not return a second index output. ## S03 semantics Real `==`, `~=`, `<`, `<=`, `>`, and `>=` use direct MPFR comparisons with Octave-compatible scalar and two-dimensional singleton expansion. Complex `==` and `~=` compare the native MPFR real and imaginary components; NaN is unequal. Complex ordered comparisons remain a deliberate firewall because no numeric ordering is defined for MPC values. `logical`, `&`, `|`, `xor`, and `~` classify native MPFR/MPC values directly; NaN is true and a complex value is true when either component is nonzero. `any` and `all` support the default or explicit dimension and `"all"`. `find` supports linear, row/column, and three-output forms, including a count and `"first"`/`"last"` direction. Dense numeric vector and logical-mask indexing and value-semantic assignment follow column-major order. ## S04 semantics `diag` constructs or extracts two-dimensional diagonals with an optional offset. `triu` and `tril` preserve the dense matrix shape and support an optional diagonal offset; the sparse-style `"pack"` form is intentionally rejected because the package's dense two-dimensional contract has no packed output type. `repmat` accepts scalar repetition counts or a two-element dimension vector. `flip`, `fliplr`, and `flipud` copy rows or columns natively, and `rot90` supports arbitrary integer quarter-turn counts. `cat(1, ...)` and `cat(2, ...)` use the existing native vertical and horizontal concatenation paths; dimensions above two remain rejected. `zeros`, `ones`, `eye`, `NaN`, and `Inf` support the explicit `"like"` form when the template is an `mp` value. These constructors preserve template precision and real/complex storage kind, and all special values are written through MPFR/MPC directly. ## S05 semantics The two- and three-argument colon forms construct real MPFR row vectors by repeated native MPFR addition at the operation precision. Increasing, decreasing, empty, negative-step, high-precision decimal-step, and zero-step cases are covered; a step that rounds away at the selected precision is rejected instead of silently looping. Complex colon ranges are an explicit unsupported boundary. `linspace` uses native MPFR for real endpoints and MPC for complex endpoints, with exact first and last values, Octave-compatible default counts, and the `n == 0`/`n == 1` cases. `logspace` uses native MPFR powers of ten and retains the supplied final endpoint for Octave's `pi` special case. Complex logspace is intentionally rejected. `floor`, `ceil`, `fix`, and `round` operate element-wise through MPFR and retain the source precision. `rem`, `mod`, `hypot`, and `atan2` use native MPFR with two-dimensional singleton expansion; remainder/modulus signs follow their respective Octave conventions. `signbit` exposes native MPFR sign bits as logical values, including signed zero. `eps` returns the local MPFR spacing above each stored value, so it is neither binary64-derived nor a constant. Complex rounding, remainder/modulus, utility forms, `signbit`, and `eps` are rejected explicitly where the dense mp contract is real-only. All S05 numerical paths avoid binary64 generation and preserve the operation's MPFR/MPC precision scope. The dedicated S05 tests include 1024-bit `2^-700` and 2048-bit `2^-1500` canaries and ambient-precision restoration. ## S06 semantics `mean` supports the default and explicit two-dimensional dimensions, `"all"`, `omitnan`/`includenan`, and an explicit `"double"` output boundary. Real means use MPFR accumulators; complex means use MPC accumulators and retain their complex result. `median` sorts with native MPFR ordering for real data and native magnitude/phase ordering for complex data, then averages the two middle native values for even-sized slices. `var` and `std` support the common normalization forms `0` (N-1) and `1` (N), the default and explicit dimensions, `"all"`, NaN flags, and the optional second output containing the mean. Complex variance and standard deviation are real MPFR values computed from native squared magnitudes, while their second output is the native complex mean. The implementation first computes the mean and then accumulates squared deviations, avoiding the catastrophically cancelling sum-of-squares formula. `range` and `bounds` use native minimum/maximum ordering and default to `omitnan`, matching Octave's statistics functions. Their complex ordering is the same native magnitude/phase ordering used by the existing dense extrema surface; complex `range` subtracts the selected native lower bound from the selected upper bound. Empty/all-NaN slices produce native NaN results. S06 accepts only the dense two-dimensional statistics surface. Weighted statistics, multi-dimensional vector-dimension forms, and unrelated statistics families remain outside this milestone. No statistics path routes through builtin binary64 arithmetic or through a complex kernel for a real-only input. ## S07 graphics semantics The `plot`, `semilogx`, `semilogy`, `loglog`, `scatter`, `stem`, and `stairs` class wrappers convert only `mp` data to builtin double immediately before calling the host graphics routine. The private graphics helper leaves axes handles, line-style strings, property/value pairs, and other non-`mp` arguments unchanged. It therefore supports single-series, multiple-series, axes-handle-first, and mixed builtin-double/`mp` calls. A complex `mp` vector is passed as a builtin complex vector at this boundary, matching Octave's single-complex-vector plotting behavior (real component on x, imaginary on y). This conversion is intentionally confined to visualization. It is not used by any numerical operation, and very small or very large arbitrary-precision values can become zero or infinity when represented as graphics doubles. Transform data in `mp` first when that range matters, for example: ```octave plot (bits, double (log10 (residual_mp))) ``` The documented Grcar example is: ```octave A = mp (gallery ("grcar", 32)); e = eig (A); plot (real (e), imag (e), "o"); axis equal; grid on; ``` Balance/nobalance overlays use the same final-boundary wrappers: ```octave eb = eig (A, "balance"); en = eig (A, "nobalance"); plot (real (eb), imag (eb), "o"); hold on; plot (real (en), imag (en), "x"); ``` Surface and matrix graphics beyond this line-graphics bridge remain S08 closure candidates. No S07 numerical path uses a binary64 fallback. ## S08 ordinary script corpus S08 closes the ordinary dense-script corpus with six executable scripts. The scripts cover the following complete flows: * Script A: `linspace`, power, `sqrt`, `exp`/`log`, trigonometric functions, reductions, and plotting. * Script B: comparisons, `isfinite`, logical indexing, extrema, `mean`, and `std`. * Script C: `like` constructors, `diag`, triangular extraction, replication, flips, and concatenation. * Script D: norm, right division, eigenvalues, SVD, rank, and condition. * Script E: the Grcar eigenvalue workflow, residual plotting, and balance/no-balance comparison. * Script F: negative-domain promotion, complex elementary functions, magnitude/phase operations, complex statistics, and complex plotting. The sequence methods used by the corpus are also native. `sort` supports dimensions one and two, ascending/descending order, stable ties, one-based indices within the sorted dimension, and MPFR comparison. Complex `sort` orders by native MPC magnitude and then phase; ascending NaNs are last and descending NaNs are first. `diff` supports order and dimension forms and performs repeated MPFR/MPC subtraction at the source precision. Order-zero `diff` returns a value-semantic copy, while the scalar default positive-order case produces the same empty result shape as Octave. The S08 structural audit covers `length`, `size`, `rows`, `columns`, `numel`, `ndims`, and `isempty`, including empty matrices. The 1024-bit `2^-700` and 2048-bit `2^-1500` tails verify that sequence results retain the operation precision and that changing the ambient default afterward does not rewrite stored values. Native sequence tests run under ASan and UBSan. Surface graphics such as `mesh` remain intentionally rejected. The common line-graphics bridge from S07 remains the supported visualization boundary. Unsupported calls are tested as explicit stops, and builtin non-`mp` calls remain available to Octave. No ordinary-script numerical path falls back to builtin binary64 complex arithmetic. ## Known intentional stops The compatibility firewall still rejects APIs that are outside the current dense two-dimensional surface, including surface/matrix graphics such as `mesh`, sparse and symbolic workflows, and general N-D storage. The accepted line-graphics conversion remains confined to the final plotting boundary and is never reused by numerical functions. mplapack-interop-0.5.1/docs/mplapack-interop-hilbert.md0000644000230300031750000000353215274353473022416 0ustar rafaelrafael# Hilbert inverse: `mplapack-interop` This example shows a high-precision Hilbert inverse at the Octave package boundary: GNU Octave uses the `mplapack-interop` package and its public `mp` class. Hilbert matrices are ill-conditioned, so constructing them in binary64 first would hide the precision that the example is intended to demonstrate. The example therefore forms `1/(i+j-1)` directly at the selected MPFR precision. ## Octave ```octave pkg load mplapack-interop previous_bits = mpbits (); unwind_protect mpbits (1024); n = 6; H = mp (zeros (n, n)); for j = 1:n for i = 1:n H(i, j) = mp ("1") ./ mp (sprintf ("%d", i + j - 1)); endfor endfor I = mp (eye (n)); Hinv = H \ I; residual = H * Hinv - I; disp (Hinv); disp (residual); fprintf ("binary64 residual infinity norm: %.3e\n", norm (double (residual), inf)); unwind_protect_cleanup mpbits (previous_bits); end_unwind_protect ``` `H \ I` remains a useful multiple-right-hand-side solve. N01 also provides `inv(H)` when an explicit inverse is desired, using the same stored precision and operation-owned LAPACK path. The solve uses the public MPLAPACK-backed left-division path and supports multiple right-hand sides. `hilb(n)` is not used because its builtin result is a binary64 matrix. `double` appears only in the final diagnostic, after the high-precision calculation is complete. The wrapper restores the caller's ambient MPFR precision even if the calculation raises an error. The runnable file is [`../examples/05_hilbert_inverse.m`](../examples/05_hilbert_inverse.m). ## MPLAPACK release QA The installed MPLAPACK public-header consumer boundary, including `MplapackMpfrPrecisionScope` and the MPFR backend routines, is validated by the separate MPLAPACK release QA. The C++ consumer source is intentionally not shipped in this Octave package's examples. mplapack-interop-0.5.1/docs/conversion-display.md0000644000230300031750000001035315274353473021350 0ustar rafaelrafael# Scalar conversion and display ## Scope M05 defines conversion and display for one public scalar `mp` value. M10 extends the same native primitives to dense matrices for read-only `double` and `disp`; matrix `char` and serialization remain deferred. ## Canonical decimal representation Finite nonzero values use normalized base-10 scientific notation: ```text [-]d[.digits]e[+|-]exponent ``` There is one nonzero digit before the optional decimal point, the exponent marker is lower-case `e`, the exponent sign is always present, and its magnitude has no leading zeroes. Redundant trailing zeroes in the fractional significand are removed without changing the decimal value. The implementation calls `mpfr_get_str` with base 10, zero requested digits, and `MPFR_RNDN`. MPFR 4.2.2 defines zero requested digits as `mpfr_get_str_ndigits(10, p)`, where `p` is the source value's precision. That is the certified digit count with which rounding-to-nearest output can be read back at the same precision using rounding to nearest. This behavior and the matching `mpfr_free_str` ownership rule were audited against the [MPFR 4.2.2 conversion-function manual](https://www.mpfr.org/mpfr-4.2.2/mpfr.html#Conversion-Functions-1). ## Round-trip guarantee For a finite scalar `x` with precision `p`, parsing `char(x)` at precision `p` reconstructs the same MPFR value. The text is not promised to be the shortest decimal and is not a precision-independent exact serialization of the binary rational. Future save/load support will need an explicit serialization contract and precision metadata. ## Precision dependence Formatting reads the immutable precision stored in the object. It never uses or changes the current default precision. Consequently, changing `mpbits` does not change `char(x)` or `disp(x)` for an existing value. ## Special values Canonical special forms are: ```text Inf -Inf NaN ``` The existing native text constructor accepts these forms. ## Signed zero Positive zero is `0` and negative zero is `-0`. Both the canonical text path and explicit binary64 conversion preserve the zero sign where the host IEEE binary64 implementation supports signed zero. ## Locale independence Canonical digits come directly from `mpfr_get_str`; no locale-sensitive stream, `printf` numeric conversion, or Octave binary64 formatter participates. The decimal point is always `.`. M05 does not change the process locale. ## Binary64 conversion `double(x)` calls `mpfr_get_d` directly on the stored value. It does not pass through decimal text. This conversion is explicitly lossy whenever the value cannot be represented exactly in IEEE binary64. ## Rounding mode Both canonical digit extraction and binary64 conversion explicitly request `MPFR_RNDN`, round to nearest with ties to even. They do not depend on or modify MPFR's mutable default rounding mode. ## Display behavior Scalar `disp(x)` writes `char(x)` followed by one newline. It therefore uses the same canonical multiprecision representation and does not convert through binary64. The result is intentionally independent of Octave `format short` and `format long` settings. M10 matrix `double(A)` preserves the matrix shape and calls `mpfr_get_d` directly for every native element. Matrix `disp(A)` applies the same canonical scalar formatter in column order and emits deterministic row-separated text. Neither operation changes the source precision or current default. ## Memory and error handling The buffer returned by `mpfr_get_str` is held by a project RAII owner and released with `mpfr_free_str` on every path. Output size arithmetic is checked before reserving or appending to a C++ string. Allocation and native conversion failures are translated at the Octave extension boundary. ## Non-goals M05 does not add implicit numeric or textual conversion. Unsupported operators and generic numeric functions remain errors. User-selectable display precision, shortened display modes, `printf` integration, and exact serialization are outside this milestone. ## Future matrix display considerations M05's formatter is a scalar primitive that future dense matrix display may reuse. Dense matrices will use the native M07 representation and will not be represented or displayed as arrays of independent scalar wrapper objects. mplapack-interop-0.5.1/docs/svd-tiers.md0000644000230300031750000002166115274353473017444 0ustar rafaelrafael# Tier S/A/V SVD examples `examples/svd_tiers/` is a reproducible example and verification harness for difficult dense singular-value problems. It is not another SVD implementation and it does not add a public package API. The existing `mp`/`svd` path remains the only numerical solver path; the harness records its actual inputs and outputs, then applies separate reference and certificate checks. The suite has three layers: | Tier | Purpose | What is implemented | |---|---|---| | S | Structured difficult inputs | NRO blocks, Jacobi--Stirling, Lah, and DD representations | | A | Accuracy-oriented families and controls | Pascal, dyadic Vandermonde, bidiagonal, Lauchli, Hadamard, and NRO companion-like inputs | | V | Self-contained verification baselines | polar/Weyl singular-value inclusions, signed-dilation projectors, compatible factor boxes, and Neumann inverse certificates | The V methods are conservative baselines for the corresponding claims. They are not ports of the complete algorithms in the cited papers. In particular, the implementation does not claim interval-input coverage, sharp componentwise bounds, or the operation count of those algorithms. ## Quick start From a configured checkout with `mplapack-interop` loaded: ```octave pkg load mplapack-interop addpath (fullfile (pwd (), "examples", "svd_tiers")); smoke = mp_svd_tiers ("smoke"); demo = mp_svd_tiers ("demo", struct ("tier", "all", ... "output_dir", fullfile (pwd (), "svt-demo"), ... "plot", false)); assert (demo.ok); ``` The smoke profile contains 20 cases and exactly 120 measured SVD rows. The demo profile contains 23 cases and exactly 184 measured rows. References, inverse solves, and V jobs are reported separately from these SVD rows. Stress is opt-in and is not part of the default acceptance wall. The numbered top-level files are family indexes and full smoke aggregators; the one-case worked examples are: ```text examples/14_svd_tier_s.m Tier-S case index plus full smoke aggregator examples/15_svd_tier_a.m Tier-A case index plus full smoke aggregator examples/16_svd_verified.m V1 singular-value and V3 inverse certificates ``` The one-case runnable files and matching detailed explanations are indexed by `docs/examples/tiered/README.md`. The full profile commands above remain the authoritative way to obtain all measured rows and verification jobs. ## Precision and input identity The harness keeps four precision roles distinct: 1. `work_bits` is the stored precision of the actual SVD input; 2. construction precision is the precision used while materializing a model; 3. reference precision is used for a separate high-precision SVD of the frozen represented input; and 4. evaluation precision is used to widen values for diagnostics and interval arithmetic. An exact model and its represented input are both retained in the fixture identity. A below-guard diagonally dominant row is explicitly labeled as a rounded recipe; the ideal model spectrum is never silently imposed on that rounded input. Native rows are made by one explicit conversion from an exact model and are frozen for both values-only and economy calls. The arithmetic and certificate paths use the stored MPFR/MPC values at one operation precision. A result may be widened for diagnostics, but it is never recomputed at a higher precision and substituted for the measured result. No measurement, comparison, or certificate is routed through binary64. Optional plots are presentation-only conversions and are not fed back into any gate. ## Case inventory The normative case list is `docs/codex/svt/cases.json`. The smoke cases are: ```text S1-NRO-TWO S1-NRO-THREE S1-NRO-GRADED S2-JS S3-LAH S4-DD-SYM S4-DD-NONSYM A1-PASCAL-LOWER A1-PASCAL-SYM A2-VAND A3-BDI-RAW A3-BDI-MIXED A4-LAU-TALL A4-LAU-WIDE A5-GEO A5-CLOSE A5-REPEAT A5-RANK4 A5-RANK5 A6-NRO-COMPANION ``` The demo adds `A4-LAU-COMPLEX`, `S1-NRO-SCALE-UP`, and `S1-NRO-SCALE-DOWN`. These controls exercise complex phase handling and global scale range without changing the solver or precision contract. ## Ordinary diagnostics For each measured row the writer records the case, tier, family, mode, native flag, work precision, input identity, timing, and status. Economy rows also record reconstruction and the two triplet residuals: ```text rho_rec = ||A-U*S*V'||F / ||A||F rho_R = ||A*V-U*S||F / (||A||F*||V||F) rho_L = ||A'*U-V*S||F / (||A||F*||U||F) ``` Orthogonality/unitarity, positive ordering, frozen-input error, model error, zero leakage, and condition diagnostics remain separate fields. Factor signs and complex phases are not compared column-by-column. Repeated singular values are checked as subspaces or by a compatible-factor claim. ## Output bundle When `output_dir` is supplied it must be new and empty. The harness refuses to overwrite a previous run. It writes: ```text summary.tsv singular-values.tsv verification.tsv certificates.json summary.json inputs-and-factors.json environment.txt report.md plots/ # only when plot=true ``` The files use schema `svt-v1`. TSV decimal strings are display fields. JSON certificates and factor records include exact MPFR/MPC V4 dyadic snapshots, source precision, and canonical SHA-256 bindings. `inputs-and-factors.json` contains the actual target matrix and factors used by the replay checker; it is not a decimal-only export. `svt_replay_snapshots` decodes those snapshots independently before checking their shapes, values, and canonical hashes. `svt_check_coverage` rejects an empty, incomplete, or duplicate row set. These are hard structural checks, not reporting conveniences. ## Tier V jobs V1A uses method ID `svt_polar_weyl_v1` and encloses every ordered singular value from the actual stored factors. V1B uses `svt_dilation_projector_v1` for declared positive clusters, including structural zero directions in rectangular problems. Internal multiplicity is allowed; a collapsed external dilation gap produces `INCONCLUSIVE`. V2 uses `svt_dilation_factor_boxes_v1`. It returns compatible norm-derived entrywise boxes for separated simple singular pairs and applies one common sign/phase to the left/right pair. Individual identification of repeated vectors is explicitly `UNSUPPORTED_MULTIPLICITY`, while the V1 subspace result remains valid. V3 uses `svt_neumann_inverse_v1`. It consumes a public solve output and checks an outward residual bound `r < 1` before returning a positive inverse-norm or `sigma_min` lower bound. Singular, poor-inverse, and rectangular controls are recorded as `INCONCLUSIVE` or `UNSUPPORTED_RECTANGULAR`; none is reported as a singularity proof merely because a sufficient condition failed. Valid statuses are deliberately distinct: ```text CERTIFIED INCONCLUSIVE UNSUPPORTED INVALID_DATA ARITHMETIC_CONTRACT_UNPROVEN ``` Every verification job has a separate `gate_ok` and `meets_accuracy_target` field. A broad but valid inclusion can therefore be reported as certified without being advertised as a narrow accuracy result. All jobs record `paper_algorithm_reproduction=false`. ## Integrated tests `test/test_svd_tiers.m` and `test/test_svd_verification.m` are run from the existing `test/run_tests.m` runner. The former covers the Tier S/A constructors, input identity, measured SVD contract, and all allocated families. The latter covers V0 arithmetic preconditions, V1 values/projectors, V2 factor boxes, V3 inverse bounds, and adversarial controls. Existing N02 SVD and NEIG tests remain in the same runner and are not replaced. `tools/test-doc-examples.sh` runs examples 01--16, including the three SVT examples, and performs the existing help-text wall. `tools/check-docs.sh` checks the Texinfo chapter, generated Markdown, API inventory, backend map, examples, and help coverage. No SVT example changes the installed `mp` API. ## Source and interpretation ledger The exact source/interpretation ledger is `docs/codex/svt/SOURCES.md`. The NRO, Jacobi--Stirling, Lah, DD, Pascal, totally-nonnegative, Lauchli, and verification references motivate the families or claim classes. Dimensions, dyadic scalings, phase controls, acceptance targets, and the exact replay format are suite adaptations. They are not reproduced published tables. The implementation uses the public `mp`, `mpbits`, dense arithmetic, `svd`, and solve operations. It adds no backend, SVD driver, rounding setter, dependency, or installed header. See `docs/svd-verification.md` for the proof-to-code boundary and failure classification. ## Limitations The default acceptance is smoke/demo, not the opt-in stress profile. Native binary64 rows are explicit rounded-input comparisons, not high-precision answers. Repeated individual singular vectors are not uniquely certifiable. The V methods certify only their stated sufficient conditions; an `INCONCLUSIVE` result is not evidence of singularity. Plot output, operating system portability, and binary distribution are outside this example suite.