From 05f704d51a9d5100bb541eebb4425ecdfbb22b34 Mon Sep 17 00:00:00 2001 From: Jacob Watters <47160062+jacobdwatters@users.noreply.github.com> Date: Fri, 21 Feb 2025 14:06:40 -0700 Subject: [PATCH] Add Support For LaTeX in Docs (#125) * Add some latex for MathJax testing. * Improve forward and backward Javadoc. * Texify Everything (#124) Adds the ability to specify LaTeX in Javadoc. Adds a GitHub action to automatically parse and inject latex into Javadocs published on the GitHub pages website. --- .github/workflows/javadoc-gh-pages.yml | 29 +- .gitignore | 1 + README.md | 2 + figures/intelij_doc_render.png | Bin 0 -> 3164 bytes figures/latex_in_javadoc.png | Bin 0 -> 10953 bytes scripts/USAGE.md | 262 +++++++++++++++++ scripts/convert_latex.py | 222 ++++++++++++++ .../java/org/flag4j/linalg/DirectSum.java | 57 ++-- src/main/java/org/flag4j/linalg/Invert.java | 34 ++- .../java/org/flag4j/linalg/MatrixNorms.java | 107 +++---- .../flag4j/linalg/PositiveDefiniteness.java | 50 ++-- .../java/org/flag4j/linalg/TensorInvert.java | 7 +- .../java/org/flag4j/linalg/VectorNorms.java | 75 ++--- .../decompositions/balance/Balancer.java | 156 +++++++--- .../balance/ComplexBalancer.java | 94 +++++- .../decompositions/balance/RealBalancer.java | 94 +++++- .../linalg/decompositions/chol/Cholesky.java | 36 ++- .../decompositions/chol/ComplexCholesky.java | 23 +- .../decompositions/chol/RealCholesky.java | 19 +- .../decompositions/hess/ComplexHess.java | 70 +++-- .../linalg/decompositions/hess/HermHess.java | 55 ++-- .../linalg/decompositions/hess/RealHess.java | 72 +++-- .../linalg/decompositions/hess/SymmHess.java | 55 ++-- .../linalg/decompositions/lu/ComplexLU.java | 35 ++- .../linalg/decompositions/lu/FieldLU.java | 39 ++- .../flag4j/linalg/decompositions/lu/LU.java | 49 ++-- .../linalg/decompositions/lu/RealLU.java | 38 ++- .../linalg/decompositions/qr/ComplexQR.java | 28 +- .../linalg/decompositions/qr/RealQR.java | 24 +- .../decompositions/schur/ComplexSchur.java | 37 +-- .../decompositions/schur/RealSchur.java | 47 +-- .../linalg/decompositions/schur/Schur.java | 74 +++-- .../linalg/decompositions/svd/ComplexSVD.java | 49 ++-- .../linalg/decompositions/svd/RealSVD.java | 56 ++-- .../flag4j/linalg/decompositions/svd/SVD.java | 49 ++-- .../unitary/ComplexUnitaryDecomposition.java | 4 +- .../linalg/solvers/LinearMatrixSolver.java | 17 +- .../flag4j/linalg/solvers/LinearSolver.java | 12 +- .../solvers/exact/ComplexExactSolver.java | 39 ++- .../exact/ComplexExactTensorSolver.java | 13 +- .../linalg/solvers/exact/ExactSolver.java | 73 +++-- .../solvers/exact/ExactTensorSolver.java | 45 +-- .../linalg/solvers/exact/RealExactSolver.java | 39 ++- .../solvers/exact/RealExactTensorSolver.java | 26 +- .../solvers/exact/triangular/BackSolver.java | 5 +- .../exact/triangular/ComplexBackSolver.java | 61 ++-- .../triangular/ComplexForwardSolver.java | 92 +++--- .../exact/triangular/ForwardSolver.java | 10 +- .../exact/triangular/RealBackSolver.java | 60 ++-- .../exact/triangular/RealForwardSolver.java | 87 +++--- .../solvers/lstsq/ComplexLstsqSolver.java | 98 ++++--- .../linalg/solvers/lstsq/LstsqSolver.java | 116 +++++--- .../linalg/solvers/lstsq/RealLstsqSolver.java | 105 ++++--- .../flag4j/linalg/transformations/Givens.java | 276 +++++++++++------- .../linalg/transformations/Householder.java | 94 +++--- .../linalg/transformations/Projection.java | 17 +- .../linalg/transformations/Rotation.java | 228 +++++++++------ .../java/org/flag4j/rng/RandomComplex.java | 177 ++++++++--- .../org/flag4j/rng/RandomDenseTensor.java | 8 +- .../distributions/Complex128BiGaussian.java | 44 ++- .../distributions/Complex128UniformDisk.java | 43 ++- .../distributions/Complex128UniformRect.java | 30 +- .../rng/distributions/RealGaussian.java | 16 +- .../flag4j/rng/distributions/RealUniform.java | 21 +- 64 files changed, 2623 insertions(+), 1278 deletions(-) create mode 100644 figures/intelij_doc_render.png create mode 100644 figures/latex_in_javadoc.png create mode 100644 scripts/USAGE.md create mode 100644 scripts/convert_latex.py diff --git a/.github/workflows/javadoc-gh-pages.yml b/.github/workflows/javadoc-gh-pages.yml index 2de4bb655..264679a51 100644 --- a/.github/workflows/javadoc-gh-pages.yml +++ b/.github/workflows/javadoc-gh-pages.yml @@ -2,7 +2,8 @@ name: Build and Deploy Javadoc on: push: - branches: [ "master" ] + branches: + - master jobs: # 1) Build the Javadoc and upload as artifact build-docs: @@ -11,35 +12,35 @@ jobs: - name: Check out code uses: actions/checkout@v4.2.2 + # 1.1) Setup Java - name: Set up JDK 23 uses: actions/setup-java@v4.7.0 with: distribution: 'zulu' java-version: 23 + # 1.2) Setup python + - name: Set up Python + uses: actions/setup-python@v5.4.0 + with: + python-version: '3.x' + + # 1.3) Build Javadoc - name: Build Javadoc run: | - mvn clean install + mvn clean install -DskipTests mvn javadoc:javadoc \ -Dmaven.javadoc.failOnError=false \ -Dmaven.javadoc.skip=false - # - name: Inject MathJax script - # # inject MathJax for rendering - - # run: | - # find target/reports/apidocs -type f -name "*.html" -exec \ - # sed -i '/<\/head>/i ' {} + + # 1.5) Find and convert all specified HTML equations to LaTeX equations and inject MathJax script + - name: Convert LaTeX + run: python scripts/convert_latex.py + # 1.6) Upload generated docs as artifact - name: Upload Pages Artifact - # This action collects the directory containing docs - # and makes it available as an artifact for later jobs uses: actions/upload-pages-artifact@v3.0.1 with: - # Path to the folder containing generated docs - # Adjust path to match your actual Javadoc output path: target/reports/apidocs # 2) Deploy the artifact to GitHub Pages diff --git a/.gitignore b/.gitignore index 8fbc09f6f..b039abd98 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ qodana.yaml # Build files and docs /target/ /docs/ +/local_scripts/ diff --git a/README.md b/README.md index faab1363d..907a9667e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ + +[![Build and Deploy Javadoc](https://github.com/jacobdwatters/Flag4j/actions/workflows/javadoc-gh-pages.yml/badge.svg)](https://github.com/jacobdwatters/Flag4j/actions/workflows/javadoc-gh-pages.yml) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=jacobdwatters_Flag4j&metric=coverage)](https://sonarcloud.io/summary/new_code?id=jacobdwatters_Flag4j) [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=jacobdwatters_Flag4j&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=jacobdwatters_Flag4j) diff --git a/figures/intelij_doc_render.png b/figures/intelij_doc_render.png new file mode 100644 index 0000000000000000000000000000000000000000..8d9188b27f2e04668b80e7b7d6c43a7f448c6c06 GIT binary patch literal 3164 zcmZ`+c{mhm7a!TTY$IF7dfhZvGb)V89;Qe|V`!pD$V7I=*4T$IQ{g5kHlYHr-m8g)s5C8xWgjv{YRCTnfY^J;(gQ@9_P8OWt z?dvAviyNsmd)S`7M`W_BDJxc0xj$8G?yih`nNHYAAGm~6+PR(!_a8U#hdEvgS^F5p0G(`BCS=2%5;%s*U+xsmJxGbtqe5DK?@_X z^-z*+)*S=LghdiF{!ykilmx}FK`ag8C1j0XqKYQR1=V?(`sG!tM=-g2=mkERgpphV z;b-ehlA1_#lpkn0zXRj%h&xsz!Ozy^KO!G_AIJk7e~~s6YRqe7Dqg zHVoMS1`M)@t$Er(AR`HL$gEl*EkVInHsuXDcvWTV1dGH1uBR8?2tUK+8>JYX9H^nf zGp)NDK<}~Lsa%#y3VWW(NHD;w>=Iwx7yw(ADJPNc2qj3AlLQt-S#bl(1(n83No26^ux#rzfJbuvvG z>Y;u})_mahsc_(I!Bll!(H18w2f1wElP^EeyI)==?Q04zHB&BK^@P((uifRCGzj*$hnWjD-!F3{+q&kv!s3nfsvNw|3QYLCNpMC>c!>0x5v%AXtkd&e=>bD@=39-y(^OQycIT2T4%<)lioW^C%yG7(Cduc zyWYa`x$#-AwW#F&=%NL#UhF;SnEswCLQQ|eg?mBRmOkCI}MxSaTzJ` zYCkToRY4B%*`DF|s!A{HlpC2l(N^317&1js=AK2!CztQZdC`8Zv#VTlg=tI_OO&Z; z+(4~1A@f3kHsXFIep=+rIBj=_P=LvGcg^!l+}3p=BK+Ou+Bc{U0 zt~tq)0;tr6-y|3Aq-}P<&TkviE*D|p=5>aRNg->ZL@ymADxWV8CU^AB;K z!i_f(jeWUfbkU~|Ow6Wvby`37Dhn1`nJA6vd62n&=H#~KK3%_NS7pp{K4u%1W8lQhA*ivoBap>d!+g>gu?asM zw{n{)JM-jmXFvCdI|FCwas_BJ$g-aB1I4+(O`a3$`j%0vc28N>YId#@y}8QYI@Vbl zS$%{&R>|blbaLCVrpUtN0(n6&f5~i3LiaK<3o0#W->ItM@rTCmHk%7~ba-OuOi07p zXlRQ{-3x~B&sZ{pb&o=_4!fvqst_8!z;mTg>x7_%%ve2h1^8 znkKBrc-cK6Ab3RY`$hZtj^QxndT+yqM272%NyR|a!itCgZ(%swqr~5{#~khF3G76- zp?L8~QU$0e_?2s=rs)+V*QKIHT{ph!#Vy&yZQqnad`}07)Ng#K^Qk+mI?(t$1g~mn zG5)4WLou(N?dB~$H#7PAW9?f^&5iSr0bGQx(@VsfROw|#ap&P@-P(x=QIbw_dl)PJ zVao0~P2jikoGW_8&&EtfcgY)s)%2*p!K9DPMxZ$cZA`FPQ zUkXXS)nh(44XggS>qFid-z)v2T((thZR&|6FwY=94nL-Lx{*|uEX+Kr1Q0M&IYJvp zVGQp52R%$=?r#Nj`vP1l8{<50IbYT+V^y-Yrxrt(sk8G_ZHwE_pjt{+Sxao6NZc+x zggoLK&Y#*|eT+-DM|Yn&V_A3Qv?PMC+xo9&) z)10bpHXQ{HCfHS#hBBJGD9WUC;u$>`-R6U*nfmhSGRtk|l*UAKE-H^dZPm_LUIFZO zkdz}yEKfKxvp*BwpP_t~41-YmkTMps4F#Lg>fXIw9ajEL%HOqBTif;!F6l5__G=Mx zshQ439A$D-#`*04W$w=&Gdb%V89TV90^}K==hl4T+ASDJ_q7;EbB{YifoLzZIeVAf z+{A#^|5UkEK1!6&Y;(SX)CW`ga&^U2zQwqGUYq_PdrIR-MFo!LInrv_>^m!JH)m)6 zI7X)k7E~>kNYp7vrx>p&oEG9XP%>S->~FpbBgxc*$}=5wpUR1g@2d0h5bA10=ubs~ zv|fpU-bB| zCJSr&cas$qmwVgtpYC*IgurG3G7Bdkh_~|oC2|N>1@(-o8t)g=djJ0$a|iFRv8{R~ zzfFJ5rw--23eN?wqYxG?4)wz8*ICTLHd%)eFLg;< znTOh7Eo{q=n(RF+h%~^0fN)wL5qf>rMSCGp#*J#0>!PkyR~?6cM1iHOVHwh;!-FSEfSm} zWz+ZlcIWra?9S}|v1cYHIrE(4$$8|yulu^LXe|vz0=&m~004kMSxHU@06^zMeSVLF zg*rby*yBgNp}FZO$^dF7X!cMSKpSawX#k);5&zBt6LpR2tYqW{01)>5eW49GmA?W2 zI82r0r1iW_4_AGiU(WlpAwQ+tH}dEmO1)R4X_iZs@&qmELMjWq<)4xNi~|Tl_<3eM z7}`TpK7I|Ye9KN6YK2|PImm4>ACinyugcn#-zJkSnDf!yQmX-?_fkv0S07$0#~uT< zfHz?+iT2K*DR6g`UlMg3b@pZfqgDMR`7?g_Ye9~F-Az2}b~{p^|76xp2tgg0zj>$0 zV&NqF z%gqJHs_hmXp*DsZ8%|5+0Z+JK+=cZ%KmOcPPul-X?WFSNW`*UrJb?Yo=2ho~K%rEH z6bv9skmjxV8rN!326)9kG=tsf@tpZv`jt}SU`(C;5((y z0!f3`9@yl;3Y^^9b87m0Fpn?a+2HfEMGLo(TEG78_u~+M#oPGX6k^epNO<$phiKOw z=-}nA;`Ud?n>aK#91$A*Xn>I#LT{{g?c$XpR@S!kg0PdxLGxwyMP-P~N-!)kL~F${ z_!lO>K$D5NYRMo&L{V~-K@y@}R|y?KFB0({LqQvW0cfDK!N;feK&aZS$9RaIzx2%q z=HGc^V`K~H;}&Y`H}4ER(UI9_C=# zMoT%cSTgYFU?})-V1ITaM5AVwf|q^18a@Ole;%OP7QSD+w-+qbO*Z(`#f3ukJcCx2 zEg5m(0`F>FXsuc|rb^#-!+*Sc#N%U)IkS7q#FPREV!o5imMVosyxL52bRaFRXI?u= zpMa|X*Zq1!qox6o-#{05`x38Ez3Z4{_s(Dkb(P6cYWZOm_(_+A{Gn^|_MK<~2H>&? zRrB6_(h{F@?EBJ=7dxda32Dt+qX|2-1%6z0Z1GGNVM`qgOZxSq$C%c=Ia-*qu!8@k292T9*KY--h6So`;HxQ5QK8LNUaP?7Yb>#SH1U%U zepKp)hQr3)o@+QAYkY==S!Mf8d*;__5;4-JemL)EW0Q)Ka^-jZ9Hrwm-d6B)^3jib zy?Jl)#C*Y#or{%??>A8nxg0=f7Q)lPjHCxOa2sN{6LIINE%&J)$_I ztj3?z7NL~siho-}mnGVtrTVd*IfGd<{?hK$w*0rB4?ZY_Vc|goQ1R>-(sU{)iHf(} z4CL87Kl|95rOY7orHy2kHupFUqZSr(UeeudbySy{+}?Ux?$)KyZ^x@S`pxyiWNqH} z@}x#F-hH7K8Z`wGCdyJ>YMt$V&!y(c%N&Dt$tXg|`%ptYFgih>T+(TyJM5Pc!royf z1V8U_Trfpi?xX)&$4^!Me24Q9`xeNgVu|c-2x4ayk6pxX#T0ah>04V3*+9h&U(EP> z#(KZ_(?MyFjN2J#8~O`d7yOezmw$f=Xd#sSr#|%=Nd*;Zs5oJM6b-)}8OTMOX35;` zGR!XFSDP;0insO3ZJBl?;zEF5Q#b;?gngZ#=>3=Ral7i92URt742E05rEc9-2Qr4K zn1(BoEW4%x8~DpC^Ky}om?Y@^Bu_1Ws*2sJAFF`Eo89*6x4I~7Lxxf5uCbR}j6Q;* zaDkn8)&C{l_(KRWOH)iP<mTZ0m&AQl2}jx9DdpgkD}1au4!fi{ zxlH|MOBs4efVfR6v?0{KQ=H!Rbq_7{P2HXB37LUpKl@f-tC{LFlIX{&2fZ*1@0+vP z#xZSv((jv+_SlIDKnl{@y5}WHh;+9FN#3>Qa}by}(S12?9NbMM*K|+(RdAc)eWo&mnqo}Stv)?n z#8gO$1hQ{Y68I3waek+qDP{4N$mf`wYwqJZ=Xm6k-=BlsX$q`Dp+qgjH()LIbMsx^ zNOLlGoA-XvM<*1ck!YyrNo7tzDoftAPEyl}-G|<_#|N9mTiy`BFZqd?!@4ytl!u-U z-M{5EF5k3Erh#^G-&x?bbz4G>fkc2(NYsWq4)jfR{O-U60dQy|B9)hNR;CH#w zc?kD<_>x3a)bX1Gz1J=8-ghMd?Ofb^aD58A@%9jL{3v2)3vG9ifzAFT7Jl%KE>zV! zk;#`k_nawv)YtfjV_U%ejmMq}#5iEe%HTz!H6BObH;Dyd)vKh8tKOw!Vl@^sxDUR9 zsgU7&AXU&e0bpQLpkmdt!?3-4vo;~kRyQiE+wjc@ODgJx*s0H*iarYg0>Gj=gPha8 zsb67rUn_Sh$Y=5vfU=3WrQ^osG4A&IDGvcyB7UCks?Fa>V$IKgpvCEbEtn1%z)z=1 z{t`Y}Uqg6}HEQO9n!}HJLl@gDptaSV`4F#NyVSovd?)qk~=r8Y`nae|);r?IjX;`Qu>Rl(bLm zc7`T{6a~>fvav-(*+xTA=cp)S)MWiXLc;$WELju9z#708wQi!)=7Xuk=sA~&#GbzR z3p&>rSaW0`Btch3oLq^bP#;m&RoN~b+18X|=0-B8fGTK~wRl?=MSUZmAKRjY?bxh!Gy!N(w0plfLg5 z_q7nrMBGLSwFE%Jp}(Fq_8S;81#$fyAESM!RsT-tv7%|5U-T@Qu@7erF)FqFh1Apk zpl%)*?yD^ETk$BB`Sc?a8Od3BZ3>oFw4iCE3g?C5o>30O&{;+sJl+v7qM^^4F5^T^W%L5-_}5r(tiN?_)2hW z00H9k`QLR+AB0AjN4q+GC`X`g^Lx=21#zn|y5Of?3VRH!|A}GMtmil{>h4a28e=`X zVrYY>xfstC3FUgHnh_|>g(qR=>5Ashfv21J89 zBH0?yYDt!02Ir1oMPkE1iSXeQhC+Q)qWZIdum|#%F zpk#Pv9t;0{D;~jE;8ECCt$yMC&je|;oM|)>-^g`MRpFGW(x81(pYxBmQ_ZcN4n3W= z`*@Z*NXc*bJCF8mP9Hx);(z*P_r##8fbZPmfie!kCGYPQJ-nGQV-$d1xK^_W!$5W+ zLO+9j1Q=UiieKBKOWnrRKTt^u4xkHj`N>}!SZ0e}vIgKe?NuEO1 z_^sA296WQrN1QNPonS9yQ(|Dy$xVM{T~FxwY})qC(oPF}1_wG&2=^{x`@tSA2edQj zX-5h1XZtRT7^&og%?w2Gj*ASuA(`?QN5pXl70wBAHLr|8-mu*#E=^?+(**}QR5`mO zP}i~w6+X}As!_n=JBdxEdidpX%`?tKH(7eQS{SnJNa{nsAO2(Fl-ov~n^yLE6>164 z;WushJ`vdum9UP`aIYx^qD^trJ2wJo&Q&9fQBP5Y@)Dg=FZU1)humoyi*l zZ$(*MnP?4vL6Iv^ABqzRWw{WX2{u4K^n#WM?*fK@xyD;@0E^$y>q%S>Um!8WOHUI^ z7)Bq_eB-2$g}xt;L!`FWRa(qJO1GYdw3RLVc+`qy60iW(g_g)__X1Dg@C#%umKB@)w`#?%(k|63f zC4oemU|+*Md^Th?uI#ZjWem*BC{5tKAAJ&D z-lE}mH{#o0zNel`)Q$aEW_ZSKezf+Ck?kA-Rwj4GA*|OqV>CX+HGPD_t&H;3z zXd2+20w3P2etQ8ued}h`9hf7n_B|VWj@P$AT1}Wn(le!{8CC7r!x8O^AKY^uIVP4I z`0MBWQ>!YW2a$+R@PXWwuZCl=*YEbhcP_6+afuGHsA&axBCRD@FVgcWHVMz^M#z{C zua^1lG77x$^U6=nw!A9&qAIc%e7WOP7XerZDKD@3Zat;=F3G1dxB#Wzhd$gBISnsk z=xHV8_m2`x^5_}zNx1_D;VU6{ZEHM6WHvbTV7Dpi)9}Vyg_yfTatU5aeDlXl9!v4> z^MCrzSO}SXW!3RlF%%7wW|f&#RRni(t#}uG)x_ktcHiTWuqD4TuD_i)=w10m^_+7t zSWbplTnEQIWwp*%0owS9XmFJK%wx(S7J4*Y(D2j06L0l-^Xt4}KvoT5WYpE@SXW@6miojV>#xS+ZJugsMlNa4GRd8n8(jw2FhS+~B@OrOfG%)v z{l+C)_^l1TG7$848HzTcs8g+mdbxBvAC2z?G~@9Xv(--57@ASr`mRkO;A5N z9g?3-CG()iE_4AaspOL3*gcvcS65cc8^452#cy|BJAQdd1<-r$*~h>&OKyBFSM9~#7)#0KZ_zznvzp&S+18Y0qijrBm5kR6%ua1OgcK+sDA+*5O&f^ApV z=>9*?^vd6SUo8%j+?4{=CxZs^KfN*C&Dr@|_sdiq2aHYG^PmH1fFs3o?6k z1^{nO7hJ315%Ocv!^D{Ssm8VqqD{Z|d3qlNIxUY@v&rA7O@u>pu+9Uu3fl!~!{;S{ zfkHvSgXr_~_M`FRW>u0|WKQgbGGNl7YIBw0eY-)O_~;unz+U3hXe|Jeo?cnV0K#KF z3xmD3e_HXa43Aq!%W8f{m06fKO%E^nATfFdopWDB`{TzH0EMPA)L1hlgp)Ky z61s$vjBGfV8PkPhRezJ{M%UK59&)&-{V4|b+Ftr$Y`b#f;e)A!UUw;e;-?qDjPz|- z8;^Dvu_qwOpm`)Ow-`Ef_1dxUvT3m&`_=aX?byZG@NDwehK7rC<<}=JKsV{q!4Rhu zJD;(biLqBC?r7^r6Z^*ZfH6gT+`gZi-L;(V`Be{Dwz`MYXDxb@&R8rEx za2P_ZbZnSk}h#-hymxZMAH)r*aA@}Uoc-RCvUSuD|OEzp)>f&F~H&ogco`|3rFvIwO zA_n22YIYu6rfoux#h%L7u-ayY`JS|y2okfZRM%#_ZQ>fvg(?GphHh!$^z-abr9F#T zH60*BLv`G7vbNu&`m7uLMRk%{w4G)95r@w`$T()fSo*)7k7DV|OtmT)c%>U9(xcBeVRKMy2=vXuO4~Wu<(Xb+Ul_sSyO@iUXHr816U+k1Rkw^EcO{FAzg6UU{~ksR6_V!4#0U04Ya~(E8kuNLn2fe zwBLG3qbRXE%-V<>;SU>D6p4&})}W)Iai}DJ@C#$K3(w~X-j&|YbIbc|kHxXepI3G- zkPKlr2p>WGbF;_1(1dcX?0*T7#h5z2fYrIk%~#U3X+{gD3wSBd#H>tdbBL823LgmT zX#n%^`jq(#aq>8Uw)@L-N=JPnmXvo$k;`67dfDO{+NH^5m;TKlZ3IqxMwoQ!ey%!8 zC`ZNbJp9^`1W&!dE1_;{an{&r9ESHIhhbahLN6jnBFeH=g=`En85B(T=kPwnk0hUW zrqkXu`-RE!@=0Q4ErJ@5XY$lEils>%HPqWfCde)c^yN90kHc>7Cn}@! z{;0Dtspu-@t~O$bssE&$kok_+VbU9#>Y#WPD%4`?Ps@a@0_sjC`EsML0-(5IgYUM+ ztcF-t9Z5#bcba-r?wz$2p^cx%Zb_DKR$gh3`_roDPZ-zP3gFIY8T!)ll-OI0;TgyF zG8qi}+YWvo%0XgT^|U#@puzspXz-4HuH?G`@5wG-^_rH4^xB>AZpPR<{2G4(8Wotz z9)p5FWX$8X&yTXvPadh^J3?1&np4y>V04UOK-{t$j7@on4!z%|71cX9+9)Bn9)T}F z;A;ov#Jm;4n5c)nGuKfUzwp*p^IOn7-1ycyRrXv!9ca!EepL$kE5Jouc2}z&MlW7$&XFU0b?sdZ-CrwB3IyiNK zvCb@{CDaIDl%I)*`eQR65%uwAIvreIuOu-@i$u#6^lC*E>D1& zXA#1WdGFMhc*(Y}^9@+L3_M`^k^MNhRvD9yRiYWDD(@Hf+n$ioDuDd?pJ#b;pdXVG zs-@s*{I}A$BW)Pj+YrLMiN{2NxnWa=Ut{`KG($r7j#8Ii0W2Z}ta=SdIL3aQzT1}Z z*iY@FOsZ_fW|`s-QGuyCxCBdR#*N(|aa^~NE&jKo#Vk$Mx2%QuC23)=GnHs0fmiQX z&TkLuh$wE)i=GQpVg)U98}N}vm4~Zi-iw#e<#?1g%<_7;f|6Tf-93o7@;)718Gm3W zsuYUNqntKJN)s1nMoC_7PGOIWIHG4nG4=l#p>uFY*iK0(VnKT(i=aymF z5oLUP!pw~O9{;yq4nrpmS(S5xJ1mv#;?IU_MHNMMNTAX#(Yiit}ww=SkkP! zF3wKp6Cv5=$J^=t$a`;^?^6K|9~^3`Ck#G)6=8KHPZ#38l+gQmCA7@HYAJcXVV-Dv zS;#uyV>L~t6Gf8>D)BVdI?qWsL%ZGq9NIiiH_#D_df%a2uKRKzP;w{y{^g>~>n5}W zN$!inrY%;-r?mm>pTxqtBtd~XvB5(lESZ%B6hOSGE4TMHZwgnE<3)Gv38+TEO*bBn z>>ZyAi&3n+WN`gKUd`er$GuL|Qxdk^L7q1$CnW`Tm^;5sg_zDWHNW@Kr(Br(mP*3fG{tT*~pYBGUu4tv2IMk_@qpaWDKg zHJU|bk1z&(xVQL>BE$-I`KYlHlp}P~*&QGc_9WWn^>3_7@S6e#La8jqThy^(70>is z!+3p+Yn)b0fU(jkM7sAgm!F+o$auR_<^(Kq3ovhr;C z{653A3PV^nEUZnCVM5mb>h= z`?C6V)9;-xjtAFY^5v^z=FAezGcB8d}Y!9&Cp@#ML`og@mF_lo2KKX?p@fcLW(7h?=_VE zZcsBEj^idcjG0*P=&_Gl8oy?FTEWa7dxs}w$lmGjPAnsRfB(eo56QjAhqpvsx6R=Y z^>=6bKn?5WEeR*zAD*E6V>EuO#0apHePqBSRE(EM%1k22gd+TSd!Rr#EEH*l^SWCX zI^9T%R>A_o$vw9^V4=P|ns^k@#Reh&O*4hD)d#1y8|L_iy3tKhdb zq~8%+QFibxjwet0HQLNq#iOD}0eYh6fy?24+Ev6-g5|%`8!=4XLATBe zE|KZz06g(n&U7(0c;4;}Kwql$3r5bBlkA#}Z~iaarP#OH_dkD&UtdN)-~)Djc8x?H zkY2^@Gd#3?KO2NvG;Hk8@dVF_sOq;23z6z-kgG03c|{_^HmrP3!&2dBIp(N!KlC1b zHG10c2UpL&L-D#R<@V(NP_?)5bk>~u;P*`$Sd{;r!Ti8!aov~cyJd$6og!Vlwe}F^ zGFx@s?DP_hso1o_*)}z)&?>s+^jz@LBSjjX{Zsy7@fG;bHaZ*}ZO6N;Iqx%yi;xm_+;MVk z^4MnqMX#83@amBQrJ>Scy!a#WP5#c^OJ?6BU-lKzLq8tw& zHU2Q_*J@Sh-WAe!H4pxfr0(ODh-1psk!m%FPOMo5%9_#NNYq3Wn#9+=kz20^ktxU< z$QFd{H;Y<4J%`uHVtc@n$qcmDc|(w@{&k&3<%@S(iXA3H2sNUv$Y2;fFr$0?#e zq>j%7^}PzTDhj5k5x2gq?rRm5kc_se59A9TFZPCtbC1)%{mG|Rw0nz|jS?pEGIu~P zY01q7;D6l{f={Cg!YfVIM>Wp^%1Suuwq6a;B|i?$D2(nzQS5T#3IE~tK-a0bv+a`` zXe~;cQ*4#y*dvn|NwjAE>++bHM(jZtlT#r}*=&!p( z-)`xS*p6U~v<=M-C2WwPPUTzwUnPeV?m0R27^iwx2ter{MzXl-7vjIHCF8||%`f<) z80~c8L6#eoYqpf6ayo5Y zg!Z@V0ZsIe_in6ptiXLo%!LLY5}1%3kG2(INGzr(w&jArI{Gi-t6EG6N(lVFVt1Pm?tbTe|DX$Jhz(#n1sc) ziG)`W0sJ*JPbgBZK{98pnB?bIMbE@bd#{Em=6B%mg%Uj8u?|zAUDP^H_7I`{C3%nXKaF$@-%kks{JCa zD2GWodGU_R8;!QlkJG{9^XIlkNYrzPSU+HDQ4=7PPfc89_zQY_6=>VSs4*eOX2JWH z>bqPdwS@tAWENYHHl>+a?0IR(e^nU$ z*lTQDys=FKrPUe3Z?&~G`ewU8?BUm35|^!)w=JZSy% zc|!c(ef+-q)lTB@^!J8}R}yhr=L>*K!b!`%bQ7e{so*wCE>=KbMFWlT-R6s(ZQLn>0x;{4&k zIB<9m>c_T~jx+I3r=`+m&Z6^`Z>D}L?}-}gho$=Y8AXl_a#eYKq zh`EF#f1!m-k0O`|22wIx1^~$KPa7{`owGOnJAVVT*5^*#GmZZug$aqjNa0lcFlZ2c zd4hvJY37BPR|?BWkk$GR z0RVZj=1=ufwAgn>1??j60k$G~}C2{U= zOdubfJ~4H=(Q40lX8Ph*e74)uvJ;buH>+x2K@EjMToFVA*3>4Nj|O0BqsrGg&7$kn z2Wdx)|JeIb35v0hLTG28CkWfS2XlwXxEejk9=HD+Ub%t(a>6$TK`g#;g!kWMrE1{_ z!btQ9_Gfb5L2>;B$1jny^fOmo=Ue|c5X;G#(VZn+K=zl3J)Noxdt~z0CM1W=wZzrQ zf5Vv^$}9qj)4m1Y(X$eZH45LNe_a{Eo1{T>X#_AW{j33eo`z(B zNPVL}ray!*hhy_ccWqC|K)N*Ynm@as3n`#=-{Fiv{$%c}G{|^qz{~Njde{a2fz&Pv7B=9I! S$VS;u0m||ka...` block. This will replace +the content in the block with `\( .... \)` and convert any sub/superscripts, common mathematical +symbols, and greek letters from html form to $ \LaTeX $. For a full list of all replacements made for +simple latex replacements, see [A1](#a1-simple--latex--regex-replacements). + +`
...
` will be discarded when making the conversion. +Simple fractions of the form `(...) / (...) ` are also supported. +The parentheses are required for proper conversion. + +The following docstring, +```java +/** + * The equation y = &alpha;x + b + * will be solved for x. + * + * (3x2) / (&radic;(2y - 1)) + */ +``` + +will be converted to the following in the final HTML, +```html +The equation \( y = \alpha x + b \) +will be solved for \( x \). + +\( \cfrac{3x^{2}}{\sqrt{2y - 1}} \) +``` +--- + +### 2.2 Simple Display $ \LaTeX $ Replacements + +To render $ \LaTeX $ in display mode, use the tags +`...` + +The same rules apply as in the inline rendering. + +The following docstring, +```java +/** + * The equation y = &alpha;x + b + * will be solved for x. + * + * (3x2) / (&radic;(2y - 1)) + */ +``` + +will be converted to the following in the final HTML, +```html +The equation \[ y = \alpha x + b \] +will be solved for \( x \). + +\[ \cfrac{3x^{2}}{\sqrt{2y - 1}} \] +``` + +--- + +### 2.3 Aligned $ \LaTeX $ Replacements + +If you would like to align a multi-line HTML equation by equal or "implies" signs, use +the tags `...`. There must be exactly one '=' +per line of the equation. Similarly, `...` can +be used for implication chains. + +The following docstring, +```java +/** + * + *
+ *     A = T B T-1
+ *       = P D B D-1 P-1
+ *
+ * + * + *
+ *      x < α &Implies; x < &Sigma;i=1N (yi);
+ *            &Implies; x < &beta;
+ *
+ */ +``` + +will be converted to the following in the final HTML, +```html + \[ \begin{align*} A &= T B T^{-1} \\ +&= P D B D^{-1} P^{-1}. \end{align*} \] + +\[ \begin{align*} x < \alpha &\implies x < \sum_{i=1}^{N} \left (y_{i}\right ) \\ +&\implies x < \beta \end{align*} \] +``` + +--- + +### 2.4 Customized $ \LaTeX $ Replacements +For more complicated $ \LaTeX $ Replacements we may want to specify exactly what +the $ \LaTeX $ should be replacing the HTML. To do this we utilize the `...` block. + +To specify custom $ \LaTeX $ you must provide an HTML equation for simple rendering within an IDE. +This allows users to avoid seeing raw $ \LaTeX $ in the docs rendered by the IDE. + +You can then optionally provide a $ \LaTeX $ equation within an HTML comment to replace the preceding HTML equation. + +#### 2.1.1 Specifying An HTML Equation Is "$ \LaTeX $ Replaceable" +The following doc comment specifies that an equation is replaceable +```java +/** + * + *
+ *                   [ T1     X*D1       Y   ]
+ *   D-1 P-1 A P D = [  0  D1-1*B1*D1  D1-1*Z  ]
+ *                   [  0      0         T2  ]
+ *
+ */ +``` +The `` tag indicates that the following HTML equation may be replaced by +a $ \LaTeX $ equation when building the docs. This tag and the closing `` must +be included for the equation to be replaced. If there is not a latex equations following this, the +tag will be ignored. + +Providing the equation as HTML allows The InteliJ IDE to render the equations as: + +![image](../figures/intelij_doc_render.png) + +This looks okay, but we know that $ \LaTeX $ could look SO much better! + +#### 2.1.2 Specifying A Custom $ \LaTeX $ Equation +We do not want the $ \LaTeX $ equation to rendered in an IDE as raw text. To avoid this, we place +the equation inside a special HTML comment. The comment must begin with ` + */ +``` + +The HTML comment `` must immediately follow the `...` +block for it to be utilized (white space and newlines are allowed between the two). +Otherwise, the $ \LaTeX $ comment will be ignored. + +The single '\$' character is not supported for inline $ \LaTeX $ (i.e. `$ ... $`) in default MathJax. +Instead, use `\( ... \)` for inline equations. Both ``$$ ... $$`` and `\[ ... \]` may be used for display mode. + +#### 2.1.3 Full Example +The full doc comment would look something like, +```java +/** + * Some stuff... + * + * + *
+ *                   [ T1     X*D1       Y   ]
+ *   D-1 P-1 A P D = [  0  D1-1*B1*D1  D1-1*Z  ]
+ *                   [  0      0         T2  ]
+ *
+ * + * + * + * + * Some more stuff... + */ +``` + +The exact regex used in python to match such instances is: +```regexp +(.*?)\s* +``` +where `.*` will match any character including newlines. If the text in the generated +HTML does not match this, no replacements will be made. + +In an IDE, the $ \LaTeX $ in the comment will not be rendered. The user will only see the +HTML equation. Once the Javadocs are built, parsed, and deployed to the [Flag4j API website](https://jacobdwatters.github.io/Flag4j/), +the HTML equation will be fully replaced with the $ \LaTeX $ equation and MathJax will render it as: + +![image](../figures/latex_in_javadoc.png) + +Wow! That looks so much better! Enjoy your $ \LaTeX $. + +# Appendix +## A.1 Simple $ \LaTeX $ Regex Replacements +This is the full regex replacement mapping for simple latex tags: ``, +``, ``, ``. + +Replacements are performed in the same order they appear in the mapping. + +```python +html2latex = { + # Braces + r"\{": r"\\left {", r"\}": r"\\right }", + + # Simple fractions + r"\([ ]*([^()<>]+)[ ]*\)[ ]*/[ ]*\([ ]*([^()<>]+)[ ]*\)": r"\\cfrac{\g<1>}{\g<2>}", + + # Parens, brackets + r"\(": r"\\left (", r"\)": r"\\right )", r"\[": r"\\left [", r"]": r"\\right ]", + + # Sums and products + r"&Sigma;(.*?)(.*?)": r"\\sum_{\g<1>}^{\g<2>}", + r"&Pi;(.*?)(.*?)": r"\\prod_{\g<1>}^{\g<2>}", + + # Lowercase greek + r"&alpha;": r"\\alpha ", r"&beta;": r"\\beta ", r"&gamma;": r"\\gamma ", r"&delta;": r"\\delta ", r"&epsilon;": r"\\epsilon ", + r"&zeta;": r"\\zeta ", r"&eta;": r"\\eta ", r"&theta;": r"\\theta ", r"&iota;": r"\\iota ", r"&kappa;": r"\\kappa ", + r"&lambda;": r"\\lambda ", r"&mu;": r"\\mu ", r"&nu;": r"\\nu ", r"&xi;": r"\\xi ", r"&omicron;": r"\\omicron ", r"&pi;": r"\\pi ", + r"&rho;": r"\\rho ", r"&sigma;": r"\\sigma ", r"&tau;": r"\\tau ", r"&upsilon;": r"\\upsilon ", r"&phi;": r"\\phi ", + r"&chi;": r"\\chi ", r"&psi;": r"\\psi ", r"&omega;": r"\\omega ", + + # Uppercase greek + r"&Alpha;": r"\\Alpha ", r"&Beta;": r"\\Beta ", r"&Gamma;": r"\\Gamma ", r"&Delta;": r"\\Delta ", r"&Epsilon;": r"\\Epsilon ", + r"&Zeta;": r"\\Zeta ", r"&Eta;": r"\\Eta ", r"&Theta;": r"\\Theta ", r"&Iota;": r"\\Iota ", r"&Kappa;": r"\\Kappa ", + r"&Lambda;": r"\\Lambda ", r"&Mu;": r"\\Mu ", r"&Nu;": r"\\Nu ", r"&Xi;": r"\\Xi ", r"&Omicron;": r"\\Omicron ", r"&Pi;": r"\\Pi ", + r"&Rho;": r"\\Rho ", r"&Sigma;": r"\\Sigma ", r"&Tau;": r"\\Tau ", r"&Upsilon;": r"\\Upsilon ", r"&Phi;": r"\\Phi ", + r"&Chi;": r"\\Chi ", r"&Psi;": r"\\Psi ", r"&Omega;": r"\\Omega ", + + # Sub/superscripts + r"": r"_{", "": "}", r"": r"^{", "": r"}", + + # Boldface + r"(.*?)": r"\\mathbf{\g<1>}", r"(.*?)": r"\\mathbf{\g<1>}", + + # Common sets. + r"ℝ": r"\\mathbb{R}", r"ℚ": r"\\mathbb{Q}", r"ℂ": r"\\mathbb{C}", r"ℤ": r"\\mathbb{Z}", r"ℕ": r"\\mathbb{N}", + + # Operators + r"&lt;": r"<", r"&gt;": r">", r"&le;": r"\\leq ", r"&ge;": r"\\geq ", r"&ne;": r"\\neq ", r"&plusmn;": r"\\pm ", + r"&isin;": r"\\in ", r"&notin;": r"\\notin ", r"&radic;\((.*)?\)": r"\\sqrt{\g<1>}", r"≈": r"\\approx ", + r"&oplus;": r"\\oplus ", r"&Implies;": r"\\implies", r"&times;": r"\\times", r"&middot;": r"\\cdot", + + # Other symbols. + r"&infin;": r"\\inf ", r"\.\.\.": r"\\cdots ", r"&ell;": r"\\ell " +} +``` diff --git a/scripts/convert_latex.py b/scripts/convert_latex.py new file mode 100644 index 000000000..bdce68a3d --- /dev/null +++ b/scripts/convert_latex.py @@ -0,0 +1,222 @@ +# +# MIT License +# +# Copyright (c) 2025. Jacob Watters +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WArANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WArANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +import glob +import re +import sys + + +# Mapping between common html characters and strings to equivalent latex. +# The order that these are applied in matters and must match the order of insertion. +# Must be using pyton 3.7+ to guarantee a dict maintains insertion order. +html2latex = { + # Braces + r"\{": r"\\left\{", r"\}": r"\\right\}", + + # Simple fractions + r"\([ ]*([^()<>]+)[ ]*\)[ ]*/[ ]*\([ ]*([^()<>]+)[ ]*\)": r"\\cfrac{\g<1>}{\g<2>}", + + # Parens, brackets + r"\(": r"\\left(", r"\)": r"\\right)", r"\[": r"\\left[", r"]": r"\\right]", + + # Sums and products + r"Σ(.*?)(.*?)": r"\\sum_{\g<1>}^{\g<2>}", + r"Π(.*?)(.*?)": r"\\prod_{\g<1>}^{\g<2>}", + + # Lowercase greek + r"α": r"\\alpha ", r"β": r"\\beta ", r"γ": r"\\gamma ", r"δ": r"\\delta ", r"ε": r"\\varepsilon ", + r"ζ": r"\\zeta ", r"η": r"\\eta ", r"θ": r"\\theta ", r"ι": r"\\iota ", r"κ": r"\\kappa ", + r"λ": r"\\lambda ", r"μ": r"\\mu ", r"ν": r"\\nu ", r"ξ": r"\\xi ", r"ο": r"\\omicron ", r"π": r"\\pi ", + r"ρ": r"\\rho ", r"σ": r"\\sigma ", r"τ": r"\\tau ", r"υ": r"\\upsilon ", r"φ": r"\\phi ", + r"χ": r"\\chi ", r"ψ": r"\\psi ", r"ω": r"\\omega ", + + # Uppercase greek + r"Α": r"\\Alpha ", r"Β": r"\\Beta ", r"Γ": r"\\Gamma ", r"Δ": r"\\Delta ", r"Ε": r"\\Epsilon ", + r"Ζ": r"\\Zeta ", r"Η": r"\\Eta ", r"Θ": r"\\Theta ", r"Ι": r"\\Iota ", r"Κ": r"\\Kappa ", + r"Λ": r"\\Lambda ", r"Μ": r"\\Mu ", r"Ν": r"\\Nu ", r"Ξ": r"\\Xi ", r"Ο": r"\\Omicron ", r"Π": r"\\Pi ", + r"Ρ": r"\\Rho ", r"Σ": r"\\Sigma ", r"Τ": r"\\Tau ", r"Υ": r"\\Upsilon ", r"Φ": r"\\Phi ", + r"Χ": r"\\Chi ", r"Ψ": r"\\Psi ", r"Ω": r"\\Omega ", + + # Sub/superscripts + r"": r"_{", "": "}", r"": r"^{", "": r"}", + + # Boldface + r"(.*?)": r"\\mathbf{\g<1>}", r"(.*?)": r"\\mathbf{\g<1>}", + + # Common sets. + r"ℝ": r"\\mathbb{R}", r"ℚ": r"\\mathbb{Q}", r"ℂ": r"\\mathbb{C}", r"ℤ": r"\\mathbb{Z}", r"ℕ": r"\\mathbb{N}", + + # Operators + r"<": r"<", r">": r">", r"≤": r"\\leq ", r"≥": r"\\geq ", r"≠": r"\\neq ", r"±": r"\\pm ", + r"∈": r"\\in ", r"∉": r"\\notin ", r"√\((.*)?\)": r"\\sqrt{\g<1>}", r"≈": r"\\approx ", + r"⊕": r"\\oplus ", r"⇒": r"\\implies", r"×": r"\\times", r"·": r"\\cdot", + + # Other symbols. + r"∞": r"\\inf ", r"\.\.\.": r"\\cdots ", r"ℓ": r"\\ell ", r"°": r"^{\\circ}", r"exp": r"\\exp", + r"log": r"\\log", r"ln": r"\\ln", r"sin": r"\\sin", r"cos": r"\\cos", r"tan": r"\\tan", + r"cot": r"\\cot", r"sec": r"\\sec", r"csc": r"\\csc", r"min": r"\\min", r"max": r"\\max", + r"Re": r"\\Re", r"Im": r"\\Im", +} + +mathjax_script = '' + +def inject_mathjax(content: str) -> str: + """ + Injects the MathJax script into the header of a html file. + :param content: The html content. + :return: The original html content with the MathJax script injected. + """ + head_match = re.search(r'', content, re.IGNORECASE) + if head_match: + head_end = head_match.end() + content = content[:head_end] + "\n " + mathjax_script + content[head_end:] + print(f"[LATEX CONVERT] -- - injecting MathJax script") + + return content + + +def convert_simple_inline(match: re.Match) -> str: + """ + Converts matched content within a latex-inline tag to inline latex. + :param match: The matched content. + :return: The matched content formatted as inline latex. + """ + return convert_simple(match, "\\(", "\\)") + + +def convert_simple_display(match: re.Match) -> str: + """ + Converts matched content within a latex-display tag to display mode latex. + :param match: The matched content. + :return: The matched content formatted as display mode latex. + """ + return convert_simple(match, "\\[", "\\]") + + +def convert_simple(match: re.Match, opened: str, closed: str) -> str: + """ + Converts matched content within a latex-simple-(inline)|(display) tag to latex. + :param match: The matched content. + :param opened: Opening string for math block. Must be one of ["\\(", "\\[", "$$"] + :param closed: Closing string for math block. Must be one of ["\\)", "\\]", "$$"] + :return: The matched content formatted as latex. + """ + content = (match.group(1) + .replace("
", "")
+               .replace("
", "") + .replace("
", "") + .replace("
", "") + .strip()) + for pattern, replacement in html2latex.items(): + content = re.sub(pattern, replacement, content) + return f"{opened} {content} {closed}" + + +def convert_simple_eq_aligned(match: re.Match) -> str: + """ + Converts matched text from a latex-simple-aligned tag to latex in an 'align' block. Each line will be aligned by the equals + or implies symbol. Assumes that there is only one equals symbol per line. + :param match: Matched content. + :return: The matched content within a latex 'align' block such that each line is aligned by an equals' character. + """ + return convert_simple_aligned(match, "=", "=") + + +def convert_simple_impl_aligned(match: re.Match) -> str: + """ + Converts matched text from a latex-simple-aligned tag to latex in an 'align' block. Each line will be aligned by the equals + or implies symbol. Assumes that there is only one equals symbol per line. + :param match: Matched content. + :return: The matched content within a latex 'align' block such that each line is aligned by an equals' character. + """ + return convert_simple_aligned(match, "⇒", "\\implies") + + +def convert_simple_aligned(match: re.Match, align_token, align_replacement) -> str: + content = (match.group(1) + .replace("
", "")
+               .replace("
", "") + .replace("
", "") + .replace("
", "") + .replace(align_token, f"&{align_replacement}") + .strip() + .replace("\n", " \\\\ \n")) + for pattern, replacement in html2latex.items(): + content = re.sub(pattern, replacement, content) + return f"\\[ \\begin{{align*}} {content} \\end{{align*}} \\]" + + +def replace_match(match: re.Match) -> str: + """ + Extracts latex from html comment for generic latex-replaceable tags. + :param match: Matched content. + :return: The latex content within the html comment. + """ + latex_block = match.group(3) # The LaTeX content inside the comment. + return f"{latex_block}" + + +def process_javadoc(file_path) -> None: + """ + Processes a single html Javadoc file to replace specified html formatted equations with latex. + :param file_path: Path to the Javadoc file. + """ + with open(file_path, "r", encoding="utf-8") as f: + content = f.read() + print(f"[LATEX CONVERT] -- parsing file {file_path}") + + content = inject_mathjax(content) + + print(f"[LATEX CONVERT] -- - performing simple LaTeX replacements") + # Handle simply replaceable html. + + content = re.sub(r'\s*(.*?)\s*', + convert_simple_inline, content, flags=re.DOTALL) + content = re.sub(r'\s*(.*?)\s*', + convert_simple_display, content, flags=re.DOTALL) + content = re.sub(r'\s*(.*?)\s*', + convert_simple_eq_aligned, content, flags=re.DOTALL) + content = re.sub(r'\s*(.*?)\s*', + convert_simple_impl_aligned, content, flags=re.DOTALL) + + # Handel custom replacements. + pattern = re.compile( + r'(.*?)\s*', + re.DOTALL + ) + + # Apply the replacement. + content = pattern.sub(replace_match, content) + + print(f"[LATEX CONVERT] -- - performing custom LaTeX replacement") + with open(file_path, "w", encoding="utf-8") as f: + f.write(content) + + +# Process all Javadoc HTML files in +base_dir = sys.argv[1] if len(sys.argv) > 1 else "target/reports/apidocs" +for file in glob.glob(base_dir + "/**/*.html", recursive=True): + process_javadoc(file) + +print("[LATEX CONVERT] -- complete") diff --git a/src/main/java/org/flag4j/linalg/DirectSum.java b/src/main/java/org/flag4j/linalg/DirectSum.java index a1db31f20..de830e78b 100644 --- a/src/main/java/org/flag4j/linalg/DirectSum.java +++ b/src/main/java/org/flag4j/linalg/DirectSum.java @@ -36,6 +36,9 @@ import org.flag4j.util.ArrayUtils; +/** + * Utility class for commuting the direct sum of two matrices. + */ public final class DirectSum { private DirectSum() { @@ -54,14 +57,12 @@ public static Matrix directSum(Matrix A, Matrix B) { Matrix sum = new Matrix(A.numRows+B.numRows, A.numCols+B.numCols); // Copy over first matrix. - for(int i=0; iL
using a back-solve algorithm, then solving + * UA-1 = L-1 + * for A-1. * * @param src Matrix to compute inverse of. * @return The inverse of this matrix. @@ -74,8 +75,9 @@ public static Matrix inv(Matrix src) { /** * Computes the inverse of this matrix. This is done by computing the {@link LU LU decomposition} of - * this matrix, inverting L using a back-solve algorithm, then solving U*inv(src)=inv(L) - * for inv(src). + * this matrix, inverting L using a back-solve algorithm, then solving + * UA-1 = L-1 + * for A-1. * * @param src Matrix to compute inverse of. * @return The inverse of this matrix. @@ -272,13 +274,13 @@ public static CMatrix invHermPosDef(CMatrix src, boolean checkPosDef) { // ------------------------------------------- Pseudo-inverses ------------------------------------------- /** - * Computes the pseudo-inverse of this matrix. That is, for a matrix A, computes the Moore–Penrose - * A+ such that the following hold: + * Computes the pseudo-inverse of this matrix. That is, for a matrix A, + * computes the Moore–Penrose A+ such that the following hold: *
    - *
  1. AA+A=A.
  2. - *
  3. A+AA+=A+.
  4. - *
  5. AA+ is Hermitian.
  6. - *
  7. A+A is also Hermitian.
  8. + *
  9. AA+A=A.
  10. + *
  11. A+AA+=A+.
  12. + *
  13. AA+ is Hermitian.
  14. + *
  15. A+A is also Hermitian.
  16. *
* * @return The Moore–Penrose pseudo-inverse of this matrix. @@ -292,13 +294,13 @@ public static Matrix pInv(Matrix src) { /** - * Computes the pseudo-inverse of this matrix. That is, for a matrix A, computes the Moore–Penrose - * A+ such that the following hold: + * Computes the pseudo-inverse of this matrix. That is, for a matrix A, + * computes the Moore–Penrose A+ such that the following hold: *
    - *
  1. AA+ A=A.
  2. - *
  3. A+ AA+ =A+.
  4. - *
  5. AA+ is Hermitian.
  6. - *
  7. A+ A is also Hermitian.
  8. + *
  9. AA+A=A.
  10. + *
  11. A+AA+=A+.
  12. + *
  13. AA+ is Hermitian.
  14. + *
  15. A+A is also Hermitian.
  16. *
* * @return The Moore–Penrose pseudo-inverse of this matrix. diff --git a/src/main/java/org/flag4j/linalg/MatrixNorms.java b/src/main/java/org/flag4j/linalg/MatrixNorms.java index d60f647c7..44a959a4f 100644 --- a/src/main/java/org/flag4j/linalg/MatrixNorms.java +++ b/src/main/java/org/flag4j/linalg/MatrixNorms.java @@ -67,7 +67,8 @@ * (maximum/minimum absolute row sum) * * - *
  • Lp,q norms for both dense and sparse (COO/CSR) matrices.
  • + *
  • Lp,q norms + * for both dense and sparse (COO/CSR) matrices.
  • *
  • Common norms like the Frobenius norm, maximum absolute value (max norm), * and infinite norm (maximum row sum) for real and complex matrices.
  • *
  • Entry-wise p-norms, computed by flattening the matrix and computing the vector p-norm.
  • @@ -101,7 +102,8 @@ private MatrixNorms() { * @param p The p value in the Schatten p-norm. Some common cases include: *
      *
    • {@code p=1}: The nuclear (or trace) norm. Equivalent to the sum of singular values.
    • - *
    • {@code p=2}: Frobenius (or L2, 2) norm. Equivalent to the square root of the sum of the absolute squares + *
    • {@code p=2}: Frobenius (or L2, 2) norm. + * Equivalent to the square root of the sum of the absolute squares * of all entries in the matrix.
    • *
    • {@code p=Double.POSITIVE_INFINITY}: The spectral norm. Equivalent to the maximum singular value.
    • *
    • {@code p=Double.NEGATIVE_INFINITY}: The minimum singular value.
    • @@ -130,7 +132,8 @@ public static double schattenNorm(Matrix src, double p) { * @param p The p value in the Schatten p-norm. Must be greater than or equal to 1. Some common cases include: *
        *
      • {@code p=1}: The nuclear (or trace) norm. Equivalent to the sum of singular values.
      • - *
      • {@code p=2}: Frobenius (or L2, 2) norm. Equivalent to the square root of the sum of the absolute squares + *
      • {@code p=2}: Frobenius (or L2, 2) norm. + * Equivalent to the square root of the sum of the absolute squares * of all entries in the matrix.
      • *
      • {@code p=Double.POSITIVE_INFINITY}: The spectral norm. Equivalent to the largest singular value.
      • *
      @@ -156,8 +159,10 @@ public static double schattenNorm(CMatrix src, double p) { /** *

      Computes the matrix operator norm of a real dense matrix "induced" by the vector p-norm. * Specifically, this method computes the operator norm of the matrix as: - *

      -     *     ||A||p = supx≠0(||Ax||p / ||x||p).
      + *
      +     *     ||A||p = supx≠0(||Ax||p / ||x||p).
      + * + * * *

      This method supports a limited set of {@code p} values which yield simple formulas. When {@code p < 1}, the result this method * returns is not a true mathematical norm. However, these values may still be useful for numerical purposes. @@ -200,8 +205,10 @@ public static double inducedNorm(Matrix src, double p) { /** *

      Computes the matrix operator norm of a complex dense matrix "induced" by the vector p-norm. * Specifically, this method computes the operator norm of the matrix as: - *

      -     *     ||A||p = supx≠0(||Ax||p / ||x||p).
      + *
      +     *     ||A||p = supx≠0(||Ax||p / ||x||p).
      + * + * * *

      This method supports a limited set of {@code p} values which yield simple formulas. When {@code p < 1}, the result this method * returns is not a true mathematical norm. However, these values may still be useful for numerical purposes. @@ -242,7 +249,7 @@ public static double inducedNorm(CMatrix src, double p) { /** - *

      Computes the Frobenius (or L2, 2) norm of a real dense matrix. + *

      Computes the Frobenius (or L2, 2) norm of a real dense matrix. * *

      The Frobenius norm is defined as the square root of the sum of absolute squares of all entries in the matrix. * @@ -261,7 +268,7 @@ public static double norm(Matrix src) { /** - *

      Computes the Frobenius (or L2, 2) norm of a real dense matrix. + *

      Computes the Frobenius (or L2, 2) norm of a real dense matrix. * *

      The Frobenius norm is defined as the square root of the sum of absolute squares of all entries in the matrix. * @@ -328,7 +335,7 @@ public static double infNorm(AbstractDenseRingMatrix src) { /** - *

      Computes the Lp, q norm of a real dense matrix. + *

      Computes the Lp,q norm of a real dense matrix. *

      Some common special cases are: *

        *
      • {@code p=2}, {@code q=1}: The sum of Euclidean norms of the column vectors of the matrix.
      • @@ -336,7 +343,7 @@ public static double infNorm(AbstractDenseRingMatrix src) { * the matrix. *
      * - *

      The Lp, q norm is computed as if by: + *

      The Lp,q norm is computed as if by: *

      {@code
            *      double norm = 0;
            *      for(int j=0; j src) {
            *      return Math.pow(norm, 1.0 / q);
            * }
      * - * @param p p value in the Lp, q norm. - * @param q q value in the Lp, q norm. - * @return The Lp, q norm of {@code src}. + * @param p p value in the Lp,q norm. + * @param q q value in the Lp,q norm. + * @return The Lp,q norm of {@code src}. */ public static double norm(Matrix src, double p, double q) { if(p == q) return VectorNorms.norm(src.data, p); @@ -361,7 +368,7 @@ public static double norm(Matrix src, double p, double q) { /** - *

      Computes the Lp, q norm of a real dense matrix. + *

      Computes the Lp,q norm of a real dense matrix. *

      Some common special cases are: *

        *
      • {@code p=2}, {@code q=1}: The sum of Euclidean norms of the column vectors of the matrix.
      • @@ -369,7 +376,7 @@ public static double norm(Matrix src, double p, double q) { * the matrix. *
      * - *

      The Lp, q norm is computed as if by: + *

      The Lp,q norm is computed as if by: *

      {@code
            *      double norm = 0;
            *      for(int j=0; j
            *
      -     * @param p p value in the Lp, q norm.
      -     * @param q q value in the Lp, q norm.
      -     * @return The Lp, q norm of {@code src}.
      +     * @param p p value in the Lp,q norm.
      +     * @param q q value in the Lp,q norm.
      +     * @return The Lp,q norm of {@code src}.
            */
           public static double norm(AbstractDenseRingMatrix src, double p, double q) {
               if(p == q) return VectorNorms.norm(src.data, p);
      @@ -425,7 +432,7 @@ public static double entryWiseNorm(CMatrix src, double p) {
       
           // ------------------------------ Sparse COO Matrices ------------------------------
           /**
      -     * 

      Computes the Lp, q norm of a real COO matrix. + *

      Computes the Lp,q norm of a real COO matrix. *

      Some common special cases are: *

        *
      • {@code p=2}, {@code q=1}: The sum of Euclidean norms of the column vectors of the matrix.
      • @@ -433,9 +440,9 @@ public static double entryWiseNorm(CMatrix src, double p) { * the matrix. *
      * - * @param p p value in the Lp, q norm. - * @param q q value in the Lp, q norm. - * @return The Lp, q norm of {@code src}. + * @param p p value in the Lp,q norm. + * @param q q value in the Lp,q norm. + * @return The Lp,q norm of {@code src}. */ public static double norm(CooMatrix src, double p, double q) { // Sparse implementation is usually only faster for very sparse matrices. @@ -445,7 +452,7 @@ public static double norm(CooMatrix src, double p, double q) { /** - *

      Computes the Lp, q norm of a complex COO matrix. + *

      Computes the Lp,q norm of a complex COO matrix. *

      Some common special cases are: *

        *
      • {@code p=2}, {@code q=1}: The sum of Euclidean norms of the column vectors of the matrix.
      • @@ -453,9 +460,9 @@ public static double norm(CooMatrix src, double p, double q) { * the matrix. *
      * - * @param p p value in the Lp, q norm. - * @param q q value in the Lp, q norm. - * @return The Lp, q norm of {@code src}. + * @param p p value in the Lp,q norm. + * @param q q value in the Lp,q norm. + * @return The Lp,q norm of {@code src}. */ public static double norm(CooCMatrix src, double p, double q) { // Sparse implementation is usually only faster for very sparse matrices. @@ -465,11 +472,11 @@ public static double norm(CooCMatrix src, double p, double q) { /** - * Computes the Frobenius (L2, 2) norm of this complex COO matrix. This is equivalent to + * Computes the Frobenius (L2, 2) norm of this complex COO matrix. This is equivalent to * {@link #norm(CooMatrix, double, double) norm(src, 2, 2)}. * - * @param src Matrix to compute the L2, 2 norm of. - * @return the Frobenius (L2, 2) norm of this tensor. + * @param src Matrix to compute the L2, 2 norm of. + * @return the Frobenius (L2, 2) norm of this tensor. */ public static double norm(CooMatrix src) { // Sparse implementation is usually only faster for very sparse matrices. @@ -479,11 +486,11 @@ public static double norm(CooMatrix src) { /** - * Computes the Frobenius (L2, 2) norm of this complex COO matrix. This is equivalent to + * Computes the Frobenius (L2, 2) norm of this complex COO matrix. This is equivalent to * {@link #norm(CooCMatrix, double, double) norm(src, 2, 2)}. * - * @param src Matrix to compute the L2, 2 norm of. - * @return the Frobenius (L2, 2) norm of this tensor. + * @param src Matrix to compute the L2, 2 norm of. + * @return the Frobenius (L2, 2) norm of this tensor. */ public static double norm(CooCMatrix src) { // Sparse implementation is usually only faster for very sparse matrices. @@ -516,7 +523,7 @@ public static double maxNorm(CooMatrix src) { // ------------------------------ Sparse CSR Matrices ------------------------------ /** - *

      Computes the Lp, q norm of a real CSR matrix. + *

      Computes the Lp,q norm of a real CSR matrix. *

      Some common special cases are: *

        *
      • {@code p=2}, {@code q=1}: The sum of Euclidean norms of the column vectors of the matrix.
      • @@ -524,9 +531,9 @@ public static double maxNorm(CooMatrix src) { * the matrix. *
      * - * @param p p value in the Lp, q norm. - * @param q q value in the Lp, q norm. - * @return The Lp, q norm of {@code src}. + * @param p p value in the Lp,q norm. + * @param q q value in the Lp,q norm. + * @return The Lp,q norm of {@code src}. */ public static double norm(CsrMatrix src, double p, double q) { if(p == 0 || q == 0) @@ -560,7 +567,7 @@ public static double norm(CsrMatrix src, double p, double q) { /** - *

      Computes the Lp, q norm of a complex CSR matrix. + *

      Computes the Lp,q norm of a complex CSR matrix. *

      Some common special cases are: *

        *
      • {@code p=2}, {@code q=1}: The sum of Euclidean norms of the column vectors of the matrix.
      • @@ -568,9 +575,9 @@ public static double norm(CsrMatrix src, double p, double q) { * the matrix. *
      * - * @param p p value in the Lp, q norm. - * @param q q value in the Lp, q norm. - * @return The Lp, q norm of {@code src}. + * @param p p value in the Lp,q norm. + * @param q q value in the Lp,q norm. + * @return The Lp,q norm of {@code src}. */ public static double norm(CsrCMatrix src, double p, double q) { if(p == 0 || q == 0) @@ -626,7 +633,7 @@ public static double maxNorm(CsrCMatrix src) { /** - * Computes the Frobenius (L2, 2) of this matrix. This is equivalent to {@link #norm(CsrMatrix, double, double) norm + * Computes the Frobenius (L2, 2) of this matrix. This is equivalent to {@link #norm(CsrMatrix, double, double) norm * (src, 2, 2)}. * * @param src Matrix to compute the norm of. @@ -650,12 +657,12 @@ public static double norm(CsrCMatrix src) { // -------------------------------------------------- Low-level implementations -------------------------------------------------- /** - * Compute the Lp, q norm of a matrix. + * Compute the Lp,q norm of a matrix. * @param src Entries of the matrix. * @param shape Shape of the matrix. - * @param p First parameter in Lp, q norm. - * @param q Second parameter in Lp, q norm. - * @return The Lp, q norm of the matrix. + * @param p First parameter in Lp,q norm. + * @param q Second parameter in Lp,q norm. + * @return The Lp,q norm of the matrix. */ private static double matrixNormLpq(double[] src, Shape shape, double p, double q) { if(p == 0 || q == 0) @@ -678,12 +685,12 @@ private static double matrixNormLpq(double[] src, Shape shape, double p, double /** - * Compute the Lp, q norm of a matrix. + * Compute the Lp,q norm of a matrix. * @param src Entries of the matrix. * @param shape Shape of the matrix. - * @param p First parameter in Lp, q norm. - * @param q Second parameter in Lp, q norm. - * @return The Lp, q norm of the matrix. + * @param p First parameter in Lp,q norm. + * @param q Second parameter in Lp,q norm. + * @return The Lp,q norm of the matrix. */ private static > double matrixNormLpq(T[] src, Shape shape, double p, double q) { if(p == 0 || q == 0) diff --git a/src/main/java/org/flag4j/linalg/PositiveDefiniteness.java b/src/main/java/org/flag4j/linalg/PositiveDefiniteness.java index 140d557d0..cb20d4e73 100644 --- a/src/main/java/org/flag4j/linalg/PositiveDefiniteness.java +++ b/src/main/java/org/flag4j/linalg/PositiveDefiniteness.java @@ -32,7 +32,18 @@ /** - * This class contains several methods for determining the positive-definiteness of a matrix. + *

      Utility class for checking the positive-(semi-)definiteness of a real or complex matrix. + * + *

      A matrix M is positive-definite iff + * Re[xHMx] > 0 for any vector x or equivalently, if + * all eigenvalues are real and strictly greater than zero. + * + *

      In the case where M is real, this simplifies to + * xTMx > 0. + * + *

      Similarly, a matrix M is positive-semi-definite iff + * Re[xHMx] >= 0 for any vector x or equivalently, if + * all eigenvalues are real and greater than or equal to than zero. */ public final class PositiveDefiniteness { @@ -40,12 +51,10 @@ private PositiveDefiniteness() { // Hide default constructor for utility class. } - // TODO: Improve javadoc in this class. - /** - * Checks if the matrix is positive-definite. A matrix {@code M} is positive-definite iff - * {@code x}T{@code Mx > 0} for any vector {@code x}, or equivalently, if + * Checks if the matrix is positive-definite. A matrix M is positive-definite iff + * xTMx > 0 for any vector x or equivalently, if * all eigenvalues are strictly greater than zero. * * @param src Matrix to check if it is positive-definite. @@ -66,9 +75,9 @@ public static boolean isPosDef(Matrix src) { /** - * Checks if the matrix is positive-definite. A matrix {@code M} is positive-definite iff - * {@code x}T{@code Mx > 0} for any vector {@code x}, or equivalently, if the matrix is Hermitian and - * all eigenvalues are strictly greater than zero. + * Checks if the matrix is positive-definite. A matrix M is positive-definite iff + * Re[xTMx] > 0 for any vector x or equivalently, + * if all eigenvalues are strictly greater than zero. * * @param src Matrix to check if it is positive-definite. * @return {@code true} if the matrix is positive-definite; {@code false} otherwise. @@ -88,15 +97,16 @@ public static boolean isPosDef(CMatrix src) { /** - * Checks if the matrix is symmetric positive-definite. A matrix {@code M} is positive-definite iff - * {@code x}T{@code Mx > 0} for any vector {@code x}, or equivalently, if all eigenvalues are strictly - * greater than zero. + * Checks if the matrix is symmetric positive-definite. A matrix M is symmetric + * positive-definite iff the matrix is symmetric and + * xHMx > 0 for any vector x or + * equivalently, if all eigenvalues are real and strictly greater than zero. * * @param src Matrix to check if it is positive-definite. * @return {@code true} if the matrix is positive-definite; {@code false} otherwise. * @see #isPosSemiDef(Matrix) */ - public static boolean isHermPosDef(Matrix src) { + public static boolean isSymmPosDef(Matrix src) { boolean result = true; try { @@ -110,9 +120,10 @@ public static boolean isHermPosDef(Matrix src) { /** - * Checks if the matrix is symmetric positive-definite. A matrix {@code M} is positive-definite iff - * {@code x}T{@code Mx > 0} for any vector {@code x}, or equivalently, if all eigenvalues are strictly - * greater than zero. + * Checks if the matrix is Hermitian positive-definite. A matrix M is Hermitian + * positive-definite iff the matrix is Hermitian and + * Re[xHMx] > 0 for any vector x or + * equivalently, if all eigenvalues are real and strictly greater than zero. * * @param src Matrix to check if it is positive-definite. * @return {@code true} if the matrix is positive-definite; {@code false} otherwise. @@ -132,8 +143,8 @@ public static boolean isHermPosDef(CMatrix src) { /** - * Checks if the matrix is positive semi-definite. A matrix {@code M} is positive semi-definite iff - * {@code x}T{@code Mx >= 0} for any vector {@code x}, or equivalently, if the matrix is symmetric and + * Checks if the matrix is positive semi-definite. A matrix M is positive-semi-definite iff + * xTMx >= 0 for any vector x, or equivalently, if * all eigenvalues are greater than or equal to zero. * * @param src Matrix to check if it is positive semi-definite. @@ -154,8 +165,9 @@ public static boolean isPosSemiDef(Matrix src) { /** - * Checks if the matrix is positive semi-definite. A matrix {@code M} is positive semi-definite iff - * {@code x}T{@code Mx >= 0} for any vector {@code x}, or equivalently, if the matrix is Hermitian and + * Checks if the matrix is positive semi-definite. A matrix M is positive-semi-definite iff + * Re[xTMx] >= 0 for any vector x, or + * equivalently, if * all eigenvalues are greater than or equal to zero. * * @param src Matrix to check if it is positive semi-definite. diff --git a/src/main/java/org/flag4j/linalg/TensorInvert.java b/src/main/java/org/flag4j/linalg/TensorInvert.java index 4717f2c52..8137d1287 100644 --- a/src/main/java/org/flag4j/linalg/TensorInvert.java +++ b/src/main/java/org/flag4j/linalg/TensorInvert.java @@ -27,7 +27,6 @@ import org.flag4j.arrays.Shape; import org.flag4j.arrays.backend.primitive_arrays.AbstractDenseDoubleTensor; -import org.flag4j.arrays.backend.primitive_arrays.AbstractDoubleTensor; import org.flag4j.arrays.dense.CMatrix; import org.flag4j.arrays.dense.CTensor; import org.flag4j.arrays.dense.Matrix; @@ -47,7 +46,7 @@ private TensorInvert() { /** *

      Computes the 'inverse' of a tensor. That is, computes the tensor {@code X=this.tensorInv()} such that - * {@link Tensor#tensorDot(AbstractDoubleTensor, int[], int[]) src.tensorDot(X, numIndices)} is the 'identity' tensor for the + * {@code src.tensorDot(X, numIndices)} is the 'identity' tensor for the * tensor dot product operation. * *

      A tensor {@code I} is the identity for a tensor dot product if {@code src.tensorDot(I, numIndices).equals(this)}. @@ -73,7 +72,7 @@ public static Tensor inv(Tensor src, int numIndices) { /** *

      Computes the 'inverse' of a tensor. That is, computes the tensor {@code X=this.tensorInv()} such that - * {@link Tensor#tensorDot(TensorOverSemiRing, int) src.tensorDot(X, numIndices)} is the 'identity' tensor for the + * {@code src.tensorDot(X, numIndices)} is the 'identity' tensor for the * tensor dot product operation. * *

      A tensor {@code I} is the identity for a tensor dot product if @@ -101,7 +100,7 @@ public static > T inv( /** *

      Computes the 'inverse' of a tensor. That is, computes the tensor {@code X=this.tensorInv()} such that - * {@link Tensor#tensorDot(TensorOverSemiRing, int) src.tensorDot(X, numIndices)} is the 'identity' tensor for the tensor + * {@cide src.tensorDot(X, numIndices)} is the 'identity' tensor for the tensor * dot product operation. *

      A tensor {@code I} is the identity for a tensor dot product if {@code src.tensorDot(I, numIndices).equals(this)}. * @param src Tensor to compute inverse of. diff --git a/src/main/java/org/flag4j/linalg/VectorNorms.java b/src/main/java/org/flag4j/linalg/VectorNorms.java index 673294b0b..0bc4ebd04 100644 --- a/src/main/java/org/flag4j/linalg/VectorNorms.java +++ b/src/main/java/org/flag4j/linalg/VectorNorms.java @@ -30,14 +30,14 @@ /** - * A utility class for computing vector norms, including various types of ℓp norms, + * A utility class for computing vector norms, including various types of p norms, * with support for both dense and sparse vectors. This class provides methods to compute norms * for vectors with real entries as well as vectors with entries that belong to a {@link Ring}. * - *

      The methods in this class utilize scaling internally when computing the ℓp norm to protect against + *

      The methods in this class utilize scaling internally when computing the p norm to protect against * overflow and underflow for very large or very small values of {@code p} (in absolute value). * - *

      Note: When {@code p < 1}, the results of the ℓp norm methods are not + *

      Note: When {@code p < 1}, the results of the p norm methods are not * technically true mathematical norms but may still be useful for numerical tasks. However, {@code p = 0} * will result in {@link Double#NaN}. * @@ -56,12 +56,12 @@ private VectorNorms() { } /** - *

      Computes the Euclidean (ℓ2) norm of a real dense or sparse vector. + *

      Computes the Euclidean (2) norm of a real dense or sparse vector. *

      Zeros do not contribute to this norm so this function may be called on the entries of a dense vector or the non-zero entries * of a sparse vector. * * @param src Entries of the vector (or non-zero data if vector is sparse) to compute norm of. - * @return Euclidean (ℓ2) norm + * @return Euclidean (2) norm */ public static double norm(double... src) { return scaledL2Norm(src); @@ -69,13 +69,13 @@ public static double norm(double... src) { /** - *

      Computes the Euclidean (ℓ2) norm of a dense or sparse vector whose entries are members of a + *

      Computes the Euclidean (2) norm of a dense or sparse vector whose entries are members of a * {@link Ring}. *

      Zeros do not contribute to this norm so this function may be called on the entries of a dense vector or the non-zero entries * of a sparse vector. * * @param src Entries of the vector (or non-zero data if vector is sparse) to compute norm of. - * @return Euclidean (ℓ2) norm + * @return Euclidean (2) norm */ public static > double norm(T... src) { return scaledL2Norm(src); @@ -83,18 +83,18 @@ public static > double norm(T... src) { /** - *

      Computes the ℓp norm (or p-norm) of a real dense or sparse vector. + *

      Computes the p norm (or p-norm) of a real dense or sparse vector. *

      Some common norms: *

        *
      • {@code p=1}: The taxicab, city block, or Manhattan norm.
      • - *
      • {@code p=2}: The Euclidean or ℓ2 norm.
      • + *
      • {@code p=2}: The Euclidean or 2 norm.
      • *
      * *

      Zeros do not contribute to this norm so this function may be called on the entries of a dense vector or the non-zero entries * of a sparse vector. * * @param src Entries of the vector (or non-zero data if vector is sparse). - * @param p The {@code p} value in the {@code p}-norm. When {@code p < 1}, the result of this method is not technically a + * @param p The {@code p} value in the p-norm. When {@code p < 1}, the result of this method is not technically a * true mathematical norm. However, it may be useful for various numerical tasks. *

        *
      • If {@code p} is finite, then the norm is computed as if by: @@ -112,7 +112,7 @@ public static > double norm(T... src) { *
      * *

      Warning, if {@code p} is very large in absolute value, overflow errors may occur. - * @return The {@code p}-norm of the vector. + * @return The p-norm of the vector. */ public static double norm(double[] src, double p) { if (src.length == 0) return 0; @@ -136,18 +136,19 @@ public static double norm(double[] src, double p) { /** - *

      Computes the ℓp norm (or p-norm) of a dense or sparse vector whose entries are members of a {@link Ring}. + *

      Computes the p norm (or p-norm) of a dense or sparse vector whose + * entries are members of a {@link Ring}. *

      Some common norms: *

        *
      • {@code p=1}: The taxicab, city block, or Manhattan norm.
      • - *
      • {@code p=2}: The Euclidean or ℓ2 norm.
      • + *
      • {@code p=2}: The Euclidean or 2 norm.
      • *
      * *

      Zeros do not contribute to this norm so this function may be called on the entries of a dense vector or the non-zero entries * of a sparse vector. * * @param src Entries of the vector (or non-zero data if vector is sparse). - * @param p The {@code p} value in the {@code p}-norm. When {@code p < 1}, the result of this method is not technically a + * @param p The {@code p} value in the p-norm. When {@code p < 1}, the result of this method is not technically a * true mathematical norm. However, it may be useful for various numerical tasks. *

        *
      • If {@code p} is finite, then the norm is computed as if by: @@ -165,7 +166,7 @@ public static double norm(double[] src, double p) { *
      * *

      Warning, if {@code p} is very large in absolute value, overflow errors may occur. - * @return The {@code p}-norm of the vector. + * @return The p-norm of the vector. */ public static > double norm(T[] src, double p) { if (src.length == 0) return 0; @@ -189,13 +190,13 @@ public static > double norm(T[] src, double p) { /** - * Computes the scaled ℓp norm of a vector. + * Computes the scaled p norm of a vector. * This method uses scaling to protect against numerical instability such as overflow or underflow - * when computing the ℓp norm for large or small values of {@code p}. + * when computing the p norm for large or small values of {@code p}. * - * @param src The input vector (or non-zero values if vector is sparse) whose ℓp norm is to be computed. - * @param p The value of {@code p} for the ℓp norm. - * @return The scaled ℓp norm of the input vector. + * @param src The input vector (or non-zero values if vector is sparse) whose p norm is to be computed. + * @param p The value of {@code p} for the p norm. + * @return The scaled p norm of the input vector. */ private static double scaledLpNorm(double[] src, double p) { // Find the maximum absolute value in the vector. @@ -216,12 +217,12 @@ private static double scaledLpNorm(double[] src, double p) { /** - * Computes the scaled ℓ2 norm (Euclidean norm) of a vector. + * Computes the scaled 2 norm (Euclidean norm) of a vector. * This method uses scaling to protect against numerical instability such as overflow or underflow - * when computing the ℓ2 norm for vectors with very large or very small values. + * when computing the 2 norm for vectors with very large or very small values. * - * @param src The input vector (or non-zero entries if the vector is sparse) whose ℓ2 norm is to be computed. - * @return The scaled ℓ2 norm of the input vector. + * @param src The input vector (or non-zero entries if the vector is sparse) whose 2 norm is to be computed. + * @return The scaled 2 norm of the input vector. */ private static double scaledL2Norm(double[] src) { // Find the maximum absolute value in the vector. @@ -244,13 +245,13 @@ private static double scaledL2Norm(double[] src) { /** - * Computes the scaled ℓp norm of a vector. + * Computes the scaled p norm of a vector. * This method uses scaling to protect against numerical instability such as overflow or underflow - * when computing the ℓp norm for large or small values of {@code p}. + * when computing the p norm for large or small values of {@code p}. * - * @param src The input vector (or non-zero values if vector is sparse) whose ℓp norm is to be computed. - * @param p The value of {@code p} for the ℓp norm. - * @return The scaled ℓp norm of the input vector. + * @param src The input vector (or non-zero values if vector is sparse) whose p norm is to be computed. + * @param p The value of {@code p} for the p norm. + * @return The scaled p norm of the input vector. */ private static > double scaledLpNorm(T[] src, double p) { // Find the maximum absolute value in the vector. @@ -271,12 +272,12 @@ private static > double scaledLpNorm(T[] src, double p) { /** - * Computes the scaled ℓ2 norm (Euclidean norm) of a vector. + * Computes the scaled 2 norm (Euclidean norm) of a vector. * This method uses scaling to protect against numerical instability such as overflow or underflow - * when computing the ℓ2 norm for vectors with very large or very small values. + * when computing the 2 norm for vectors with very large or very small values. * - * @param src The input vector (or non-zero entries if the vector is sparse) whose ℓ2 norm is to be computed. - * @return The scaled ℓ2 norm of the input vector. + * @param src The input vector (or non-zero entries if the vector is sparse) whose 2 norm is to be computed. + * @return The scaled 2 norm of the input vector. */ private static > double scaledL2Norm(T[] src) { // Find the maximum absolute value in the vector. @@ -299,7 +300,7 @@ private static > double scaledL2Norm(T[] src) { /** - *

      Computes the ℓ2 (Euclidean) norm of a sub-vector within {@code src}, + *

      Computes the 2 (Euclidean) norm of a sub-vector within {@code src}, * starting at index {@code start} and considering {@code n} elements spaced by {@code stride}. * *

      More formally, this method examines and computes the norm of the elements at indices: @@ -319,7 +320,7 @@ private static > double scaledL2Norm(T[] src) { * @param n The number of elements to consider within {@code src1}. Must be positive but this is not explicitly enforced. * @param stride The gap (in indices) between consecutive elements of the sub-vector within {@code src}. * Must be positive but this is not explicitly enforced. - * @return The ℓ2 (Euclidean) norm of the specified sub-vector of {@code src}. + * @return The 2 (Euclidean) norm of the specified sub-vector of {@code src}. * * @throws IndexOutOfBoundsException If {@code start + (n-1)*stride} exceeds {@code src.length - 1}. */ @@ -345,7 +346,7 @@ public static double norm(double[] src, final int start, final int n, final int /** - *

      Computes the ℓ2 (Euclidean) norm of a sub-vector within {@code src}, + *

      Computes the 2 (Euclidean) norm of a sub-vector within {@code src}, * starting at index {@code start} and considering {@code n} elements spaced by {@code stride}. * *

      More formally, this method examines and computes the norm of the elements at indices: @@ -365,7 +366,7 @@ public static double norm(double[] src, final int start, final int n, final int * @param n The number of elements to consider within {@code src1}. Must be positive but this is not explicitly enforced. * @param stride The gap (in indices) between consecutive elements of the sub-vector within {@code src}. * Must be positive but this is not explicitly enforced. - * @return The ℓ2 (Euclidean) norm of the specified sub-vector of {@code src}. + * @return The 2 (Euclidean) norm of the specified sub-vector of {@code src}. * * @throws IndexOutOfBoundsException If {@code start + (n-1)*stride} exceeds {@code src.length - 1}. */ diff --git a/src/main/java/org/flag4j/linalg/decompositions/balance/Balancer.java b/src/main/java/org/flag4j/linalg/decompositions/balance/Balancer.java index a392e9b13..f389efe57 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/balance/Balancer.java +++ b/src/main/java/org/flag4j/linalg/decompositions/balance/Balancer.java @@ -44,37 +44,94 @@ * balancing transformation is a similarity transformation, the eigenvalues are preserved. Further, when permutations are * done during balancing it is possible to isolate decoupled eigenvalues. * - *

      The similarity transformation of a square matrix A into the balanced matrix B can be described as: + *

      The similarity transformation of a square matrix A into the + * balanced matrix B can be described as: + * *

        *     B = T-1 A T
        *       = D-1 P-1 A P D.
      - * Solving for A, balancing may be viewed as the following decomposition: + * + * + * Solving for A, + * balancing may be viewed as the following decomposition: + * *
        *     A = T B T-1
        *       = P D B D-1 P-1.
      - * Where P is a permutation matrix, and D is a diagonal scaling matrix. + *
      + * + * Where P is a permutation matrix, + * and D is a diagonal scaling matrix. * *

      When permutations are used during balancing we obtain a specific form. First, + * *

        *             [ T1  X   Y  ]
        *   P-1 A P = [  0  B1  Z  ]
        *             [  0  0   T2 ]
      - * Where T1 and T2 are upper triangular matrices whose eigenvalues lie along the diagonal. These are also - * eigenvalues of A. Then, if scaling is applied we obtain: + * + * + * + * + * Where T1 + * and T2 are upper triangular + * matrices whose eigenvalues lie along the diagonal. + * These are also eigenvalues of A. + * Then, if scaling is applied we obtain: + * + * *
        *                   [ T1     X*D1       Y   ]
        *   D-1 P-1 A P D = [  0  D1-1*B1*D1  D1-1*Z  ]
        *                   [  0      0         T2  ]
      + *
      * - * where D1 is a diagonal matrix such that, + * + * + * where D1 is a diagonal matrix such that, + * *
        *         [ I1 0  0  ]
        *     D = [ 0  D1 0  ]
        *         [ 0  0  I2 ]
      - * Where I1 and I2 are identity matrices with equivalent shapes to T1 and T2. + *
      + * + * + * + * Where I1 and + * I2 are identity matrices with + * equivalent shapes to T1 and + * T2. * - *

      Once balancing has been applied, one need only compute the eigenvalues of B1 and combine them with the diagonal - * entries of T1 and T2 to obtain all eigenvalues of A. + *

      Once balancing has been applied, one need only compute the eigenvalues of + * B1 and combine them with the diagonal + * entries of T1 and + * T2 + * to obtain all eigenvalues of A. * *

      The code in this class if heavily based on LAPACK's reference implementations of * xGEBAL (v 3.12.1). @@ -216,7 +273,8 @@ protected Balancer(boolean doPermutations, boolean doScaling, boolean inPlace) { /** - * Computes the ℓ2 norm of a vector with {@code n} elements from {@link #balancedMatrix}'s 1D data array + * Computes the 2 norm of a vector with {@code n} elements from + * {@link #balancedMatrix}'s 1D data array * starting at index {@code start} and spaced by {@code stride}. * @param start Starting index within {@link #balancedMatrix}'s 1D data array to compute norm of. * @param n The number of elements in the vector to compute norm of. @@ -301,16 +359,34 @@ public Balancer decompose(T src) { * eigenvalue are pushed to the left of the matrix. To ensure that the row/column swaps are similarity transforms, if any two * rows are swapped the same columns are swapped. * - *

      Such row and column permutations transform the original matrix {@code A} into the following form: + *

      Such row and column permutations transform the original matrix A into the + * following form: + * *

      -     *             [ T1  X  Y  ]
      -     *   P-1 A P = [  0  B  Z  ]
      -     *             [  0  0  T2 ]
      - *

      Where T1 and T2 are upper-triangular matrices whose eigenvalues are the diagonal elements of the matrix. - * P is the permutation matrix representing the row and column swaps performed within this method. + * [ T1 X Y ] + * P-1 A P = [ 0 B1 Z ] + * [ 0 0 T2 ]

      + * + * + * + * + *

      Where T1 and T2 + * are upper-triangular matrices whose eigenvalues are the diagonal elements of the matrix. + * P is the permutation matrix representing the row and column swaps performed within + * this method. * *

      {@link #iLow} and {@link #iHigh} Specify the starting (inclusive) and ending (exclusive) row/column index of the submatrix - * B. + * B. */ protected void doIterativePermutations() { boolean notConverged = true; @@ -386,11 +462,14 @@ protected void doIterativePermutations() { *

      Performs the scaling step of matrix balancing. * *

      That is, computes scaling factors such that when a column is scaled by such value and the row is scaled by the reciprocal - * of that value, there ℓ1 norms are "close". Scaling need only be done for rows/column of the matrix which do not - * isolate eigenvalues; rows between {@link #iLow} (inclusive) to {@link #iHigh} (exclusive). + * of that value, there 1 norms are "close". Scaling need only be done for + * rows/column of the matrix which do not isolate eigenvalues; rows between {@link #iLow} (inclusive) to {@link #iHigh} + * (exclusive). * - *

      D1 is the diagonal matrix describing such scaling and is the diagonal matrix computed by this method. - * The diagonal values of D1 are stored in {@link #scalePerm} between indices {@link #iLow} (inclusive) to + *

      ℓD1 is the diagonal matrix describing such scaling and is + * the diagonal matrix computed by this method. + * The diagonal values of ℓD1 are stored in {@link #scalePerm} + * between indices {@link #iLow} (inclusive) to * {@link #iHigh} (exclusive). */ protected void doIterativeScaling() { @@ -494,7 +573,8 @@ protected void ensureHasBalanced() { /** - * Gets the starting index (inclusive) for the sub-matrix B1 of the balanced matrix which did not isolate + * Gets the starting index (inclusive) for the sub-matrix B1 + * of the balanced matrix which did not isolate * eigenvalues. * @return The starting index (inclusive) for the sub-matrix of the balanced matrix which did not isolate eigenvalues. * @throws IllegalStateException If {@link #decompose(MatrixMixin)} has not yet been called on this instance. @@ -506,7 +586,8 @@ public int getILow() { /** - * Gets the starting index (exclusive) for the sub-matrix B1 of the balanced matrix which did not isolate + * Gets the starting index (exclusive) for the sub-matrix B1 + * of the balanced matrix which did not isolate * eigenvalues. * @return The starting index (exclusive) for the sub-matrix of the balanced matrix which did not isolate eigenvalues. * @throws IllegalStateException If {@link #decompose(MatrixMixin)} has not yet been called on this instance. @@ -529,7 +610,8 @@ public T getB() { /** - * Gets the sub-matrix B1 of the full balanced matrix which did not isolate eigenvalues. + * Gets the sub-matrix B1 of the full balanced matrix + * which did not isolate eigenvalues. * @return The sub-matrix of the full balanced matrix which did not isolate eigenvalues. * @throws IllegalStateException If {@link #decompose(MatrixMixin)} has not yet been called on this instance. */ @@ -656,8 +738,8 @@ public PermutationMatrix getP() { /** - * Get the combined permutation and diagonal scaling matrix, T=PD, from the last matrix balanced. - * This is equivalent to {@code getP().leftMult(getD(true))}. + * Get the combined permutation and diagonal scaling matrix, T = PD, from the last + * matrix balanced. This is equivalent to {@code getP().leftMult(getD(true))}. * @return The combined permutation and diagonal scaling matrix from the last matrix balanced. * @throws IllegalStateException If {@link #decompose(MatrixMixin)} has not yet been called on this instance. */ @@ -667,8 +749,10 @@ public Matrix getT() { /** - * Gets the inverse of the full diagonal scaling matrix D-1 from the balancing problem. - * @return The inverse of the full diagonal scaling matrix D-1 from the balancing problem. + * Gets the inverse of the full diagonal scaling matrix, + * D-1, from the balancing problem. + * @return The inverse of the full diagonal scaling matrix, + * D-1, from the balancing problem. * @throws IllegalStateException If {@link #decompose(MatrixMixin)} has not yet been called on this instance. */ public Matrix getDInv() { @@ -677,8 +761,8 @@ public Matrix getDInv() { /** - * Gets the inverse of the permutation matrix P-1 from the balancing problem. - * @return The inverse of the permutation matrix P-1 from the balancing problem. + * Gets the inverse of the permutation matrix, P-1, from the balancing problem. + * @return The inverse of the permutation matrix, P-1, from the balancing problem. * @throws IllegalStateException If {@link #decompose(MatrixMixin)} has not yet been called on this instance. */ public PermutationMatrix getPInv() { @@ -688,7 +772,7 @@ public PermutationMatrix getPInv() { /** * Get the inverse of combined permutation and diagonal scaling matrix, - * T-1=D-1P-1, from the last matrix balanced. + * T-1 = D-1P-1, from the last matrix balanced. * This is equivalent to {@code getP().inv().rightMult(getDInv())}. * @return The combined permutation and diagonal scaling matrix from the last matrix balanced. * @throws IllegalStateException If {@link #decompose(MatrixMixin)} has not yet been called on this instance. @@ -699,17 +783,19 @@ public Matrix getTInv() { /** - * Efficiently left multiplies PD to the provided {@code src} matrix. + * Efficiently left multiplies PD to the provided {@code src} matrix. * @param src Matrix to apply transform to. - * @return The result of left multiplying PD to the {@code src} matrix. + * @return The result of left multiplying PD to the {@code src} matrix. */ public abstract T applyLeftTransform(T src); /** - * Efficiently right multiplies D-1P-1 to the provided {@code src} matrix. + * Efficiently right multiplies D-1P-1 + * to the provided {@code src} matrix. * @param src Matrix to apply transform to. - * @return The result of right multiplying D-1P-1 to the {@code src} matrix. + * @return The result of right multiplying D-1P-1 + * to the {@code src} matrix. */ public abstract T applyRightTransform(T src); } diff --git a/src/main/java/org/flag4j/linalg/decompositions/balance/ComplexBalancer.java b/src/main/java/org/flag4j/linalg/decompositions/balance/ComplexBalancer.java index 6436a7987..6a07c258e 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/balance/ComplexBalancer.java +++ b/src/main/java/org/flag4j/linalg/decompositions/balance/ComplexBalancer.java @@ -42,38 +42,99 @@ * balancing transformation is a similarity transformation, the eigenvalues are preserved. Further, when permutations are * done during balancing it is possible to isolate decoupled eigenvalues. * - *

      The similarity transformation of a square matrix A into the balanced matrix B can be described as: + *

      The similarity transformation of a square matrix A into the + * balanced matrix B can be described as: + * *

        *     B = T-1 A T
        *       = D-1 P-1 A P D.
      - * Solving for A, balancing may be viewed as the following decomposition: + * + * + * Solving for A, + * balancing may be viewed as the following decomposition: + * *
        *     A = T B T-1
        *       = P D B D-1 P-1.
      - * Where P is a permutation matrix, and D is a diagonal scaling matrix. + *
      + * + * Where P is a permutation matrix, + * and D is a diagonal scaling matrix. * *

      When permutations are used during balancing we obtain a specific form. First, + * *

        *             [ T1  X   Y  ]
        *   P-1 A P = [  0  B1  Z  ]
        *             [  0  0   T2 ]
      - * Where T1 and T2 are upper triangular matrices whose eigenvalues lie along the diagonal. These are also - * eigenvalues of A. Then, if scaling is applied we obtain: + * + * + * + * + * Where T1 + * and T2 are upper triangular + * matrices whose eigenvalues lie along the diagonal. + * These are also eigenvalues of A. + * Then, if scaling is applied we obtain: + * + * *
        *                   [ T1     X*D1       Y   ]
      - *   D-1 P-1 A P D = [  0  D1-1*B*1D1  D1-1*Z  ]
      + *   D-1 P-1 A P D = [  0  D1-1*B1*D1  D1-1*Z  ]
        *                   [  0      0         T2  ]
      - * Where D1 is a diagonal matrix such that, + *
      + * + * + * + * where D1 is a diagonal matrix such that, + * *
        *         [ I1 0  0  ]
        *     D = [ 0  D1 0  ]
        *         [ 0  0  I2 ]
      - * Where I1 and I2 are identity matrices with equivalent shapes to T1 and T2. + *
      + * + * + * + * Where I1 and + * I2 are identity matrices with + * equivalent shapes to T1 and + * T2. * - *

      Once balancing has been applied, one need only compute the eigenvalues of B1 and combine them with the diagonal - * entries of T1 and T2 to obtain all eigenvalues of A. + *

      Once balancing has been applied, one need only compute the eigenvalues of + * B1 and combine them with the diagonal + * entries of T1 and + * T2 + * to obtain all eigenvalues of A. * - * @param The type of matrix being balanced. + *

      The code in this class if heavily based on LAPACK's reference implementations of + * xGEBAL (v 3.12.1). * * @see #getB() * @see #getBSubMatrix() @@ -181,7 +242,7 @@ protected boolean isZero(int idx) { /** - * Computes the ℓ2 norm of a vector with {@code n} elements from {@link #balancedMatrix}'s 1D data array + * Computes the 2 norm of a vector with {@code n} elements from {@link #balancedMatrix}'s 1D data array * starting at index {@code start} and spaced by {@code stride}. * * @param start Starting index within {@link #balancedMatrix}'s 1D data array to compute norm of. @@ -229,9 +290,9 @@ protected void vectorScale(double factor, int start, int n, int stride) { /** - * Efficiently left multiplies PD to the provided {@code src} matrix. + * Efficiently left multiplies PD to the provided {@code src} matrix. * @param src Matrix to apply transform to. - * @return The result of left multiplying PD to the {@code src} matrix. + * @return The result of left multiplying PD to the {@code src} matrix. */ @Override public CMatrix applyLeftTransform(CMatrix src) { @@ -257,9 +318,10 @@ public CMatrix applyLeftTransform(CMatrix src) { /** - * Efficiently right multiplies D-1P-1 to the provided {@code src} matrix. + * Efficiently right multiplies D-1P-1 to the provided {@code src} matrix. * @param src Matrix to apply transform to. - * @return The result of right multiplying D-1P-1 to the {@code src} matrix. + * @return The result of right multiplying D-1P-1 + * to the {@code src} matrix. */ @Override public CMatrix applyRightTransform(CMatrix src) { diff --git a/src/main/java/org/flag4j/linalg/decompositions/balance/RealBalancer.java b/src/main/java/org/flag4j/linalg/decompositions/balance/RealBalancer.java index f0e2ec884..6746c174a 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/balance/RealBalancer.java +++ b/src/main/java/org/flag4j/linalg/decompositions/balance/RealBalancer.java @@ -41,38 +41,99 @@ * balancing transformation is a similarity transformation, the eigenvalues are preserved. Further, when permutations are * done during balancing it is possible to isolate decoupled eigenvalues. * - *

      The similarity transformation of a square matrix A into the balanced matrix B can be described as: + *

      The similarity transformation of a square matrix A into the + * balanced matrix B can be described as: + * *

        *     B = T-1 A T
        *       = D-1 P-1 A P D.
      - * Solving for A, balancing may be viewed as the following decomposition: + * + * + * Solving for A, + * balancing may be viewed as the following decomposition: + * *
        *     A = T B T-1
        *       = P D B D-1 P-1.
      - * Where P is a permutation matrix, and D is a diagonal scaling matrix. + *
      + * + * Where P is a permutation matrix, + * and D is a diagonal scaling matrix. * *

      When permutations are used during balancing we obtain a specific form. First, + * *

        *             [ T1  X   Y  ]
        *   P-1 A P = [  0  B1  Z  ]
        *             [  0  0   T2 ]
      - * Where T1 and T2 are upper triangular matrices whose eigenvalues lie along the diagonal. These are also - * eigenvalues of A. Then, if scaling is applied we obtain: + * + * + * + * + * Where T1 + * and T2 are upper triangular + * matrices whose eigenvalues lie along the diagonal. + * These are also eigenvalues of A. + * Then, if scaling is applied we obtain: + * + * *
        *                   [ T1     X*D1       Y   ]
      - *   D-1 P-1 A P D = [  0  D1-1*B*1D1  D1-1*Z  ]
      + *   D-1 P-1 A P D = [  0  D1-1*B1*D1  D1-1*Z  ]
        *                   [  0      0         T2  ]
      - * Where D1 is a diagonal matrix such that, + *
      + * + * + * + * where D1 is a diagonal matrix such that, + * *
        *         [ I1 0  0  ]
        *     D = [ 0  D1 0  ]
        *         [ 0  0  I2 ]
      - * Where I1 and I2 are identity matrices with equivalent shapes to T1 and T2. + *
      + * + * + * + * Where I1 and + * I2 are identity matrices with + * equivalent shapes to T1 and + * T2. * - *

      Once balancing has been applied, one need only compute the eigenvalues of B1 and combine them with the diagonal - * entries of T1 and T2 to obtain all eigenvalues of A. + *

      Once balancing has been applied, one need only compute the eigenvalues of + * B1 and combine them with the diagonal + * entries of T1 and + * T2 + * to obtain all eigenvalues of A. * - * @param The type of matrix being balanced. + *

      The code in this class if heavily based on LAPACK's reference implementations of + * xGEBAL (v 3.12.1). * * @see #getB() * @see #getBSubMatrix() @@ -180,7 +241,8 @@ protected boolean isZero(int idx) { /** - * Computes the ℓ2 norm of a vector with {@code n} elements from {@link #balancedMatrix}'s 1D data array + * Computes the 2 norm of a vector with {@code n} + * elements from {@link #balancedMatrix}'s 1D data array * starting at index {@code start} and spaced by {@code stride}. * * @param start Starting index within {@link #balancedMatrix}'s 1D data array to compute norm of. @@ -228,9 +290,9 @@ protected void vectorScale(double factor, int start, int n, int stride) { /** - * Efficiently left multiplies PD to the provided {@code src} matrix. + * Efficiently left multiplies PD to the provided {@code src} matrix. * @param src Matrix to apply transform to. - * @return The result of left multiplying PD to the {@code src} matrix. + * @return The result of left multiplying PD to the {@code src} matrix. */ @Override public Matrix applyLeftTransform(Matrix src) { @@ -256,9 +318,9 @@ public Matrix applyLeftTransform(Matrix src) { /** - * Efficiently right multiplies D-1P-1 to the provided {@code src} matrix. + * Efficiently right multiplies D-1P-1 to the provided {@code src} matrix. * @param src Matrix to apply transform to. - * @return The result of right multiplying D-1P-1 to the {@code src} matrix. + * @return The result of right multiplying D-1P-1 to the {@code src} matrix. */ @Override public Matrix applyRightTransform(Matrix src) { diff --git a/src/main/java/org/flag4j/linalg/decompositions/chol/Cholesky.java b/src/main/java/org/flag4j/linalg/decompositions/chol/Cholesky.java index 1dc670351..7596cbad6 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/chol/Cholesky.java +++ b/src/main/java/org/flag4j/linalg/decompositions/chol/Cholesky.java @@ -32,21 +32,24 @@ /** *

      An abstract base class for Cholesky decomposition of symmetric (or Hermitian) positive-definite matrices. * - *

      The Cholesky decomposition factorizes a symmetric/Hermitian, positive-definite matrix A as: - *

      - *     A = LLH
      - * where L is a lower triangular matrix. + *

      The Cholesky decomposition factorizes a symmetric/Hermitian, positive-definite matrix A as: + * + *

      + *     A = LLH
      + * where L is a lower triangular matrix. * The decomposition is primarily used for efficient numerical solutions to linear systems, computing matrix inverses, * and generating samples from multivariate normal distributions. * *

      Hermitian Verification:

      *

      This class provides an option to explicitly check whether the input matrix is Hermitian. If {@code enforceHermitian} is set - * to {@code true}, the implementation will verify that A satisfies A = AH before performing decomposition. + * to {@code true}, the implementation will verify that A + * satisfies A = AH before performing decomposition. * If set to {@code false}, the matrix is assumed to be Hermitian, no explicit check will be performed, and only the lower-diagonal - * entries of A are accessed. + * entries of A are accessed. * *

      positive-definiteness Check:

      - *

      To ensure numerical stability, the algorithm verifies that all diagonal entries of L are positive. + *

      To ensure numerical stability, the algorithm verifies that all diagonal entries of L + * are positive. * A tolerance threshold, {@code posDefTolerance}, is used to determine whether a diagonal entry is considered * non-positive, indicating that the matrix is not positive-definite. This threshold can be adjusted using * {@link #setPosDefTolerance(double)}. @@ -81,7 +84,7 @@ public abstract class Cholesky> extends Decomp */ protected boolean enforceHermitian; /** - * Tolerance for determining if an entry along the diagonal of {@code L} is not positive-definite. + * Tolerance for determining if an entry along the diagonal of L is not positive-definite. */ protected double posDefTolerance = 1.0e-14; @@ -106,7 +109,8 @@ protected Cholesky(boolean enforceHermitian) { /** *

      Sets the tolerance for determining if the matrix being decomposed is positive-definite. - *

      The matrix being decomposed will be considered to not be positive-definite if any diagonal entry of L + *

      The matrix being decomposed will be considered to not be positive-definite if any diagonal entry of + * L * is {@code <= tol}. By default, this value is {@code 1.0e-14}. * @param tol Tolerance to use. Must be non-negative. * @throws IllegalArgumentException If {@code tol < 0}. @@ -119,14 +123,16 @@ public void setPosDefTolerance(double tol) { /** - * The lower triangular matrix, L, resulting from the Cholesky decomposition A=LLH. + * The lower triangular matrix, L, resulting from the Cholesky decomposition + * A = LLH. */ protected T L; /** - * Gets the L matrix computed by the Cholesky decomposition A=LLH. - * @return The L matrix from the Cholesky decomposition A=LLH. + * Gets the L matrix computed by the Cholesky decomposition A = LLH. + * @return The L matrix from the Cholesky decomposition + * A = LLH. * @throws IllegalStateException If {@link #decompose(MatrixMixin)} has not been called on this instance. */ public T getL() { @@ -136,8 +142,10 @@ public T getL() { /** - * Gets the LH matrix computed by the Cholesky decomposition A=LLH. - * @return The LH matrix from the Cholesky decomposition A=LLH. + * Gets the LH matrix computed by the Cholesky decomposition + * A = LLH. + * @return The LH matrix from the Cholesky decomposition + * A = LLH. * @throws IllegalStateException If {@link #decompose(MatrixMixin)} has not been called on this instance. */ public T getLH() { diff --git a/src/main/java/org/flag4j/linalg/decompositions/chol/ComplexCholesky.java b/src/main/java/org/flag4j/linalg/decompositions/chol/ComplexCholesky.java index 13339e56c..d8e0777d0 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/chol/ComplexCholesky.java +++ b/src/main/java/org/flag4j/linalg/decompositions/chol/ComplexCholesky.java @@ -35,22 +35,23 @@ /** *

      An abstract base class for Cholesky decomposition of Hermitian (or Hermitian) positive-definite matrices. * - *

      The Cholesky decomposition factorizes a Hermitian/Hermitian, positive-definite matrix A as: - *

      - *     A = LLH
      - * where L is a lower triangular matrix. + *

      The Cholesky decomposition factorizes a Hermitian/Hermitian, positive-definite matrix A as: + *

      + *     A = LLH
      + * where L is a lower triangular matrix. * The decomposition is primarily used for efficient numerical solutions to linear systems, computing matrix inverses, * and generating samples from multivariate normal distributions. * *

      Hermitian Verification:

      *

      This class provides an option to explicitly check whether the input matrix is Hermitian. If {@code enforceHermitian} is set - * to {@code true}, the implementation will verify that A satisfies A = AH before performing decomposition. + * to {@code true}, the implementation will verify that A satisfies + * A = AH before performing decomposition. * If set to {@code false}, the matrix is assumed to be Hermitian, no explicit check will be performed, and only the lower-diagonal - * entries of A are accessed. + * entries of A are accessed. * *

      positive-definiteness Check:

      - *

      To ensure numerical stability, the algorithm verifies that all diagonal entries of L are positive. - * A tolerance threshold, {@code posDefTolerance}, is used to determine whether a diagonal entry is considered + *

      To ensure numerical stability, the algorithm verifies that all diagonal entries of L + * are positive. A tolerance threshold, {@code posDefTolerance}, is used to determine whether a diagonal entry is considered * non-positive, indicating that the matrix is not positive-definite. This threshold can be adjusted using * {@link #setPosDefTolerance(double)}. * @@ -62,6 +63,7 @@ *

    • Retrieve the factorized matrices using {@link #getL()} or {@link #getLH()}.
    • * * + * @see RealCholesky * @see Decomposition * @see CMatrix * @see #setPosDefTolerance(double) @@ -91,8 +93,9 @@ public ComplexCholesky(boolean enforceHermitian) { /** - * Decompose a matrix into A=LLH where L is a lower triangular matrix and LH is - * the conjugate transpose of L. + * Decompose a matrix into A = LLH where L is a + * lower triangular matrix and LH is + * the conjugate transpose of L. * * @param src The source matrix to decompose. Must be Hermitian positive-definite. * @return A reference to this decomposer. diff --git a/src/main/java/org/flag4j/linalg/decompositions/chol/RealCholesky.java b/src/main/java/org/flag4j/linalg/decompositions/chol/RealCholesky.java index 3c2910d8a..739959120 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/chol/RealCholesky.java +++ b/src/main/java/org/flag4j/linalg/decompositions/chol/RealCholesky.java @@ -34,21 +34,22 @@ /** *

      An abstract base class for Cholesky decomposition of symmetric (or symmetric) positive-definite matrices. * - *

      The Cholesky decomposition factorizes a symmetric/symmetric, positive-definite matrix A as: - *

      - *     A = LLT
      - * where L is a lower triangular matrix. + *

      The Cholesky decomposition factorizes a symmetric/symmetric, positive-definite matrix A as: + *

      + *     A = LLT
      + * where L is a lower triangular matrix. * The decomposition is primarily used for efficient numerical solutions to linear systems, computing matrix inverses, * and generating samples from multivariate normal distributions. * *

      Symmetric Verification:

      *

      This class provides an option to explicitly check whether the input matrix is symmetric. If {@code enforceSymmetric} is set - * to {@code true}, the implementation will verify that A satisfies A = AT before performing decomposition. + * to {@code true}, the implementation will verify that A satisfies + * A = AT before performing decomposition. * If set to {@code false}, the matrix is assumed to be symmetric, no explicit check will be performed, and only the lower-diagonal - * entries of A are accessed. + * entries of A are accessed. * *

      positive-definiteness Check:

      - *

      To ensure numerical stability, the algorithm verifies that all diagonal entries of L are positive. + *

      To ensure numerical stability, the algorithm verifies that all diagonal entries of L are positive. * A tolerance threshold, {@code posDefTolerance}, is used to determine whether a diagonal entry is considered * non-positive, indicating that the matrix is not positive-definite. This threshold can be adjusted using * {@link #setPosDefTolerance(double)}. @@ -61,6 +62,7 @@ *

    • Retrieve the factorized matrices using {@link #getL()} or {@link #getLH()}.
    • * * + * @see ComplexCholesky * @see Decomposition * @see Matrix * @see #setPosDefTolerance(double) @@ -90,7 +92,8 @@ public RealCholesky(boolean enforceSymmetric) { /** - * Decompose a matrix into A=LLT where L is a lower triangular matrix and LT is the + * Decompose a matrix into A=LLT where L is a lower triangular matrix and + * LT is the * transpose of L. * * @param src The source matrix to decompose. Must be symmetric positive-definite. Note, symmetry will only be checked explicitly diff --git a/src/main/java/org/flag4j/linalg/decompositions/hess/ComplexHess.java b/src/main/java/org/flag4j/linalg/decompositions/hess/ComplexHess.java index 6ce24f7fe..5f80b669c 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/hess/ComplexHess.java +++ b/src/main/java/org/flag4j/linalg/decompositions/hess/ComplexHess.java @@ -32,26 +32,36 @@ /** *

      Computes the Hessenberg decomposition of a complex dense square matrix. - *

      The Hessenberg decomposition decomposes a given square matrix A into the product: - *

      - *     A = QHQH
      - * where Q is a unitary matrix and H is an upper Hessenberg matrix, which is similar to A + *

      The Hessenberg decomposition decomposes a given square matrix A into the product: + *

      + *     A = QHQH
      + * where Q is a unitary matrix and H is an upper Hessenberg matrix, which * (i.e., it has the same eigenvalues). * - *

      A matrix H is in upper Hessenburg form if it is nearly upper triangular. Specifically, if H has + *

      A matrix H is in upper Hessenburg form if it is nearly upper triangular. + * Specifically, if H has * all zeros below the first sub-diagonal. * - *

      For example, the following matrix is in upper Hessenburg form where each '×' may hold a different value: - *

      + * 

      For example, the following matrix is in upper Hessenburg form where each '×' + * may hold a different value: + *

        *     [[ × × × × × ]
        *      [ × × × × × ]
        *      [ 0 × × × × ]
        *      [ 0 0 × × × ]
      - *      [ 0 0 0 × × ]]
      + * [ 0 0 0 × × ]]
      + * + * * *

      Efficiency Considerations:

      *
        - *
      • If the unitary matrix Q is not required, setting {@code computeQ = false} in the constructor + *
      • If the unitary matrix Q is not required, setting {@code computeQ = false} in the constructor * may improve performance.
      • *
      • Support for in-place decomposition to reduce memory usage.
      • *
      • Support for decomposition of matrix sub-blocks, enabling efficient eigenvalue computations.
      • @@ -125,8 +135,9 @@ public ComplexHess(boolean computeQ, boolean inPlace) { /** *

        Computes the Hessenberg decomposition of the specified matrix. * - *

        Note, the computation of the orthogonal matrix Q in the decomposition is - * deferred until {@link #getQ()} is explicitly called. This allows for efficient decompositions when Q is not needed. + *

        Note, the computation of the orthogonal matrix Q in the decomposition is + * deferred until {@link #getQ()} is explicitly called. This allows for efficient decompositions when + * Q is not needed. * * @param src The source matrix to decompose. * @return A reference to this decomposer. @@ -142,21 +153,31 @@ public ComplexHess decompose(CMatrix src) { /** *

        Applies decomposition to the source matrix. Note, the computation of the unitary matrix in the decomposition is - * deferred until {@link #getQ()} is explicitly called. This allows for efficient decompositions when Q is not needed. + * deferred until {@link #getQ()} is explicitly called. This allows for efficient decompositions when + * Q is not needed. * *

        This method can be used specify that only a sub-block within the full matrix needs to be * reduced. This is useful when you know that an upper and lower diagonal block of the matrix is already * in the correct form, and you only need to reduce an inner sub-block of the full matrix. * Most commonly this would be useful after balancing a matrix using * {@link org.flag4j.linalg.decompositions.balance.ComplexBalancer ComplexBalancer}, which results in the form - *

        -     *      [ T1   X  Y  ]
        -     *      [  0   B  Z  ]
        -     *      [  0   0  T2 ]
        - * where T1 and T2 are in upper-triangular form. As such, only the B block needs to be reduced. - * The staring row/column index of B (inclusive) is specified by {@code iLow} and the ending row/column - * index (exclusive) is specified by {@code iHigh}. It should be noted that the blocks X and Z will also be updated - * during the reduction of B so the full matrix must still be passed. + *
        +     *      [  T1  X  Y  ]
        +     *      [  0   B  Z  ]
        +     *      [  0   0  T2 ]
        + * + * + * + * where T1 and T2 + * are in upper-triangular form. As such, only the B block needs to be reduced. + * The staring row/column index of B (inclusive) is specified by {@code iLow} and the ending row/column + * index (exclusive) is specified by {@code iHigh}. It should be noted that the blocks + * X and Z will also be updated + * during the reduction of B so the full matrix must still be passed. * * @param src The source matrix to decompose. * @param iLow Lower bound (inclusive) of the sub-matrix to reduce to upper Hessenburg form. @@ -172,7 +193,7 @@ public ComplexHess decompose(CMatrix src, int iLow, int iHigh) { /** - * Creates and initializes Q to the appropriately sized identity matrix. + * Creates and initializes Q to the appropriately sized identity matrix. * * @return An identity matrix with the appropriate size. */ @@ -183,7 +204,8 @@ protected CMatrix initQ() { /** - * Gets the upper Hessenburg matrix from the last decomposition. Same as {@link #getH()} + * Gets the upper Hessenburg matrix, H, from the last decomposition. + * Same as {@link #getH()} * * @return The upper Hessenburg matrix from the last decomposition. */ @@ -194,8 +216,8 @@ public CMatrix getUpper() { /** - * Gets the upper Hessenburg matrix H from the Hessenburg decomposition. - * @return The upper Hessenburg matrix H from the Hessenburg decomposition. + * Gets the upper Hessenburg matrix H from the Hessenburg decomposition. + * @return The upper Hessenburg matrix H from the Hessenburg decomposition. */ public CMatrix getH() { return getUpper(new CMatrix(numRows)); diff --git a/src/main/java/org/flag4j/linalg/decompositions/hess/HermHess.java b/src/main/java/org/flag4j/linalg/decompositions/hess/HermHess.java index 850deeacd..9b1199075 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/hess/HermHess.java +++ b/src/main/java/org/flag4j/linalg/decompositions/hess/HermHess.java @@ -32,26 +32,37 @@ /** *

        Computes the Hessenberg decomposition of a real dense Hermitian matrix. - *

        The Hessenberg decomposition decomposes a given Hermitian matrix A into the product: - *

        - *     A = QHQH
        - * where Q is an orthogonal matrix and H is a Hermitian tri-diagonal matrix (special case of Hessenburg form) - * which is similar to A (i.e. has the same eigenvalues) + *

        The Hessenberg decomposition decomposes a given Hermitian matrix A into the product: + *

        + *     A = QHQH
        + * where Q is an orthogonal matrix and H + * is a Hermitian tri-diagonal matrix (special case of Hessenburg form) + * which is similar to A (i.e. has the same eigenvalues) * - *

        A matrix H is in tri-diagonal form if it has all zeros below the first sub-diagonal and above the first super-diagonal. + *

        A matrix H is in tri-diagonal form if it has all zeros below the first + * sub-diagonal and above the first super-diagonal. * - *

        For example, the following matrix is in Hermitian tri-diagonal form where each '×' may hold a different value (provided - * the matrix is Hermitian): - *

        + * 

        For example, the following matrix is in symmetric tri-diagonal form where each '×' + * may hold a different value (provided + * the matrix is symmetric): + *

          *     [[ × × 0 0 0 ]
          *      [ × × × 0 0 ]
          *      [ 0 × × × 0 ]
          *      [ 0 0 × × × ]
        - *      [ 0 0 0 × × ]]
        + * [ 0 0 0 × × ]]
        + * + * * *

        Efficiency Considerations:

        *
          - *
        • If the orthogonal matrix Q is not required, setting {@code computeQ = false} in the constructor + *
        • If the orthogonal matrix Q is not required, setting {@code computeQ = false} in the constructor * may improve performance.
        • *
        • Support for in-place decomposition to reduce memory usage.
        • *
        @@ -77,7 +88,7 @@ public class HermHess extends ComplexHess { /** * Constructs a Hessenberg decomposer for Hermitian matrices. By default, the Householder vectors used in the decomposition will be - * stored so that the full unitary Q matrix can be formed by calling {@link #getQ()}. + * stored so that the full unitary Q matrix can be formed by calling {@link #getQ()}. */ public HermHess() { super(); @@ -86,8 +97,8 @@ public HermHess() { /** * Constructs a Hessenberg decomposer for Hermitian matrices. - * @param computeQ Flag indicating if the unitary Q matrix from the Hessenberg decomposition should be explicitly computed. - * If true, then the Q matrix will be computed explicitly. + * @param computeQ Flag indicating if the unitary Q matrix from the Hessenberg decomposition should be explicitly computed. + * if {@code true}, then the Q matrix will be computed explicitly. */ public HermHess(boolean computeQ) { super(computeQ); @@ -96,10 +107,10 @@ public HermHess(boolean computeQ) { /** * Constructs a Hessenberg decomposer for Hermitian matrices. - * @param computeQ Flag indicating if the unitary Q matrix from the Hessenberg decomposition should be explicitly computed. - * If true, then the Q matrix will be computed explicitly. + * @param computeQ Flag indicating if the unitary Q matrix from the Hessenberg decomposition should be explicitly computed. + * if {@code true}, then the Q matrix will be computed explicitly. * @param enforceHermitian Flag indicating if an explicit check should be made to ensure any matrix passed to - * {@link #decompose(CMatrix)} is truly Hermitian. If true, an exception will be thrown if the matrix is not Hermitian. If false, + * {@link #decompose(CMatrix)} is truly Hermitian. if {@code true}, an exception will be thrown if the matrix is not Hermitian. If false, * the decomposition will proceed under the assumption that the matrix is Hermitian whether it actually is or not. If the * matrix is not Hermitian, then the values in the upper triangular portion of the matrix are taken to be the values. */ @@ -111,10 +122,10 @@ public HermHess(boolean computeQ, boolean enforceHermitian) { /** * Constructs a Hessenberg decomposer for Hermitian matrices. - * @param computeQ Flag indicating if the unitary Q matrix from the Hessenberg decomposition should be explicitly computed. - * If true, then the Q matrix will be computed explicitly. + * @param computeQ Flag indicating if the unitary Q matrix from the Hessenberg decomposition should be explicitly computed. + * if {@code true}, then the Q matrix will be computed explicitly. * @param enforceHermitian Flag indicating if an explicit check should be made to ensure any matrix passed to - * {@link #decompose(CMatrix)} is truly Hermitian. If true, an exception will be thrown if the matrix is not Hermitian. If false, + * {@link #decompose(CMatrix)} is truly Hermitian. if {@code true}, an exception will be thrown if the matrix is not Hermitian. If false, * the decomposition will proceed under the assumption that the matrix is Hermitian whether it actually is or not. If the * matrix is not Hermitian, then the values in the upper triangular portion of the matrix are taken to be the values. * @param inPlace Flag indicating if the decomposition should be done in-place. @@ -143,8 +154,8 @@ public HermHess decompose(CMatrix src) { /** - * Gets the Hessenberg matrix, H, from the decomposition. The matrix will be Hermitian tri-diagonal. - * @return The Hermitian tri-diagonal (Hessenberg) matrix, H, from this decomposition. + * Gets the Hessenberg matrix, H, from the decomposition. The matrix will be Hermitian tri-diagonal. + * @return The Hermitian tri-diagonal (Hessenberg) matrix, H, from this decomposition. */ @Override public CMatrix getH() { diff --git a/src/main/java/org/flag4j/linalg/decompositions/hess/RealHess.java b/src/main/java/org/flag4j/linalg/decompositions/hess/RealHess.java index 4d67f4d51..a65d55b8e 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/hess/RealHess.java +++ b/src/main/java/org/flag4j/linalg/decompositions/hess/RealHess.java @@ -33,26 +33,37 @@ /** *

        Computes the Hessenberg decomposition of a real dense square matrix. - *

        The Hessenberg decomposition decomposes a given square matrix A into the product: - *

        - *     A = QHQT
        - * where Q is an orthogonal matrix and H is an upper Hessenberg matrix, which is similar to A + *

        The Hessenberg decomposition decomposes a given square matrix A into the product: + *

        + *     A = QHQT
        + * where Q is an orthogonal matrix and H is an upper Hessenberg matrix, which is similar to + * A * (i.e., it has the same eigenvalues). * - *

        A matrix H is in upper Hessenburg form if it is nearly upper triangular. Specifically, if H has + *

        A matrix H is in upper Hessenburg form if it is nearly upper triangular. Specifically, + * if H has * all zeros below the first sub-diagonal. * - *

        For example, the following matrix is in upper Hessenburg form where each '×' may hold a different value: - *

        + * 

        For example, the following matrix is in upper Hessenburg form where each '×' + * may hold a different value: + *

          *     [[ × × × × × ]
          *      [ × × × × × ]
          *      [ 0 × × × × ]
          *      [ 0 0 × × × ]
        - *      [ 0 0 0 × × ]]
        + * [ 0 0 0 × × ]]
        + * + * * *

        Efficiency Considerations:

        *
          - *
        • If the orthogonal matrix Q is not required, setting {@code computeQ = false} in the constructor + *
        • If the orthogonal matrix Q is not required, setting {@code computeQ = false} in the constructor * may improve performance.
        • *
        • Support for in-place decomposition to reduce memory usage.
        • *
        • Support for decomposition of matrix sub-blocks, enabling efficient eigenvalue computations.
        • @@ -125,8 +136,9 @@ public RealHess(boolean computeQ, boolean inPlace) { /** *

          Computes the Hessenberg decomposition of the specified matrix. * - *

          Note, the computation of the orthogonal matrix Q in the decomposition is - * deferred until {@link #getQ()} is explicitly called. This allows for efficient decompositions when Q is not needed. + *

          Note, the computation of the orthogonal matrix Q in the decomposition is + * deferred until {@link #getQ()} is explicitly called. This allows for efficient decompositions when + * Q is not needed. * * @param src The source matrix to decompose. * @return A reference to this decomposer. @@ -141,22 +153,31 @@ public RealHess decompose(Matrix src) { /** - *

          Applies decomposition to the source matrix. Note, the computation of the orthogonal matrix Q in the decomposition is - * deferred until {@link #getQ()} is explicitly called. This allows for efficient decompositions when Q is not needed. + *

          Applies decomposition to the source matrix. Note, the computation of the orthogonal matrix Q in the decomposition is + * deferred until {@link #getQ()} is explicitly called. This allows for efficient decompositions when Q is not needed. * *

          This method can be used specify that only a sub-block within the full matrix needs to be * reduced. This is useful when you know that an upper and lower diagonal block of the matrix is already * in the correct form, and you only need to reduce an inner sub-block of the full matrix. * Most commonly this would be useful after balancing a matrix using * {@link org.flag4j.linalg.decompositions.balance.RealBalancer RealBalancer}, which results in the form - *

          -     *      [ T1   X  Y  ]
          -     *      [  0   B  Z  ]
          -     *      [  0   0  T2 ]
          - * where T1 and T2 are in upper-triangular form. As such, only the B block needs to be reduced. - * The staring row/column index of B is specified by {@code iLow} (inclusive) and the ending row/column - * index is specified by {@code iHigh} (exclusive). It should be noted that the blocks X and Z will also be updated - * during the reduction of B so the full matrix must still be passed. + *
          +     *      [  T1  X  Y  ]
          +     *      [  0   B  Z  ]
          +     *      [  0   0  T2 ]
          + * + * + * + * where T1 and T2 + * are in upper-triangular form. As such, only the B block needs to be reduced. + * The staring row/column index of B is specified by {@code iLow} (inclusive) and the ending row/column + * index is specified by {@code iHigh} (exclusive). It should be noted that the blocks X + * and Z will also be updated + * during the reduction of B so the full matrix must still be passed. * * @param src The source matrix to decompose. * @param iLow Lower bound (inclusive) of the sub-matrix to reduce to upper Hessenburg form. @@ -172,7 +193,7 @@ public RealHess decompose(Matrix src, int iLow, int iHigh) { /** - * Creates and initializes Q to the appropriately sized identity matrix. + * Creates and initializes Q to the appropriately sized identity matrix. * * @return An identity matrix with the appropriate size. */ @@ -183,7 +204,8 @@ protected Matrix initQ() { /** - * Gets the upper Hessenburg matrix from the last decomposition. Same as {@link #getH()} + * Gets the upper Hessenburg matrix, H, from the last decomposition. + * Same as {@link #getH()} * * @return The upper Hessenburg matrix from the last decomposition. */ @@ -194,8 +216,8 @@ public Matrix getUpper() { /** - * Gets the upper Hessenburg matrix H from the Hessenburg decomposition. - * @return The upper Hessenburg matrix H from the Hessenburg decomposition. + * Gets the upper Hessenburg matrix, H, from the Hessenburg decomposition. + * @return The upper Hessenburg matrix, H, from the Hessenburg decomposition. */ public Matrix getH() { return getUpper(new Matrix(numRows)); diff --git a/src/main/java/org/flag4j/linalg/decompositions/hess/SymmHess.java b/src/main/java/org/flag4j/linalg/decompositions/hess/SymmHess.java index 2e36dcbb0..d07073ce2 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/hess/SymmHess.java +++ b/src/main/java/org/flag4j/linalg/decompositions/hess/SymmHess.java @@ -33,26 +33,36 @@ /** *

          Computes the Hessenberg decomposition of a real dense symmetric matrix. - *

          The Hessenberg decomposition decomposes a given symmetric matrix A into the product: - *

          - *     A = QHQT
          - * where Q is an orthogonal matrix and H is a symmetric tri-diagonal matrix (special case of Hessenburg form) - * which is similar to A (i.e. has the same eigenvalues) + *

          The Hessenberg decomposition decomposes a given symmetric matrix A into the product: + *

          + *     A = QHQT
          + * where Q is an orthogonal matrix and H + * is a symmetric tri-diagonal matrix (special case of Hessenburg form) + * which is similar to A (i.e. has the same eigenvalues) * - *

          A matrix H is in tri-diagonal form if it has all zeros below the first sub-diagonal and above the first super-diagonal. + *

          A matrix H is in tri-diagonal form if it has all zeros below the first sub-diagonal + * and above the first super-diagonal. * - *

          For example, the following matrix is in symmetric tri-diagonal form where each '×' may hold a different value (provided - * the matrix is symmetric): - *

          + * 

          For example, the following matrix is in symmetric tri-diagonal form where each '×' + * may hold a different value (provided the matrix is symmetric): + *

            *     [[ × × 0 0 0 ]
            *      [ × × × 0 0 ]
            *      [ 0 × × × 0 ]
            *      [ 0 0 × × × ]
          - *      [ 0 0 0 × × ]]
          + * [ 0 0 0 × × ]]
          + * + * * *

          Efficiency Considerations:

          *
            - *
          • If the orthogonal matrix Q is not required, setting {@code computeQ = false} in the constructor + *
          • If the orthogonal matrix Q is not required, setting {@code computeQ = false} in the constructor * may improve performance.
          • *
          • Support for in-place decomposition to reduce memory usage.
          • *
          @@ -79,7 +89,7 @@ public class SymmHess extends RealHess { /** * Constructs a Hessenberg decomposer for symmetric matrices. By default, the Householder vectors used in the decomposition will be - * stored so that the full orthogonal Q matrix can be formed by calling {@link #getQ()}. + * stored so that the full orthogonal Q matrix can be formed by calling {@link #getQ()}. */ public SymmHess() { super(); @@ -89,9 +99,10 @@ public SymmHess() { /** * Constructs a Hessenberg decomposer for symmetric matrices. * - * @param computeQ Flag indicating if the orthogonal Q matrix from the Hessenberg decomposition should be explicitly computed. - * If true, then the Q matrix will be computed explicitly. If Q is not - * needed, setting this to {@code false} may yield an increase in performance. + * @param computeQ Flag indicating if the orthogonal Q matrix from the Hessenberg decomposition should be explicitly computed. + * if {@code true}, then the Q matrix will be computed explicitly. + * If Q is not needed, setting this to {@code false} may yield an increase in + * performance. */ public SymmHess(boolean computeQ) { super(computeQ); @@ -100,8 +111,10 @@ public SymmHess(boolean computeQ) { /** * Constructs a Hessenberg decomposer for symmetric matrices. - * @param computeQ Flag indicating if the orthogonal Q matrix from the Hessenberg decomposition should be explicitly computed. - * If true, then the Q matrix will be computed explicitly. If Q is not + * @param computeQ Flag indicating if the orthogonal Q matrix from the + * Hessenberg decomposition should be explicitly computed. + * if {@code true}, then the Q matrix will be computed explicitly. + * If Q is not * needed, setting this to {@code false} may yield an increase in performance. * @param enforceSymmetric Flag indicating if an explicit check should be made to ensure any matrix passed to * {@link #decompose(Matrix)} is truly symmetric. If {@code true}, an exception will be thrown if the matrix is not symmetric. If @@ -116,8 +129,8 @@ public SymmHess(boolean computeQ, boolean enforceSymmetric) { /** * Constructs a Hessenberg decomposer for symmetric matrices. - * @param computeQ Flag indicating if the orthogonal Q matrix from the Hessenberg decomposition should be explicitly computed. - * If true, then the Q matrix will be computed explicitly. If Q is not + * @param computeQ Flag indicating if the orthogonal Q matrix from the Hessenberg decomposition should be explicitly computed. + * if {@code true}, then the Q matrix will be computed explicitly. If Q is not * needed, setting this to {@code false} may yield an increase in performance. * @param enforceSymmetric Flag indicating if an explicit check should be made to ensure any matrix passed to * {@link #decompose(Matrix)} is truly symmetric. If {@code true}, an exception will be thrown if the matrix is not symmetric. If @@ -149,8 +162,8 @@ public SymmHess decompose(Matrix src) { /** - * Gets the Hessenberg matrix, H, from the decomposition. The matrix will be symmetric tri-diagonal. - * @return The symmetric tri-diagonal (Hessenberg) matrix, H, from this decomposition. + * Gets the Hessenberg matrix, H, from the decomposition. The matrix will be symmetric tri-diagonal. + * @return The symmetric tri-diagonal (Hessenberg) matrix, H, from this decomposition. */ @Override public Matrix getH() { diff --git a/src/main/java/org/flag4j/linalg/decompositions/lu/ComplexLU.java b/src/main/java/org/flag4j/linalg/decompositions/lu/ComplexLU.java index c7386726b..b354242ee 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/lu/ComplexLU.java +++ b/src/main/java/org/flag4j/linalg/decompositions/lu/ComplexLU.java @@ -34,10 +34,11 @@ /** *

          Instances of this class can be used to compute the LU decomposition of a complex dense matrix. * - *

          The LU decomposition decomposes a matrix A into the product of - * a unit-lower triangular matrix L and an upper triangular matrix U, such that: - *

          - *     A = LU
          + *

          The LU decomposition decomposes a matrix A into the product of + * a unit-lower triangular matrix L and an upper triangular matrix + * U, such that: + *

          + *     A = LU
          * *

          Pivoting Strategies:

          *

          Pivoting may be used to improve the stability of the decomposition. Pivoting involves swapping rows and/or columns within the @@ -45,17 +46,20 @@ * *

          This class supports three pivoting strategies via the {@link Pivoting} enum: *

            - *
          • {@link Pivoting#NONE}: No pivoting is performed. This pivoting strategy is generally not recommended.
          • + *
          • {@link Pivoting#NONE}: No pivoting is performed. This pivoting strategy is generally not recommended. + *
            + *         A = LU
          • *
          • {@link Pivoting#PARTIAL}: Only row pivoting is performed to improve numerical stability. * Generally, this is the preferred pivoting strategy. The decomposition then becomes, - *
            - *         PA = LU
          • - * where P is a {@link PermutationMatrix permutation matrix} representing the row swaps. + *
            + *         PA = LU
            + * where P is a {@link PermutationMatrix permutation matrix} representing the row swaps. *
          • {@link Pivoting#FULL}: Both row and column pivoting are performed to enhance numerical robustness. * The decomposition then becomes, - *
            - *         PAQ = LU
            - * where P and Q are {@link PermutationMatrix permutation matrices} representing the row and column swaps + *
            + *         PAQ = LU
            + * where P and Q are + * {@link PermutationMatrix permutation matrices} representing the row and column swaps * respectively. * *

            Full pivoting may be useful for highly ill-conditioned matrices but, for practical @@ -65,19 +69,22 @@ *

            Storage Format:

            * The computed LU decomposition is stored within a single matrix {@code LU}, where: *
              - *
            • The upper triangular part (including the diagonal) represents the non-zero values of U.
            • - *
            • The strictly lower triangular part represents the non-zero, non-diagonal values of L. Since L is + *
            • The upper triangular part (including the diagonal) represents the non-zero values of U.
            • + *
            • The strictly lower triangular part represents the non-zero, non-diagonal values of L. + * Since L is * unit-lower triangular, the diagonal is not stored as it is known to be all zeros.
            • *
            * *

            Usage:

            * The decomposition workflow typically follows these steps: *
              - *
            1. Instantiate a concrete subclass of {@code LU}.
            2. + *
            3. Instantiate an instance of {@code ComplexLU}.
            4. *
            5. Call {@link LU#decompose(MatrixMixin)} to perform the factorization.
            6. *
            7. Retrieve the resulting matrices using {@link #getL()}, {@link #getU()}, {@link #getP()}, and {@link #getQ()}.
            8. *
            * + * @see RealLU + * @see FieldLU * @see Pivoting * @see PermutationMatrix * @see CMatrix diff --git a/src/main/java/org/flag4j/linalg/decompositions/lu/FieldLU.java b/src/main/java/org/flag4j/linalg/decompositions/lu/FieldLU.java index a50c57a7e..fc2cd1d3d 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/lu/FieldLU.java +++ b/src/main/java/org/flag4j/linalg/decompositions/lu/FieldLU.java @@ -32,12 +32,13 @@ /** - *

            Instances of this class can be used to compute the LU decomposition of a dense field matrix. + *

            Instances of this class can be used to compute the LU decomposition of a complex dense matrix. * - *

            The LU decomposition decomposes a rectangular matrix A into the product of - * a unit-lower triangular matrix L and an upper triangular matrix U, such that: - *

            - *     A = LU
            + *

            The LU decomposition decomposes a matrix A into the product of + * a unit-lower triangular matrix L and an upper triangular matrix + * U, such that: + *

            + *     A = LU
            * *

            Pivoting Strategies:

            *

            Pivoting may be used to improve the stability of the decomposition. Pivoting involves swapping rows and/or columns within the @@ -45,17 +46,20 @@ * *

            This class supports three pivoting strategies via the {@link Pivoting} enum: *

              - *
            • {@link Pivoting#NONE}: No pivoting is performed. This pivoting strategy is generally not recommended.
            • + *
            • {@link Pivoting#NONE}: No pivoting is performed. This pivoting strategy is generally not recommended. + *
              + *         A = LU
            • *
            • {@link Pivoting#PARTIAL}: Only row pivoting is performed to improve numerical stability. * Generally, this is the preferred pivoting strategy. The decomposition then becomes, - *
              - *         PA = LU
            • - * where P is a {@link PermutationMatrix permutation matrix} representing the row swaps. + *
              + *         PA = LU
              + * where P is a {@link PermutationMatrix permutation matrix} representing the row swaps. *
            • {@link Pivoting#FULL}: Both row and column pivoting are performed to enhance numerical robustness. * The decomposition then becomes, - *
              - *         PAQ = LU
              - * where P and Q are {@link PermutationMatrix permutation matrices} representing the row and column swaps + *
              + *         PAQ = LU
              + * where P and Q are + * {@link PermutationMatrix permutation matrices} representing the row and column swaps * respectively. * *

              Full pivoting may be useful for highly ill-conditioned matrices but, for practical @@ -65,21 +69,24 @@ *

              Storage Format:

              * The computed LU decomposition is stored within a single matrix {@code LU}, where: *
                - *
              • The upper triangular part (including the diagonal) represents the non-zero values of U.
              • - *
              • The strictly lower triangular part represents the non-zero, non-diagonal values of L. Since L is + *
              • The upper triangular part (including the diagonal) represents the non-zero values of U.
              • + *
              • The strictly lower triangular part represents the non-zero, non-diagonal values of L. + * Since L is * unit-lower triangular, the diagonal is not stored as it is known to be all zeros.
              • *
              * *

              Usage:

              * The decomposition workflow typically follows these steps: *
                - *
              1. Instantiate a concrete subclass of {@code LU}.
              2. + *
              3. Instantiate an instance of {@code FieldLU}.
              4. *
              5. Call {@link LU#decompose(MatrixMixin)} to perform the factorization.
              6. *
              7. Retrieve the resulting matrices using {@link #getL()}, {@link #getU()}, {@link #getP()}, and {@link #getQ()}.
              8. *
              * - * @param The type of matrix on which LU decomposition is performed. + * @param The type of the field the elements of the matrix to decompose are members of. * + * @see RealLU + * @see ComplexLU * @see Pivoting * @see PermutationMatrix * @see FieldMatrix diff --git a/src/main/java/org/flag4j/linalg/decompositions/lu/LU.java b/src/main/java/org/flag4j/linalg/decompositions/lu/LU.java index 9d0f10406..1042be931 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/lu/LU.java +++ b/src/main/java/org/flag4j/linalg/decompositions/lu/LU.java @@ -33,10 +33,11 @@ /** *

              An abstract base class for LU decomposition of a matrix. * - *

              The LU decomposition decomposes a matrix A into the product of - * a unit-lower triangular matrix L and an upper triangular matrix U, such that: - *

              - *     A = LU
              + *

              The LU decomposition decomposes a matrix A into the product of + * a unit-lower triangular matrix L and an upper triangular matrix + * U, such that: + *

              + *     A = LU
              * *

              Pivoting Strategies:

              *

              Pivoting may be used to improve the stability of the decomposition. Pivoting involves swapping rows and/or columns within the @@ -44,17 +45,21 @@ * *

              This class supports three pivoting strategies via the {@link Pivoting} enum: *

                - *
              • {@link Pivoting#NONE}: No pivoting is performed. This pivoting strategy is generally not recommended.
              • + *
              • {@link Pivoting#NONE}: No pivoting is performed. This pivoting strategy is generally not recommended. + *
                + *         A = LU
              • *
              • {@link Pivoting#PARTIAL}: Only row pivoting is performed to improve numerical stability. * Generally, this is the preferred pivoting strategy. The decomposition then becomes, - *
                - *         PA = LU
              • - * where P is a {@link PermutationMatrix permutation matrix} representing the row swaps. + *
                + *         PA = LU
                + * + * where P is a {@link PermutationMatrix permutation matrix} representing the row swaps. *
              • {@link Pivoting#FULL}: Both row and column pivoting are performed to enhance numerical robustness. * The decomposition then becomes, - *
                - *         PAQ = LU
                - * where P and Q are {@link PermutationMatrix permutation matrices} representing the row and column swaps + *
                + *         PAQ = LU
                + * where P and Q are + * {@link PermutationMatrix permutation matrices} representing the row and column swaps * respectively. * *

                Full pivoting may be useful for highly ill-conditioned matrices but, for practical @@ -64,8 +69,10 @@ *

                Storage Format:

                * The computed LU decomposition is stored within a single matrix {@code LU}, where: *
                  - *
                • The upper triangular part (including the diagonal) represents the non-zero values of U.
                • - *
                • The strictly lower triangular part represents the non-zero, non-diagonal values of L. Since L is + *
                • The upper triangular part (including the diagonal) represents the non-zero values of + * U.
                • + *
                • The strictly lower triangular part represents the non-zero, non-diagonal values of L. + * Since L is * unit-lower triangular, the diagonal is not stored as it is known to be all zeros.
                • *
                * @@ -111,11 +118,13 @@ public abstract class LU> extends Decompositio */ protected final boolean inPlace; /** - *

                Storage for L and U matrices. Stored in a single matrix. + *

                Storage for L and U matrices. Stored in a single matrix. * - *

                The upper triangular portion of {@code LU}, including the diagonal, stores the non-zero values of U while the lower - * triangular portion, excluding the diagonal, stores the non-zero, non-diagonal values of L. - * Since L is unit-lower triangular, the diagonal need not be stored as it is known to be all ones. + *

                The upper triangular portion of {@code LU}, including the diagonal, stores the non-zero values of + * U while the lower + * triangular portion, excluding the diagonal, stores the non-zero, non-diagonal values of L. + * Since L is unit-lower triangular, + * the diagonal need not be stored as it is known to be all ones. */ protected T LU; /** @@ -216,9 +225,9 @@ protected void initLU(T src) { /** - * Gets the L and U matrices of the decomposition combined in a single matrix. - * @return The L and U matrices of the decomposition stored together in a single matrix. - * The diagonal of L is all ones and is not stored allowing the diagonal of U to be stored along + * Gets the L and U matrices of the decomposition combined in a single matrix. + * @return The L and U matrices of the decomposition stored together in a single matrix. + * The diagonal of L is all ones and is not stored allowing the diagonal of U to be stored along * the diagonal of the combined matrix. * @throws IllegalStateException If this method is called before {@link #decompose(MatrixMixin)}. */ diff --git a/src/main/java/org/flag4j/linalg/decompositions/lu/RealLU.java b/src/main/java/org/flag4j/linalg/decompositions/lu/RealLU.java index 104515a04..7313c4856 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/lu/RealLU.java +++ b/src/main/java/org/flag4j/linalg/decompositions/lu/RealLU.java @@ -33,10 +33,11 @@ /** *

                Instances of this class can be used to compute the LU decomposition of a real dense matrix. * - *

                The LU decomposition decomposes a matrix A into the product of - * a unit-lower triangular matrix L and an upper triangular matrix U, such that: - *

                - *     A = LU
                + *

                The LU decomposition decomposes a matrix A into the product of + * a unit-lower triangular matrix L and an upper triangular matrix + * U, such that: + *

                + *     A = LU
                * *

                Pivoting Strategies:

                *

                Pivoting may be used to improve the stability of the decomposition. Pivoting involves swapping rows and/or columns within the @@ -44,17 +45,20 @@ * *

                This class supports three pivoting strategies via the {@link Pivoting} enum: *

                  - *
                • {@link Pivoting#NONE}: No pivoting is performed. This pivoting strategy is generally not recommended.
                • + *
                • {@link Pivoting#NONE}: No pivoting is performed. This pivoting strategy is generally not recommended. + *
                  + *         A = LU
                • *
                • {@link Pivoting#PARTIAL}: Only row pivoting is performed to improve numerical stability. * Generally, this is the preferred pivoting strategy. The decomposition then becomes, - *
                  - *         PA = LU
                • - * where P is a {@link PermutationMatrix permutation matrix} representing the row swaps. + *
                  + *         PA = LU
                  + * where P is a {@link PermutationMatrix permutation matrix} representing the row swaps. *
                • {@link Pivoting#FULL}: Both row and column pivoting are performed to enhance numerical robustness. * The decomposition then becomes, - *
                  - *         PAQ = LU
                  - * where P and Q are {@link PermutationMatrix permutation matrices} representing the row and column swaps + *
                  + *         PAQ = LU
                  + * where P and Q are + * {@link PermutationMatrix permutation matrices} representing the row and column swaps * respectively. * *

                  Full pivoting may be useful for highly ill-conditioned matrices but, for practical @@ -64,21 +68,23 @@ *

                  Storage Format:

                  * The computed LU decomposition is stored within a single matrix {@code LU}, where: *
                    - *
                  • The upper triangular part (including the diagonal) represents the non-zero values of U.
                  • - *
                  • The strictly lower triangular part represents the non-zero, non-diagonal values of L. Since L is + *
                  • The upper triangular part (including the diagonal) represents the non-zero values of + * U.
                  • + *
                  • The strictly lower triangular part represents the non-zero, non-diagonal values of + * L. Since L is * unit-lower triangular, the diagonal is not stored as it is known to be all zeros.
                  • *
                  * *

                  Usage:

                  * The decomposition workflow typically follows these steps: *
                    - *
                  1. Instantiate a concrete subclass of {@code LU}.
                  2. + *
                  3. Instantiate an instance of {@code RealLU}.
                  4. *
                  5. Call {@link LU#decompose(MatrixMixin)} to perform the factorization.
                  6. *
                  7. Retrieve the resulting matrices using {@link #getL()}, {@link #getU()}, {@link #getP()}, and {@link #getQ()}.
                  8. *
                  * - * @param The type of matrix on which LU decomposition is performed. - * + * @see ComplexLU + * @see FieldLU * @see Pivoting * @see PermutationMatrix * @see Matrix diff --git a/src/main/java/org/flag4j/linalg/decompositions/qr/ComplexQR.java b/src/main/java/org/flag4j/linalg/decompositions/qr/ComplexQR.java index ea0b342cd..a64c5062d 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/qr/ComplexQR.java +++ b/src/main/java/org/flag4j/linalg/decompositions/qr/ComplexQR.java @@ -31,23 +31,25 @@ /** *

                  Computes the QR decomposition of dense complex matrix. * - *

                  The QR decomposition factorizes a given matrix A into the product of an orthogonal matrix Q - * and an upper triangular matrix R, such that: - *

                  - *     A = QR
                  + *

                  The QR decomposition factorizes a given matrix A into the product of an orthogonal + * matrix Q + * and an upper triangular matrix R, such that: + *

                  + *     A = QR
                  * *

                  The decomposition can be computed in either the full or reduced form: *

                    *
                  • Reduced QR decomposition: When {@code reduced = true}, the decomposition produces a compact form where - * Q has the same number of rows as A but only as many columns as the rank of A.
                  • + * Q has the same number of rows as A but only as many + * columns as the rank of A. *
                  • Full QR decomposition: When {@code reduced = false}, the decomposition produces a square orthogonal matrix - * Q with the same number of rows as A.
                  • + * Q with the same number of rows as A. *
                  * *

                  Usage:

                  * The decomposition workflow typically follows these steps: *
                    - *
                  1. Instantiate an instance of {@code RealQR}.
                  2. + *
                  3. Instantiate an instance of {@code ComplexQR}.
                  4. *
                  5. Call {@link #decompose(CMatrix)} to perform the factorization.
                  6. *
                  7. Retrieve the resulting matrices using {@link #getQ()} and {@link #getR()}.
                  8. *
                  @@ -56,7 +58,7 @@ * QR decomposition efficiently. The decomposition uses Householder transformations to iteratively * zero out sub-diagonal entries while maintaining numerical stability. * - * @see ComplexUnitaryDecomposition + * @see RealQR * @see #getR() * @see #getQ() */ @@ -106,7 +108,7 @@ public ComplexQR decompose(CMatrix src) { /** - * Creates and initializes Q to the appropriately sized identity matrix. + * Creates and initializes Q to the appropriately sized identity matrix. * * @return An identity matrix with the appropriate size. */ @@ -118,9 +120,9 @@ protected CMatrix initQ() { /** - * Gets the upper triangular matrix {@code R} from the last decomposition. + * Gets the upper triangular matrix, R, from the last decomposition. * - * @return The upper triangular matrix {@code R} from the last decomposition. + * @return The upper triangular matrix, R, from the last decomposition. */ @Override public CMatrix getUpper() { @@ -129,8 +131,8 @@ public CMatrix getUpper() { /** - * Gets the upper triangular matrix {@code R} from the {@code QR} decomposition. - * @return The upper triangular matrix {@code R} from the {@code QR} decomposition. + * Gets the upper triangular matrix, R, from the QR decomposition. + * @return The upper triangular matrix, R, from the QR decomposition. */ public CMatrix getR() { int rRows = reduced ? minAxisSize : numRows; // Get R in reduced form or not. diff --git a/src/main/java/org/flag4j/linalg/decompositions/qr/RealQR.java b/src/main/java/org/flag4j/linalg/decompositions/qr/RealQR.java index ef8c614d6..51e31065b 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/qr/RealQR.java +++ b/src/main/java/org/flag4j/linalg/decompositions/qr/RealQR.java @@ -32,17 +32,19 @@ /** *

                  Computes the QR decomposition of a real dense matrix. * - *

                  The QR decomposition factorizes a given matrix A into the product of an orthogonal matrix Q - * and an upper triangular matrix R, such that: - *

                  - *     A = QR
                  + *

                  The QR decomposition factorizes a given matrix A into the product of an + * orthogonal matrix Q + * and an upper triangular matrix R, such that: + *

                  + *     A = QR
                  * *

                  The decomposition can be computed in either the full or reduced form: *

                    *
                  • Reduced QR decomposition: When {@code reduced = true}, the decomposition produces a compact form where - * Q has the same number of rows as A but only as many columns as the rank of A.
                  • + * Q has the same number of rows as A but only as + * many columns as the rank of A. *
                  • Full QR decomposition: When {@code reduced = false}, the decomposition produces a square orthogonal matrix - * Q with the same number of rows as A.
                  • + * Q with the same number of rows as A. *
                  * *

                  Usage:

                  @@ -57,7 +59,7 @@ * QR decomposition efficiently. The decomposition uses Householder transformations to iteratively * zero out sub-diagonal entries while maintaining numerical stability. * - * @see RealUnitaryDecomposition + * @see ComplexQR * @see #getR() * @see #getQ() */ @@ -111,7 +113,7 @@ public RealQR decompose(Matrix src) { /** - * Creates and initializes the Q matrix to the appropriately sized identity matrix. + * Creates and initializes the Q matrix to the appropriately sized identity matrix. * * @return An identity matrix with the appropriate size. */ @@ -123,7 +125,7 @@ protected Matrix initQ() { /** - * Gets the upper triangular matrix R from the last decomposition. Same as {@link #getR()}. + * Gets the upper triangular matrix, R, from the last decomposition. Same as {@link #getR()}. * * @return The upper triangular matrix from the last decomposition. */ @@ -134,8 +136,8 @@ public Matrix getUpper() { /** - * Gets the upper triangular matrix R from the QR decomposition. - * @return The upper triangular matrix R from the QR decomposition. + * Gets the upper triangular matrix, R, from the QR decomposition. + * @return The upper triangular matrix, R, from the QR decomposition. */ public Matrix getR() { int rRows = reduced ? minAxisSize : numRows; // Get R in reduced form or not. diff --git a/src/main/java/org/flag4j/linalg/decompositions/schur/ComplexSchur.java b/src/main/java/org/flag4j/linalg/decompositions/schur/ComplexSchur.java index 61022e21b..c9b40f210 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/schur/ComplexSchur.java +++ b/src/main/java/org/flag4j/linalg/decompositions/schur/ComplexSchur.java @@ -41,12 +41,14 @@ /** *

                  Instanced of this class can be used for computing the Schur decomposition of a real dense square matrix. * - *

                  The Schur decomposition decomposes a given square matrix A into: - *

                  - *     A = UTUT
                  - * where U is an orthogonal matrix T is a - * quasi-upper triangular matrix known as the Schur form of A. This means T is upper triangular except - * for possibly 2×2 blocks along its diagonal, which correspond to complex conjugate pairs of eigenvalues. + *

                  The Schur decomposition decomposes a given square matrix A into: + *

                  + *     A = UTUT
                  + * where U is an orthogonal matrix T is a + * quasi-upper triangular matrix known as the Schur form of A. + * This means T is upper triangular except + * for possibly 2×2 blocks along its diagonal, which correspond to complex conjugate pairs + * of eigenvalues. * *

                  The Schur decomposition proceeds by an iterative algorithm with possible random behavior. For reproducibility, constructors * support specifying a seed for the pseudo-random number generator. @@ -96,8 +98,8 @@ public class ComplexSchur extends Schur { */ protected Complex128 norm; /** - * Stores the scalar factor &alpha for use in computation of the Householder reflector - * P = I - α vvT. + * Stores the scalar factor α for use in computation of the Householder reflector + * P = I - αvvT. */ protected Complex128 currentFactor; @@ -114,18 +116,18 @@ public ComplexSchur() { /** - *

                  Creates a decomposer to compute the Schur decomposition for a real dense matrix where the U matrix may or may not + *

                  Creates a decomposer to compute the Schur decomposition for a real dense matrix where the U matrix may or may not * be computed. * - *

                  If the U matrix is not needed, passing {@code computeU = false} may provide a performance improvement. + *

                  If the U matrix is not needed, passing {@code computeU = false} may provide a performance improvement. * - *

                  By default, if a constructor with no {@code computeU} parameter is called, U will be computed. + *

                  By default, if a constructor with no {@code computeU} parameter is called, U will be computed. * *

                  Note: This decomposer may use random numbers during the decomposition. If reproducible results are desired, * set the seed for the pseudo-random number generator using {@link #ComplexSchur(boolean, long)} * * @param computeU Flag indicating if the unitary U matrix should be computed for the Schur decomposition. If true, - * U will be computed. If false, U will not be computed. + * U will be computed. If false, U will not be computed. */ public ComplexSchur(boolean computeU) { super(computeU, new RandomComplex(), new ComplexHess(computeU, true), new ComplexBalancer()); @@ -177,10 +179,10 @@ public ComplexSchur enforceFinite(boolean enforceFinite) { /** *

                  Reverts the scaling and permutations applied during the balancing step to obtain the correct form. *

                  Specifically, this method computes - *

                  -     *     U := PDU
                  -     *        = TU
                  - * where P and D are the permutation and scaling matrices respectively from balancing. + *
                  +     *     U := PDU
                  +     *        = TU
                  + * where P and D are the permutation and scaling matrices respectively from balancing. */ @Override protected void unbalance() { @@ -503,7 +505,8 @@ protected boolean makeReflector(int i, Complex128 p1, Complex128 p2) { /** - * Checks for convergence of lower 2×2 sub-matrix within working matrix to upper triangular or block upper triangular form. If + * Checks for convergence of lower 2×2 sub-matrix within working matrix to upper + * triangular or block upper triangular form. If * convergence is found, this will also zero out the values which have converged to near zero. * @param workEnd The ending row (inclusive) of the current active working block. * @return Returns the amount the working matrix size should be deflated. Will be zero if no convergence is detected, one if diff --git a/src/main/java/org/flag4j/linalg/decompositions/schur/RealSchur.java b/src/main/java/org/flag4j/linalg/decompositions/schur/RealSchur.java index f1a35e551..995d7d162 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/schur/RealSchur.java +++ b/src/main/java/org/flag4j/linalg/decompositions/schur/RealSchur.java @@ -42,12 +42,13 @@ /** *

                  Instanced of this class can be used for computing the Schur decomposition of a real dense square matrix. * - *

                  The Schur decomposition decomposes a given square matrix A into: - *

                  - *     A = UTUT
                  - * where U is an orthogonal matrix T is a - * quasi-upper triangular matrix known as the Schur form of A. This means T is upper triangular except - * for possibly 2×2 blocks along its diagonal, which correspond to complex conjugate pairs of eigenvalues. + *

                  The Schur decomposition decomposes a given square matrix A into: + *

                  + *     A = UTUT
                  + * where U is an orthogonal matrix T is a + * quasi-upper triangular matrix known as the Schur form of A. + * This means T is upper triangular except + * for possibly 2×2 blocks along its diagonal, which correspond to complex conjugate pairs of eigenvalues. * *

                  The Schur decomposition proceeds by an iterative algorithm with possible random behavior. For reproducibility, constructors * support specifying a seed for the pseudo-random number generator. @@ -93,8 +94,8 @@ public class RealSchur extends Schur { */ protected double norm; /** - * Stores the scalar factor α for use in computation of the Householder reflector - * P = I - α vvT. + * Stores the scalar factor α for use in computation of the Householder reflector + * P = I - α vvT. */ protected double currentFactor; @@ -111,18 +112,19 @@ public RealSchur() { /** - *

                  Creates a decomposer to compute the Schur decomposition for a real dense matrix where the U matrix may or may not + *

                  Creates a decomposer to compute the Schur decomposition for a real dense matrix where the U matrix may or may not * be computed. * - *

                  If the U matrix is not needed, passing {@code computeU = false} may provide a performance improvement. + *

                  If the U matrix is not needed, passing {@code computeU = false} may provide a performance improvement. * - *

                  By default, if a constructor with no {@code computeU} parameter is called, U will be computed. + *

                  By default, if a constructor with no {@code computeU} parameter is called, U will be computed. * *

                  Note: This decomposer may use random numbers during the decomposition. If reproducible results are needed, * set the seed for the pseudo-random number generator using {@link #RealSchur(boolean, long)} * - * @param computeU Flag indicating if the unitary U matrix should be computed for the Schur decomposition. If true, - * U will be computed. If false, U will not be computed. + * @param computeU Flag indicating if the unitary U matrix should be computed for the + * Schur decomposition. If {@code true}, U will be computed. If {@code false}, + * U will not be computed. */ public RealSchur(boolean computeU) { super(computeU, new RandomComplex(), new RealHess(computeU, true), new RealBalancer()); @@ -177,10 +179,10 @@ public RealSchur enforceFinite(boolean enforceFinite) { /** *

                  Reverts the scaling and permutations applied during the balancing step to obtain the correct form. *

                  Specifically, this method computes - *

                  -     *     U := PDU
                  -     *        = TU
                  - * where P and D are the permutation and scaling matrices respectively from balancing. + *
                  +     *    U := PDU
                  +     *       = TU
                  + * where P and D are the permutation and scaling matrices respectively from balancing. */ @Override protected void unbalance() { @@ -501,7 +503,7 @@ protected boolean makeReflector(int i, double p1, double p2) { /** - * Checks for convergence of lower 2×2 sub-matrix within working matrix to upper triangular or block upper triangular form. If + * Checks for convergence of lower 2×2 sub-matrix within working matrix to upper triangular or block upper triangular form. If * convergence is found, this will also zero out the values which have converged to near zero. * @param workEnd The ending row (inclusive) of the current active working block. * @return Returns the amount the working matrix size should be deflated. Will be zero if no convergence is detected, one if @@ -554,14 +556,15 @@ protected void checkFinite(Matrix src) { * *

                  That is, converts the real block * upper triangular Schur matrix to a complex valued properly upper triangular matrix. If the unitary transformation matrix - * U was computed, the transformations will also be updated accordingly. + * U was computed, the transformations will also be updated accordingly. * *

                  This method was adapted from the code given by * scipy.linalg.rsf2csf (v1.12.0). * - * @return An array of length 2 containing the complex Schur matrix T from the last decomposition, and if computed, the - * complex unitary transformation matrix U from the decomposition. If U was not computed, then the arrays second - * value will be null. + * @return An array of length 2 containing the complex Schur matrix T + * from the last decomposition, and if computed, the + * complex unitary transformation matrix U from the decomposition. + * If U was not computed, then the arrays second value will be null. */ public CMatrix[] real2ComplexSchur() { // Convert matrices to complex matrices. diff --git a/src/main/java/org/flag4j/linalg/decompositions/schur/Schur.java b/src/main/java/org/flag4j/linalg/decompositions/schur/Schur.java index bb6dde9e3..4ca38f454 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/schur/Schur.java +++ b/src/main/java/org/flag4j/linalg/decompositions/schur/Schur.java @@ -37,12 +37,14 @@ /** *

                  An abstract base class for computing the Schur decomposition of a square matrix. * - *

                  The Schur decomposition decomposes a given square matrix A into: - *

                  - *     A = UTUH
                  - * where U is a unitary (or orthogonal for real matrices) matrix T is a - * quasi-upper triangular matrix known as the Schur form of A. This means T is upper triangular except - * for possibly 2×2 blocks along its diagonal, which correspond to complex conjugate pairs of eigenvalues. + *

                  The Schur decomposition decomposes a given square matrix A into: + *

                  + *     A = UTUH
                  + * where U is a unitary (or orthogonal for real matrices) matrix T + * is a quasi-upper triangular matrix known as the Schur form of A. + * This means T is upper triangular except + * for possibly 2×2 blocks along its diagonal, which correspond to complex conjugate + * pairs of eigenvalues. * *

                  The Schur decomposition proceeds by an iterative algorithm with possible random behavior. For reproducibility, constructors * support specifying a seed for the pseudo-random number generator. @@ -63,12 +65,12 @@ * Fundamentals of Matrix * Computations 3rd Edition by David S. Watkins. * - * @implNote This decomposition is performed using the implicit double-shift QR algorithm, which iteratively + * @implNote This decomposition is performed using the implicit double-shift QR algorithm, which iteratively * reduces the matrix to Schur form using orthogonal transformations. In addition to this, random shifting is used in cases where * normal convergence fails. * *

                  As a preprocessing step to improve conditioning and stability, the matrix is first {@link Balancer balanced} then reduced to - * Hessenberg form via a {@link UnitaryDecomposition}. + * Hessenberg form via a {@link UnitaryDecomposition}. * * @param The type of matrix to be decomposed. * @param The type for the internal storage data structure of the matrix to be decomposed. @@ -96,11 +98,11 @@ public abstract class Schur, U> extends Decomp */ protected final int DEFAULT_MAX_ITERS_FACTOR = 50; /** - *For storing the (possibly block) upper triangular matrix T in the Schur decomposition. + *For storing the (possibly block) upper triangular matrix T in the Schur decomposition. */ protected T T; /** - *For storing the unitary U matrix in the Schur decomposition. + *For storing the unitary U matrix in the Schur decomposition. */ protected T U; /** @@ -127,13 +129,15 @@ public abstract class Schur, U> extends Decomp */ protected int numRows; /** - * Stores the vector v in the Householder reflector P = I - α vvT. + * Stores the vector v in the Householder reflector + * P = I - αvvT. */ protected U householderVector; /** * Stores the non-zero data of the first column of the shifted matrix - * (A- ρ1I)(A-ρ2 I) - * where ρ1 and ρ2 are the two shifts. + * (A- ρ1I)(A-ρ2 I) + * where ρ1 and ρ2 + * are the two shifts. */ protected U shiftCol; /** @@ -173,10 +177,10 @@ public abstract class Schur, U> extends Decomp */ protected boolean checkFinite = false; /** - * Flag indicating if the orthogonal matrix U in the Schur decomposition should be computed. + * Flag indicating if the orthogonal matrix U in the Schur decomposition should be computed. *

                    - *
                  • If {@code true}, U will be computed.
                  • - *
                  • If {@code false}, U will not be computed. This may improve performance if U + *
                  • If {@code true}, U will be computed.
                  • + *
                  • If {@code false}, U will not be computed. This may improve performance if U * is not required.
                  • *
                  */ @@ -186,12 +190,13 @@ public abstract class Schur, U> extends Decomp /** *

                  Creates a decomposer to compute the Schur decomposition for a real dense matrix. * - *

                  If the U matrix is not needed, passing {@code computeU = false} may provide a performance improvement. + *

                  If the U matrix is not needed, passing {@code computeU = false} may provide a performance improvement. * - * @param computeU Flag indicating if the orthogonal matrix U in the Schur decomposition should be computed. + * @param computeU Flag indicating if the orthogonal matrix U in the Schur decomposition should be computed. *

                    - *
                  • If {@code true}, U will be computed.
                  • - *
                  • If {@code false}, U will not be computed. This may improve performance if U + *
                  • If {@code true}, U will be computed.
                  • + *
                  • If {@code false}, U will not be computed. This may + * improve performance if U * is not required.
                  • *
                  * @param rng Random number generator to use when performing random exceptional shifts. @@ -273,8 +278,10 @@ public Schur enforceFinite(boolean enforceFinite) { /** - * Gets the upper, or possibly block-upper, triangular Schur matrix T from the Schur decomposition - * @return The T matrix from the Schur decomposition A=UTUH + * Gets the upper, or possibly block-upper, triangular Schur matrix T + * from the Schur decomposition + * @return The T matrix from the Schur decomposition + * A=UTUH. */ public T getT() { ensureHasDecomposed(); @@ -283,8 +290,10 @@ public T getT() { /** - * Gets the unitary matrix U from the Schur decomposition containing the Schur vectors as its columns. - * @return A=UTUH + * Gets the unitary matrix U from the Schur decomposition containing + * the Schur vectors as its columns. + * @return The U matrix from the Schur decomposition + * A=UTUH. */ public T getU() { ensureHasDecomposed(); @@ -300,8 +309,7 @@ public T getU() { * matrix is not converging which greatly minimizes this issue. It is unlikely that a general matrix will fail to converge with * these random shifts however, no guarantees of convergence can be made. * @param src The source matrix to decompose. - * @throws LinearAlgebraException If the decomposition does not converge within the specified number of max iterations. See - * {@link } + * @throws LinearAlgebraException If the decomposition does not converge within the specified number of max iterations. */ protected void decomposeBase(T src) { setUp(src); @@ -377,10 +385,11 @@ protected void setUp(T src) { *

                  Reverts the scaling and permutations applied during the balancing step to obtain the correct form. * *

                  Specifically, this method computes - *

                  -     *     U := PDU
                  -     *        = TU
                  - * where P and D are the permutation and scaling matrices respectively from balancing. + *
                  +     *     U := PDU
                  +     *        = TU
                  + * where P and D are the permutation and + * scaling matrices respectively from balancing. */ protected abstract void unbalance(); @@ -409,8 +418,9 @@ protected void setUp(T src) { /** - * Checks for convergence of lower 2×2 sub-matrix within working matrix to upper triangular or block upper triangular form. If - * convergence is found, this will also zero out the values which have converged to near zero. + * Checks for convergence of lower 2×2 sub-matrix within working matrix to upper + * triangular or block upper triangular form. + * If convergence is found, this will also zero out the values which have converged to near zero. * @param workEnd The ending row (inclusive) of the current active working block. * @return Returns the amount the working matrix size should be deflated. Will be zero if no convergence is detected, one if * convergence to upper triangular form is detected and two if convergence to block upper triangular form is detected. diff --git a/src/main/java/org/flag4j/linalg/decompositions/svd/ComplexSVD.java b/src/main/java/org/flag4j/linalg/decompositions/svd/ComplexSVD.java index cb6a48308..016f8fd98 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/svd/ComplexSVD.java +++ b/src/main/java/org/flag4j/linalg/decompositions/svd/ComplexSVD.java @@ -25,6 +25,7 @@ package org.flag4j.linalg.decompositions.svd; import org.flag4j.arrays.Shape; +import org.flag4j.arrays.backend.MatrixMixin; import org.flag4j.arrays.dense.CMatrix; import org.flag4j.arrays.dense.CVector; import org.flag4j.linalg.DirectSum; @@ -36,9 +37,11 @@ * {@link CMatrix complex dense matrix}. * * - *

                  That is, decomposes a rectangular matrix M into M=UΣVH where U and V are - * unitary matrices whose columns are the left and right singular vectors of M and Σ is a rectangular - * diagonal matrix containing the singular values of M. + *

                  That is, decomposes a rectangular matrix M into M=UΣVH + * where U and V are + * unitary matrices whose columns are the left and right singular vectors of M and + * Σ is a rectangular + * diagonal matrix containing the singular values of M. * *

                  The SVD may also be used to compute the (numerical) rank of the matrix using {@link #getRank()}. * @@ -49,7 +52,7 @@ * The decomposition workflow typically follows these steps: *

                    *
                  1. Instantiate a concrete instance of {@code ComplexSVD}.
                  2. - *
                  3. Call {@link #decompose(CMatrix)} to perform the factorization.
                  4. + *
                  5. Call {@link SVD#decompose(MatrixMixin)} to perform the factorization.
                  6. *
                  7. Retrieve the resulting matrices using {@link #getU()} and {@link #getS()}.
                  8. *
                  * @@ -76,11 +79,14 @@ public ComplexSVD() { /** * Creates a decomposer to compute the Schur decomposition. * - * @param computeUV A flag which indicates if the unitary matrices U and V should be computed + * @param computeUV A flag which indicates if the unitary matrices U and + * V should be computed * (i.e. the singular vectors). *
                    - *
                  • If {@code true}, the U and V matrices will be computed.
                  • - *
                  • If {@code false}, the U and V matrices will not be computed. If it is not + *
                  • If {@code true}, the U and V + * matrices will be computed.
                  • + *
                  • If {@code false}, the U and V + * matrices will not be computed. If it is not * needed, this may provide a performance improvement.
                  • *
                  */ @@ -91,11 +97,14 @@ public ComplexSVD(boolean computeUV) { /** * Creates a decomposer to compute the singular value decomposition of a real matrix. - * @param computeUV A flag which indicates if the unitary matrices U and V should be computed + * @param computeUV A flag which indicates if the unitary matrices U + * and V should be computed * (i.e. the singular vectors). *
                    - *
                  • If {@code true}, the U and V matrices will be computed.
                  • - *
                  • If {@code false}, the U and V matrices will not be computed. If it is not + *
                  • If {@code true}, the U and V + * matrices will be computed.
                  • + *
                  • If {@code false}, the U and V + * matrices will not be computed. If it is not * needed, this may provide a performance improvement.
                  • *
                  * @param reduced Flag which indicates if the reduced (or full) SVD should be computed. @@ -111,11 +120,13 @@ public ComplexSVD(boolean computeUV, boolean reduced) { /** * Creates a decomposer to compute the Schur decomposition. - * @param computeUV A flag which indicates if the unitary matrices U and V should be computed + * @param computeUV A flag which indicates if the unitary matrices U and V should be computed * (i.e. the singular vectors). *
                    - *
                  • If {@code true}, the U and V matrices will be computed.
                  • - *
                  • If {@code false}, the U and V matrices will not be computed. If it is not + *
                  • If {@code true}, the U and V + * matrices will be computed.
                  • + *
                  • If {@code false}, the U and V + * matrices will not be computed. If it is not * needed, this may provide a performance improvement.
                  • *
                  * @param reduced Flag which indicates if the reduced (or full) SVD should be computed. @@ -179,10 +190,11 @@ protected void makeEigenVals(CMatrix B, double[] eigVals) { /** - * Initializes the unitary U and V matrices for the SVD. + * Initializes the unitary U and V + * matrices for the SVD. * * @param src Shape of the source matrix being decomposed. - * @param cols The number of columns for U and V. + * @param cols The number of columns for U and V. */ @Override protected void initUV(Shape src, int cols) { @@ -192,11 +204,12 @@ protected void initUV(Shape src, int cols) { /** - * Extracts the singular vectors, normalizes them and sets the columns of U - * and V to be the left/right singular vectors. + * Extracts the singular vectors, normalizes them and sets the columns of U + * and V to be the left/right singular vectors. * * @param singularVecs Computed left and right singular vectors. - * @param j Index of the column of U and V to set. + * @param j Index of the column of U and + * V to set. */ @Override protected void extractNormalizedCols(CMatrix singularVecs, int j) { diff --git a/src/main/java/org/flag4j/linalg/decompositions/svd/RealSVD.java b/src/main/java/org/flag4j/linalg/decompositions/svd/RealSVD.java index 3b2ecab4b..8ac380fe5 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/svd/RealSVD.java +++ b/src/main/java/org/flag4j/linalg/decompositions/svd/RealSVD.java @@ -26,6 +26,7 @@ import org.flag4j.arrays.Shape; +import org.flag4j.arrays.backend.MatrixMixin; import org.flag4j.arrays.dense.CMatrix; import org.flag4j.arrays.dense.CVector; import org.flag4j.arrays.dense.Matrix; @@ -36,9 +37,11 @@ *

                  Instances of this class can be used to compute the singular value decomposition (SVD) of a * {@link Matrix real dense matrix}. * - *

                  That is, decomposes a rectangular matrix M into M=UΣVT where U and V are - * orthogonal matrices whose columns are the left and right singular vectors of M and Σ is a rectangular - * diagonal matrix containing the singular values of M. + *

                  That is, decomposes a rectangular matrix M into + * M=UΣVT where U and V are + * orthogonal matrices whose columns are the left and right singular vectors of + * M and Σ is a rectangular + * diagonal matrix containing the singular values of M. * *

                  The SVD may also be used to compute the (numerical) rank of the matrix using {@link #getRank()}. * @@ -49,7 +52,7 @@ * The decomposition workflow typically follows these steps: *

                    *
                  1. Instantiate an instance of {@code RealSVD}.
                  2. - *
                  3. Call {@link #decompose(Matrix)} to perform the factorization.
                  4. + *
                  5. Call {@link SVD#decompose(MatrixMixin)} to perform the factorization.
                  6. *
                  7. Retrieve the resulting matrices using {@link #getU()} and {@link #getS()}.
                  8. *
                  * @@ -74,11 +77,12 @@ public RealSVD() { /** * Creates a decomposer to compute the singular value decomposition of a real matrix. - * @param computeUV A flag which indicates if the unitary matrices U and V should be computed + * @param computeUV A flag which indicates if the unitary matrices U and V should be computed * (i.e. the singular vectors). *
                    - *
                  • If {@code true}, the U and V matrices will be computed.
                  • - *
                  • If {@code false}, the U and V matrices will not be computed. If it is not + *
                  • If {@code true}, the U and V matrices will be computed.
                  • + *
                  • If {@code false}, the U and V matrices will not be computed. + * If it is not * needed, this may provide a performance improvement.
                  • *
                  */ @@ -89,18 +93,24 @@ public RealSVD(boolean computeUV) { /** * Creates a decomposer to compute the singular value decomposition of a real matrix. - * @param computeUV A flag which indicates if the unitary matrices U and V should be computed + * @param computeUV A flag which indicates if the unitary matrices U and + * V should be computed * (i.e. the singular vectors). *
                    - *
                  • If {@code true}, the U and V matrices will be computed.
                  • - *
                  • If {@code false}, the U and V matrices will not be computed. If it is not + *
                  • If {@code true}, the U and V + * matrices will be computed.
                  • + *
                  • If {@code false}, the U and V + * matrices will not be computed. If it is not * needed, this may provide a performance improvement.
                  • *
                  - * @param computeUV A flag which indicates if the unitary matrices U and V should be computed + * @param computeUV A flag which indicates if the unitary matrices U + * and V should be computed * (i.e. the singular vectors). *
                    - *
                  • If {@code true}, the U and V matrices will be computed.
                  • - *
                  • If {@code false}, the U and V matrices will not be computed. If it is not + *
                  • If {@code true}, the U and V + * matrices will be computed.
                  • + *
                  • If {@code false}, the U and V + * matrices will not be computed. If it is not * needed, this may provide a performance improvement.
                  • *
                  */ @@ -111,11 +121,14 @@ public RealSVD(boolean computeUV, boolean reduced) { /** * Creates a decomposer to compute the Schur decomposition. - * @param computeUV A flag which indicates if the unitary matrices U and V should be computed + * @param computeUV A flag which indicates if the unitary matrices U + * and V should be computed * (i.e. the singular vectors). *
                    - *
                  • If {@code true}, the U and V matrices will be computed.
                  • - *
                  • If {@code false}, the U and V matrices will not be computed. If it is not + *
                  • If {@code true}, the U and V + * matrices will be computed.
                  • + *
                  • If {@code false}, the U and V + * matrices will not be computed. If it is not * needed, this may provide a performance improvement.
                  • *
                  * @param reduced Flag which indicates if the reduced (or full) SVD should be computed. @@ -179,10 +192,11 @@ protected void makeEigenVals(Matrix B, double[] eigVals) { /** - * Initializes the unitary U and V matrices for the SVD. + * Initializes the unitary U and V + * matrices for the SVD. * * @param src Shape of the source matrix being decomposed. - * @param cols The number of columns for U and V. + * @param cols The number of columns for U and V. */ @Override protected void initUV(Shape src, int cols) { @@ -192,11 +206,11 @@ protected void initUV(Shape src, int cols) { /** - * Extracts the singular vectors, normalizes them and sets the columns of U - * and V to be the left/right singular vectors. + * Extracts the singular vectors, normalizes them and sets the columns of U + * and V to be the left/right singular vectors. * * @param singularVecs Computed left and right singular vectors. - * @param j Index of the column of U and V to set. + * @param j Index of the column of U and V to set. */ @Override protected void extractNormalizedCols(Matrix singularVecs, int j) { diff --git a/src/main/java/org/flag4j/linalg/decompositions/svd/SVD.java b/src/main/java/org/flag4j/linalg/decompositions/svd/SVD.java index 611699544..95b0bbba1 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/svd/SVD.java +++ b/src/main/java/org/flag4j/linalg/decompositions/svd/SVD.java @@ -37,9 +37,12 @@ /** *

                  This abstract class specifies methods for computing the singular value decomposition (SVD) of a matrix. * - *

                  That is, decomposes a rectangular matrix M into M=UΣVH where U and V are - * unitary matrices whose columns are the left and right singular vectors of M and Σ is a rectangular - * diagonal matrix containing the singular values of M. + *

                  That is, decomposes a rectangular matrix M into + * M=UΣVH + * where U and V are + * unitary matrices whose columns are the left and right singular vectors of M and + * Σ is a rectangular + * diagonal matrix containing the singular values of M. * *

                  The SVD may also be used to compute the (numerical) rank of the matrix using {@link #getRank()}. * @@ -87,15 +90,15 @@ public abstract class SVD> extends Decompositi */ protected boolean reduced; /** - * The unitary matrix U corresponding to M=UΣVH in the SVD. + * The unitary matrix U corresponding to M=UΣVH in the SVD. */ protected T U; /** - * The rectangular diagonal Σ corresponding to M=UΣVH in the SVD. + * The rectangular diagonal Σ corresponding to M=UΣVH in the SVD. */ protected Matrix S; /** - * The unitary matrix V corresponding to M=UΣVH in the SVD. + * The unitary matrix V corresponding to M=UΣVH in the SVD. */ protected T V; /** @@ -106,11 +109,11 @@ public abstract class SVD> extends Decompositi /** * Creates a decomposer to compute the Schur decomposition. - * @param computeUV A flag which indicates if the unitary matrices U and V should be computed + * @param computeUV A flag which indicates if the unitary matrices U and V should be computed * (i.e. the singular vectors). *

                    - *
                  • If {@code true}, the U and V matrices will be computed.
                  • - *
                  • If {@code false}, the U and V matrices will not be computed. If it is not + *
                  • If {@code true}, the U and V matrices will be computed.
                  • + *
                  • If {@code false}, the U and V matrices will not be computed. If it is not * needed, this may provide a performance improvement.
                  • *
                  * @param reduced Flag which indicates if the reduced (or full) SVD should be computed. @@ -128,11 +131,11 @@ protected SVD(boolean computeUV, boolean reduced) { /** * Creates a decomposer to compute the Schur decomposition. - * @param computeUV A flag which indicates if the unitary matrices U and V should be computed + * @param computeUV A flag which indicates if the unitary matrices U and V should be computed * (i.e. the singular vectors). *
                    - *
                  • If {@code true}, the U and V matrices will be computed.
                  • - *
                  • If {@code false}, the U and V matrices will not be computed. If it is not + *
                  • If {@code true}, the U and V matrices will be computed.
                  • + *
                  • If {@code false}, the U and V matrices will not be computed. If it is not * needed, this may provide a performance improvement.
                  • *
                  * @param reduced Flag which indicates if the reduced (or full) SVD should be computed. @@ -152,8 +155,8 @@ protected SVD(boolean computeUV, boolean reduced, long seed) { /** - * Gets the unitary matrix U corresponding to M=UΣVH in the SVD. - * @return U corresponding to M=UΣVH in the SVD. + * Gets the unitary matrix U corresponding to M=UΣVH in the SVD. + * @return U corresponding to M=UΣVH in the SVD. */ public T getU() { ensureHasDecomposed(); @@ -162,8 +165,8 @@ public T getU() { /** - * Gets the diagonal matrix Σ corresponding to M=UΣVH in the SVD. - * @return Σ corresponding to M=UΣVH in the SVD. + * Gets the diagonal matrix Σ corresponding to M=UΣVH in the SVD. + * @return Σ corresponding to M=UΣVH in the SVD. */ public Matrix getS() { ensureHasDecomposed(); @@ -183,8 +186,8 @@ public Vector getSingularValues() { /** - * Gets the unitary matrix V corresponding to M=UΣVH in the SVD. - * @return V corresponding to M=UΣVH in the SVD. Note that the Hermitian transpose has + * Gets the unitary matrix V corresponding to M=UΣVH in the SVD. + * @return V corresponding to M=UΣVH in the SVD. Note that the Hermitian transpose has * not been computed. */ public T getV() { @@ -307,18 +310,18 @@ protected void computeRank(int rows, int cols, double[] singularValues) { /** - * Initializes the unitary U and V matrices for the SVD. + * Initializes the unitary U and V matrices for the SVD. * @param src Shape of the source matrix being decomposed. - * @param cols The number of columns for U and V. + * @param cols The number of columns for U and V. */ protected abstract void initUV(Shape src, int cols); /** - * Extracts the singular vectors, normalizes them and sets the columns of U - * and V to be the left/right singular vectors. + * Extracts the singular vectors, normalizes them and sets the columns of U + * and V to be the left/right singular vectors. * @param singularVecs Computed left and right singular vectors. - * @param j Index of the column of U and V to set. + * @param j Index of the column of U and V to set. */ protected abstract void extractNormalizedCols(T singularVecs, int j); } diff --git a/src/main/java/org/flag4j/linalg/decompositions/unitary/ComplexUnitaryDecomposition.java b/src/main/java/org/flag4j/linalg/decompositions/unitary/ComplexUnitaryDecomposition.java index 8eac0f769..f9483f982 100644 --- a/src/main/java/org/flag4j/linalg/decompositions/unitary/ComplexUnitaryDecomposition.java +++ b/src/main/java/org/flag4j/linalg/decompositions/unitary/ComplexUnitaryDecomposition.java @@ -138,12 +138,12 @@ public ComplexUnitaryDecomposition(int subDiagonal, boolean storeReflectors, boo /** - *

                  Gets the unitary {@code Q} matrix from the {@code QR} decomposition. + *

                  Gets the unitary {@code Q} matrix from the QR decomposition. * *

                  Note, if the reflectors for this decomposition were not saved, then {@code Q} can not be computed and this method will be * {@code null}. * - * @return The {@code Q} matrix from the {@code QR} decomposition. Note, if the reflectors for this decomposition were not saved, + * @return The {@code Q} matrix from the QR decomposition. Note, if the reflectors for this decomposition were not saved, * then {@code Q} can not be computed and this method will return {@code null}. */ @Override diff --git a/src/main/java/org/flag4j/linalg/solvers/LinearMatrixSolver.java b/src/main/java/org/flag4j/linalg/solvers/LinearMatrixSolver.java index 84555bb78..70a46c59e 100644 --- a/src/main/java/org/flag4j/linalg/solvers/LinearMatrixSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/LinearMatrixSolver.java @@ -29,8 +29,10 @@ /** *

                  Interface representing a solver for linear systems involving matrices and vectors. Implementations - * of this interface provide methods to solve equations such as Ax=b and - * AX=B, where A, B, and X are matrices, and x and b are vectors. + * of this interface provide methods to solve equations such as Ax = b and + * AX = B, where A, B, + * and X are matrices, and x and + * b are vectors. * *

                  Solvers may compute exact solutions or approximate solutions in a least squares sense, depending on the properties of the system. * @@ -42,21 +44,22 @@ public interface LinearMatrixSolver, /** - * Solves the linear system of equations Ax=b for the vector x. + * Solves the linear system of equations Ax = b for the vector + * x. * - * @param A The coefficient matrix A in the linear system. + * @param A The coefficient matrix A in the linear system. * @param b The constant vector in the linear system. - * @return The solution vector x satisfying Ax=b. + * @return The solution vector x satisfying Ax = b. */ U solve(T A, U b); /** - * Solves the linear matrix equation AX=B for the matrix X. + * Solves the linear matrix equation AX = B for the matrix X. * * @param A The coefficient matrix in the linear system. * @param B The constant matrix in the linear system. - * @return The solution matrix X satisfying AX=B. + * @return The solution matrix X satisfying AX = B. */ @Override T solve(T A, T B); diff --git a/src/main/java/org/flag4j/linalg/solvers/LinearSolver.java b/src/main/java/org/flag4j/linalg/solvers/LinearSolver.java index ec179303c..4dca99a1d 100644 --- a/src/main/java/org/flag4j/linalg/solvers/LinearSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/LinearSolver.java @@ -27,8 +27,8 @@ /** *

                  Interface representing a linear system solver for tensor equations. Implementations of this interface - * provide methods to solve linear equations involving tensors, such as AX=B, where - * A, B, and X are tensors. + * provide methods to solve linear equations involving tensors, such as AX = B, where + * A, B, and X are tensors. * *

                  Solvers may compute exact solutions or approximate solutions in a least squares sense, depending on the * properties of the tensor equation. @@ -38,13 +38,15 @@ public interface LinearSolver { /** - * Solves the linear tensor equation AX=B for the tensor X. The multiplication AX is defined such that - * it performs a tensor dot product over all indices of X with the rightmost indices of A, equivalent to + * Solves the linear tensor equation AX = B for the tensor X. + * The multiplication AX is defined such that + * it performs a tensor dot product over all indices of X with the rightmost indices + * of A, equivalent to * {@code A.tensorDot(X, X.getRank())}. * * @param A The coefficient tensor in the linear system. * @param B The constant tensor in the linear system. - * @return The solution tensor X satisfying AX=B. + * @return The solution tensor X satisfying AX = B. */ T solve(T A, T B); } diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/ComplexExactSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/ComplexExactSolver.java index 0283da804..79080e51c 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/ComplexExactSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/ComplexExactSolver.java @@ -24,6 +24,8 @@ package org.flag4j.linalg.solvers.exact; +import org.flag4j.arrays.backend.MatrixMixin; +import org.flag4j.arrays.backend.VectorMixin; import org.flag4j.arrays.dense.CMatrix; import org.flag4j.arrays.dense.CVector; import org.flag4j.linalg.decompositions.lu.ComplexLU; @@ -31,35 +33,44 @@ import org.flag4j.linalg.solvers.exact.triangular.ComplexForwardSolver; /** - *

                  Solves a well determined system of equations Ax=b or AX=B in an exact sense by using a + *

                  Solves a well determined system of equations Ax = b or AX = B + * in an exact sense by using a * {@link ComplexLU LU decomposition} - * where A, B, and X are matrices, and x and b are vectors. + * where A, B, and X + * are matrices, and x and b are vectors. * - *

                  If the system is not well determined, i.e. A is not square or not full rank, then use a + *

                  If the system is not well determined, i.e. A is not square or not full rank, then use a * {@link org.flag4j.linalg.solvers.lstsq.ComplexLstsqSolver least-squares solver}. * *

                  Usage:

                  - *

                  A single system may be solved by calling either {@link #solve(CMatrix, CVector)} or - * {@link #solve(CMatrix, CVector)}. + *

                  A single system may be solved by calling either {@link ExactSolver#solve(MatrixMixin, VectorMixin)} or + * {@link ExactSolver#solve(MatrixMixin, VectorMixin)}. * - *

                  Instances of this solver may also be used to efficiently solve many systems of the form Ax=b or AX=B - * for the same coefficient matrix A but numerous constant vectors/matrices b or B. To do this, the workflow + *

                  Instances of this solver may also be used to efficiently solve many systems of the form Ax = b + * or AX = B + * for the same coefficient matrix A but numerous constant vectors/matrices + * b or B. To do this, the workflow * would be as follows: *

                    *
                  1. Create an instance of {@code ComplexExactSolver}.
                  2. - *
                  3. Call {@link #decompose(CMatrix) decompse(A)} once on the coefficient matrix A.
                  4. - *
                  5. Call {@link #solve(CVector) solve(b)} or {@link #solve(CMatrix) solve(B)} as many times as needed to solve each - * system for with the various b vectors and/or B matrices.
                  6. + *
                  7. Call {@link ExactSolver#decompose(MatrixMixin) decompse(A)} once on the coefficient matrix + * A.
                  8. + *
                  9. Call {@link ExactSolver#solve(VectorMixin) solve(b)} or {@link ExactSolver#solve(MatrixMixin) + * solve(B)} as many times as needed to + * solve each + * system for with the various b vectors and/or + * B matrices.
                  10. *
                  * - * Note: Any call made to one of the following methods after a call to {@link #decompose(CMatrix) decompse(A)} will + * Note: Any call made to one of the following methods after a call to + * {@link ExactSolver#decompose(MatrixMixin) decompse(A)} will * override the coefficient matrix set that call: *
                    - *
                  • {@link #solve(CMatrix, CVector)}
                  • - *
                  • {@link #solve(CMatrix, CMatrix)}
                  • + *
                  • {@link ExactSolver#solve(MatrixMixin, VectorMixin)}
                  • + *
                  • {@link ExactSolver#solve(MatrixMixin, MatrixMixin)}
                  • *
                  * - *

                  Specialized solvers are provided for inversion using {@link #solveIdentity(CMatrix)}. This should be preferred + *

                  Specialized solvers are provided for inversion using {@link ExactSolver#solveIdentity(MatrixMixin)}. This should be preferred * over calling on of the other solve methods and providing an identity matrix explicitly. * * @param The type of the coefficient matrix in the linear system. diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/ComplexExactTensorSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/ComplexExactTensorSolver.java index 79ba4aae9..3994fb55e 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/ComplexExactTensorSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/ComplexExactTensorSolver.java @@ -26,13 +26,24 @@ import org.flag4j.arrays.Shape; +import org.flag4j.arrays.backend.semiring_arrays.TensorOverSemiring; import org.flag4j.arrays.dense.CMatrix; import org.flag4j.arrays.dense.CTensor; import org.flag4j.arrays.dense.CVector; /** - * Solver for solving a complex well determined linear tensor equation A*X=B in an exact sense. + *

                  Solver for solving a real well determined linear tensor equation AX = B in an exact sense. + * + *

                  All indices of X are summed over in the tensor product with the rightmost indices of + * A as if by + * {@link TensorOverSemiring#tensorDot(TensorOverSemiring, int[], int[]) A.tensorDot(X, M, N)} where + * {@code M = new int[]{X.rank()-1, X.rank(), X.rank()+1, ..., A.rank()-1}} and + * {@code N = new int[]{0, 1, ..., X.rank()-1}}. + * + * @see RealExactSolver + * @see ExactTensorSolver + * @see org.flag4j.linalg.TensorInvert */ public class ComplexExactTensorSolver extends ExactTensorSolver { diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/ExactSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/ExactSolver.java index 1e67bdfe1..52acb740a 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/ExactSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/ExactSolver.java @@ -39,25 +39,30 @@ import static org.flag4j.linalg.decompositions.lu.LU.Pivoting.PARTIAL; /** - *

                  Solves a well determined system of equations Ax = b or AX = B in an exact sense. - *

                  If the system is not well determined, i.e. A is not square or not full rank, then use a + *

                  Solves a well determined system of equations Ax = b or + * AX = B in an exact sense. + *

                  If the system is not well determined, i.e. A is not square or not full rank, then use a * {@link org.flag4j.linalg.solvers.lstsq.LstsqSolver least-squares solver}. * *

                  Usage:

                  *

                  A single system may be solved by calling either {@link #solve(MatrixMixin, VectorMixin)} or * {@link #solve(MatrixMixin, VectorMixin)}. * - *

                  Instances of this solver may also be used to efficiently solve many systems of the form Ax = b or AX = B - * for the same coefficient matrix A but numerous constant vectors/matrices b or B. To do this, the workflow + *

                  Instances of this solver may also be used to efficiently solve many systems of the form + * Ax = b or AX = B + * for the same coefficient matrix A but numerous constant vectors/matrices + * b or B. To do this, the workflow * would be as follows: *

                    *
                  1. Create a concrete instance of {@code LinearMatrixSolver}.
                  2. - *
                  3. Call {@link #decompose(MatrixMixin) decompse(A)} once on the coefficient matrix A.
                  4. + *
                  5. Call {@link #decompose(MatrixMixin) decompse(A)} once on the coefficient matrix A.
                  6. *
                  7. Call {@link #solve(VectorMixin) solve(b)} or {@link #solve(MatrixMixin) solve(B)} as many times as needed to solve each - * system for with the various b vectors and/or B matrices.
                  8. + * system for with the various b vectors and/or + * B matrices. *
                  * - * Note: Any call made to one of the following methods after a call to {@link #decompose(MatrixMixin) decompse(A)} will + * Note: Any call made to one of the following methods after a call to + * {@link #decompose(MatrixMixin) decompse(A)} will * override the coefficient matrix set that call: *
                    *
                  • {@link #solve(MatrixMixin, VectorMixin)}
                  • @@ -102,8 +107,10 @@ public abstract class ExactSolver, /** * Constructs an exact LU solver with a specified LU decomposer. * @param lu LU decomposer to employ in solving the linear system. - * @param forwardSolver Solver to use when solving LY = b. - * @param backSolver Solver to use when solving LY = b. + * @param forwardSolver Solver to use when solving Ly = b or + * LY = B. + * @param backSolver Solver to use when solving Ly = b or + * LY = B. * @throws IllegalArgumentException If the LU decomposer does not use partial pivoting. */ protected ExactSolver(LU lu, ForwardSolver forwardSolver, BackSolver backSolver) { @@ -119,16 +126,17 @@ protected ExactSolver(LU lu, ForwardSolver forwardSolver, BackSolver /** - * Decomposes a matrix A using an {@link LU LU decomposition}. This decomposition is then used by + * Decomposes a matrix A using an {@link LU LU decomposition}. This decomposition is then used by * {@link #solve(VectorMixin)} and {@link #solve(MatrixMixin)} to efficiently solve the systems - * Ax = b and AX = B respectively. + * Ax = b and AX = B respectively. * *

                    Note: Any subsequent call to {@link #solve(MatrixMixin, VectorMixin)} or {@link #solve(MatrixMixin, MatrixMixin)} * after a call to this method will override the coefficient matrix. * *

                    This is useful, and more efficient than {@link #solve(MatrixMixin, VectorMixin)} and * {@link #solve(MatrixMixin, MatrixMixin)}, if you need to solve multiple systems of this form - * for the same A but numerous b's or B's that may not all be available at the same time. + * for the same A but numerous b's or + * B's that may not all be available at the same time. * * @param A Matrix to decompose. */ @@ -148,10 +156,12 @@ public void decompose(T A) { /** - *

                    Solves the linear system of equations given by Ax = b for the vector x. The system must be well + *

                    Solves the linear system of equations given by Ax = b for the vector + * x. The system must be well * determined. - * @param b Vector of constants, b, in the linear system. - * @return The solution to x in the linear system Ax = b for the last A passed to + * @param b Vector of constants, b, in the linear system. + * @return The solution to x in the linear system + * Ax = b for the last A passed to * {@link #decompose(MatrixMixin)}. * @throws IllegalStateException If no coefficient matrix has been specified for this solver by first calling one of the following: *

                      @@ -172,9 +182,10 @@ public U solve(U b) { /** - *

                      Solves the set of linear system of equations given by AX = B for the matrix X. + *

                      Solves the set of linear system of equations given by AX = B for the matrix + * X. * - * @param B Matrix of constants, B, in the linear system. + * @param B Matrix of constants, B, in the linear system. * @throws IllegalStateException If no coefficient matrix has been specified for this solver by first calling one of the following: *

                        *
                      • {@link #decompose(MatrixMixin)}
                      • @@ -194,16 +205,17 @@ public T solve(T B) { /** - *

                        Solves the linear system of equations given by Ax = b for the vector x. The system must be well + *

                        Solves the linear system of equations given by Ax = b for the vector + * x. The system must be well * determined. * *

                        Note: Any call of this method will override the coefficient matrix specified in any previous calls to * {@link #decompose(MatrixMixin)} on the same solver instance. * - * @param A Coefficient matrix, A, in the linear system. Must be square and have full rank + * @param A Coefficient matrix, A, in the linear system. Must be square and have full rank * (i.e. all rows, or equivalently columns, must be linearly independent). - * @param b Vector of constants, b, in the linear system. - * @return The solution to x in the linear system Ax = b. + * @param b Vector of constants, b, in the linear system. + * @return The solution to x in the linear system Ax = b. * @throws IllegalArgumentException If the number of columns in {@code A} is not equal to the number of data in * {@code b}. * @throws IllegalArgumentException If {@code A} is not square. @@ -221,15 +233,16 @@ public U solve(T A, U b) { /** - *

                        Solves the set of linear system of equations given by AX = B for the matrix X. + *

                        Solves the set of linear system of equations given by AX = B for the matrix + * X. * *

                        Note: Any call of this method will override the coefficient matrix specified in any previous calls to * {@link #decompose(MatrixMixin)} on the same solver instance. * - * @param A Coefficient matrix, A, in the linear system. Must be square and have full rank + * @param A Coefficient matrix, A, in the linear system. Must be square and have full rank * (i.e. all rows, or equivalently columns, must be linearly independent). - * @param B Matrix of constants, B, in the linear system. - * @return The solution to x in the linear system AX = B. + * @param B Matrix of constants, B, in the linear system. + * @return The solution to x in the linear system AX = B. * @throws IllegalArgumentException If the number of columns in {@code A} is not equal to the number of rows in * {@code B}. * @throws IllegalArgumentException If {@code A} is not square. @@ -247,15 +260,17 @@ public T solve(T A, T B) { /** - * Solves the set of linear system of equations given by AX=I for the matrix x where I - * is the identity matrix of the appropriate size. Thus, X = A-1 meaning this method computes the inverse of - * A. + * Solves the set of linear system of equations given by AX = I for the matrix + * x where I + * is the identity matrix of the appropriate size. Thus, X = A-1 + * meaning this method computes the inverse of + * A. * *

                        This method should be preferred over {@code solve(A, Matrix.I(A.shape))} or {@code solve(A, CMatrix.I(A.shape))} as it uses * specialized solvers that take advantage of the structure of the identity matrix. * * @param A Coefficient matrix in the linear system. - * @return The solution to x in the linear system AX=I. + * @return The solution to x in the linear system AX = I. * @throws IllegalArgumentException If {@code A} is not square. * @throws SingularMatrixException If {@code A} is singular. */ diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/ExactTensorSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/ExactTensorSolver.java index aede324ae..ba643ad30 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/ExactTensorSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/ExactTensorSolver.java @@ -35,7 +35,14 @@ import org.flag4j.util.ValidateParameters; /** - *

                        Solves a well determined system of equations AX=B in an exact sense where A, X, and B are tensors. + *

                        Solves a well determined system of equations AX = B in an exact sense where + * A, X, and B are tensors. + * + *

                        All indices of X are summed over in the tensor product with the rightmost indices of + * A as if by + * {@link TensorOverSemiring#tensorDot(TensorOverSemiring, int[], int[]) A.tensorDot(X, M, N)} where + * {@code M = new int[]{X.rank()-1, X.rank(), X.rank()+1, ..., A.rank()-1}} and + * {@code N = new int[]{0, 1, ..., X.rank()-1}}. * * @param Type of tensor in equation to solve. * @param Matrix type equivalent of tensor to solve. @@ -46,8 +53,9 @@ public abstract class ExactTensorSolver, V extends VectorMixin> implements LinearSolver { /** - * Solver to solve a linear matrix equation Cx=d for x where C is a matrix and - * x and d are vectors. + * Solver to solve a linear matrix equation Cx = d for x + * where C is a matrix and + * x and d are vectors. */ private final LinearMatrixSolver matrixSolver; @@ -63,15 +71,17 @@ protected ExactTensorSolver(LinearMatrixSolver matrixSolver) { /** - *

                        Solves the linear tensor equation given by AX=B for the tensor X. + *

                        Solves the linear tensor equation given by AX = B for the tensor + * X. * - *

                        All indices of X are summed over in the tensor product with the rightmost indices of A as if by - * {@link org.flag4j.arrays.backend.semiring_arrays.TensorOverSemiring#tensorDot(TensorOverSemiring, int[], int[])} where + *

                        All indices of X are summed over in the tensor product with the rightmost indices of + * A as if by + * {@link TensorOverSemiring#tensorDot(TensorOverSemiring, int[], int[]) A.tensorDot(X, M, N)} where * {@code M = new int[]{X.rank()-1, X.rank(), X.rank()+1, ..., A.rank()-1}} and - * {@code N = new int[]{0, 1, ..., X.rank()-1}} + * {@code N = new int[]{0, 1, ..., X.rank()-1}}. * @param A Coefficient tensor in the linear system. * @param B Tensor of constants in the linear system. - * @return The solution to X in the linear system AX=B. + * @return The solution to X in the linear system AX = B. */ @Override public T solve(T A, T B) { @@ -97,10 +107,10 @@ public T solve(T A, T B) { /** * Constructs the shape of the output. - * @param A Tensor corresponding to A in AX=B. - * @param B Tensor corresponding to B in AX=B. + * @param A Tensor corresponding to A in AX = B. + * @param B Tensor corresponding to B in AX = B. * @param aRankOriginal Original rank of {@code A} before any reshaping. - * @return The shape of X in AX=B. + * @return The shape of X in AX = B. */ protected Shape getOutputShape(T A, T B, int aRankOriginal) { int start = -(aRankOriginal - B.getRank()); @@ -115,7 +125,7 @@ protected Shape getOutputShape(T A, T B, int aRankOriginal) { /** * Ensures that {@code aNumEntries==prod}. - * @param aNumEntries The total number of data in the A tensor. + * @param aNumEntries The total number of data in the A tensor. * @param prod Product of all axis lengths in the output shape. */ protected void checkSize(int aNumEntries, int prod) { @@ -126,8 +136,8 @@ protected void checkSize(int aNumEntries, int prod) { /** * Initializes matrix for equivalent linear matrix equation. * @param A Tensor to convert to matrix. - * @param prod Product of all axis lengths in A. - * @return A matrix with the same data as tensor A with shape (prod, prod). + * @param prod Product of all axis lengths in A. + * @return A matrix with the same data as tensor A with shape (prod, prod). */ protected abstract U initMatrix(T A, int prod); @@ -142,9 +152,10 @@ protected void checkSize(int aNumEntries, int prod) { /** * Wraps solution as a tensor and reshapes to the proper shape. - * @param x Vector solution to matrix linear equation which is equivalent to the tensor equation Ax=b. - * @param outputShape Shape for the solution tensor x. - * @return The solution x to the linear tensor equation Ax=b. + * @param x Vector solution to matrix linear equation which is equivalent to the tensor equation + * Ax=b. + * @param outputShape Shape for the solution tensor x. + * @return The solution x to the linear tensor equation Ax = b. */ protected abstract T wrap(V x, Shape outputShape); } diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/RealExactSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/RealExactSolver.java index 1f2b1f606..0102db4c8 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/RealExactSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/RealExactSolver.java @@ -25,6 +25,8 @@ package org.flag4j.linalg.solvers.exact; +import org.flag4j.arrays.backend.MatrixMixin; +import org.flag4j.arrays.backend.VectorMixin; import org.flag4j.arrays.dense.Matrix; import org.flag4j.arrays.dense.Vector; import org.flag4j.linalg.decompositions.lu.RealLU; @@ -32,35 +34,44 @@ import org.flag4j.linalg.solvers.exact.triangular.RealForwardSolver; /** - *

                        Solves a well determined system of equations Ax=b or AX=B in an exact sense by using a + *

                        Solves a well determined system of equations Ax = b or AX = B + * in an exact sense by using a * {@link RealLU LU decomposition} - * where A, B, and X are matrices, and x and b are vectors. + * where A, B, and X + * are matrices, and x and b are vectors. * - *

                        If the system is not well determined, i.e. A is not square or not full rank, then use a + *

                        If the system is not well determined, i.e. A is not square or not full rank, then use a * {@link org.flag4j.linalg.solvers.lstsq.RealLstsqSolver least-squares solver}. * *

                        Usage:

                        - *

                        A single system may be solved by calling either {@link #solve(Matrix, Vector)} or - * {@link #solve(Matrix, Vector)}. + *

                        A single system may be solved by calling either {@link ExactSolver#solve(MatrixMixin, VectorMixin)} or + * {@link ExactSolver#solve(MatrixMixin, VectorMixin)}. * - *

                        Instances of this solver may also be used to efficiently solve many systems of the form Ax=b or AX=B - * for the same coefficient matrix A but numerous constant vectors/matrices b or B. To do this, the workflow + *

                        Instances of this solver may also be used to efficiently solve many systems of the form Ax = b + * or AX = B + * for the same coefficient matrix A but numerous constant vectors/matrices + * b or B. To do this, the workflow * would be as follows: *

                          *
                        1. Create an instance of {@code RealExactSolver}.
                        2. - *
                        3. Call {@link #decompose(Matrix) decompse(A)} once on the coefficient matrix A.
                        4. - *
                        5. Call {@link #solve(Vector) solve(b)} or {@link #solve(Matrix) solve(B)} as many times as needed to solve each - * system for with the various b vectors and/or B matrices.
                        6. + *
                        7. Call {@link ExactSolver#decompose(MatrixMixin) decompse(A)} once on the coefficient matrix A.
                        8. + *
                        9. Call {@link ExactSolver#solve(VectorMixin) solve(b)} or {@link ExactSolver#solve(MatrixMixin) solve(B)} as many times as + * needed to solve + * each + * system for with the various b vectors and/or + * B matrices.
                        10. *
                        * - * Note: Any call made to one of the following methods after a call to {@link #decompose(Matrix) decompse(A)} will + * Note: Any call made to one of the following methods after a call to {@link ExactSolver#decompose(MatrixMixin) decompse(A)} + * will * override the coefficient matrix set that call: *
                          - *
                        • {@link #solve(Matrix, Vector)}
                        • - *
                        • {@link #solve(Matrix, Matrix)}
                        • + *
                        • {@link ExactSolver#solve(MatrixMixin, VectorMixin)}
                        • + *
                        • {@link ExactSolver#solve(MatrixMixin, VectorMixin)}
                        • *
                        * - *

                        Specialized solvers are provided for inversion using {@link #solveIdentity(Matrix)}. This should be preferred + *

                        Specialized solvers are provided for inversion using {@link ExactSolver#solveIdentity(MatrixMixin)}. This should be preferred * over calling on of the other solve methods and providing an identity matrix explicitly. * * @param The type of the coefficient matrix in the linear system. diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/RealExactTensorSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/RealExactTensorSolver.java index 85e19b3c6..4d62265d7 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/RealExactTensorSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/RealExactTensorSolver.java @@ -26,18 +26,29 @@ import org.flag4j.arrays.Shape; +import org.flag4j.arrays.backend.semiring_arrays.TensorOverSemiring; import org.flag4j.arrays.dense.Matrix; import org.flag4j.arrays.dense.Tensor; import org.flag4j.arrays.dense.Vector; /** - * Solver for solving a real well determined linear tensor equation A*X=B in an exact sense. + *

                        Solver for solving a real well determined linear tensor equation AX = B in an exact sense. + * + *

                        All indices of X are summed over in the tensor product with the rightmost indices of + * A as if by + * {@link TensorOverSemiring#tensorDot(TensorOverSemiring, int[], int[]) A.tensorDot(X, M, N)} where + * {@code M = new int[]{X.rank()-1, X.rank(), X.rank()+1, ..., A.rank()-1}} and + * {@code N = new int[]{0, 1, ..., X.rank()-1}}. + * + * @see ComplexExactSolver + * @see ExactTensorSolver + * @see org.flag4j.linalg.TensorInvert */ public class RealExactTensorSolver extends ExactTensorSolver { /** - * Creates an exact tensor solver for solving a well determined linear tensor equation A*X=B - * for X in an exact sense. + * Creates an exact tensor solver for solving a well determined linear tensor equation AX = B + * for X in an exact sense. */ public RealExactTensorSolver() { super(new RealExactSolver()); @@ -47,7 +58,7 @@ public RealExactTensorSolver() { /** * Initializes matrix for equivalent linear matrix equation. * - * @param A Tensor to convert to matrix. + * @param A Tensor to convert to matrix. * @param prod Product of all axis lengths in {@code A}. * @return A matrix with the same data as tensor {@code A} with shape (prod, prod). */ @@ -72,9 +83,10 @@ protected Vector initVector(Tensor B) { /** * Wraps solution as a tensor and reshapes to the proper shape. * - * @param x Vector solution to linear matrix equation which is equivalent to the tensor equation A*X=B. - * @param outputShape Shape for the solution tensor X. - * @return The solution X to the linear tensor equation A*X=B. + * @param x Vector solution to linear matrix equation which is equivalent to the tensor equation + * AX = B. + * @param outputShape Shape for the solution tensor X. + * @return The solution X to the linear tensor equation AX = B. */ @Override protected Tensor wrap(Vector x, Shape outputShape) { diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/BackSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/BackSolver.java index 48f44b234..debfbd906 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/BackSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/BackSolver.java @@ -34,8 +34,9 @@ import org.flag4j.util.exceptions.SingularMatrixException; /** - * Base class for solvers which solve a linear system of equations Ux = b or UX = B - * where U is an upper triangular matrix. This accomplished using a simple backward substitution. + * Base class for solvers which solve a linear system of equations Ux = b or + * UX = B where U is an + * upper triangular matrix. This system is solved in an exact sense. * * @param Type of matrix to decompose. * @param Vector type equivalent of matrix. diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ComplexBackSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ComplexBackSolver.java index baf19dcac..0f44da76a 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ComplexBackSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ComplexBackSolver.java @@ -28,12 +28,16 @@ import org.flag4j.algebraic_structures.Complex128; import org.flag4j.arrays.dense.CMatrix; import org.flag4j.arrays.dense.CVector; +import org.flag4j.arrays.dense.Matrix; import org.flag4j.util.exceptions.SingularMatrixException; /** - * This solver solves linear systems of equations where the coefficient matrix in an upper triangular complex dense matrix - * and the constant vector is a complex dense vector. + * This solver solves linear systems of the form Ux = b or + * UX = B where U is an + * upper triangular matrix. This system is solved in an exact sense. + * + * @see RealBackSolver */ public class ComplexBackSolver extends BackSolver { @@ -89,15 +93,14 @@ public Complex128 getDet() { /** - * Solves the linear system of equations given by Ux = b where the coefficient matrix U - * is an upper triangular matrix. + * Solves the linear system of equations given by Ux = b where the coefficient matrix + * U is an {@link Matrix#isTriU() upper triangular} matrix. * - * @param U Upper triangular coefficient matrix in the linear system. If {@code U} is not actually - * upper triangular, it will be treated as if it were. + * @param U Upper triangular coefficient matrix in the linear system. If {@code enforceTriU} was set to {@code false} when + * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were. * @param b Vector of constants in the linear system. - * @return The solution to x in the linear system A*x=b. - * @throws SingularMatrixException If the matrix {@code U} is singular (i.e. if it has a zero along - * the principle diagonal). + * @return The solution to x in the linear system Ux = b. + * @throws SingularMatrixException If the matrix {@code U} is singular (i.e. has a zero on the principle diagonal). */ @Override public CVector solve(CMatrix U, CVector b) { @@ -130,13 +133,13 @@ public CVector solve(CMatrix U, CVector b) { /** - * Solves the linear system of equations given by UX = B where the coefficient matrix U - * is an upper triangular matrix. + * Solves the linear system of equations given by UX = B where the coefficient matrix + * U is an {@link Matrix#isTriU() upper triangular} matrix. * - * @param U Upper triangular coefficient matrix in the linear system. If {@code U} is not actually - * upper triangular, it will be treated as if it were. + * @param U Upper triangular coefficient matrix in the linear system. If {@code enforceTriU} was set to {@code false} when + * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were. * @param B Matrix of constants in the linear system. - * @return The solution to X in the linear system A*X=B. + * @return The solution to X in the linear system UX = B. * @throws SingularMatrixException If the matrix {@code U} is singular (i.e. has a zero on the principle diagonal). */ @Override @@ -183,13 +186,15 @@ public CMatrix solve(CMatrix U, CMatrix B) { /** - * Solves the linear system of equations given by UX = I where the coefficient matrix U - * is an {@link CMatrix#isTriU() upper triangular} matrix and I is the {@link CMatrix#isI() identity} - * matrix of appropriate size. + * Solves the linear system of equations given by UX = I where the coefficient matrix + * U + * is an {@link Matrix#isTriU() upper triangular} matrix and I is the {@link Matrix#isI() identity} + * matrix of appropriate size. This essentially inverts the upper triangular matrix since + * UU-1 = I. * - * @param U Upper triangular coefficient matrix in the linear system. If {@code U} is not actually - * upper triangular, it will be treated as if it were. - * @return The solution to X in the linear system UX = B. + * @param U Upper triangular coefficient matrix in the linear system. If {@code enforceTriU} was set to {@code false} when + * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were. + * @return The solution to X in the linear system UX = B. * @throws SingularMatrixException If the matrix {@code U} is singular (i.e. has a zero on the principle diagonal). */ public CMatrix solveIdentity(CMatrix U) { @@ -237,13 +242,17 @@ public CMatrix solveIdentity(CMatrix U) { /** - * Solves a special case of the linear system UX = L for X where the coefficient matrix U - * is an {@link CMatrix#isTriU() upper triangular} matrix and the constant matrix L is - * {@link CMatrix#isTriL() lower triangular}. + * Solves a special case of the linear system UX = L for X + * where the coefficient matrix U + * is an {@link Matrix#isTriU() upper triangular} matrix and the constant matrix L is + * {@link Matrix#isTriL() lower triangular}. * - * @param U Upper triangular coefficient matrix - * @param L Lower triangular constant matrix. - * @return The result of solving the linear system UX = L for the matrix X. + * @param U Upper triangular coefficient matrix in the linear system. If {@code enforceTriU} was set to {@code false} when + * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were. + * @param L Lower triangular constant matrix. This is not explicit checked. If {@code L} is not lower triangular, values above + * the principle diagonal will be ignored and the result will still be correctly computed. + * @return The result of solving the linear system UX = L for the matrix + * X. */ public CMatrix solveLower(CMatrix U, CMatrix L) { checkParams(U, L.shape); diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ComplexForwardSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ComplexForwardSolver.java index 49b3c9a56..dcf026f17 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ComplexForwardSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ComplexForwardSolver.java @@ -32,8 +32,9 @@ import org.flag4j.util.exceptions.SingularMatrixException; /** - * This solver solves linear systems of equations where the coefficient matrix is lower triangular. - * That is, solves the systems Lx = b or LX = B where L is a lower triangular + * This solver solves a complex linear system of equations where the coefficient matrix is lower triangular. + * That is, solves the systems Lx = b or LX = B + * where L is a lower triangular * matrix. This is accomplished using a simple forward substitution. * * @see RealForwardSolver @@ -91,12 +92,12 @@ public Complex128 getDet() { /** - * Performs forward substitution for a unit lower triangular matrix L and a vector b. - * That is, solves the linear system Lx = b for x where L is lower triangular. - * @param L Lower triangular coefficient matrix L. {@code L} is assumed to be lower triangular and only entries + * Performs forward substitution for a unit lower triangular matrix L and a vector b. + * That is, solves the linear system Lx = b for x where L is lower triangular. + * @param L Lower triangular coefficient matrix L. {@code L} is assumed to be lower triangular and only entries * at and below the principle diagonal will be accessed. - * @param b Constant vector b. - * @return The result of solving the linear system Lx = b where L is a lower triangular. + * @param b Constant vector b. + * @return The result of solving the linear system Lx = b where L is a lower triangular. * @throws SingularMatrixException If {@code L} is singular (i.e. has at least one zero on the principle diagonal). */ @Override @@ -106,12 +107,12 @@ public CVector solve(CMatrix L, CVector b) { /** - * Performs forward substitution for a unit lower triangular matrix L and a matrix B. - * That is, solves the linear system LX = B for X where L is lower triangular. - * @param L Lower triangular coefficient matrix L. {@code L} is assumed to be lower triangular and only entries + * Performs forward substitution for a unit lower triangular matrix L and a matrix B. + * That is, solves the linear system LX = B for X where L is lower triangular. + * @param L Lower triangular coefficient matrix L. {@code L} is assumed to be lower triangular and only entries * at and below the principle diagonal will be accessed. - * @param b Constant matrix B. - * @return The result of solving the linear system LX = B where L is a lower triangular. + * @param b Constant matrix B. + * @return The result of solving the linear system LX = B where L is a lower triangular. * @throws SingularMatrixException If {@code L} is singular (i.e. has at least one zero on the principle diagonal). */ @Override @@ -121,13 +122,11 @@ public CMatrix solve(CMatrix L, CMatrix B) { /** - * Solves a linear system LX = P for X where L is a lower triangular matrix and - * P is a permutation matrix. - * - * @param L Lower triangular coefficient matrix. - * @param P Constant permutation matrix. - * - * @return The solution of X for the linear system LX = P. + * Solves a linear system LX = P for X where L is a lower triangular matrix and + * P is a permutation matrix. + * @param L Lower triangular coefficient matrix L. + * @param P Constant permutation matrix P. + * @return The solution to X in the linear system LX = P. */ @Override public CMatrix solve(CMatrix L, PermutationMatrix P) { @@ -136,14 +135,14 @@ public CMatrix solve(CMatrix L, PermutationMatrix P) { /** - * Performs forward substitution for a unit lower triangular matrix L and the identity matrix. - * That is, solves the linear system LX = I where L is a lower triangular matrix and I is - * the appropriately sized identity matrix. - * @param L Lower triangular coefficient matrix. If {@code L} is not lower triangular, it will be treated - * as if it were. - * @return The result of solving the linear system LX = B where L is a lower triangular matrix. - * @throws SingularMatrixException If the matrix lower triangular {@code L} is singular (i.e. has a zero on - * the principle diagonal). + * Performs forward substitution for a unit lower triangular matrix L and the identity matrix. + * That is, solves the linear system LX = I where L is a lower triangular matrix and + * I is the appropriately sized identity matrix. + * @param L Lower triangular coefficient matrix, L. If {@code L} is not lower triangular, it will be treated + * as if it were and only data in the lower triangular portion will be accessed. + * @return The result of solving the linear system LX = B where L is a lower triangular matrix. + * @throws SingularMatrixException If the matrix lower triangular {@code L} is singular + * (i.e. has at least one zero on the principle diagonal). */ public CMatrix solveIdentity(CMatrix L) { return isUnit ? solveUnitLowerIdentity(L) : solveLowerIdentity(L); @@ -151,11 +150,10 @@ public CMatrix solveIdentity(CMatrix L) { /** - * Solves a linear system where the coefficient matrix is unit lower triangular. - * @param L Lower triangular coefficient matrix. If {@code L} is not lower triangular, it will be treated - * as if it were. + * Solves the linear system Lx = b where L is unit lower triangular. + * @param L Unit lower triangular matrix. * @param b Vector of constants in the linear system. - * @return The solution of x for the linear system Lx = b. + * @return The solution of x for the linear system Lx = b. */ private CVector solveUnitLower(CMatrix L, CVector b) { checkParams(L, b.size); @@ -184,9 +182,7 @@ private CVector solveUnitLower(CMatrix L, CVector b) { * Solves a linear system where the coefficient matrix is unit lower triangular and the constant matrix * is the identity matrix. * @param L Unit lower triangular matrix. - * @return The solution of X for the linear system LX = I. - * @throws SingularMatrixException If the matrix lower triangular {@code L} is singular (i.e. has a zero on - * the principle diagonal). + * @return The solution of X for the linear system LX = I. */ private CMatrix solveUnitLowerIdentity(CMatrix L) { checkParams(L, L.numRows); @@ -221,11 +217,11 @@ private CMatrix solveUnitLowerIdentity(CMatrix L) { /** - * Solves a linear system LX = I where the coefficient matrix L is lower triangular and the + * Solves a linear system LX = I where the coefficient matrix L is lower triangular and the * constant matrix I is the appropriately sized identity matrix. * @param L Unit lower triangular matrix (Note, this is not checked). * If {@code L} is not lower triangular, it will be treated as if it were. No error will be thrown. - * @return The solution of X for the linear system LX = I. + * @return The solution of X for the linear system LX = I. * @throws SingularMatrixException If the lower triangular matrix {@code L} is singular (i.e. has a zero on the * principle diagonal). */ @@ -271,7 +267,7 @@ private CMatrix solveLowerIdentity(CMatrix L) { * Solves a linear system where the coefficient matrix is lower triangular. * @param L Unit lower triangular matrix. * @param b Vector of constants in the linear system. - * @return The solution of x for the linear system Lx = b. + * @return The solution of x for the linear system Lx = b. * @throws SingularMatrixException If the lower triangular matrix {@code L} is singular (i.e. has a zero on the * principle diagonal). */ @@ -306,7 +302,7 @@ private CVector solveLower(CMatrix L, CVector b) { * Solves a linear system where the coefficient matrix is unit lower triangular. * @param L Unit lower triangular matrix. * @param B Matrix of constants in the linear system. - * @return The solution of X for the linear system LX = B. + * @return The solution to X in the linear system LX = B. */ private CMatrix solveUnitLower(CMatrix L, CMatrix B) { checkParams(L, B.numRows); @@ -345,7 +341,7 @@ private CMatrix solveUnitLower(CMatrix L, CMatrix B) { * Solves a linear system where the coefficient matrix is lower triangular. * @param L Unit lower triangular matrix. * @param B Matrix of constants in the linear system. - * @return The solution of X for the linear system LX = B. + * @return The solution of X for the linear system LX = B. * @throws SingularMatrixException If the lower triangular matrix {@code L} is singular (i.e. has a zero on the * principle diagonal). */ @@ -389,10 +385,11 @@ private CMatrix solveLower(CMatrix L, CMatrix B) { /** - * Solves a linear system LX=P where the coefficient matrix L is lower triangular and the - * constant matrix P is a permutation matrix. - * @param L Lower triangular coefficient matrix L. - * @return The solution of X to the linear system LX=P. + * Solves a linear system LX = P where the coefficient matrix L is lower triangular and the + * constant matrix P is a permutation matrix. + * @param L Lower triangular coefficient matrix L. + * @return The solution of X to the linear system LX = P. * @throws SingularMatrixException If {@code L} is singular (i.e. has a zero on the principle diagonal). */ private CMatrix solvePerm(CMatrix L, PermutationMatrix P) { @@ -439,10 +436,11 @@ private CMatrix solvePerm(CMatrix L, PermutationMatrix P) { /** - * Solves a linear system LX=P where the coefficient matrix L is unit-lower triangular and the - * constant matrix P is a permutation matrix. - * @param L Unit lower triangular coefficient matrix L. - * @return The solution of X to the linear system LX=P. + * Solves a linear system LX = P where the coefficient matrix L is unit-lower triangular and the + * constant matrix P is a permutation matrix. + * @param L Unit lower triangular coefficient matrix L. + * @return The solution of X to the linear system LX = P. */ private CMatrix solveUnitPerm(CMatrix L, PermutationMatrix P) { checkParams(L, P.size); diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ForwardSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ForwardSolver.java index 234aa977c..add4de9f0 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ForwardSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/ForwardSolver.java @@ -35,7 +35,8 @@ /** * This solver solves linear systems of equations where the coefficient matrix is lower triangular. - * That is, solves the systems Lx = b or LX = B where L is a lower triangular + * That is, solves the systems Lx = b or LX = B + * where L is a lower triangular * matrix. This is accomplished using a simple forward substitution. * * @param Type of coefficient matrix. @@ -92,11 +93,12 @@ protected ForwardSolver(boolean isUnit, boolean enforceLower) { /** - * Solves a linear system LX = P for X where L is a lower triangular matrix and - * P is a permutation matrix. + * Solves a linear system LX = P for + * X where L is a lower triangular matrix and + * P is a permutation matrix. * @param L Lower triangular coefficient matrix. * @param P Constant permutation matrix. - * @return The solution of X for the linear system LX = P. + * @return The solution of X for the linear system LX = P. */ public abstract T solve(T L, PermutationMatrix P); diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/RealBackSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/RealBackSolver.java index 1f5a22698..a0a9995e9 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/RealBackSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/RealBackSolver.java @@ -30,11 +30,11 @@ /** - *

                        This solver solves linear systems of equations where the coefficient matrix in an {@link Matrix#isTriU() upper triangular} - * real dense matrix and the constant vector is a real dense vector or matrix. + * This solver solves linear systems of the form Ux = b or + * UX = B where U is an + * upper triangular matrix. This system is solved in an exact sense. * - *

                        That is, solves a linear system of equations Ux = b or UX = B where - * U is an upper triangular matrix. + * @see ComplexBackSolver */ public class RealBackSolver extends BackSolver { @@ -88,14 +88,13 @@ public double getDet() { /** - * Solves the linear system of equations given by Ux = b where the coefficient matrix U - * is an {@link Matrix#isTriU() upper triangular} matrix. + * Solves the linear system of equations given by Ux = b where the coefficient matrix + * U is an {@link Matrix#isTriU() upper triangular} matrix. * - * @param U Upper triangular coefficient matrix, U, in the linear system. If {@code enforceTriU} was set to - * {@code false} when this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if - * it were. - * @param b Constant vector, b, in the linear system. - * @return The solution to x in the linear system Ux = b. + * @param U Upper triangular coefficient matrix in the linear system. If {@code enforceTriU} was set to {@code false} when + * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were. + * @param b Vector of constants in the linear system. + * @return The solution to x in the linear system Ux = b. * @throws SingularMatrixException If the matrix {@code U} is singular (i.e. has a zero on the principle diagonal). */ @Override @@ -131,14 +130,13 @@ public Vector solve(Matrix U, Vector b) { /** - * Solves the linear system of equations given by UX = B where the coefficient matrix U - * is an {@link Matrix#isTriU() upper triangular} matrix. + * Solves the linear system of equations given by UX = B where the coefficient matrix + * U is an {@link Matrix#isTriU() upper triangular} matrix. * * @param U Upper triangular coefficient matrix in the linear system. If {@code enforceTriU} was set to {@code false} when - * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were - * and only the upper triangular entries will be accessed. - * @param B Constant matrix, B, in the linear system. - * @return The solution to X in the linear system UX = B. + * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were. + * @param B Matrix of constants in the linear system. + * @return The solution to X in the linear system UX = B. * @throws SingularMatrixException If the matrix {@code U} is singular (i.e. has a zero on the principle diagonal). */ @Override @@ -186,14 +184,15 @@ public Matrix solve(Matrix U, Matrix B) { /** - * Solves the linear system of equations given by UX = I where the coefficient matrix U + * Solves the linear system of equations given by UX = I where the coefficient matrix + * U * is an {@link Matrix#isTriU() upper triangular} matrix and I is the {@link Matrix#isI() identity} - * matrix of appropriate size. This essentially inverts the upper triangular matrix since UU-1 = I. + * matrix of appropriate size. This essentially inverts the upper triangular matrix since + * UU-1 = I. * * @param U Upper triangular coefficient matrix in the linear system. If {@code enforceTriU} was set to {@code false} when - * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were - * and only the upper triangular entries will be accessed. - * @return The solution to X in the linear system UX = B. + * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were. + * @return The solution to X in the linear system UX = B. * @throws SingularMatrixException If the matrix {@code U} is singular (i.e. has a zero on the principle diagonal). */ public Matrix solveIdentity(Matrix U) { @@ -237,16 +236,17 @@ public Matrix solveIdentity(Matrix U) { /** - * Solves a special case of the linear system UX = L for X where the coefficient matrix - * U is an {@link Matrix#isTriU() upper triangular} matrix and the constant matrix L is + * Solves a special case of the linear system UX = L for X + * where the coefficient matrix U + * is an {@link Matrix#isTriU() upper triangular} matrix and the constant matrix L is * {@link Matrix#isTriL() lower triangular}. * - * @param U Upper triangular coefficient matrix, U, in the linear system. If {@code enforceTriU} was set to - * {@code false} when this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if - * it were and only the upper triangular entries will be accessed. - * @param L Lower triangular constant matrix, L. This is not explicit checked. If {@code L} is not lower - * triangular, it will be treated as if it were and only the lower triangular entries will be accessed. - * @return The result of solving the linear system UX = L for the matrix X. + * @param U Upper triangular coefficient matrix in the linear system. If {@code enforceTriU} was set to {@code false} when + * this solver instance was created and {@code U} is not actually upper triangular, it will be treated as if it were. + * @param L Lower triangular constant matrix. This is not explicit checked. If {@code L} is not lower triangular, values above + * the principle diagonal will be ignored and the result will still be correctly computed. + * @return The result of solving the linear system UX = L for the matrix + * X. */ public Matrix solveLower(Matrix U, Matrix L) { checkParams(U, L.shape); diff --git a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/RealForwardSolver.java b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/RealForwardSolver.java index 5a6ae8b4c..d38d67b40 100644 --- a/src/main/java/org/flag4j/linalg/solvers/exact/triangular/RealForwardSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/exact/triangular/RealForwardSolver.java @@ -32,8 +32,9 @@ import org.flag4j.util.exceptions.SingularMatrixException; /** - * This solver solves linear systems of equations where the coefficient matrix is lower triangular. - * That is, solves the systems Lx = b or LX = B where L is a lower triangular + * This solver solves a real linear system of equations where the coefficient matrix is lower triangular. + * That is, solves the systems Lx = b or LX = B + * where L is a lower triangular * matrix. This is accomplished using a simple forward substitution. * * @see ComplexForwardSolver @@ -94,12 +95,15 @@ public double getDet() { /** - * Performs forward substitution for a unit lower triangular matrix L and a vector b. - * That is, solves the linear system Lx = b for x where L is lower triangular. - * @param L Lower triangular coefficient matrix L. {@code L} is assumed to be lower triangular and only entries + * Performs forward substitution for a unit lower triangular matrix L and a vector + * b. + * That is, solves the linear system Lx = b for x + * where L is lower triangular. + * @param L Lower triangular coefficient matrix L. {@code L} is assumed to be lower + * triangular and only entries * at and below the principle diagonal will be accessed. - * @param b Constant vector b. - * @return The result of solving the linear system Lx = b where L is a lower triangular. + * @param b Constant vector b. + * @return The result of solving the linear system Lx = b where L is a lower triangular. * @throws SingularMatrixException If {@code L} is singular (i.e. has at least one zero on the principle diagonal). */ @Override @@ -109,12 +113,16 @@ public Vector solve(Matrix L, Vector b) { /** - * Performs forward substitution for a unit lower triangular matrix L and a matrix B. - * That is, solves the linear system LX = B for X where L is lower triangular. - * @param L Lower triangular coefficient matrix L. {@code L} is assumed to be lower triangular and only entries + * Performs forward substitution for a unit lower triangular matrix L and a matrix + * B. + * That is, solves the linear system LX = B for X where + * L is lower triangular. + * @param L Lower triangular coefficient matrix L. {@code L} is assumed to be lower + * triangular and only entries * at and below the principle diagonal will be accessed. - * @param b Constant matrix B. - * @return The result of solving the linear system LX = B where L is a lower triangular. + * @param b Constant matrix B. + * @return The result of solving the linear system LX = B where + * L is a lower triangular. * @throws SingularMatrixException If {@code L} is singular (i.e. has at least one zero on the principle diagonal). */ @Override @@ -124,11 +132,12 @@ public Matrix solve(Matrix L, Matrix B) { /** - * Solves a linear system LX = P for X where L is a lower triangular matrix and - * P is a permutation matrix. - * @param L Lower triangular coefficient matrix L. - * @param P Constant permutation matrix P. - * @return The solution to X in the linear system LX = P. + * Solves a linear system LX = P for X where + * L is a lower triangular matrix and + * P is a permutation matrix. + * @param L Lower triangular coefficient matrix L. + * @param P Constant permutation matrix P. + * @return The solution to X in the linear system LX = P. */ @Override public Matrix solve(Matrix L, PermutationMatrix P) { @@ -138,12 +147,12 @@ public Matrix solve(Matrix L, PermutationMatrix P) { /** - * Performs forward substitution for a unit lower triangular matrix L and the identity matrix. - * That is, solves the linear system LX = I where L is a lower triangular matrix and - * I is the appropriately sized identity matrix. - * @param L Lower triangular coefficient matrix, L. If {@code L} is not lower triangular, it will be treated + * Performs forward substitution for a unit lower triangular matrix L and the identity matrix. + * That is, solves the linear system LX = I where L is a lower triangular matrix and + * I is the appropriately sized identity matrix. + * @param L Lower triangular coefficient matrix, L. If {@code L} is not lower triangular, it will be treated * as if it were and only data in the lower triangular portion will be accessed. - * @return The result of solving the linear system LX = B where L is a lower triangular matrix. + * @return The result of solving the linear system LX = B where L is a lower triangular matrix. * @throws SingularMatrixException If the matrix lower triangular {@code L} is singular * (i.e. has at least one zero on the principle diagonal). */ @@ -154,10 +163,10 @@ public Matrix solveIdentity(Matrix L) { /** - * Solves the linear system Lx = b where L is unit lower triangular. + * Solves the linear system Lx = b where L is unit lower triangular. * @param L Unit lower triangular matrix. * @param b Vector of constants in the linear system. - * @return The solution of x for the linear system Lx = b. + * @return The solution of x for the linear system Lx = b. */ private Vector solveUnitLower(Matrix L, Vector b) { checkParams(L, b.size); @@ -188,7 +197,7 @@ private Vector solveUnitLower(Matrix L, Vector b) { * Solves a linear system where the coefficient matrix is lower triangular. * @param L Unit lower triangular matrix. * @param b Vector of constants in the linear system. - * @return The solution of x for the linear system Lx = b. + * @return The solution of x for the linear system Lx = b. * @throws SingularMatrixException If the lower triangular matrix {@code L} is singular (i.e. has a zero on the * principle diagonal). */ @@ -224,7 +233,7 @@ private Vector solveLower(Matrix L, Vector b) { * Solves a linear system where the coefficient matrix is unit lower triangular. * @param L Unit lower triangular matrix. * @param B Matrix of constants in the linear system. - * @return The solution of X for the linear system LX = B. + * @return The solution to X in the linear system LX = B. */ private Matrix solveUnitLower(Matrix L, Matrix B) { checkParams(L, B.numRows); @@ -263,7 +272,7 @@ private Matrix solveUnitLower(Matrix L, Matrix B) { * Solves a linear system where the coefficient matrix is lower triangular. * @param L Unit lower triangular matrix. * @param B Matrix of constants in the linear system. - * @return The solution of X for the linear system LX = B. + * @return The solution of X for the linear system LX = B. * @throws SingularMatrixException If the lower triangular matrix {@code L} is singular (i.e. has a zero on the * principle diagonal). */ @@ -312,7 +321,7 @@ private Matrix solveLower(Matrix L, Matrix B) { * Solves a linear system where the coefficient matrix is unit lower triangular and the constant matrix * is the identity matrix. * @param L Unit lower triangular matrix. - * @return The solution of X for the linear system LX = I. + * @return The solution of X for the linear system LX = I. */ private Matrix solveUnitLowerIdentity(Matrix L) { checkParams(L, L.numRows); @@ -348,11 +357,11 @@ private Matrix solveUnitLowerIdentity(Matrix L) { /** - * Solves a linear system LX = I where the coefficient matrix L is lower triangular and the + * Solves a linear system LX = I where the coefficient matrix L is lower triangular and the * constant matrix I is the appropriately sized identity matrix. * @param L Unit lower triangular matrix (Note, this is not checked). * If {@code L} is not lower triangular, it will be treated as if it were. No error will be thrown. - * @return The solution of X for the linear system LX = I. + * @return The solution of X for the linear system LX = I. * @throws SingularMatrixException If the lower triangular matrix {@code L} is singular (i.e. has a zero on the * principle diagonal). */ @@ -394,10 +403,11 @@ private Matrix solveLowerIdentity(Matrix L) { /** - * Solves a linear system LX=P where the coefficient matrix L is lower triangular and the - * constant matrix P is a permutation matrix. - * @param L Lower triangular coefficient matrix L. - * @return The solution of X to the linear system LX=P. + * Solves a linear system LX = P where the coefficient matrix L is lower triangular and the + * constant matrix P is a permutation matrix. + * @param L Lower triangular coefficient matrix L. + * @return The solution of X to the linear system LX = P. * @throws SingularMatrixException If {@code L} is singular (i.e. has a zero on the principle diagonal). */ private Matrix solvePerm(Matrix L, PermutationMatrix P) { @@ -444,10 +454,11 @@ private Matrix solvePerm(Matrix L, PermutationMatrix P) { /** - * Solves a linear system LX=P where the coefficient matrix L is unit-lower triangular and the - * constant matrix P is a permutation matrix. - * @param L Unit lower triangular coefficient matrix L. - * @return The solution of X to the linear system LX=P. + * Solves a linear system LX = P where the coefficient matrix L is unit-lower triangular and the + * constant matrix P is a permutation matrix. + * @param L Unit lower triangular coefficient matrix L. + * @return The solution of X to the linear system LX = P. */ private Matrix solveUnitPerm(Matrix L, PermutationMatrix P) { checkParams(L, P.size); diff --git a/src/main/java/org/flag4j/linalg/solvers/lstsq/ComplexLstsqSolver.java b/src/main/java/org/flag4j/linalg/solvers/lstsq/ComplexLstsqSolver.java index 5e9ef5f0b..3278a5689 100644 --- a/src/main/java/org/flag4j/linalg/solvers/lstsq/ComplexLstsqSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/lstsq/ComplexLstsqSolver.java @@ -25,71 +25,93 @@ package org.flag4j.linalg.solvers.lstsq; +import org.flag4j.arrays.backend.MatrixMixin; +import org.flag4j.arrays.backend.VectorMixin; import org.flag4j.arrays.dense.CMatrix; import org.flag4j.arrays.dense.CVector; import org.flag4j.linalg.decompositions.qr.ComplexQR; import org.flag4j.linalg.solvers.exact.triangular.ComplexBackSolver; /** - *

                        Instances of this class solve real linear systems of the form Ax = b or AX = B + *

                        Instances of this class solve complex linear systems of the form Ax = b or + * AX = B * in a least-squares sense. The system may be under-, well-, or over-determined. * Specifically, this solver minimizes the sum of squared residuals: *

                          - *
                        • ||Ax - b||22 for vector-based problems, or
                        • - *
                        • ||AX - B||F2 for matrix-based where problems
                        • + *
                        • ||Ax - b||22 for vector-based problems, or
                        • + *
                        • ||AX - B||F2 for matrix-based where problems
                        • *
                        - * where ||·||2 is the Euclidean vector norm and ||·||F + * where ||·||2 is the Euclidean vector norm and + * ||·||F * is the Frobenius norm. This is equivalent to solving the normal equations given by: - * AHAx = AHb or AHAX = AHB + * AHAx = AHb or + * AHAX = AHB * *

                        Usage:

                        - *

                        A single system may be solved by calling either {@link #solve(CMatrix, CVector)} or - * {@link #solve(CMatrix, CVector)}. + *

                        A single system may be solved by calling either {@link LstsqSolver#solve(MatrixMixin, VectorMixin)} or + * {@link LstsqSolver#solve(MatrixMixin, VectorMixin)}. * - *

                        Instances of this solver may also be used to efficiently solve many systems of the form Ax = b or - * AX = B - * for the same coefficient matrix A but numerous constant vectors/matrices b or - * B. To do this, the workflow would be as follows: + *

                        Instances of this solver may also be used to efficiently solve many systems of the form + * Ax = b or + * AX = B + * for the same coefficient matrix A but numerous constant vectors/matrices + * b or B. + * To do this, the workflow would be as follows: *

                          *
                        1. Create an instance of {@code RealLstsqSolver}.
                        2. - *
                        3. Call {@link #decompose(CMatrix) decompse(A)} once on the coefficient matrix A.
                        4. - *
                        5. Call {@link #solve(CVector) solve(b)} or {@link #solve(CMatrix) solve(B)} as many times as needed to solve each - * system for with the various b vectors and/or B matrices.
                        6. + *
                        7. Call {@link LstsqSolver#decompose(MatrixMixin) decompse(A)} once on the coefficient matrix A.
                        8. + *
                        9. Call {@link LstsqSolver#solve(VectorMixin) solve(b)} or {@link LstsqSolver#solve(MatrixMixin) solve(B)} as many times as + * needed to solve each + * system for with the various b vectors and/or + * B matrices.
                        10. *
                        * - * Note: Any call made to one of the following methods after a call to {@link #decompose(CMatrix) decompse(A)} will - * override the coefficient matrix set that call: + * Note: Any call made to one of the following methods after a call to {@link LstsqSolver#decompose(MatrixMixin) + * decompse(A)} will override the coefficient matrix set that call: *
                          - *
                        • {@link #solve(CMatrix, CVector)}
                        • - *
                        • {@link #solve(CMatrix, CMatrix)}
                        • + *
                        • {@link LstsqSolver#solve(MatrixMixin, VectorMixin)}
                        • + *
                        • {@link LstsqSolver#solve(MatrixMixin, MatrixMixin)}
                        • *
                        * *

                        Implementation Notes:

                        *

                        Minimizing the sum of squared residuals is achieved by computing a QR decomposition of the coefficient - * matrix A: - *

                        - * A = QR - *
                        - * where Q is an orthonormal matrix and R is an upper triangular matrix. - * The normal equations then reduces to: - *
                        - * AHAx = AHb or AHAX = AHB
                        + * matrix A: + *
                        + * A = QR + *
                        + * where Q is a unity matrix and R + * is an upper triangular matrix. The normal equations then reduces to: + *
                        + * AHAx = AHb or AHAX = AHB
                        * - * ⇒ (QR)HQRx = (QR)Hb - *   or   (QR)HQRX = (QR)HB
                        + * ⇒ (QR)HQRx = (QR)Hb + *   or   (QR)HQRX = (QR)HB
                        * - * ⇒ RHQHQRx = RHQHb - *   or   RHQHQRX = RHQHB
                        + * ⇒ RHQHQRx = RHQHb + *   or   RHQHQRX = RHQHB
                        * - * ⇒ RHRx = RHQHb - *   or   RHRX = RHQHB - * since Q is orthonormal.
                        + * ⇒ RHRx = RHQHb + *   or   RHRX = RHQHB + * since Q is unity.
                        * - * ⇒ Rx = QHb - *   or   RX = QHB - *
                        - * which is easily solved by back-substitution on R. In the real case, QH simply - * becomes QH. + * ⇒ Rx = QHb + *   or   RX = QHB + *
                        + * + * + * + * which is easily solved by back-substitution on R. + * + * @see ComplexLstsqSolver */ public class ComplexLstsqSolver extends LstsqSolver { diff --git a/src/main/java/org/flag4j/linalg/solvers/lstsq/LstsqSolver.java b/src/main/java/org/flag4j/linalg/solvers/lstsq/LstsqSolver.java index 021021963..9e2b9780c 100644 --- a/src/main/java/org/flag4j/linalg/solvers/lstsq/LstsqSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/lstsq/LstsqSolver.java @@ -32,30 +32,33 @@ /** - *

                        An abstract solver for linear systems of the form Ax = b or AX = B + *

                        An abstract solver for linear systems of the form Ax = b or + * AX = B * in a least-squares sense. The system may be under-, well-, or over-determined. * Specifically, this solver minimizes the sum of squared residuals: *

                          - *
                        • ||Ax - b||22 for vector-based problems, or
                        • - *
                        • ||AX - B||F2 for matrix-based where problems
                        • + *
                        • ||Ax - b||22 for vector-based problems, or
                        • + *
                        • ||AX - B||F2 for matrix-based where problems
                        • *
                        - * where ||·||2 is the Euclidean vector norm and ||·||F + * where ||·||2 is the Euclidean vector norm and + * ||·||F * is the Frobenius norm. This is equivalent to solving the normal equations given by: - * AHAx = AHb or AHAX = AHB + * AHAx = AHb or + * AHAX = AHB * *

                        Usage:

                        *

                        A single system may be solved by calling either {@link #solve(MatrixMixin, VectorMixin)} or * {@link #solve(MatrixMixin, VectorMixin)}. * - *

                        Instances of this solver may also be used to efficiently solve many systems of the form Ax = b or - * AX = B - * for the same coefficient matrix A but numerous constant vectors/matrices b or - * B. To do this, the workflow would be as follows: + *

                        Instances of this solver may also be used to efficiently solve many systems of the form + * Ax = b or AX = B + * for the same coefficient matrix A but numerous constant vectors/matrices b or + * B. To do this, the workflow would be as follows: *

                          *
                        1. Create a concrete instance of {@code LstsqSolver}.
                        2. - *
                        3. Call {@link #decompose(MatrixMixin) decompse(A)} once on the coefficient matrix A.
                        4. + *
                        5. Call {@link #decompose(MatrixMixin) decompse(A)} once on the coefficient matrix A.
                        6. *
                        7. Call {@link #solve(VectorMixin) solve(b)} or {@link #solve(MatrixMixin) solve(B)} as many times as needed to solve each - * system for with the various b vectors and/or B matrices.
                        8. + * system for with the various b vectors and/or B matrices. *
                        * * Note: Any call made to one of the following methods after a call to {@link #decompose(MatrixMixin) decompse(A)} will @@ -67,30 +70,42 @@ * *

                        Implementation Notes:

                        *

                        Minimizing the sum of squared residuals is achieved by computing a QR decomposition of the coefficient - * matrix A: - *

                        - * A = QR - *
                        - * where Q is a unitary/orthonormal matrix and R is an upper triangular matrix. - * The normal equations then reduces to: - *
                        - * AHAx = AHb or AHAX = AHB
                        + * matrix A: + *
                        + * A = QR + *
                        + * where Q is a unitary/orthonormal matrix and R + * is an upper triangular matrix. The normal equations then reduces to: + *
                        + * AHAx = AHb or AHAX = AHB
                        * - * ⇒ (QR)HQRx = (QR)Hb - *   or   (QR)HQRX = (QR)HB
                        + * ⇒ (QR)HQRx = (QR)Hb + *   or   (QR)HQRX = (QR)HB
                        * - * ⇒ RHQHQRx = RHQHb - *   or   RHQHQRX = RHQHB
                        + * ⇒ RHQHQRx = RHQHb + *   or   RHQHQRX = RHQHB
                        * - * ⇒ RHRx = RHQHb - *   or   RHRX = RHQHB - * since Q is unitary/orthonormal.
                        + * ⇒ RHRx = RHQHb + *   or   RHRX = RHQHB + * since Q is unitary/orthonormal.
                        * - * ⇒ Rx = QHb - *   or   RX = QHB - *
                        - * which is easily solved by back-substitution on R. In the real case, QH simply - * becomes QT. + * ⇒ Rx = QHb + *   or   RX = QHB + *
                        + * + * + * + * which is easily solved by back-substitution on R. In the real case, + * QH simply + * becomes QT. * * @param The matrix type in the linear system. * @param The vector type in the linear system. @@ -108,11 +123,11 @@ public abstract class LstsqSolver, U extends V */ protected final UnitaryDecomposition qr; /** - * The Hermitian transpose of the unitary matrix, Q, from the QR decomposition. + * The Hermitian transpose of the unitary matrix, Q, from the QR decomposition. */ protected T Qh; /** - * The upper triangular matrix, R, from the QR decomposition. + * The upper triangular matrix, R, from the QR decomposition. */ protected T R; @@ -129,14 +144,15 @@ protected LstsqSolver(UnitaryDecomposition qr, LinearMatrixSolver ba /** - * Solves the linear system given by Ax = b in a least-squares sense. + * Solves the linear system given by Ax = b in a least-squares sense. * *

                        Note: Any call of this method will override the coefficient matrix specified in any previous calls to * {@link #decompose(MatrixMixin)} on the same solver instance. * - * @param A Coefficient matrix, A, in the linear system. - * @param b Constant vector, b, in the linear system. - * @return The least-squares solution to x in the linear system Ax = b. + * @param A Coefficient matrix, A, in the linear system. + * @param b Constant vector, b, in the linear system. + * @return The least-squares solution to c in the linear system + * Ax = b. */ @Override public U solve(T A, U b) { @@ -146,15 +162,16 @@ public U solve(T A, U b) { /** - * Solves the linear system of equation given by AX = B for the matrix X in a + * Solves the linear system of equation given by AX = B for the matrix + * X in a * least-squares sense. * *

                        Note: Any call of this method will override the coefficient matrix specified in any previous calls to * {@link #decompose(MatrixMixin)} on the same solver instance. * - * @param A Coefficient matrix, A, in the linear system. - * @param B Constant matrix, B, in the linear system. - * @return The solution to x in the linear system AX = B. + * @param A Coefficient matrix, A, in the linear system. + * @param B Constant matrix, B, in the linear system. + * @return The solution to X in the linear system AX = B. */ @Override public T solve(T A, T B) { @@ -164,10 +181,11 @@ public T solve(T A, T B) { /** - * Solves the linear system given by Ax = b in a least-squares sense. + * Solves the linear system given by Ax = b in a least-squares sense. * - * @param b Constant vector, b, in the linear system. - * @return The solution to x in the linear system Ax = b for the last A passed to + * @param b Constant vector, b, in the linear system. + * @return The solution to x in the linear system Ax = b + * for the last A passed to * {@link #decompose(MatrixMixin)}. * @throws IllegalStateException If no coefficient matrix has been specified for this solver by first calling one of the following: *

                          @@ -187,10 +205,12 @@ public U solve(U b) { /** - * Solves the set of linear system of equations given by AX = B for the matrix X in a least-squares sense. + * Solves the set of linear system of equations given by AX = B for the matrix + * X in a least-squares sense. * - * @param B Constant matrix, B, in the linear system. - * @return The solution to X in the linear system AX = B for the last A passed to + * @param B Constant matrix, B, in the linear system. + * @return The solution to X in the linear system AX = B + * for the last A passed to * {@link #decompose(MatrixMixin)}. * @throws IllegalStateException If no coefficient matrix has been specified for this solver by first calling one of the following: *
                            @@ -210,7 +230,7 @@ public T solve(T B) { /** - *

                            Computes (or updates) the QR decomposition of the given matrix A + *

                            Computes (or updates) the QR decomposition of the given matrix A * for use in subsequent solves. * *

                            Subclasses may override this method to customize how the QR decomposition is computed or updated. diff --git a/src/main/java/org/flag4j/linalg/solvers/lstsq/RealLstsqSolver.java b/src/main/java/org/flag4j/linalg/solvers/lstsq/RealLstsqSolver.java index 88ab14677..da06e7ed7 100644 --- a/src/main/java/org/flag4j/linalg/solvers/lstsq/RealLstsqSolver.java +++ b/src/main/java/org/flag4j/linalg/solvers/lstsq/RealLstsqSolver.java @@ -24,6 +24,8 @@ package org.flag4j.linalg.solvers.lstsq; +import org.flag4j.arrays.backend.MatrixMixin; +import org.flag4j.arrays.backend.VectorMixin; import org.flag4j.arrays.dense.Matrix; import org.flag4j.arrays.dense.Vector; import org.flag4j.linalg.decompositions.qr.RealQR; @@ -31,77 +33,98 @@ /** - *

                            Instances of this class solve real linear systems of the form Ax = b or AX = B + *

                            Instances of this class solve real linear systems of the form Ax = b or + * AX = B * in a least-squares sense. The system may be under-, well-, or over-determined. * Specifically, this solver minimizes the sum of squared residuals: *

                              - *
                            • ||Ax - b||22 for vector-based problems, or
                            • - *
                            • ||AX - B||F2 for matrix-based where problems
                            • + *
                            • ||Ax - b||22 for vector-based problems, or
                            • + *
                            • ||AX - B||F2 for matrix-based where problems
                            • *
                            - * where ||·||2 is the Euclidean vector norm and ||·||F + * where ||·||2 is the Euclidean vector norm and + * ||·||F * is the Frobenius norm. This is equivalent to solving the normal equations given by: - * ATAx = ATb or ATAX = ATB + * ATAx = ATb or + * ATAX = ATB * *

                            Usage:

                            - *

                            A single system may be solved by calling either {@link #solve(Matrix, Vector)} or - * {@link #solve(Matrix, Vector)}. + *

                            A single system may be solved by calling either {@link LstsqSolver#solve(MatrixMixin, VectorMixin)} or + * {@link LstsqSolver#solve(MatrixMixin, VectorMixin)}. * - *

                            Instances of this solver may also be used to efficiently solve many systems of the form Ax = b or - * AX = B - * for the same coefficient matrix A but numerous constant vectors/matrices b or - * B. To do this, the workflow would be as follows: + *

                            Instances of this solver may also be used to efficiently solve many systems of the form + * Ax = b or + * AX = B + * for the same coefficient matrix A but numerous constant vectors/matrices + * b or B. + * To do this, the workflow would be as follows: *

                              *
                            1. Create an instance of {@code RealLstsqSolver}.
                            2. - *
                            3. Call {@link #decompose(Matrix) decompse(A)} once on the coefficient matrix A.
                            4. - *
                            5. Call {@link #solve(Vector) solve(b)} or {@link #solve(Matrix) solve(B)} as many times as needed to solve each - * system for with the various b vectors and/or B matrices.
                            6. + *
                            7. Call {@link LstsqSolver#decompose(MatrixMixin) decompse(A)} once on the coefficient matrix A.
                            8. + *
                            9. Call {@link LstsqSolver#solve(VectorMixin) solve(b)} or {@link LstsqSolver#solve(MatrixMixin) solve(B)} as many times as + * needed to solve each + * system for with the various b vectors and/or + * B matrices.
                            10. *
                            * - * Note: Any call made to one of the following methods after a call to {@link #decompose(Matrix) decompse(A)} will - * override the coefficient matrix set that call: + * Note: Any call made to one of the following methods after a call to {@link LstsqSolver#decompose(MatrixMixin) + * decompse(A)} will override the coefficient matrix set that call: *
                              - *
                            • {@link #solve(Matrix, Vector)}
                            • - *
                            • {@link #solve(Matrix, Matrix)}
                            • + *
                            • {@link LstsqSolver#solve(MatrixMixin, VectorMixin)}
                            • + *
                            • {@link LstsqSolver#solve(MatrixMixin, MatrixMixin)}
                            • *
                            * *

                            Implementation Notes:

                            *

                            Minimizing the sum of squared residuals is achieved by computing a QR decomposition of the coefficient - * matrix A: - *

                            - * A = QR - *
                            - * where Q is an orthonormal matrix and R is an upper triangular matrix. - * The normal equations then reduces to: - *
                            - * ATAx = ATb or ATAX = ATB
                            + * matrix A: + *
                            + * A = QR + *
                            + * where Q is a orthonormal matrix and R + * is an upper triangular matrix. The normal equations then reduces to: + *
                            + * ATAx = ATb or ATAX = ATB
                            * - * ⇒ (QR)TQRx = (QR)Tb - *   or   (QR)TQRX = (QR)TB
                            + * ⇒ (QR)TQRx = (QR)Tb + *   or   (QR)TQRX = (QR)TB
                            * - * ⇒ RTQTQRx = RTQTb - *   or   RTQTQRX = RTQTB
                            + * ⇒ RTQTQRx = RTQTb + *   or   RTQTQRX = RTQTB
                            * - * ⇒ RTRx = RTQTb - *   or   RTRX = RTQTB - * since Q is orthonormal.
                            + * ⇒ RTRx = RTQTb + *   or   RTRX = RTQTB + * since Q is orthonormal.
                            * - * ⇒ Rx = QTb - *   or   RX = QTB - *
                            - * which is easily solved by back-substitution on R. In the real case, QT simply - * becomes QT. + * ⇒ Rx = QTb + *   or   RX = QTB + *
                            + * + * + * + * which is easily solved by back-substitution on R. + * + * @see ComplexLstsqSolver */ public class RealLstsqSolver extends LstsqSolver { /** - * Creates a solver for solving real linear systems of the form Ax = b or AX = B + * Creates a solver for solving real linear systems of the form Ax = b + * or AX = B * in a least-squares sense. The system may be under-, well-, or over-determined. * The solution is computed by minimizing the sum of squared residuals: * *
                              - *
                            • ||Ax - b||22 for vector-based problems, or
                            • - *
                            • ||AX - B||F2 for matrix-based where problems
                            • + *
                            • ||Ax - b||22 for vector-based problems, or
                            • + *
                            • ||AX - B||F2 for matrix-based where problems
                            • *
                            */ public RealLstsqSolver() { diff --git a/src/main/java/org/flag4j/linalg/transformations/Givens.java b/src/main/java/org/flag4j/linalg/transformations/Givens.java index f096d20a6..37d11e9f2 100644 --- a/src/main/java/org/flag4j/linalg/transformations/Givens.java +++ b/src/main/java/org/flag4j/linalg/transformations/Givens.java @@ -38,17 +38,19 @@ /** * Utility class for constructing and applying Givens rotation matrices for both real and complex-valued matrices. * - *

                            Givens rotations are orthogonal (unitary in the complex case) transformations used in numerical linear algebra - * for applications such as QR decomposition, Hessenberg reduction, and least-squares solutions. - * A Givens rotation is a matrix G(i, j, θ) which, when left multiplied to a vector, represents - * a counterclockwise rotation of θ radians of the vector in the (i, j) plane. + *

                            Givens rotations are orthogonal (unitary in the complex case) transformations used for applications such as + * the QR decomposition, Hessenberg reduction, and least-squares solutions. + * A Givens rotation is a matrix G(i, j, θ) which, when left multiplied to a vector, + * represents a counterclockwise rotation of a vector in the (i, j) plane by + * θ radians. * *

                            Supported Operations:

                            *
                              *
                            • General Givens rotation matrices for arbitrary rotation angles.
                            • *
                            • Specialized rotators for zeroing elements in a given vector.
                            • - *
                            • Efficient 22 Givens rotations for small-scale transformations.
                            • - *
                            • Optimized left and right multiplication of 2×2 rotators for structured matrices.
                            • + *
                            • Efficient 2×2 Givens rotations for small-scale transformations.
                            • + *
                            • Optimized left and right multiplication of 2×2 rotators + * for structured matrices.
                            • *
                            * *

                            Usage Examples:

                            @@ -78,7 +80,7 @@ * } * * - *
                          • Applying a 2×2 Givens Rotator. + *
                          • Applying a 2×2 Givens Rotator. *
                            {@code
                              * Matrix A = ...;  // Some matrix
                              * Matrix G = Givens.get2x2Rotator(3.0, 4.0);
                            @@ -97,14 +99,15 @@ private Givens() {
                             
                                 /**
                                  * Constructs a general Givens rotation matrix. This method can be numerically unstable. See
                            -     * {@link #getRotator(Vector, int)} if the goal is to zero an element of a vector using a Givens rotator. This method
                            +     * {@link #getRotator(Vector, int)} if the goal is to zero an element of a vector using a Givens rotator. That method
                                  * will produce more accurate results in general and is more robust to overflows.
                                  * @param size The size of the Givens' rotation matrix.
                                  * @param i Index of the first axis to rotate through.
                                  * @param j Index of the second axis to rotate through.
                            -     * @param theta Angle in radians of rotation through the (i, j) plane.
                            +     * @param theta Angle in radians of rotation through the (i, j) plane.
                                  * @return A Givens' rotation matrix with specified {@code size} which, when left multiplied to a vector,
                            -     * represents a counterclockwise rotation of {@code theta} radians of the vector in the (i, j) plane.
                            +     * represents a counterclockwise rotation of {@code theta} radians of the vector in the
                            +     * (i, j) plane.
                                  * @throws IndexOutOfBoundsException If {@code i} or {@code j} is greater than or equal to {@code size}.
                                  */
                                 public static Matrix getGeneralRotator(int size, int i, int j, double theta) {
                            @@ -127,13 +130,24 @@ public static Matrix getGeneralRotator(int size, int i, int j, double theta) {
                             
                             
                                 /**
                            -     * Constructs a Givens rotator G such that for a vector v,
                            -     * Gv = [r1 ... ri ... rn] where ri=0.
                            -     * That is, when the rotator G is left multiplied to the vector v, it zeros out the entry at position {@code i}.
                            -     * @param v Vector v to construct Givens rotator for.
                            -     * @param i Position to zero out when applying the rotator to v.
                            -     * @return A Givens rotator G such that for a vector v,
                            -     * Gv = [r1 ... ri ... rn] where ri=0.
                            +     * Constructs a Givens rotator G such that for a vector
                            +     * v,
                            +     * Gv = [r1 ... ri ... rn]
                            +     *      where
                            +     * ri = 0.
                            +     * That is, when the rotator G is left multiplied to the vector v,
                            +     * it zeros out the entry at position {@code i}.
                            +     * @param v Vector v to construct Givens rotator for.
                            +     * @param i Position to zero out when applying the rotator to v.
                            +     * @return A Givens rotator G such that for a vector
                            +     * v,
                            +     * 
                            +     *  where
                            +     * ri = 0.
                                  * @throws IndexOutOfBoundsException If {@code i} is not in the range [0, v.size).
                                  */
                                 public static Matrix getRotator(Vector v, int i) {
                            @@ -142,14 +156,24 @@ public static Matrix getRotator(Vector v, int i) {
                             
                             
                                 /**
                            -     * Constructs a Givens rotator G such that for a vector v,
                            -     * Gv = [r1 ... ri ... rn] where ri=0.
                            -     * That is, when the rotator G is left multiplied to the vector v,
                            +     * Constructs a Givens rotator G such that for a vector 
                            +     * v,
                            +     * 
                            +     *     Gv = [r1 ... ri ... rn]
                            +     *      where ri = 0.
                            +     * That is, when the rotator G is left multiplied to the vector 
                            +     * v,
                                  * it zeros out the entry at position {@code i}.
                            -     * @param v Vector v to construct Givens rotator for.
                            -     * @param i Position to zero out when applying the rotator to v.
                            -     * @return A Givens rotator G such that for a vector v,
                            -     * Gv = [r1 ... ri ... rn] where ri=0.
                            +     * @param v Vector v to construct Givens rotator for.
                            +     * @param i Position to zero out when applying the rotator to v.
                            +     * @return A Givens rotator G such that for a vector 
                            +     * v,
                            +     * Gv = [r1 ... ri ... rn]
                            +     *      where ri = 0.
                                  * @throws IndexOutOfBoundsException If {@code i} is not in the range [0, v.size).
                                  */
                                 public static Matrix getRotator(double[] v, int i) {
                            @@ -169,14 +193,26 @@ public static Matrix getRotator(double[] v, int i) {
                             
                             
                                 /**
                            -     * Constructs a Givens rotator G such that for a vector v,
                            -     * Gv = [r1 ... ri ... rn] where ri=0.
                            -     * That is, when the rotator G is left multiplied to the vector v,
                            +     * Constructs a Givens rotator G such that for a vector
                            +     * v,
                            +     * 
                            +     *     Gv = [r1 ... ri ... rn]
                            +     *     
                            +     *      where ri = 0.
                            +     * That is, when the rotator G is left multiplied to the vector 
                            +     * v,
                                  * it zeros out the entry at position {@code i}.
                            -     * @param v Vector v to construct Givens rotator for.
                            -     * @param i Position to zero out when applying the rotator to v.
                            -     * @return A Givens rotator G such that for a vector v,
                            -     * Gv = [r1 ... ri ... rn] where ri=0.
                            +     * @param v Vector v to construct Givens rotator for.
                            +     * @param i Position to zero out when applying the rotator to v.
                            +     * @return A Givens rotator G such that for a vector v,
                            +     * 
                            +     *     Gv = [r1 ... ri ... rn]
                            +     *     
                            +     *      where ri = 0.
                                  * @throws IndexOutOfBoundsException If {@code i} is not in the range [0, v.size).
                                  */
                                 public static CMatrix getRotator(CVector v, int i) {
                            @@ -198,11 +234,14 @@ public static CMatrix getRotator(CVector v, int i) {
                             
                             
                                 /**
                            -     * Constructs a Givens rotator G of size 2 such that for a vector v = [a, b] we have
                            -     * Gv = [r, 0].
                            -     * @param v Vector v of size 2 to construct Givens rotator for.
                            -     * @return A Givens rotator G of size 2 such that for a vector v = [a, b] we have
                            -     * Gv = [r, 0].
                            +     * Constructs a Givens rotator G of size 2 such that for a vector
                            +     * v = [a, b]  we have
                            +     * Gv = [r, 0] .
                            +     * @param v Vector v of size 2 to construct Givens rotator for.
                            +     * @return A Givens rotator G of size 2 such that for a vector
                            +     * v = [a, b] 
                            +     *     we have
                            +     * Gv = [r, 0] .
                                  * @throws IllegalArgumentException If {@code v.size != 2}.
                                  */
                                 public static Matrix get2x2Rotator(Vector v) {
                            @@ -212,11 +251,14 @@ public static Matrix get2x2Rotator(Vector v) {
                             
                             
                                 /**
                            -     * Constructs a Givens rotator G of size 2 such that for a vector v = [a, b] we have Gv = [r, 0].
                            -     * @param v0 First entry in vector v to construct rotator for.
                            -     * @param v1 Second entry in vector v to construct rotator for.
                            -     * @return A Givens rotator G of size 2 such that for a vector v = [a, b] we have
                            -     * Gv = [r, 0].
                            +     * Constructs a Givens rotator G of size 2 such that for a vector
                            +     * v = [a, b]  we have
                            +     * Gv = [r, 0] .
                            +     * @param v0 First entry in vector v to construct rotator for.
                            +     * @param v1 Second entry in vector v to construct rotator for.
                            +     * @return A Givens rotator G of size 2 such that for a vector
                            +     * v = [a, b]  we have
                            +     * Gv = [r, 0] .
                                  */
                                 public static Matrix get2x2Rotator(double v0, double v1) {
                                     double[] cs = stableTrigVals(v0, v1);
                            @@ -229,33 +271,38 @@ public static Matrix get2x2Rotator(double v0, double v1) {
                             
                             
                                 /**
                            -     * 

                            Left multiplies a 2×2 Givens rotator to a matrix at the specified row. This is done in place. + *

                            Left multiplies a 2×2 Givens rotator to a matrix at the specified i. + * This is done in place. * - *

                            Specifically, computes G*A[i-1:i+1][i-1:i+1] where i={@code row}, G is the 2×2 Givens rotator, - * A is the matrix to apply the reflector to, and A[i-1:i+1][i-1:] - * represents the slice of A the reflector effects which has shape 2×{@code (A.numCols - i - 1)}. + *

                            Specifically, computes GA[i-1:i+1][i-1:i+1] where i={@code i}, + * G is the + * 2×2 Givens rotator, + * A is the matrix to apply the reflector to, and + * A[i-1:i+1][i-1:] + * represents the slice of A the reflector effects which has shape + * 2×{@code (A.numCols - i - 1)}. * *

                            This method is likely to be faster than computing this multiplication explicitly. * * @param src The matrix to left multiply the rotator to (modified). - * @param G The 2×2 givens rotator. Note, the size is not explicitly checked. - * @param row The row to the rotator is being applied to. + * @param G The 2×2 givens rotator. Note, the size is not explicitly checked. + * @param i The i to the rotator is being applied to. * @param workArray Array to store temporary values. If {@code null}, a new array will be created (modified). * @throws ArrayIndexOutOfBoundsException If the {@code workArray} is not at least large enough to store the * {@code 2*(A.numCols - i - 1)} data. */ - public static void leftMult2x2Rotator(Matrix src, Matrix G, int row, double[] workArray) { + public static void leftMult2x2Rotator(Matrix src, Matrix G, int i, double[] workArray) { double[] src1 = G.data; double[] src2 = src.data; int cols2 = src.numCols; - int destCols = cols2 - (row - 1); + int destCols = cols2 - (i - 1); if(workArray==null) workArray = new double[2*destCols]; else Arrays.fill(workArray, 0, 2*destCols, 0.0); // Ensure that the work-array gets zeroed out. - int m = row - 1; + int m = i - 1; int rowOffset1 = m*cols2 + m; int rowOffset2 = (m + 1)*cols2 + m; @@ -277,39 +324,42 @@ public static void leftMult2x2Rotator(Matrix src, Matrix G, int row, double[] wo } System.arraycopy(workArray, 0, src2, m*cols2 + m, destCols); - System.arraycopy(workArray, destCols, src2, row*cols2 + m, destCols); + System.arraycopy(workArray, destCols, src2, i*cols2 + m, destCols); } /** - *

                            Right multiplies a 2×2 Givens rotator to a matrix at the specified row. This is done in place + *

                            Right multiplies a 2×2 Givens rotator to a matrix at the specified i. + * This is done in place * - *

                            Specifically, computes A[:][i-1:i+1]*GH - * where i={@code row}, G is the 2×2 Givens rotator, A is the matrix to apply the reflector to, and - * A[:i+1][i-1:i+1] - * represents the slice of A the reflector effects which has shape {@code row+1}×2. + *

                            Specifically, computes A[:][i-1:i+1]GH + * where i={@code i}, G is the + * 2×2 Givens rotator, A is the matrix to apply the + * reflector to, and + * A[:i+1][i-1:i+1] + * represents the slice of A the reflector effects which has shape {@code i+1}×2. * *

                            This method is likely to be faster than computing this multiplication explicitly. * * @param src The matrix to left multiply the rotator to (modified). - * @param G The 2×2 givens rotator. Note, the size is not explicitly checked. - * @param row The row to the rotator is being applied to. + * @param G The 2×2 givens rotator. Note, the size is not explicitly checked. + * @param i The i to the rotator is being applied to. * @param workArray Array to store temporary values. If {@code null}, a new array will be created (modified). * If the {@code workArray} is not at least large enough to store the - * {@code 2*(row+1)} data. + * {@code 2*(i+1)} data. */ - public static void rightMult2x2Rotator(Matrix src, Matrix G, int row, double[] workArray) { + public static void rightMult2x2Rotator(Matrix src, Matrix G, int i, double[] workArray) { double[] src1 = src.data; double[] src2 = G.data; int cols1 = src.numCols; int rows1 = src.numRows; if(workArray==null) - workArray = new double[2*rows1]; // Has shape (row+1, 2). + workArray = new double[2*rows1]; // Has shape (i+1, 2). else Arrays.fill(workArray, 0, 2*rows1 + 2, 0.0); // Ensure that the work-array gets zeroed out. - int m = row - 1; + int m = i - 1; double g11 = src2[0]; double g12 = src2[1]; @@ -317,10 +367,10 @@ public static void rightMult2x2Rotator(Matrix src, Matrix G, int row, double[] w double g22 = src2[3]; // Apply the rotator. - for(int i=0; iLeft multiplies a 2×2 Givens rotator to a matrix at the specified row. This is done in place. + *

                            Left multiplies a 2×2 Givens rotator to a matrix at the specified i. + * This is done in place. * - *

                            Specifically, computes G*A[i-1:i+1][i-1:i+1] where i={@code row}, G is the 2×2 Givens rotator, - * A is the matrix to apply the reflector to, and A[i-1:i+1][i-1:] - * represents the slice of A the reflector effects which has shape 2×{@code A.numCols - i - 1}. + *

                            Specifically, computes GA[i-1:i+1][i-1:i+1] where i={@code i}, + * G is the 2×2 Givens rotator, + * A is the matrix to apply the reflector to, and + * A[i-1:i+1][i-1:] + * represents the slice of A the reflector effects which has shape + * 2×{@code A.numCols - i - 1}. * *

                            This method is likely to be faster than computing this multiplication explicitly. * * @param src The matrix to left multiply the rotator to (modified). - * @param G The 2×2 givens rotator. Note, the size is not explicitly checked. - * @param row The row to the rotator is being applied to. + * @param G The 2×2 givens rotator. Note, the size is not explicitly checked. + * @param i The i to the rotator is being applied to. * @param workArray Array to store temporary values. If {@code null}, a new array will be created (modified). * If the {@code workArray} is not at least large enough to store the * {@code 2*(A.numCols - i - 1)} data. */ - public static void leftMult2x2Rotator(CMatrix src, CMatrix G, int row, Complex128[] workArray) { + public static void leftMult2x2Rotator(CMatrix src, CMatrix G, int i, Complex128[] workArray) { Complex128[] src1 = G.data; Complex128[] src2 = src.data; int cols2 = src.shape.get(1); - int destCols = (cols2 - (row-1)); + int destCols = (cols2 - (i-1)); if(workArray==null) workArray = new Complex128[2*destCols]; else Arrays.fill(workArray, 0, 2*destCols, Complex128.ZERO); - int m = row-1; + int m = i-1; int rowOffset1 = m*cols2 + m; int rowOffset2 = (m + 1)*cols2 + m; @@ -387,36 +441,40 @@ public static void leftMult2x2Rotator(CMatrix src, CMatrix G, int row, Complex12 // Copy result back into src matrix. System.arraycopy(workArray, 0, src2, m*cols2 + m, destCols); - System.arraycopy(workArray, destCols, src2, row*cols2 + m, destCols); + System.arraycopy(workArray, destCols, src2, i*cols2 + m, destCols); } /** - *

                            Right multiplies a 2×2 Givens rotator to a matrix at the specified row. This is done in place + *

                            Right multiplies a 2×2 Givens rotator to a matrix at the specified i. + * This is done in place * - *

                            Specifically, computes A[:][i-1:i+1]*GH - * where i={@code row}, G is the 2×2 Givens rotator, A is the matrix to apply the reflector to, and - * A[:i+1][i-1:i+1] represents the slice of A the reflector effects which has shape {@code row+1}×2. + *

                            Specifically, computes A[:][i-1:i+1]GH + * where i={@code i}, G is the + * 2×2 Givens rotator, A is the matrix to + * apply the reflector to, and + * A[:i+1][i-1:i+1] represents the slice of A the reflector + * effects which has shape {@code i+1}×2. * *

                            This method is likely to be faster than computing this multiplication explicitly. * * @param src The matrix to left multiply the rotator to (modified). - * @param G The 2×2 givens rotator. Note, the size is not explicitly checked. - * @param row The row to the rotator is being applied to. + * @param G The 2×2 givens rotator. Note, the size is not explicitly checked. + * @param i The i to the rotator is being applied to. * @param workArray Array to store temporary values. If {@code null}, a new array will be created (modified). - * If the {@code workArray} is not at least large enough to store the - * {@code 2*(row+1)} data. + * If the {@code workArray} is not at least large enough to store the + * {@code 2*(i+1)} data. */ - public static void rightMult2x2Rotator(CMatrix src, CMatrix G, int row, Complex128[] workArray) { + public static void rightMult2x2Rotator(CMatrix src, CMatrix G, int i, Complex128[] workArray) { Complex128[] src1 = src.data; Complex128[] src2 = G.data; int cols1 = src.numCols; int rows1 = src.numRows; - if(workArray==null) workArray = new Complex128[2*rows1]; // Has shape (row+1, 2) + if(workArray==null) workArray = new Complex128[2*rows1]; // Has shape (i+1, 2) Arrays.fill(workArray, Complex128.ZERO); - int m = row - 1; + int m = i - 1; Complex128 g11 = src2[0].conj(); Complex128 g12 = src2[1].conj(); @@ -424,10 +482,10 @@ public static void rightMult2x2Rotator(CMatrix src, CMatrix G, int row, Complex1 Complex128 g22 = src2[3].conj(); // Apply the rotator. - for(int i=0; iG of size 2 such that for a vector v = [a, b] we have Gv = [r, 0]. - * @param v Vector v to construct Givens rotator for. - * @return A Givens rotator G of size 2 such that for a vector v = [a, b] we have Gv = [r, 0]. + * Constructs a Givens rotator G of size 2 such that for a vector + * v = [a, b] + * we have Gv = [r, 0] + * . + * @param v Vector v to construct Givens rotator for. + * @return A Givens rotator G of size 2 such that for a vector + * v = [a, b] + * we have Gv = [r, 0] + * . * @throws IllegalArgumentException If {@code v.size != 2}. */ public static CMatrix get2x2Rotator(CVector v) { @@ -457,11 +521,14 @@ public static CMatrix get2x2Rotator(CVector v) { /** - * Constructs a Givens rotator G of size 2 such that for a vector v = [a, b] we have Gv = [r, 0]. - * @param v0 First entry in vector v to construct rotator for. - * @param v1 Second entry in vector v to construct rotator for. - * @return A Givens rotator G of size 2 such that for a vector v = [a, b] we have Gv = [r, 0]. - * @throws IllegalArgumentException If {@code v.size != 2}. + * Constructs a Givens rotator G of size 2 such that for a vector + * v = [a, b] + * we have Gv = [r, 0] . + * @param v0 First entry in vector v to construct rotator for. + * @param v1 Second entry in vector v to construct rotator for. + * @return A Givens rotator G of size 2 such that for a vector + * v = [a, b] + * we have Gv = [r, 0] . */ public static CMatrix get2x2Rotator(Complex128 v0, Complex128 v1) { double maxAbs = Math.max(v0.abs(), v1.abs()); @@ -481,7 +548,8 @@ public static CMatrix get2x2Rotator(Complex128 v0, Complex128 v1) { /** - * Computes the sine and cosine values for a Givens' rotation in a stable manner which reduces the risk of over/underflow problems. + * Computes the sine and cosine values for a Givens' rotation in a stable manner + * which reduces the risk of over/underflow problems. * @return An array of length two containing in order the cosine value and sine value for the Givens' rotation. */ private static double[] stableTrigVals(double a, double b) { diff --git a/src/main/java/org/flag4j/linalg/transformations/Householder.java b/src/main/java/org/flag4j/linalg/transformations/Householder.java index a1e31fb12..acff93ab3 100644 --- a/src/main/java/org/flag4j/linalg/transformations/Householder.java +++ b/src/main/java/org/flag4j/linalg/transformations/Householder.java @@ -71,15 +71,18 @@ public static Matrix getReflector(Vector normal) { /** - * Computes the vector {@code v} in of a Householder matrix {@code H=I-2vv}T where {@code H} is a + * Computes the vector v in of a Householder matrix + * H = I-2vvT where H is a * transformation matrix which reflects a vector across the plane normal to {@code normal}. * *

                            This method may be used in conjunction with {@link #leftMultReflector(Matrix, Vector, double, int, int, int)} and - * {@link #rightMultReflector(Matrix, Vector, double, int, int, int)} to efficiently apply reflectors. Doing this is O(n^2) - * while forming the full Householder matrix and performing matrix multiplication is O(n^3) + * {@link #rightMultReflector(Matrix, Vector, double, int, int, int)} to efficiently apply reflectors. + * Doing this is O(n^2) while forming the full Householder matrix and performing + * matrix multiplication is O(n^3). * - * @param normal Vector normal to the plane which {@code H} reflects across. - * @return The vector {@code v} in of a Householder matrix {@code H=I-2vv}T which reflects across a plane + * @param normal Vector normal to the plane which H reflects across. + * @return The vector v in of a Householder matrix + * H = I-2vvT which reflects across a plane * normal to {@code normal}. */ public static Vector getVector(Vector normal) { @@ -107,8 +110,9 @@ public static Vector getVector(Vector normal) { * is normal to the specified {@code normal} vector. * *

                            This method may be used in conjunction with {@link #leftMultReflector(CMatrix, CVector, Complex128, int, int, int)} and - * {@link #rightMultReflector(CMatrix, CVector, Complex128, int, int, int)} to efficiently apply reflectors. Doing this is O(n^2) - * while forming the full Householder matrix and performing matrix multiplication is O(n^3) + * {@link #rightMultReflector(CMatrix, CVector, Complex128, int, int, int)} to efficiently apply reflectors. Doing this is + * O(n^2) + * while forming the full Householder matrix and performing matrix multiplication is O(n^3) * * @param normal The vector normal to the plane the Householder reflector will reflect through\. * @return A transformation matrix which describes a reflection through a plane containing the origin with the @@ -137,10 +141,11 @@ public static CMatrix getReflector(CVector normal) { /** - * Left multiplies a Householder matrix H = I - αvvT, represented by the vector - * v, to another matrix A. That is, computes HTA = (I - αvvT)TA. + * Left multiplies a Householder matrix H = I - αvvT, represented by the vector + * v, to another matrix A. That is, computes + * HA = (I - αvvT)A. * @param src Source matrix apply Householder vector to (modified). - * @param householderVector Householder vector v. + * @param householderVector Householder vector v. * @param alpha Scalar value in Householder matrix. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param startRow Starting row of sub-matrix in {@code src} to apply reflector to. @@ -184,10 +189,11 @@ public static void leftMultReflector(Matrix src, /** - * Right multiplies a Householder matrix {@code H=I-}&alpha{@code vv}T, represented by the vector - * {@code v}, to another matrix {@code A}. That is, computes {@code A*H = A*(I-}&alpha{@code vv}T{@code )}. + * Right multiplies a Householder matrix H = I-α vvT, represented by the vector + * v, to another matrix A. That is, computes + * AHT = A(I-α vvT)T. * @param src Source matrix apply Householder vector to (modified). - * @param householderVector Householder vector {@code v}. + * @param householderVector Householder vector v. * @param alpha Scalar value in Householder matrix. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param startRow Starting row of sub-matrix in {@code src} to apply reflector to. @@ -216,10 +222,11 @@ public static void rightMultReflector(Matrix src, /** - * Left multiplies a Householder matrix {@code H=I-}&alpha{@code vv}H, represented by the vector - * {@code v}, to another matrix {@code A}. That is, computes {@code H*A = (I-}&alpha{@code vv}H{@code )*A}. + * Left multiplies a Householder matrix H = I-α vvH, represented by the vector + * v, to another matrix A. + * That is, computes HA = (I-α vvH)A. * @param src Source matrix apply Householder vector to (modified). - * @param householderVector Householder vector {@code v}. + * @param householderVector Householder vector v. * @param alpha Scalar value in Householder matrix. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param startRow Starting row of sub-matrix in {@code src} to apply reflector to. @@ -261,10 +268,11 @@ public static void leftMultReflector(CMatrix src, /** - * Right multiplies a Householder matrix {@code H=I-}&alpha{@code vv}H, represented by the vector - * {@code v}, to another matrix {@code A}. That is, computes {@code A*H = A*(I-}&alpha{@code vv}H{@code )}. + * Right multiplies a Householder matrix H = I-α vvH, represented by the vector + * v, to another matrix A. That is, computes + * AHH = A(I-α vvH)H. * @param src Source matrix apply Householder vector to (modified). - * @param householderVector Householder vector {@code v}. + * @param householderVector Householder vector v. * @param alpha Scalar value in Householder matrix. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param startRow Starting row of sub-matrix in {@code src} to apply reflector to. @@ -294,16 +302,19 @@ public static void rightMultReflector(CMatrix src, /** - *

                            Applies a Householder matrix {@code H=I-}&alpha{@code vv}T, represented by the vector {@code v} to a - * symmetric matrix {@code A} on both the left and right side. That is, computes {@code H*A*H}. + *

                            Applies a Householder matrix H = I-α vvT, represented by the vector + * v to a + * symmetric matrix A on both the left and right side. That is, computes + * HAHT. * *

                            Note: no check is made to * explicitly check that the {@code src} matrix is actually symmetric. * * @param src Matrix to apply the Householder reflector to. Assumed to be square and symmetric. Upper triangular portion * overwritten with the result. - * @param householderVector Householder vector {@code v} from the definition of a Householder reflector matrix. - * @param alpha The scalar &alpha value in Householder reflector matrix definition. + * @param householderVector Householder vector v from the definition of a Householder reflector + * matrix. + * @param alpha The scalar α value in Householder reflector matrix definition. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param workArray Array for storing temporary values during the computation. Contents will be overwritten. */ @@ -350,13 +361,14 @@ public static void symmLeftRightMultReflector(Matrix src, /** - * Left multiplies a Householder matrix {@code H=I-}&alpha{@code vv}T, represented by the vector - * {@code v}, to another matrix {@code A}. That is, computes {@code H*A = (I-}&alpha{@code vv}T{@code )*A}. + * Left multiplies a Householder matrix H = I-α vvT, represented by the vector + * v, to another matrix A. That is, computes + * HA = (I-α vvT )A. * *

                            This method is significantly more efficient than forming the full Householder matrix and multiplying it to the other * matrix. * @param src Source matrix apply Householder vector to (modified). - * @param householderVector Householder vector {@code v}. + * @param householderVector Householder vector v. * @param alpha Scalar value in Householder matrix. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param startRow Starting row of sub-matrix in {@code src} to apply reflector to. @@ -372,14 +384,15 @@ public static void leftMultReflector(Matrix src, /** - * Right multiplies a Householder matrix {@code H=I-}&alpha{@code vv}T, represented by the vector - * {@code v}, to another matrix {@code A}. That is, computes {@code A*H = A*(I-}&alpha{@code vv}T{@code )}. + * Right multiplies a Householder matrix H = I-α vvT, represented by the vector + * v, to another matrix A. That is, computes + * AHT = A(I-α vvT)T. * *

                            This method is significantly more efficient than forming the full Householder matrix and multiplying it to the other * matrix. * * @param src Source matrix apply Householder vector to (modified). - * @param householderVector Householder vector {@code v}. + * @param householderVector Householder vector v. * @param alpha Scalar value in Householder matrix. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param startRow Starting row of sub-matrix in {@code src} to apply reflector to. @@ -396,14 +409,15 @@ public static void rightMultReflector(Matrix src, /** - * Left multiplies a Householder matrix {@code H=I-}&alpha{@code vv}H, represented by the vector - * {@code v}, to another matrix {@code A}. That is, computes {@code H*A = (I-}&alpha{@code vv}H{@code )*A}. + * Left multiplies a Householder matrix H = I-α vvH, represented by the vector + * v, to another matrix A. + * That is, computes HA = (I-α vvH)A. * *

                            This method is significantly more efficient than forming the full Householder matrix and multiplying it to the other * matrix. * * @param src Source matrix apply Householder vector to (modified). - * @param householderVector Householder vector {@code v}. + * @param householderVector Householder vector v. * @param alpha Scalar value in Householder matrix. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param startRow Starting row of sub-matrix in {@code src} to apply reflector to. @@ -419,14 +433,15 @@ public static void leftMultReflector(CMatrix src, /** - * Right multiplies a Householder matrix {@code H=I-}&alpha{@code vv}H, represented by the vector - * {@code v}, to another matrix {@code A}. That is, computes {@code A*H = A*(I-}&alpha{@code vv}H{@code )}. + * Right multiplies a Householder matrix H = I-α vvH, represented by the vector + * v, to another matrix A. + * That is, computes AHH = A(I-α vvH)H. * *

                            This method is significantly more efficient than forming the full Householder matrix and multiplying it to the other * matrix. * * @param src Source matrix apply Householder vector to (modified). - * @param householderVector Householder vector {@code v}. + * @param householderVector Householder vector v. * @param alpha Scalar value in Householder matrix. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param startRow Starting row of sub-matrix in {@code src} to apply reflector to. @@ -442,16 +457,17 @@ public static void rightMultReflector(CMatrix src, /** - *

                            Applies a Householder matrix {@code H=I-}&alpha{@code vv}H, represented by the vector {@code v} to a - * Hermitian matrix {@code A} on both the left and right side. That is, computes {@code H*A*H}. + *

                            Applies a Householder matrix H = I-α vvH, represented by the vector v to a + * Hermitian matrix A on both the left and right side. + * That is, computes HAHH. * *

                            Note: no check is made to * explicitly check that the {@code src} matrix is actually Hermitian. * * @param src Matrix to apply the Householder reflector to. Assumed to be square and Hermitian. Upper triangular portion * overwritten with the result. - * @param householderVector Householder vector {@code v} from the definition of a Householder reflector matrix. - * @param alpha The scalar &alpha value in Householder reflector matrix definition. + * @param householderVector Householder vector v from the definition of a Householder reflector matrix. + * @param alpha The scalar α value in Householder reflector matrix definition. * @param startCol Starting column of sub-matrix in {@code src} to apply reflector to. * @param workArray Array for storing temporary values during the computation. Contents will be overwritten. */ diff --git a/src/main/java/org/flag4j/linalg/transformations/Projection.java b/src/main/java/org/flag4j/linalg/transformations/Projection.java index cbc97df84..dce0f5020 100644 --- a/src/main/java/org/flag4j/linalg/transformations/Projection.java +++ b/src/main/java/org/flag4j/linalg/transformations/Projection.java @@ -62,7 +62,8 @@ private Projection() { /** - * Creates a {@code 4x4} perspective projection matrix to transform a 3D point represented in homogeneous + * Creates a 4×4 perspective projection matrix to transform a 3D point + * represented in homogeneous * coordinates. * * @param fov Field of view in radians (this is the fov in both the {@code x} and {@code y} directions). @@ -94,8 +95,8 @@ public static Matrix getPerspective(double fov, double aspectRatio, double nearC /** - * Creates a {@code 4x4} perspective projection matrix to transform a 3D point represented in homogeneous - * coordinates. + * Creates a 4×4 perspective projection matrix to transform a + * 3D point represented in homogeneous coordinates. * * @param fovX Field of view, in radians, in the {@code x} direction. * @param fovY Field of view, in radians, in the {@code y} direction. @@ -128,7 +129,7 @@ public static Matrix getPerspective(double fovX, double fovY, double aspectRatio /** - * Creates a {@code 4x4} orthogonal projection matrix to project a 3D point in homogeneous coordinates + * Creates a 4×4 orthogonal projection matrix to project a 3D point in homogeneous coordinates * onto the specified 2D coordinate grid (i.e. image plane). * This is an orthographic projection meaning the distance from the virtual camera will not affect the projection. * @param xMin Minimum {@code x} value of image plane to project to. @@ -162,7 +163,7 @@ public static Matrix getOrthogonal(double xMin, double xMax, double yMin, double /** - * Creates a {@code 4x4} orthogonal projection matrix to project a 3D point in homogeneous coordinates + * Creates a 4×4 orthogonal projection matrix to project a 3D point in homogeneous coordinates * onto the specified 2D coordinate grid (i.e. image plane). Here, the minimum {@code x} and {@code y} values are * taken to be zero. * This is an orthographic projection meaning the distance from the virtual camera will not affect the projection. @@ -192,7 +193,8 @@ public static Matrix getOrthogonal(double xMax, double yMax, /** - * Creates a {@code 4x4} orthogonal projection matrix to project a 2D point in an orthographic viewing region. + * Creates a 4×4 orthogonal projection matrix to project a 2D point in an orthographic + * viewing region. * Equivalent to {@link #getOrthogonal(double, double, double, double, double, double)} with {@code nearClip = -1} and * {@code farClip = 1}. * @param xMin Minimum {@code x} value of image plane to project to. @@ -222,7 +224,8 @@ public static Matrix getOrthogonal2D(double xMin, double xMax, double yMin, doub /** - * Creates a {@code 4x4} orthogonal projection matrix to project a 2D point in an orthographic viewing region. the + * Creates a 4×4 orthogonal projection matrix to project a + * 2D point in an orthographic viewing region. The * minimum {@code x} and {@code y} values are assumed to be zero. Equivalent to * {@link #getOrthogonal(double, double, double, double)} with {@code nearClip=-1} and * {@code farClip = 1}. diff --git a/src/main/java/org/flag4j/linalg/transformations/Rotation.java b/src/main/java/org/flag4j/linalg/transformations/Rotation.java index 940f0a869..8f162121f 100644 --- a/src/main/java/org/flag4j/linalg/transformations/Rotation.java +++ b/src/main/java/org/flag4j/linalg/transformations/Rotation.java @@ -33,12 +33,11 @@ * These matrices are designed to perform rotations of vectors in a counterclockwise direction when viewed from a * positive axis perspective in a right-handed coordinate system. * - *

                            - * *

                            This class supports: *

                              *
                            • 2D rotation matrices for rotating column vectors by a specified angle in degrees.
                            • - *
                            • 3D rotation matrices for rotating about the x-axis, y-axis, and z-axis.
                            • + *
                            • 3D rotation matrices for rotating about the x-axis, + * y-axis, and z-axis.
                            • *
                            • 3D rotation matrices for yaw-pitch-roll rotations.
                            • *
                            • 3D rotation matrices for arbitrary axis rotations.
                            • *
                            • 3D rotation matrices for proper Euler angle rotations.
                            • @@ -46,10 +45,10 @@ * *

                              Rotation matrices have the following properties: *

                                - *
                              • A rotation matrix is orthogonal: R-1 = RT.
                              • + *
                              • A rotation matrix is orthogonal: R-1 = RT.
                              • *
                              • Rotations preserve the length of vectors (orthogonal transformations).
                              • - *
                              • The inverse/transpose rotation matrix undoes the rotation: x = RTRx = - * RRTx
                              • + *
                              • The inverse/transpose rotation matrix undoes the rotation: + * x = RTRx = RRTx
                              • *
                              • Successive rotations can be composed through matrix multiplication (rotation order is from right to left).
                              • *
                              * @@ -58,13 +57,13 @@ * // Rotate a 2D vector by 45 degrees. * double theta = 45.0; * Matrix rotation2D = Rotation.rotate2D(theta); - * Vector vector2D = new Vector(1, 0); // A vector along the x-axis + * Vector vector2D = new Vector(1, 0); // A vector along the x-axis * Vector rotatedVector2D = rotation2D.mult(vector2D); * - * // Rotate a 3D vector about the x-axis by 90 degrees. + * // Rotate a 3D vector about the x-axis by 90 degrees. * double thetaX = 90.0; * Matrix rotationX3D = Rotation.rotateX3D(thetaX); - * Vector vector3D = new Vector(0, 1, 0); // A vector along the y-axis + * Vector vector3D = new Vector(0, 1, 0); // A vector along the y-axis * Vector rotatedVector3D = rotationX3D.mult(vector3D); * * // Perform a yaw-pitch-roll rotation in 3D. @@ -82,9 +81,9 @@ * Vector arbitraryRotatedVector = arbitraryAxisRotation.mult(vector3D); * * // Perform a rotation using proper Euler angles. - * double alpha = 30.0; // Rotation about z-axis - * double beta = 45.0; // Rotation about x-axis - * double gamma = 60.0; // Rotation about z-axis again + * double alpha = 30.0; // Rotation about z-axis + * double beta = 45.0; // Rotation about x-axis + * double gamma = 60.0; // Rotation about z-axis again * Matrix eulerRotation = Rotation.rotateEuler3D(alpha, beta, gamma); * Vector eulerRotatedVector = eulerRotation.mult(vector3D); * @@ -113,19 +112,21 @@ private Rotation() { /** - *

                              Constructs a rotation matrix, R(θ), which rotates 2D column vectors {@code theta} degrees. - * When {@code theta > 0} the rotation is counterclockwise. When + *

                              Constructs a rotation matrix, R(θ), which rotates 2D column vectors + * θ degrees. When θ > 0 the rotation is + * counterclockwise. * - *

                              A 2D rotation matrix R(θ), rotates a 2D column vector x, θ degrees by means of + *

                              A 2D rotation matrix R(θ), rotates a 2D column vector + * x, θ degrees by means of * the following matrix-vector multiplication: - *

                              -     *     x' = R(θ)x
                              - * The following holds R(-θ) = R(θ)-1 = R(θ)T. + *
                              +     *     x' = R(θ)x
                              + * The following holds R(-θ) = R(θ)-1 = R(θ)T. * This means the inverse/transpose may be used to undo a rotation, - *
                              -     *     x = R(θ)R(θ)Tx
                              -     *       = R(θ)TR(θ)x
                              -     *       = Ix
                              + *
                              +     *     x = R(θ)R(θ)Tx
                              +     *       = R(θ)TR(θ)x
                              +     *       = Ix
                              * * @param theta The degrees to rotate a 2D vector by. * @return A rotation matrix which rotates (counterclockwise) 2D column vectors {@code theta} degrees. @@ -142,23 +143,29 @@ public static Matrix rotate2D(double theta) { /** - *

                              Constructs a matrix which rotates 3D column vectors about the x-axis {@code theta} degrees. The rotation appears - * counterclockwise when the x-axis points toward the observer, {@code theta > 0} and the coordinate system is right-handed. + *

                              Constructs a matrix which rotates 3D column vectors about the x-axis + * θ degrees. + * The rotation appears counterclockwise when the x-axis points toward the observer, + * θ and the coordinate system is right-handed. * - *

                              A 3D rotation matrix, RX(θ), rotates a 3D column vector x about the x-axis θ degrees by + *

                              A 3D rotation matrix, Rx(θ), rotates a 3D column vector x about the + * x-axis θ + * degrees by * means of the following matrix-vector multiplication: - *

                              -     *     x' = RX(θ)x
                              - * The following holds RX(-θ) = RX(θ)-1 = RX(θ)T. + *
                              +     *     x' = Rx(θ)x
                              + * The following holds + * Rx(-θ) = Rx(θ)-1 + * = Rx(θ)T. * This means the inverse/transpose may be used to undo a rotation, - *
                              -     *     x = RX(θ)RX(θ)Tx
                              -     *       = RX(θ)TRX(θ)x
                              -     *       = Ix
                              + *
                              +     *     x = Rx(θ)Rx(θ)Tx
                              +     *       = Rx(θ)TRx(θ)x
                              +     *       = Ix
                              * * - * @param theta The degrees to rotate a 3D vector about the x-axis by. - * @return matrix which rotates 3D column vectors about the x-axis {@code theta} degrees. + * @param theta The degrees to rotate a 3D vector about the x-axis by. + * @return matrix which rotates 3D column vectors about the x-axis {@code theta} degrees. */ public static Matrix rotateX3D(double theta) { if(theta == 0) return Matrix.I(3); @@ -176,23 +183,27 @@ public static Matrix rotateX3D(double theta) { /** - *

                              Constructs a matrix which rotates 3D column vectors about the y-axis {@code theta} degrees. The rotation appears - * counterclockwise when the y-axis points toward the observer, {@code theta > 0} and the coordinate system is right-handed. + *

                              Constructs a matrix which rotates 3D column vectors about the y-axis + * θ degrees. The rotation appears + * counterclockwise when the y-axis points toward the observer, + * θ > 0 and the coordinate system is right-handed. * - *

                              A 3D rotation matrix, RY(θ), rotates a 3D column vector x about the y-axis θ degrees by + *

                              A 3D rotation matrix, Ry(θ), rotates a 3D column vector x about the + * y-axis θ degrees by * means of the following matrix-vector multiplication: - *

                              -     *     x' = RY(θ)x
                              - * The following holds RY(-θ) = RY(θ)-1 = RY(θ)T. + *
                              +     *     x' = Ry(θ)x
                              + * The following holds + * Ry(-θ) = Ry(θ)-1 + * = Ry(θ)T. * This means the inverse/transpose may be used to undo a rotation, - *
                              -     *     x = RY(θ)RY(θ)Tx
                              -     *       = RY(θ)TRY(θ)x
                              -     *       = Ix
                              - * + *
                              +     *     x = Ry(θ)Ry(θ)Tx
                              +     *       = Ry(θ)TRy(θ)x
                              +     *       = Ix
                              * - * @param theta The degrees to rotate a 3D vector about the y-axis by. - * @return matrix which rotates 3D column vectors about the y-axis {@code theta} degrees. + * @param theta The degrees to rotate a 3D vector about the y-axis by. + * @return matrix which rotates 3D column vectors about the y-axis {@code theta} degrees. */ public static Matrix rotateY3D(double theta) { if(theta == 0) return Matrix.I(3); @@ -210,23 +221,26 @@ public static Matrix rotateY3D(double theta) { /** - *

                              Constructs a matrix which rotates 3D column vectors about the z-axis {@code theta} degrees. The rotation appears - * counterclockwise when the z-axis points toward the observer, {@code theta > 0} and the coordinate system is right-handed. + *

                              Constructs a matrix which rotates 3D column vectors about the z-axis + * θ degrees. The rotation appears + * counterclockwise when the z-axis points toward the observer, + * θ > 0 and the coordinate system is right-handed. * - *

                              A 3D rotation matrix, RZ(θ), rotates a 3D column vector x about the z-axis θ degrees by + *

                              A 3D rotation matrix, Rz(θ), rotates a 3D column vector x about the + * z-axis θ degrees by * means of the following matrix-vector multiplication: - *

                              -     *     x' = RZ(θ)x
                              - * The following holds RZ(-θ) = RZ(θ)-1 = RZ(θ)T. + *
                              +     *     x' = Rz(θ)x
                              + * The following holds Rz(-θ) = Rz(θ)-1 + * = Rz(θ)T. * This means the inverse/transpose may be used to undo a rotation, - *
                              -     *     x = RZ(θ)RZ(θ)Tx
                              -     *       = RZ(θ)TRZ(θ)x
                              -     *       = Ix
                              - * + *
                              +     *     x = Rz(θ)Rz(θ)Tx
                              +     *       = Rz(θ)TRz(θ)x
                              +     *       = Ix
                              * - * @param theta The degrees to rotate a 3D vector about the z-axis by. - * @return matrix which rotates 3D column vectors about the z-axis {@code theta} degrees. + * @param theta The degrees to rotate a 3D vector about the z-axis by. + * @return matrix which rotates 3D column vectors about the z-axis {@code theta} degrees. */ public static Matrix rotateZ3D(double theta) { if(theta == 0) return Matrix.I(3); @@ -244,29 +258,41 @@ public static Matrix rotateZ3D(double theta) { /** - *

                              Constructs a 3D rotation matrix, R(α, β, γ), representing a rotation with yaw, pitch, and roll - * angles - * α, β, and γ respectively. This is equivalent to rotating by α degrees about the x-axis, - * β degrees about the y-axis, and γ degrees about the z-axis in that order. Each of the three rotations appear + *

                              Constructs a 3D rotation matrix, R(α, β, γ), representing a rotation + * with yaw, pitch, and roll angles + * α, β, and + * γ respectively. This is equivalent to rotating by + * α + * degrees about the x-axis, + * β degrees about the y-axis, and + * γ degrees about the + * z-axis in that order. Each of the three rotations appear * counterclockwise when the axis about which they occur points toward the observer, * the rotation angle is positive, and the coordinate system is right-handed. * - *

                              A 3D rotation matrix, R(α, β, γ), rotates a 3D column vector x, - * γ, β, and α degrees about the x-, y-, and z-axes in that order by means of the following matrix + *

                              A 3D rotation matrix, R(α, β, γ), rotates a 3D column vector + * x, + * γ, β, and + * α degrees about the x-, + * y-, and + * z-axes in that order by means of + * the following matrix * multiplication: - *

                              -     *     x' = R(α, β, γ)x
                              -     *        = RZ(γ)RY(β)RX(α)x
                              + *
                              +     *     x' = R(α, β, γ)x
                              +     *        = Rz(γ)Ry(β)Rx(α)x
                              * *

                              Note: This method is susceptible to gimbal lock, a phenomenon where two of the rotation axes align, * causing a loss of one degree of rotational freedom. Gimbal lock occurs when the second rotation in the sequence aligns * the axes, such as when the pitch angle (for yaw-pitch-roll) or the second Euler angle (for proper Euler angles) is - * ±90°. To avoid gimbal lock, consider using rotation representations that do not rely on sequential rotations. + * ±90°. To avoid gimbal lock, consider using rotation representations that do not + * rely on sequential rotations. * - * @param yaw Degrees to rotate about the vertical (yaw) axis (i.e. the z-axis). - * @param pitch Degrees to rotate about the lateral (pitch) axis (i.e. the y-axis). - * @param roll Degrees to rotate about the longitudinal (roll) axis (i.e. the x-axis). - * @return a rotation matrix representing a rotation with yaw, pitch, and roll angles α, β, and γ respectively. + * @param yaw Degrees to rotate about the vertical (yaw) axis (i.e. the z-axis). + * @param pitch Degrees to rotate about the lateral (pitch) axis (i.e. the y-axis). + * @param roll Degrees to rotate about the longitudinal (roll) axis (i.e. the x-axis). + * @return a rotation matrix representing a rotation with yaw, pitch, and roll angles α, + * β, and γ respectively. */ public static Matrix rotate3D(double yaw, double pitch, double roll) { if(yaw == 0.0 && pitch == 0.0 && roll == 0.0) return Matrix.I(3); @@ -291,19 +317,22 @@ public static Matrix rotate3D(double yaw, double pitch, double roll) { /** - *

                              Constructs a 3D rotation matrix, Ru(θ), which representing a rotation of θ degrees about - * an axis unit vector u. The rotation is a counterclockwise rotation when u points towards the observer, θ> 0, + *

                              Constructs a 3D rotation matrix, Ru(θ), which representing a rotation of + * θ degrees about + * an axis unit vector u. The rotation is a counterclockwise rotation when u points towards the observer, + * θ > 0, * and the coordinate system is right-handed. * - *

                              A 3D rotation matrix, Ru(θ), rotates a 3D column vector x, - * θ degrees about the vector u by means of the following matrix multiplication: - *

                              -     *     x' = Ru(θ)x
                              + *

                              A 3D rotation matrix, Ru(θ), rotates a 3D column vector x, + * θ degrees about the vector u by means of the following matrix multiplication: + *

                              +     *     x' = Ru(θ)x
                              * - * @param theta The degrees to rotate about the vector u. - * @param axis The axis vector u to rotate about. This vector will be normalized so it need not be a unit vector. + * @param theta The degrees to rotate about the vector u. + * @param axis The axis vector u to rotate about. This vector will be normalized so it need not be a unit vector. * Must satisfy {@code axis.size == 3}. - * @return + * @return A rotation matrix representing a rotation of {@code theta} degrees about the axis specified + * by {@code axis}. */ public static Matrix rotate3D(double theta, Vector axis) { if(axis.size != 3) @@ -341,25 +370,32 @@ public static Matrix rotate3D(double theta, Vector axis) { /** - *

                              Constructs a 3D rotation matrix, RE(α, β, γ), representing a rotation described - * by proper Euler angles (α, β, γ). This is equivalent to performing a rotation about the z-axis by α - * degrees, then about the x-axis by β degrees, then about the z-axis again by γ degrees. + *

                              Constructs a 3D rotation matrix, RE(α, β, γ), + * representing a rotation described + * by proper Euler angles (α, β, γ). This is equivalent to + * performing a rotation about the + * z-axis by α + * degrees, then about the x-axis by β degrees, then about the + * z-axis again by γ degrees. * - *

                              A 3D rotation matrix, RE(α, β, γ), rotates a 3D column vector x, - * according to the Euler angles (α, β, γ) by means of the following matrix multiplication: - *

                              -     *     x' = RE(α, β, γ)x
                              -     *        = RZ(γ)RX(β)RZ(α)x
                              + *

                              A 3D rotation matrix, RE(α, β, γ), rotates a 3D column vector x, + * according to the Euler angles (α, β, γ) by means of the following + * matrix multiplication: + *

                              +     *     x' = RE(α, β, γ)x
                              +     *        = Rz(γ)Rx(β)Rz(α)x
                              * *

                              Note: This method is susceptible to gimbal lock, a phenomenon where two of the rotation axes align, * causing a loss of one degree of rotational freedom. Gimbal lock occurs when the second rotation in the sequence aligns * the axes, such as when the pitch angle (for yaw-pitch-roll) or the second Euler angle (for proper Euler angles) is - * ±90°. To avoid gimbal lock, consider using rotation representations that do not rely on sequential rotations. + * ±90°. To avoid gimbal lock, consider using rotation representations that do not + * rely on sequential rotations. * - * @param alpha Degrees of first rotation about the z-axis. - * @param beta Degrees of second rotation about the x-axis. - * @param gamma Degrees of third rotation about the z-axis. - * @return Constructs a rotation matrix representing a rotation described by proper Euler angles (α, β, γ). + * @param alpha Degrees of first rotation about the z-axis. + * @param beta Degrees of second rotation about the x-axis. + * @param gamma Degrees of third rotation about the z-axis. + * @return Constructs a rotation matrix representing a rotation described by proper Euler angles + * (α, β, γ). */ public static Matrix rotateEuler(double alpha, double beta, double gamma) { if(alpha == 0.0 && beta == 0.0 && gamma == 0.0) return Matrix.I(3); diff --git a/src/main/java/org/flag4j/rng/RandomComplex.java b/src/main/java/org/flag4j/rng/RandomComplex.java index 4e3cfcf27..ddcbe28f8 100644 --- a/src/main/java/org/flag4j/rng/RandomComplex.java +++ b/src/main/java/org/flag4j/rng/RandomComplex.java @@ -137,13 +137,17 @@ public Complex128 randomComplex128(double min, double max) { min + " and max=" + max + "."); } - return randomComplex128(Math.sqrt(nextDouble()*(max*max - min*min) + min*min)); + double minSq = min*min; + + return randomComplex128(Math.sqrt(nextDouble()*(max*max - minSq) + minSq)); } /** - * Generates a pseudorandom complex number distributed uniformly in the unit square on the complex plane centered at (0.0, 0.0). - * @return A pseudorandom complex number distributed uniformly in the unit square on the complex plane centered at (0.0, 0.0). + * Generates a pseudorandom complex number distributed uniformly in the unit square on the complex plane centered at + * (0, 0). + * @return A pseudorandom complex number distributed uniformly in the unit square on the complex plane centered at + * (0, 0). * @see #randomRectComplex128(double, double, double, double) */ public Complex128 randomRectComplex128() { @@ -168,13 +172,18 @@ public Complex128 randomRectComplex128(double minRe, double maxRe, double minIm, /** *

                              Generates a pseudorandom complex number sampled from a 2D circular standard Gaussian (normal) distribution on the complex - * plain. The distribution is centered at (0.0, 0.0) with standard deviation {@code 1.0} along both the real and imaginary axes + * plain. The distribution is centered at (0, 0) + * with standard deviation σ=1 along both the real and imaginary axes * of the complex plane. * - *

                              The 2D circular standard Gaussian distribution centered at (x0, x0) with standard deviations along each - * axis, σ, is defined as: - *

                              -     *     f(x, y) = 1/(2π) exp[ -1/2 (x2 + y2) ]
                              + *

                              The 2D circular standard Gaussian distribution centered at (x0, x0) + * with standard deviation along both axes, σ, is defined as: + *

                              +     *     f(x, y) = 1/(2π) exp[ -1/2 (x2 + y2) ]
                              + * + * * * @param mean Mean of distribution. * @param std Standard deviation of distribution. Must be greater than zero. @@ -194,10 +203,16 @@ public Complex128 randnComplex128() { * The distribution is centered at ({@code mean}, {@code mean}) with standard deviation {@code std} along * both the real and imaginary axes of the complex plane. * - *

                              The 2D circular Gaussian distribution centered at (x0, x0) with standard deviations along each - * axis, σ, is defined as: - *

                              -     *     f(x, y) = 1/(2πσ2) exp[ -1/(2σ2) ((x - x0)2 + (y - x0)2) ]
                              + *

                              The 2D circular Gaussian distribution centered at (x0, x0) + * with standard deviations along each axis, σ, is defined as: + *

                              +     *     f(x, y) = 1/(2πσ2) exp[ -1/(2σ2) ((x - x0)2 + (y - y0)2) ]
                              + * + * + * * * @param mean Mean of distribution. * @param std Standard deviation of distribution. Must be greater than zero. @@ -219,8 +234,14 @@ public Complex128 randnComplex128(double mean, double std) { * *

                              The 2D Gaussian distribution centered at (x0, y0) with standard deviations along each * axis, σX and σY, is defined as: - *

                              +     * 
                                    *     f(x, y) = 1/(2πσXσY) * exp[ -(x - x0)2/2σX2 - (y - y0)2/2σY2]
                              + *
                              + * + * * * @param meanRe Mean of distribution along real axis. * @param stdRe Standard deviation of distributions along real axis. Must be greater than zero. @@ -243,14 +264,35 @@ public Complex128 randnComplex128(double meanRe, double stdRe, double meanIm, do * the real and imaginary axes of the complex plane respectively. Further, {@code corrCoeff} is the correlation coefficient * between the real and imaginary values. * - *

                              The covariance matrix, Σ, of such a distribution is expressed as: - *

                              -     *   Σ = [      stdRe*stdRe        corrCoeff*stdRe*stdIm ]
                              -     *       [ corrCoeff*stdRe*stdIm        stdIm*stdIm      ]
                              - * Let μ = [x0 y0]T be the mean column vector and z = [x y]T also be a + *

                              The covariance matrix, Σ, of such a distribution is expressed as: + *

                              +     *   Σ = [  σx2    ρσxσy ]
                              +     *       [ ρσxσy     σy2 ]
                              + * + * + * where ρ is the correlation coefficient, + * σx is the standard deviation + * along the real axis, and σy + * is the standard deviation along the imaginary axis. + * + * Let μ = [x0 y0]T + * + * be the mean column vector and z = [x y]T + * also be a * column vector. Then, the bivariate Gaussian distribution may be expressed as: - *
                              -     *     f(z) = 1/(2 π det(Σ)1/2) exp[-1/2 (z - μ)T Σ-1 (z - μ)]
                              + *
                              +     *     f(z) = 1/(2 π det(Σ)1/2) exp[-1/2 (z - μ)T Σ-1 (z - μ)]
                              + *
                              + * + * * * @param meanRe Mean of distribution along real axis. * @param stdRe Standard deviation of distributions along real axis. Must be greater than zero. @@ -273,7 +315,7 @@ public Complex128 randnComplex128(double meanRe, double stdRe, double meanIm, do if(corrCoeff <= -1.0 || corrCoeff >= 1.0) throw new IllegalArgumentException("Correlation coefficient must be in range (-1, 1) but got: " + corrCoeff + "."); - // Unrolled Cholesky decomposition of the 2×2 covariance matrix. + // Unrolled Cholesky decomposition of the 2x2 covariance matrix. double l11 = Math.sqrt(stdRe*stdRe); double l21 = corrCoeff*stdRe*stdIm / l11; double l22 = Math.sqrt(stdIm*stdIm - l21 * l21); @@ -345,10 +387,11 @@ public Complex64 randomComplex64(float min, float max) { } + /** * Generates a pseudorandom complex number distributed uniformly in the unit square on the complex plane centered at (0.0, 0.0). * @return A pseudorandom complex number distributed uniformly in the unit square on the complex plane centered at (0.0, 0.0). - * @see #randomCartComplex64(double, double, double, double) + * @see #randomCartComplex64(float, float, float, float) */ public Complex64 randomCartComplex64() { return new Complex64(nextFloat(), nextFloat()); @@ -372,21 +415,26 @@ public Complex64 randomCartComplex64(float minRe, float maxRe, float minIm, floa /** *

                              Generates a pseudorandom complex number sampled from a 2D circular standard Gaussian (normal) distribution on the complex - * plain. The distribution is centered at (0.0, 0.0) with standard deviation {@code 1.0} along both the real and imaginary axes + * plain. The distribution is centered at (0, 0) + * with standard deviation σ=1 along both the real and imaginary axes * of the complex plane. * - *

                              The 2D circular standard Gaussian distribution centered at (x0, x0) with standard deviations along each - * axis, σ, is defined as: - *

                              -     *     f(x, y) = 1/(2π) exp[ -1/2 (x2 + y2) ]
                              + *

                              The 2D circular standard Gaussian distribution centered at (x0, x0) + * with standard deviation along both axes, σ, is defined as: + *

                              +     *     f(x, y) = 1/(2π) exp[ -1/2 (x2 + y2) ]
                              + * + * * * @param mean Mean of distribution. * @param std Standard deviation of distribution. Must be greater than zero. * @return A pseudorandom complex number sampled from a 2D circular standard Gaussian (normal) distribution on the complex plain. * - * @see #randnComplex64(double, double) - * @see #randnComplex64(double, double, double, double) - * @see #randnComplex64(double, double, double, double, double) + * @see #randnComplex64(float, float) + * @see #randnComplex64(float, float, float, float) + * @see #randnComplex64(float, float, float, float, float) */ public Complex64 randnComplex64() { return randnComplex64(0f, 1f, 0f, 1f); @@ -398,18 +446,24 @@ public Complex64 randnComplex64() { * The distribution is centered at ({@code mean}, {@code mean}) with standard deviation {@code std} along * both the real and imaginary axes of the complex plane. * - *

                              The 2D circular Gaussian distribution centered at (x0, x0) with standard deviations along each - * axis, σ, is defined as: - *

                              -     *     f(x, y) = 1/(2πσ2) exp[ -1/(2σ2) ((x - x0)2 + (y - x0)2) ]
                              + *

                              The 2D circular Gaussian distribution centered at (x0, x0) + * with standard deviations along each axis, σ, is defined as: + *

                              +     *     f(x, y) = 1/(2πσ2) exp[ -1/(2σ2) ((x - x0)2 + (y - y0)2) ]
                              + * + * + * * * @param mean Mean of distribution. * @param std Standard deviation of distribution. Must be greater than zero. * @return A pseudorandom complex number sampled from a 2D circular Gaussian (normal) distribution on the complex plain. * * @see #randnComplex64() - * @see #randnComplex64(double, double, double, double) - * @see #randnComplex64(double, double, double, double, double) + * @see #randnComplex64(float, float, float, float) + * @see #randnComplex64(float, float, float, float, float) */ public Complex64 randnComplex64(float mean, float std) { return randnComplex64(mean, std, mean, std); @@ -423,8 +477,14 @@ public Complex64 randnComplex64(float mean, float std) { * *

                              The 2D Gaussian distribution centered at (x0, y0) with standard deviations along each * axis, σX and σY, is defined as: - *

                              +     * 
                                    *     f(x, y) = 1/(2πσXσY) * exp[ -(x - x0)2/2σX2 - (y - y0)2/2σY2]
                              + *
                              + * + * * * @param meanRe Mean of distribution along real axis. * @param stdRe Standard deviation of distributions along real axis. Must be greater than zero. @@ -432,9 +492,9 @@ public Complex64 randnComplex64(float mean, float std) { * @param stdIm Standard deviation of distributions along imaginary axis. Must be greater than zero. * @return A pseudorandom complex number sampled from a 2D elliptical Gaussian (normal) distribution on the complex plain. * - * @see #randnComplex64(double, double) + * @see #randnComplex64(float, float) * @see #randnComplex64() - * @see #randnComplex64(double, double, double, double, double) + * @see #randnComplex64(float, float, float, float, float) */ public Complex64 randnComplex64(float meanRe, float stdRe, float meanIm, float stdIm) { return new Complex64((float) nextGaussian(meanRe, stdRe), (float) nextGaussian(meanIm, stdIm)); @@ -447,14 +507,35 @@ public Complex64 randnComplex64(float meanRe, float stdRe, float meanIm, float s * the real and imaginary axes of the complex plane respectively. Further, {@code corrCoeff} is the correlation coefficient * between the real and imaginary values. * - *

                              The covariance matrix, Σ, of such a distribution is expressed as: - *

                              -     *   Σ = [      stdRe*stdRe        corrCoeff*stdRe*stdIm ]
                              -     *       [ corrCoeff*stdRe*stdIm        stdIm*stdIm      ]
                              - * Let μ = [x0 y0]T be the mean column vector and z = [x y]T also be a + *

                              The covariance matrix, Σ, of such a distribution is expressed as: + *

                              +     *   Σ = [  σx2    ρσxσy ]
                              +     *       [ ρσxσy     σy2 ]
                              + * + * + * where ρ is the correlation coefficient, + * σx is the standard deviation + * along the real axis, and σy + * is the standard deviation along the imaginary axis. + * + * Let μ = [x0 y0]T + * + * be the mean column vector and z = [x y]T + * also be a * column vector. Then, the bivariate Gaussian distribution may be expressed as: - *
                              -     *     f(z) = 1/(2 π det(Σ)1/2) exp[-1/2 (z - μ)T Σ-1 (z - μ)]
                              + *
                              +     *     f(z) = 1/(2 π det(Σ)1/2) exp[-1/2 (z - μ)T Σ-1 (z - μ)]
                              + *
                              + * + * * * @param meanRe Mean of distribution along real axis. * @param stdRe Standard deviation of distributions along real axis. Must be greater than zero. @@ -465,8 +546,8 @@ public Complex64 randnComplex64(float meanRe, float stdRe, float meanIm, float s * @return A pseudorandom complex number sampled from a bivariate Gaussian (normal) distribution on the complex plain. * @throws IllegalArgumentException If {@code corrCoeff <= -1 || corrCoeff >= 1} or {@code stdRe < 0.0 || stdIm < 0.0}. * - * @see #randnComplex64(double, double) - * @see #randnComplex64(double, double, double, double) + * @see #randnComplex64(float, float) + * @see #randnComplex64(float, float, float, float) * @see #randnComplex64() */ public Complex64 randnComplex64(float meanRe, float stdRe, float meanIm, float stdIm, float corrCoeff) { diff --git a/src/main/java/org/flag4j/rng/RandomDenseTensor.java b/src/main/java/org/flag4j/rng/RandomDenseTensor.java index e65bba1bb..3083d648b 100644 --- a/src/main/java/org/flag4j/rng/RandomDenseTensor.java +++ b/src/main/java/org/flag4j/rng/RandomDenseTensor.java @@ -639,10 +639,10 @@ public Matrix randomDiagMatrix(int size, int min, int max) { /** * Generates a pseudorandom symmetric positive-definite matrix. This is done as if by - *
                              +     * 
                              {@code
                                    *     Matrix D = randomDiagMatrix(size, 0, 1);
                                    *     Matrix Q = randomOrthogonalMatrix(size);
                              -     *     return Q.T().mult(D).mult(Q);
                              + * return Q.T().mult(D).mult(Q);}
                              * @param size Size of the symmetric positive-definite matrix to generate. * @return A pseudorandom symmetric positive-definite matrix. * @see #randomHermPosDefMatrix(int) @@ -656,10 +656,10 @@ public Matrix randomSymmPosDefMatrix(int size) { /** * Generates a pseudorandom symmetric positive-definite matrix. This is done as if by - *
                              +     * 
                              {@code
                                    *     Matrix D = randomDiagMatrix(size, 0, 1);
                                    *     CMatrix U = randomUnitaryMatrix(size);
                              -     *     return U.H().mult(D).mult(U);
                              + * return U.H().mult(D).mult(U);}
                              * @param size Size of the symmetric positive-definite matrix to generate. * @return A pseudorandom symmetric positive-definite matrix. * @see #randomSymmPosDefMatrix(int) diff --git a/src/main/java/org/flag4j/rng/distributions/Complex128BiGaussian.java b/src/main/java/org/flag4j/rng/distributions/Complex128BiGaussian.java index 465f416ad..52517fc56 100644 --- a/src/main/java/org/flag4j/rng/distributions/Complex128BiGaussian.java +++ b/src/main/java/org/flag4j/rng/distributions/Complex128BiGaussian.java @@ -29,7 +29,42 @@ import org.flag4j.rng.RandomComplex; /** - * A 2D bivariateGaussian distribution on the complex plane. + * A 2D bivariate Gaussian distribution on the complex plane. + * + *

                              The covariance matrix, Σ, of such a distribution is expressed as: + *

                              + *   Σ = [  σx2    ρσxσy ]
                              + *       [ ρσxσy     σy2 ]
                              + * + * + * where ρ is the correlation coefficient, + * σx is the standard deviation + * along the real axis, and σy + * is the standard deviation along the imaginary axis. + * + * Let μ = [x0 y0]T + * + * be the mean column vector and z = [x y]T + * also be a + * column vector. Then, the PDF of the bivariate Gaussian distribution may be expressed as: + *
                              + *     f(z) = 1/(2 π det(Σ)1/2) exp[-1/2 (z - μ)T Σ-1 (z - μ)]
                              + *
                              + * + * + * + * @see Complex128UniformRect + * @see Complex128UniformDisk + * @see RealUniform + * @see RealGaussian */ public class Complex128BiGaussian extends Distribution { @@ -54,9 +89,6 @@ public class Complex128BiGaussian extends Distribution -1 && corrCoeff < 1}. - /** * Validated standard deviations and correlation coefficient are within proper bounds. @@ -72,7 +104,7 @@ private void validateParameters() { /** - * Constructs 2D bivariateGaussian distribution on the complex plane with a correlation coefficient of zero. + * Constructs 2D bivariate Gaussian distribution on the complex plane with a correlation coefficient of zero. * To specify a correlation coefficient use {@link #Complex128BiGaussian(RandomComplex, double, double, double, double, double)}. * * @param rng Pseudorandom number generator to use when randomly sampling from this distribution. @@ -93,7 +125,7 @@ public Complex128BiGaussian(RandomComplex rng, double meanRe, double stdRe, doub /** - * Constructs 2D bivariateGaussian distribution on the complex plane with a specified correlation coefficient. + * Constructs 2D bivariate Gaussian distribution on the complex plane with a specified correlation coefficient. * * @param rng Pseudorandom number generator to use when randomly sampling from this distribution. * @param meanRe Mean along real axis of complex plane for the distribution. diff --git a/src/main/java/org/flag4j/rng/distributions/Complex128UniformDisk.java b/src/main/java/org/flag4j/rng/distributions/Complex128UniformDisk.java index dc5f2428c..e015f2a67 100644 --- a/src/main/java/org/flag4j/rng/distributions/Complex128UniformDisk.java +++ b/src/main/java/org/flag4j/rng/distributions/Complex128UniformDisk.java @@ -29,24 +29,57 @@ import org.flag4j.rng.RandomComplex; /** - * A uniform distribution on an annulus (e.g. washer) in the complex plane. + *

                              A uniform distribution over an annulus (i.e. washer) on the complex plane. + * + *

                              A uniform distribution over an annulus is defined over the region between two concentric circles + * with inner radius rinner + * and outer radius router + * and centered at (x, y). + * + *

                              A complex number z = x + yi + re is sampled from this distribution by + * drawing its modulus r from a uniform distribution + * U(rinner, router) + * + * and its argument θ from a uniform distribution + * U(0, 2π) . + * + *

                              The PDF of the joint distribution for a complex value z = x + yi + re is + * given by: + *

                              + *     f(z) = { 1 / [π (router2 - rinner2)] for rinner ≤ |z - (x + yi)| < router, 0 otherwise.
                              + * + * + * + *

                              This distribution ensures that points are uniformly distributed in within the annulus, meaning that the density function + * accounts for the increasing circumference as r increases avoiding "bunching" of points close + * to the inner radius. + * + * @see Complex128UniformRect + * @see Complex128BiGaussian + * @see RealUniform + * @see RealGaussian */ public class Complex128UniformDisk extends Distribution { /** - * Inner radius of the annulus (inclusive). + * Inner radius, rinner + * , of the annulus (inclusive). */ public final double min; /** - * Outer radius of the annulus (exclusive). + * Outer radius, router + * !-- LATEX \(r_{\text{outer}}\) -->, of the annulus (exclusive). */ public final double max; /** - * Real value of the center of the annulus in the complex plane. + * Real value of the center, x, of the annulus in the complex plane. */ public final double centerRe; /** - * Imaginary value of the center of the annulus in the complex plane. + * Imaginary value of the center, y, of the annulus in the complex plane. */ public final double centerIm; /** diff --git a/src/main/java/org/flag4j/rng/distributions/Complex128UniformRect.java b/src/main/java/org/flag4j/rng/distributions/Complex128UniformRect.java index 17923d09c..cca1c13e9 100644 --- a/src/main/java/org/flag4j/rng/distributions/Complex128UniformRect.java +++ b/src/main/java/org/flag4j/rng/distributions/Complex128UniformRect.java @@ -29,25 +29,45 @@ import org.flag4j.rng.RandomComplex; /** - * A rectangular uniform distribution on the complex plane. + *

                              A rectangular uniform distribution on the complex plane. + * + *

                              A rectangular uniform distribution on the complex plane is equivalent to combining two 1D uniform distributions over the real + * and imaginary axes: U(a, b) + * and U(c, d) respectively. + * + *

                              The PDF of the joint distribution of the real component x ~ U(a, b) + * and the complex component y ~ U(c, d) + * for a complex value z = x + iy is given by: + *

                              + *     f(z) = { 1 / [(b - a)(d - c)] for a ≤ Re(z) < b and c ≤ Im(z) < d,  0 otherwise.
                              + * + * + * + * @see Complex128UniformDisk + * @see Complex128BiGaussian + * @see RealUniform + * @see RealGaussian */ public class Complex128UniformRect extends Distribution { /** - * Lower bound of the real component of the uniform distribution (inclusive). + * Lower bound, a, of the real component of the uniform distribution (inclusive). */ public final double minRe; /** - * Upper bound of the real component of the uniform distribution (exclusive). + * Upper bound, b, of the real component of the uniform distribution (exclusive). */ public final double maxRe; /** - * Lower bound of the imaginary component of the uniform distribution (inclusive). + * Lower bound, c, of the imaginary component of the uniform distribution (inclusive). */ public final double minIm; /** - * Upper bound of the imaginary component of the uniform distribution (exclusive). + * Upper bound, d, of the imaginary component of the uniform distribution (exclusive). */ public final double maxIm; diff --git a/src/main/java/org/flag4j/rng/distributions/RealGaussian.java b/src/main/java/org/flag4j/rng/distributions/RealGaussian.java index ffd36baba..4b428dc1d 100644 --- a/src/main/java/org/flag4j/rng/distributions/RealGaussian.java +++ b/src/main/java/org/flag4j/rng/distributions/RealGaussian.java @@ -30,7 +30,21 @@ /** - * A real Gaussian (e.g. normal) distribution. + *

                              A 1D real Gaussian (normal) distribution N(μ, σ2) + * . + * + *

                              The PDF of the 1D real Gaussian distribution N(μ, σ2) + * with mean μ and + * standard deviation σ is given by: + *

                              + *     f(x) = 1 / (2πσ2)1/2 exp[ - (x - μ)2 / (2σ2) ]
                              + * + * + * + * @see RealUniform + * @see Complex128BiGaussian */ public class RealGaussian extends Distribution { diff --git a/src/main/java/org/flag4j/rng/distributions/RealUniform.java b/src/main/java/org/flag4j/rng/distributions/RealUniform.java index 19389d062..aa14af686 100644 --- a/src/main/java/org/flag4j/rng/distributions/RealUniform.java +++ b/src/main/java/org/flag4j/rng/distributions/RealUniform.java @@ -30,16 +30,31 @@ /** - * A uniform real distribution. + *

                              A 1D real uniform distribution U(a, b) . + * + *

                              The PDF of the uniform distribution U(a, b) + * over the half open interval [a, b) where a < b is given + * by: + *

                              + *     f(x) = { 1 / (b - a) for a ≤ x < b,  0 for x < a or x > b.
                              + * + * + * + * @see RealGaussian + * @see Complex128UniformRect + * @see Complex128UniformDisk */ public class RealUniform extends Distribution { /** - * Lower bound of the uniform distribution (inclusive). + * Lower bound, a, of the uniform distribution (inclusive). */ public final double min; /** - * Upper bound of the uniform distribution (exclusive). + * Upper bound, b, of the uniform distribution (exclusive). */ public final double max;