Skip to content

funNystrom++ - #132

Closed
mmelnich wants to merge 14 commits into
mainfrom
funnystrompp
Closed

funNystrom++#132
mmelnich wants to merge 14 commits into
mainfrom
funnystrompp

Conversation

@mmelnich

Copy link
Copy Markdown
Contributor

WIP

mmelnich added 14 commits May 7, 2026 18:49
Timing:
- NystromEVD: bool timing flag + times[11] (alloc, syrf, matvec, gram,
  potrf, trsm, svd, post_svd, error_est, rest, total); += accumulation
  across adaptive iterations; skip error_est block entirely when
  error_est_p==0 && tol==0 (the fixed-rank FunNystromPP path)
- LanczosFA: bool timing flag + times[5] (matvec, run_lanczos, apply_f,
  rest, total); _t_matvec_us accumulated inside run_lanczos per A-call,
  reset at top of both run_lanczos and call(); workspace_per_thread
  formula written as d*d+4*d-1 to match comment
- FunNystromPP benchmark: nystrom_evd.timing=true, lfa_pp.timing=true;
  per-phase printf breakdown; 32 CSV columns (up from 16)

Bug fixes:
- power_error_est: inner loop variable shadowed outer iter; m=1 column-
  scaling bug from && i!=0 guard; replaced with explicit double loop
- power_error_est: 1.0/0.0 literals -> (T)1/(T)0 for float safety;
  same fix applied throughout NystromEVD::call()
- NystromEVD::call(): int i -> int64_t i in post-SVD eigval loop
- nystrom_pc_data: auto out_state captured int return of call() instead
  of advanced RNGState; fixed to NystromAlg.call(); return state;
- Benchmark printf: nt[9] (nystrom_rest) was dropped from console output
- LFAOp: scalar_t hardcoded as double; use typename SLO_t::scalar_t
- call_all_algs: state param is never modified; changed to const&

Safety:
- Deleted copy ctor/assignment on NystromEVD, LanczosFA (+ explicit
  default ctor), Hutchinson (+ explicit default ctor), FunNystromPP
  to prevent double-free on accidental copy

Test:
- ASSERT_NEAR(err, target, 10*target) -> ASSERT_LT(err, 10*target)
mmelnich added a commit that referenced this pull request May 14, 2026
…entize

Reference-aligned Persson-Kressner port with bit-exact MATLAB↔C++
cross-validation at LAPACK noise floor.

- Phase 5: vendored RandLAPACK::LanczosFA + BlockLanczosFA from
  funnystrompp; util::upsize raw-pointer overload, util::symmetrize.
- Phase 6: SASO sketch (RandBLAS::SparseSkOp) + SkOp-aware first matvec
  via right_spmm through ExplicitSymLinOp overload.
