144 lines
13 KiB
Markdown
144 lines
13 KiB
Markdown
# LA library - notes for Claude
|
|
|
|
C++ linear algebra library (author: Jiri Pittner). This file collects the working rules, design
|
|
decisions and plans agreed with the author, so that they survive a fresh clone. Keep it ASCII, LF.
|
|
|
|
## Communication
|
|
- The author works in an ASCII xterm without UTF-8 fonts: replies in plain ASCII only, formulas in
|
|
LaTeX style (A^{-1}, U^\dagger b, \sum_{k=1}^{N}, 10^{-15}, "-" for dashes).
|
|
- Do not ask for permission to run (non-destructive) shell commands; still confirm destructive or
|
|
outward-facing actions (deleting user files, git push).
|
|
- Bug fixing workflow: locate the cause, explain it, propose the MOST EFFICIENT fix, WAIT for the
|
|
author's OK, then patch, build, test, update documentation. One item at a time. Implement new
|
|
methods only on request; design proposals: offer alternatives with a recommendation, the author picks.
|
|
|
|
## Build and test
|
|
- Build the library with `make -j 8` (after header changes most files rebuild; run it in the background).
|
|
- Flags used: `-std=gnu++11 -O3 -DDEBUG -DFORTRAN_ -DNONCLAPACK`, libs `-lcblas -lblas -llapack`.
|
|
Quick test program: `g++ -std=gnu++11 -I<repo> -O0 -DDEBUG -DFORTRAN_ -DNONCLAPACK X.cc <repo>/.libs/libla.a -lcblas -lblas -llapack`
|
|
(add `-fsanitize=address` for memory checks).
|
|
- Regression test of the optimizers: `make check` builds `testoptimize`; `./testoptimize` must report
|
|
"137 passed, 0 failed" (exit code = number of failures). New optimizer tests go to testoptimize.cc;
|
|
test problems live in testoptimize.h.
|
|
- `t` (t.cc) is a collection of if(0)/if(1) test blocks, most read n from stdin (`echo 10 | ./t`).
|
|
- NONCBLAS check: copy the repo with `cp -a` (keeps timestamps, otherwise automake reruns and fails),
|
|
`make clean; make -j 8 CBLASOPT=-DNONCBLAS CBLASLIB=`.
|
|
- laerror() runs a shell (whoami, hostname) each time: loops raising thousands of laerrors are very slow.
|
|
- The shell is tcsh (`^!` in double quotes is history expansion; use bash -c or python for scripts).
|
|
- Manual: doc/manual.tex (LaTeX, 19 chapters, macros in doc/lamacros.tex: \code, \header, \lafunc in
|
|
lareference, \latodo = yellow question box, \lawarning). Build with pdflatex three times (into a scratch
|
|
directory with -output-directory), require 0 log lines starting with "!", copy manual.pdf into doc/.
|
|
|
|
## Coding rules
|
|
- Mirror the author's style in every file: tabs; braces on their own line indented with the body;
|
|
no space after `if(`/`for(`; terse names; short `//` comments (Doxygen only where the file uses it);
|
|
errors via laerror("..."); `#ifdef DEBUG` dimension checks; NOT_GPU/SAME_LOC like neighbouring code;
|
|
noncblas.cc: follow the existing wrapper pattern (FORNAME, `#ifdef FORINT` copies).
|
|
- Byte-minimal edits; files are LF. If a CRLF file is found, report it (the author converts it), never
|
|
convert line endings yourself. Edit scripts must work in binary mode.
|
|
- Templates declared in headers, explicit specializations (double, complex<double>) in .cc files;
|
|
instantiations via `#define INSTANTIZE(T) ...` + `INSTANTIZE(double)`.
|
|
- No verbatim copying of foreign copyrighted code (GPLv3 with reference is OK).
|
|
- Always prefer the most efficient solution (no extra passes, copies or allocations), even if a wrapper
|
|
elsewhere (e.g. noncblas.cc) must be extended.
|
|
- Default scope of optimizer work: optimize.h, optimize.cc, t.cc (+ testoptimize.*); ask before
|
|
touching other files if that would give a better solution. Optimizer code must not call BLAS directly
|
|
nor loop over vector/matrix elements - use the library classes.
|
|
|
|
## Copy-on-write (core design)
|
|
- All large-data classes share data on copy/assignment (NRVec, NRMat, NRSMat, SparseMat, SparseSMat,
|
|
CSRMat, fourindex, Tensor (data, shape, names), polynomials, permutations, bitvector, *_from1).
|
|
- Every member function modifying the object as a whole must call copyonwrite() itself; a missing one
|
|
is a library bug. resize() detaches.
|
|
- Element-level access is deliberately exempt (operator[], operator(), raw pointers, NRVec::swap(i,j),
|
|
SparseMat/SparseSMat::add, bitvector bit operations): no copyonwrite() in inner loops; the caller calls
|
|
copyonwrite() once before writing. Do not add reminder comments about this to the code.
|
|
- Also check user code (t.cc, test programs) for missing copyonwrite() before element writes; read
|
|
possibly shared non-const objects through const references (DEBUG count check).
|
|
|
|
## Design decisions (2026-10)
|
|
- Complex NRSMat is HERMITIAN (lower triangle stored, upper = conj) in arithmetic: products,
|
|
NRMat(NRSMat), NRSMat(NRMat) = (A+A^\dagger)/2, NRMat +=/-= NRSMat, sum(), fprintf(), linear_solve,
|
|
diagonalize, trace2. BUT NRSMat::operator() (const AND non-const, also NRSMat_from1) is plain storage
|
|
access without conjugation - a conjugating const operator() was tried and REVERTED as too dangerous;
|
|
never reintroduce it. operator<<, permuted, submatrix(selection), rsum, csum keep storage semantics.
|
|
- SparseSMat is a general (also rectangular) row-wise sparse matrix; add(i,j,x) with default both=true
|
|
adds x at (i,j) and conj(x) at (j,i); NRSMat(SparseSMat) takes the lower triangle; operator* is the
|
|
general product A B (correct for hermitian, complex symmetric exp(iH) and general matrices);
|
|
SparseSMat::gemm computes A^T B (A^\dagger B with 'c'); otimes_sparse = M + M^\dagger incl. doubled diagonal.
|
|
- CSRMat (completed 2026-11): compressed row format, members NRVec rowptr/col/v (share independently, value-only operations keep
|
|
the index arrays shared), columns strictly ascending in each row, full matrix always stored; flag symmetric only DECLARES hermitian
|
|
(A=A^dagger, for davidson/lanczos), set by CSRMat(NRSMat) and for real types from a symmetric SparseMat, never checked. Built by
|
|
conversion (SparseMat, SparseSMat, NRMat, NRSMat, arrays); conversions drop |x|<=sparse_epsilon, arithmetic keeps cancelled zeros
|
|
(simplify). dot conjugates the left operand (as NRMat); permuteme_rows permutes only rows; CSR*CSR = Gustavson; types double, float,
|
|
complex<double>, complex<float>, CPU only (cuSPARSE format for later). Tests bugtests/core/csrmat1,3,4,5 and iterative/csrmat2.
|
|
- SparseMat with the symmetric flag is complex symmetric (no conjugation); its permuteme_* members use
|
|
0-based matrix indices, NRPerm/CyclePerm are always 1-based.
|
|
- Permutations: applypermutation(p,v,inverse) uses the same convention as NRVec::permuted (r_{p(i)}=v_i
|
|
without inverse); generate_all parity_select +1 = even, -1 = odd permutations; list_all weights = parity,
|
|
list_all_lex weights = 1. NRPerm::testik is kept inside #if 0 as the author's reminder.
|
|
- ContFrac::canonicalize works on the terms (no p/q, fixed-size integer T) and requires a_1..a_n of the
|
|
same sign (documented limitation, author's choice). Rational keeps the denominator positive.
|
|
- bitvector: set/reset/flip/assign/setblock/block &=,|=,^= are element-level (no copyonwrite, DEBUG count
|
|
check); < and > compare numerically (bit i weight 2^i); <<= enlarges the vector.
|
|
- Vec3/Mat3/Quaternion: euler2normquat is consistent with euler2rotmat for all 12 Euler types and
|
|
normquat2euler is its inverse; "zyx", normquat2eulerzyx, eulerzyx2normquat must stay unchanged (used by the
|
|
author's avionics code in arm_stm32f37). Mat3::svd(...,true) gives det U = det V = +1. randomize exists for
|
|
float and double. Embedded builds are float only (QUAT_NO_DOUBLE).
|
|
- Tensor(const NRSMat&) uses symmetry 2 (hermitian) for complex, 1 for real.
|
|
- a-X and a/X (scalar minus/divided by object) are deleted on purpose; a single integer constructor is
|
|
forbidden for NRMat, NRMat_from1, Mat3 (Mat3(double) works).
|
|
- Real-storage gdiagonalize uses the dgeev convention (Re + i Im).
|
|
- The NRMat offset view constructor is a feature. MATPTR is kept (rarely used). CSRMat: see above. NRMat::strassen (2026-11-06): native Strassen-Winograd in strassen.cc, gemm-compatible
|
|
parameters + cutoff (default LA_traits<T>::strassen_cutoff()=2048 all types, to be tuned on HPC), explicit only (gemm stays classical),
|
|
CBLAS leaves on strided quadrants, device primitives separated for CUDA; NO_STRASSEN removed everywhere. CUDA (CUDALA) is deferred/experimental
|
|
until the author has NVIDIA RTX hardware (known CUDA issues collected in suspected_bugs.md F10).
|
|
- The regression module (reg.*, regsurf.*) is experimental, not much tested in practice (remarked in the manual);
|
|
its NEA oscillator strength f=dE_min/dE is a placeholder for the true one.
|
|
|
|
## Planned (only when the author asks)
|
|
- float version (IN PROGRESS since 2026-11-05): float and complex<float> must ALWAYS use BLAS/LAPACK (s*/c* routines,
|
|
noncblas wrappers) like double/complex<double>, never generic loops. Done: noncblas, vec, mat, smat, nonclass (+ complexify
|
|
BLAS for NRSMat/NRMat), sparsemat, sparsesmat, tensor, fourindex, polynomial, header templates (matexp,
|
|
conjgrad, gmres, davidson, lanczos, diis: no changes needed beyond the defaults). Float twins are generated from the double specializations (placed right after them). Precision-
|
|
dependent defaults live in LA_precision<T> (la_traits.h, only double and float; double values unchanged). optimize done
|
|
2026-11-05: own trait opt_precision<T> in optimize.h, INSTANTIZE(float), float tests in testoptimize.cc (test_float);
|
|
float LM on badly scaled problems needs my_scaling=true. reg/regsurf, CUDA stay double-only.
|
|
Tensor Tucker bugs fixed 2026-11-06 (complex: factor = vt.transpose(false); unnamed tensors with inverseorder; bugtests/tensor/tucker.cc).
|
|
BLAS-based NRVec members are meant for floating types only, not integers.
|
|
- NRSMat: possible bool member `hermitian` toggling hermitian vs complex symmetric behaviour
|
|
(Tensor(const NRSMat&) must then respect it).
|
|
- SparseSMat: possible member `symmetry_type` (0 none, 1 symmetric, 2 hermitian) for NRSMat conversion,
|
|
otimes_sparse, gemm, issymmetric, backward compatible.
|
|
- Optimizers (optimize.h/.cc, all 11 planned methods done: BFGS/DFP/SR1, L-BFGS, CG, Nelder-Mead,
|
|
Powell, Adam/SGD, SPSA, GDIIS, QNG/Rotosolve, COBYLA, trust region/P-RFO, Levenberg-Marquardt):
|
|
open for later - global optimization layer, further Hessian-based methods, FIRE, CMA-ES, Polyak averaging.
|
|
|
|
## Status files (may be absent in a fresh clone; the author keeps them outside git)
|
|
- suspected_bugs.md: verified bug list with SOLVED / NOT A BUG / DEFERRED marks and reasons; each item
|
|
has a test in bugtests/<core|misc|tensor|reg|util|iterative>/<id>.cc (build.sh per directory).
|
|
- doc_questions.md: documentation questions with the author's answers.
|
|
- instructions, answers, answers2, answers3, optimize_discussion*.md: optimizer design discussion history.
|
|
- Bug fixing goes file by file. Done (2026-10-27/28): nonclass, vec, mat, smat, sparsemat, sparsesmat,
|
|
tensor, fourindex, permutation, polynomial/contfrac, small classes (vecmat3, quaternion, bitvector),
|
|
regression D1-D16, iterative A26-A30 + A38 (2026-10-29), misc C31, C38-C42, B4 (2026-10-30): all bugs closed;
|
|
all doc questions answered (2026-10-30), the manual has no open question boxes.
|
|
- configure.ac and Makefile.am were changed 2026-10-30 (--enable-fortran64int, TESTS = testoptimize, targets manual/doc,
|
|
doxygen; all-local builds only the manual (if pdflatex found), doxygen only on request; MANUAL_TEX lists the .tex files - add new chapters there): run autoreconf.
|
|
- configure.ac (2026-11-06): OpenBLAS (with LAPACK+CBLAS) preferred after MKL, only -lopenblas linked; --without-openblas;
|
|
not with --enable-fortran64int (its parsing moved up). Test programs then link with -lopenblas instead of -lcblas -lblas -llapack.
|
|
- matexp.h: exp()/sincos() default horner=false (polynom, faster for dense); use horner=true for sparse matrices.
|
|
- AuxStorage temporaries go to $TMPDIR (else cwd) and are unlinked at once; AuxStorage and DIIS are not copyable.
|
|
- reg.cc/regsurf.cc cache raw pointers into their NRVec/NRMat members (set in Init): never reallocate those
|
|
members (no |=, resize, assignment of a new object); copy in place with storesubvector(0,...).
|
|
|
|
## User's application files (do not modify, only check that library changes do not break them)
|
|
- quantcomp.h (uses SparseSMat via gemv_n and the obsolete QCholesky), fcidumpcheck.cc.
|
|
- arm_stm32f37/ (read-only): the author's STM32 embedded project; math/ links to vecmat3.*, quaternion.*,
|
|
simple.* of this library, built with arm-none-eabi-g++ and -DQUAT_NO_DOUBLE -DNO_NUMERIC_LIMITS
|
|
-DQUAT_NO_RANDOM -DAVOID_STDSTREAM -DAVOID_LA: changes to these files must keep compiling there.
|
|
- gelfand/ (read-only): the author's quantum chemistry programs using the library heavily (fourindex_dense
|
|
T2ijab_aces etc., Tensor, SparseSMat); check there how library features are used before changing semantics.
|
|
Observations about gelfand (possible bugs there, effects of library fixes, how to check) are kept in
|
|
readme.gelfand in the repository root; add new ones there.
|