- Phase 7a: Cholesky-fast / eig(YᵀY) HMT §5.1 path in NystromEVD_v2.
  5-rep median speedup vs SVD-pinv fall-back: 2.71×-3.80× across
  k∈{500,1000,1500,2000} at n=2000 (3.80× at k=n=2000, exceeds the
  ~2× claim in funnystrompp PR #132).
- Phase 7a-perf: force_fallback knob + tight t_specrec_ms inner timer.
- Gap port (#1,#2,#3,#5): optional f_zero correction, Phase 2 skip at
  k==n, gesdd(G)→syevd(G) in fall-back, SkOp overload on
  FunNystromPP_v2::call.
- Componentize: NystromEVD_v2 + workspace moved to drivers/rl_nystrom_evd_v2.hh.

12 cross-validation fixtures pass at tol=1e-11 (10/12 at strict
tol=1e-12; 2 misses are alg_poly.t2 ~1.4e-12 long-standing cancellation
noise). v2 unit tests 4/4. Full RandLAPACK suite 309/309.
@mmelnich

Copy link
Copy Markdown
Contributor Author

Reworking this PR in #138

@mmelnich mmelnich closed this May 15, 2026
mmelnich added a commit that referenced this pull request May 25, 2026
…pace, 11-slot timing

Bundle #2 of the v2-polish cycle:

  * Rename rl_nystrom_evd_v2.hh → rl_nystrom_evd.hh; NystromEVD_v2 free
    function → NystromEVD; NystromEVD_v2_workspace → NystromEVD_workspace.
  * Convert workspace from std::vector<T> members to raw T* + int64_t
    pairs grown via util::upsize and freed in a destructor, matching
    PR #132 / rl_revd2.hh patterns. Output params now use
    (T*&, int64_t&) references-to-pointer.
  * Add 11-slot timing vector (alloc / syrf / matvec / gram / potrf
    / trsm / svd / post_svd / error_est=0 / rest / total) with per-
    phase chrono instrumentation; gated on ws.times_enabled. Layout
    mirrors PR #132's NystromEVD for cross-driver tooling parity.
    Slot 8 (error_est) is unused in this fixed-k variant; kept at
    index 8 to preserve the V1 layout.
  * FunNystromPP_v2: U, lambda, Y_2, fAOmega, Y0 promoted from stack
    std::vectors to persistent raw-pointer class members; nystrom_ws
    promoted to a class member so allocations are reused across
    repeated call() invocations. Destructor frees all five buffers.

FunNystromPP_v2's public call signature is unchanged.

Verification:
  * make -j8 + make install -j8 + benchmark rebuild: clean
  * v2 unit tests: 4/4 PASS (FullRankCapture err_t1 = 2.426e-16)
  * 12-fixture cross-validation at tol=1e-12: 10/12 pass, same 2
    alg_poly.t2 cancellation-regime cells as pre-refactor
    (rel_Δ = 4.241e-13, 1.399e-12). est at noise floor across all
    12 fixtures (rel_Δ ∈ [0.0, 3.835e-15]).
mmelnich added a commit that referenced this pull request Aug 6, 2026
Native Windows (MSVC) support, mirroring the recipe RandBLAS PR #179
validated: Visual Studio 2022, Intel oneMKL from vcpkg with **ILP64 +
sequential** linking (RandBLAS's MKL sparse backend requires 64-bit
`MKL_INT`), and BLAS++/LAPACK++ built from the BallisticLA branches that
carry the two one-line MSVC fixes still open upstream (blaspp PR #132,
lapackpp PR #87).

An audit of the whole tree found the **library headers need zero code
changes** for MSVC — every blocker was at the edges. Four commits:

1. **RandBLAS submodule bump** to current main. The old pin (May 2026)
predates RandBLAS's Windows support, so this is a prerequisite; it also
brings in three sketching-performance PRs (#173, #174, #176). The full
local suite — RandLAPACK's 337 tests plus RandBLAS's 449 — passes
against the new pin.
2. **MSVC portability, sources + CMake**:
- Tests: `__PRETTY_FUNCTION__` (GCC/Clang-only) → the
`__RANDBLAS_PRETTY_FUNCTION__` macro RandBLAS's `comparison.hh` now
provides (36 sites; every affected file already includes that header).
- Benchmarks: the repository's only two C variable-length arrays
(`gejsv` integer workspaces) become heap allocations; a pre-existing
workspace leak in `find_test_mat_spectrum` is freed along the way.
- CMake: warning flags and benchmark `-g` become compiler-conditional
(MSVC gets `/W4`); the header-only target exports `/utf-8` to MSVC
consumers (several headers carry non-ASCII characters in string
literals); `SANITIZE_ADDRESS` learns the MSVC spelling; new
`CMake/rl_runtime_dlls.cmake` stages dependency DLLs beside test
executables (`gtest_discover_tests` runs them at build time); the
`lapackpp_DIR` recorded in the installed package config is normalized
with `TO_CMAKE_PATH` so Windows backslash paths don't arrive as escape
sequences downstream; the template-heavy test translation units get
`/bigobj`.
3. **`core-windows` workflow**: windows-2022 runner, cached dependency
stack via a composite action, Ninja build, full ctest (standard ABRIK
exclusion). The job is named `build-windows`, deliberately distinct from
the required check `build`, so it can prove itself before being made
required. (RandBLAS's own tests ran inside this job in the first CI
rounds; item 7 turns them off.)
4. **`install.ps1`**: thin companion to `install.sh` — reuses the CI
dependency script (so the recipe exists exactly once), supports
`-MklRoot` for oneAPI installs instead of vcpkg, and mirrors the
`..\RandNLA-project` layout. INSTALL.md gains a native-Windows section.

**OpenMP is off on native Windows for now**: `rl_rpchol.hh` uses an
OpenMP `collapse(2)` clause that MSVC only accepts under `/openmp:llvm`,
while RandBLAS's build system pins MSVC OpenMP to
`/openmp:experimental`. All OpenMP use is guarded, so serial builds are
fully functional; reconciling the two runtimes is a RandBLAS-side
follow-up.

Also catalogued but deliberately not fixed here (they never touch ILP64
BLAS calls): the `long`-typed timing fields overflow at ~35.8 minutes
per timer on Windows (LLP64), and `rl_memory_tracker.hh`'s byte
arithmetic overflows at 2 GiB working sets — diagnostics-only issues,
queued for post-1.0 cleanup.

Verified on Linux after all changes: clean build, 785/786 tests (the one
failure is a documented machine-local GPU issue predating this work).
The first Windows execution is this PR's own CI run.

---

**Added after the first CI round:**

5. **Fix from CI iteration 1**: `rl_hqrrp.hh` and three BQRRP benchmarks
kept dead `#ifdef LAPACK_FORTRAN_STRLEN_END` blocks *inside* LAPACK
macro invocations — undefined behavior that GCC/Clang tolerate and MSVC
rejects (C2121). Pure deletion; the lapackpp variadic macros append the
string-length arguments themselves.
6. **`install-windows` CI job**, filling the slot reserved in the
installer workflow: runs `install.ps1` end-to-end plus an idempotent
re-run, sharing the cached dependency stack with `core-windows` (new
`-DependencyRoot` installer option).
7. **Core-CI speedups** (measured before: core-linux 10–12 min,
core-windows 12–16): BLAS++/LAPACK++/Random123 installs are now cached
in core-linux/core-macos; builds use all runner cores instead of `-j2`;
the RandBLAS submodule's ~450 tests no longer build and run inside every
RandLAPACK job (`-DBUILD_TESTS=OFF` — the pinned commit is already
tested by RandBLAS's own CI; the installer lanes keep them for user
parity); and the Debug/ASan build+suite is a parallel `build-asan` job
instead of running sequentially inside `build`. The required-check job
name `build` is unchanged.
8. **Installer scripts moved to `install/`** (`install/install.sh`,
`install/install.ps1`), with a two-line wrapper kept at the root so
`bash install.sh` keeps working — the CI installer lanes call the
wrapper on purpose so it stays under test.
9. **`docs/CI.md`**: a map of the CI setup — what each of the eight jobs
validates, which checks are required, what is deliberately red (the
core-macos canary) or disabled (submodule tests, Windows OpenMP), cache
keys and how to bust them, and per-OS local-reproduction commands.
10. **RandBLAS bump to `/openmp:llvm`** (post-RandBLAS#184) and **an
OpenMP matrix leg in core-windows**: with RandBLAS selecting MSVC's LLVM
OpenMP runtime, RandLAPACK's OpenMP code (64-bit loop indices, the
`collapse(2)` in rl_rpchol) compiles under MSVC for the first time. The
workflow becomes serial + openmp, mirroring RandBLAS's own Windows
matrix; the "OpenMP disabled on MSVC" caveat retires from INSTALL.md.
11. **install.ps1 sanity-check fix**: the clone check tested a path that
never existed (`RandLAPACK/RandLAPACK.hh`; the umbrella header sits at
the repo root), so the install-windows job had never gotten past it.
mmelnich added a commit that referenced this pull request Aug 12, 2026
…upstream, pinned

Two findings from running every backend path against a real oneMKL install.

1. The architecture fix was necessary but NOT sufficient. With a correct x64
   toolchain and our own dgemm_/dgesv_ link check passing, BLAS++ still
   reported "BLAS library not found". Its try_compile log gives the real
   reason:

       ninja: error: 'C:/Program', needed by 'cmTC_x.exe', missing

   BLAS++ feeds library paths into that probe unquoted, so a path containing
   a space splits at the space. Intel installs oneMKL to
   C:\Program Files (x86)\Intel\oneAPI\ by default, so every *discovered*
   oneMKL hits this, as does any custom backend under Program Files. It was
   invisible to CI and to earlier local runs because the downloaded oneMKL
   lands in a space-free directory under the dependency root -- the one
   layout that avoids it. Proven by copying the identical libraries to a
   space-free path, after which BLAS++ finds them immediately.

   Worked around by staging backend import libraries into a space-free
   directory when, and only when, a path contains a space. Import libraries
   only name their DLL, which is still resolved at run time from the
   backend's bin directory, so this is safe. The underlying quoting bug is
   BLAS++'s and is worth reporting upstream.

2. BLAS++ and LAPACK++ were cloned from BallisticLA forks carrying two
   one-line MSVC fixes. Both merged upstream on 2026-08-06 (blaspp #132,
   lapackpp #87), so the forks are obsolete; both now come from
   icl-utk-edu. Verified the pinned commits carry the fixes.

   They were also pinned to *branch names*, i.e. a moving tip, inside a cache
   keyed on this script -- so a cache hit could restore a different revision
   than a cache miss builds. That is the same defect already fixed here for
   Random123. Clone-Head is now Clone-Pinned and takes a tag or a commit SHA,
   so every dependency is pinned to an immutable ref: blaspp 3057185,
   lapackpp 40b9d0d, GoogleTest v1.17.0, Random123 v1.14.0. Commits rather
   than tags for the first two only because the latest release of each,
   v2025.05.28, predates the merges. Cache keys renamed off the fork branches
   and bumped, so no fork-built artifact can be restored.

Verified on Windows against a real oneAPI install at the default (spaced)
location: discovery path 749/749 tests, and a full build from the upstream
pins 749/749, with both clones confirmed to originate from icl-utk-edu.

Also corrects two unverified doc claims: the quick start recommended a VS
edition and winget invocation that had never been run (missing --wait, which
returns while the installer is still going), and INSTALL_SCRIPT.md suggested
cmake@3.27 two paragraphs after stating the floor is 3.21.
mmelnich added a commit that referenced this pull request Aug 12, 2026
…ller fetches

The installer never supplies a compiler, CMake or Ninja -- those are the user's to provide,
same as on Linux and macOS. It does fetch the BLAS/LAPACK backend and the build-time
dependencies, and until now the versions were only discoverable by reading setup.ps1.

Adds a table naming each component, its exact pinned version, its upstream source and how it
is verified, plus two points that were implicit:

- oneMKL is downloaded ONLY when no existing oneAPI is discovered. When one is found the
  installer uses the user's version, so the documented version applies to the no-oneMKL case
  only.
- BLAS++ and LAPACK++ are pinned to commits rather than to their latest release,
  v2025.05.28, because that release predates the two one-line MSVC fixes this build needs
  (blaspp #132, lapackpp #87, merged upstream 2026-08-06). They move to a release tag once one
  includes them. Everything else is a stable, released version.

Sections renumbered to keep the new one in place; internal cross-references updated.
mmelnich added a commit that referenced this pull request Aug 12, 2026
…upstream, pinned

Two findings from running every backend path against a real oneMKL install.

1. The architecture fix was necessary but NOT sufficient. With a correct x64
   toolchain and our own dgemm_/dgesv_ link check passing, BLAS++ still
   reported "BLAS library not found". Its try_compile log gives the real
   reason:

       ninja: error: 'C:/Program', needed by 'cmTC_x.exe', missing

   BLAS++ feeds library paths into that probe unquoted, so a path containing
   a space splits at the space. Intel installs oneMKL to
   C:\Program Files (x86)\Intel\oneAPI\ by default, so every *discovered*
   oneMKL hits this, as does any custom backend under Program Files. It was
   invisible to CI and to earlier local runs because the downloaded oneMKL
   lands in a space-free directory under the dependency root -- the one
   layout that avoids it. Proven by copying the identical libraries to a
   space-free path, after which BLAS++ finds them immediately.

   Worked around by staging backend import libraries into a space-free
   directory when, and only when, a path contains a space. Import libraries
   only name their DLL, which is still resolved at run time from the
   backend's bin directory, so this is safe. The underlying quoting bug is
   BLAS++'s and is worth reporting upstream.

2. BLAS++ and LAPACK++ were cloned from BallisticLA forks carrying two
   one-line MSVC fixes. Both merged upstream on 2026-08-06 (blaspp #132,
   lapackpp #87), so the forks are obsolete; both now come from
   icl-utk-edu. Verified the pinned commits carry the fixes.

   They were also pinned to *branch names*, i.e. a moving tip, inside a cache
   keyed on this script -- so a cache hit could restore a different revision
   than a cache miss builds. That is the same defect already fixed here for
   Random123. Clone-Head is now Clone-Pinned and takes a tag or a commit SHA,
   so every dependency is pinned to an immutable ref: blaspp 3057185,
   lapackpp 40b9d0d, GoogleTest v1.17.0, Random123 v1.14.0. Commits rather
   than tags for the first two only because the latest release of each,
   v2025.05.28, predates the merges. Cache keys renamed off the fork branches
   and bumped, so no fork-built artifact can be restored.

Verified on Windows against a real oneAPI install at the default (spaced)
location: discovery path 749/749 tests, and a full build from the upstream
pins 749/749, with both clones confirmed to originate from icl-utk-edu.

Also corrects two unverified doc claims: the quick start recommended a VS
edition and winget invocation that had never been run (missing --wait, which
returns while the installer is still going), and INSTALL_SCRIPT.md suggested
cmake@3.27 two paragraphs after stating the floor is 3.21.
mmelnich added a commit that referenced this pull request Aug 12, 2026
…ller fetches

The installer never supplies a compiler, CMake or Ninja -- those are the user's to provide,
same as on Linux and macOS. It does fetch the BLAS/LAPACK backend and the build-time
dependencies, and until now the versions were only discoverable by reading setup.ps1.

Adds a table naming each component, its exact pinned version, its upstream source and how it
is verified, plus two points that were implicit:

- oneMKL is downloaded ONLY when no existing oneAPI is discovered. When one is found the
  installer uses the user's version, so the documented version applies to the no-oneMKL case
  only.
- BLAS++ and LAPACK++ are pinned to commits rather than to their latest release,
  v2025.05.28, because that release predates the two one-line MSVC fixes this build needs
  (blaspp #132, lapackpp #87, merged upstream 2026-08-06). They move to a release tag once one
  includes them. Everything else is a stable, released version.

Sections renumbered to keep the new one in place; internal cross-references updated.
mmelnich added a commit that referenced this pull request Aug 12, 2026
…l pinned

Everything the installer can fetch is now the newest stable release of that
component, pinned to an exact version:

  oneMKL      2025.2.0.627 -> 2026.1.0.226   (was four releases behind)
  GoogleTest  v1.17.0      -> v1.18.0
  OpenBLAS    0.3.34                          already newest
  Random123   v1.14.0                         already newest

BLAS++ and LAPACK++ stay pinned to commits rather than to v2025.05.28: that
release predates the two MSVC fixes this build needs (blaspp #132, lapackpp
#87). They move to a tag once one carries them; tracked in #158.

The oneMKL bump renames the runtime DLLs from mkl_*.2.dll to mkl_*.3.dll.
Nothing hardcodes those names -- staging globs *.dll -- so the change is
transparent, but it would have silently staged nothing had anything hardcoded
them. The package layout is otherwise unchanged (build/native/win-x64,
build/native/include, runtimes/win-x64/native).

Cache keys bumped for oneMKL and both GoogleTest variants, so no artifact
built from the old versions can be restored.

Verified on Windows, both provisioning paths:
- discovery against an installed 2026.1.0 oneAPI: link check OK
- forced NuGet download of 2026.1.0.226: both SHA256s verified, unpacked,
  "Found BLAS library", mkl_core.3.dll / mkl_sequential.3.dll staged
- GoogleTest v1.18.0 is a major bump touching every test: 749/749 pass
mmelnich added a commit that referenced this pull request Aug 12, 2026
References like "blaspp #132" and "lapackpp #87" were written bare. GitHub
resolves a bare #NNN against the repository it is rendered in, so these linked
to RandLAPACK #132 and #87 -- unrelated pull requests (funNystrom++ and a
benchmarking DNM) -- rather than to the upstream fixes they name. A reader
following them lands somewhere plausible and wrong, which is worse than a
dead link.

Now written as icl-utk-edu/blaspp#132 and icl-utk-edu/lapackpp#87, which
GitHub renders as cross-repository links. Same for the other upstream
references in these files.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant