...` 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 = αx + b + * will be solved for x. + * + * (3x2) / (√(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 = αx + b + * will be solved for x. + * + * (3x2) / (√(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 < α ⇒ x < Σi=1N (yi); + * ⇒ x < β+ * + */ +``` + +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: + + + +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: + + + +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"Σ(.*?)(.*?)": 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"\\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 ", + + # 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 " +} +``` 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'
", "") + .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; i
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: *
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(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) { /** - *src) { * return Math.pow(norm, 1.0 / 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: *
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: *
*
* - * @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) { /** - *- {@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. *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: *
*
* - * @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 ------------------------------ /** - *- {@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. *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: *
*
* - * @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) { /** - *- {@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. *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: *
*
* - * @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- {@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. *> 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 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:
+ *
* When permutations are used during balancing we obtain a specific form. First,
+ *
* 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 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:
- * The Cholesky decomposition factorizes a symmetric/Hermitian, positive-definite matrix A as:
+ *
+ * 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.
*
* 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 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:
- * The Cholesky decomposition factorizes a Hermitian/Hermitian, positive-definite matrix A as:
+ * 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.
*
* 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 @@
* 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:
- * The Cholesky decomposition factorizes a symmetric/symmetric, positive-definite matrix A as:
+ * 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.
*
* 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 @@
* Computes the Hessenberg decomposition of a complex dense square matrix.
- * The Hessenberg decomposition decomposes a given square matrix A into the product:
- * The Hessenberg decomposition decomposes a given square matrix A into the product:
+ * 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:
+ *
* 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.
*
*
* [ 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.
*
- *
- * A = LLH
- * where L is a lower triangular matrix.
+ *
+ * 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:
* positive-definiteness Check:
- *
- * A = LLH
- * where L is a lower triangular matrix.
+ *
+ * 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:
* positive-definiteness Check:
- *
- * A = LLT
- * where L is a lower triangular matrix.
+ *
+ * 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:
* positive-definiteness Check:
- *
- * A = QHQH
- * where Q is a unitary matrix and H is an upper Hessenberg matrix, which is similar to A
+ *
+ * A = QHQH
+ * where Q is a unitary matrix and H is an upper Hessenberg matrix, which
* (i.e., it has the same eigenvalues).
*
- *
+ *
* [[ × × × × × ]
* [ × × × × × ]
* [ 0 × × × × ]
* [ 0 0 × × × ]
- * [ 0 0 0 × × ]]
+ * [ 0 0 0 × × ]]
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 × × ]]
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 × × ]]
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 × × ]]
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 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: *
+ * A = LU
- * PA = LU
+ * PA = LU+ * where P is a {@link PermutationMatrix permutation matrix} representing the row swaps. *
- * 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 @@ *
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 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: *
+ * A = LU
- * PA = LU
+ * PA = LU
- * 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 @@ *
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 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: *
+ * A = LU
- * PA = LU
+ * PA = LU+ *
- * 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 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 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: *
+ * A = LU
- * PA = LU
+ * PA = LU
- * 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 @@ *
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: *
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: *
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 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
- * 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:
- * The Schur decomposition decomposes a given square matrix A into:
+ * 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 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
- * 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:
- * The Schur decomposition decomposes a given square matrix A into:
+ * 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 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.
* Reverts the scaling and permutations applied during the balancing step to obtain the correct form.
*
* Specifically, this method computes
- * 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:
* 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:
* 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 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 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 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}.
*
* 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:
* 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 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 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}.
*
* 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:
* 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:
* 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:
* 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 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}.
*
* 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:
* 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 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 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 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:
* 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:
* Minimizing the sum of squared residuals is achieved by computing a QR decomposition of the coefficient
- * matrix A:
- * 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:
* 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:
* Minimizing the sum of squared residuals is achieved by computing a QR decomposition of the coefficient
- * matrix A:
- * 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:
* 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:
* 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:
* Minimizing the sum of squared residuals is achieved by computing a QR decomposition of the coefficient
- * matrix A:
- * 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.
*
* 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; i 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; i 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:
* Rotation matrices have the following properties:
* 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:
- * 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:
- * 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:
- * 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:
- * 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:
- * 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:
- * A 3D rotation matrix, Ru(θ), rotates a 3D column vector x,
+ * θ degrees about the vector u by means of the following matrix multiplication:
+ * 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:
- * A 3D rotation matrix, RE(α, β, γ), rotates a 3D column vector x,
+ * according to the Euler angles (α, β, γ) by means of the following
+ * matrix multiplication:
+ * 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:
- * The 2D circular standard Gaussian distribution centered at (x0, x0)
+ * with standard deviation along both axes, σ, is defined as:
+ * The 2D circular Gaussian distribution centered at (x0, x0) with standard deviations along each
- * axis, σ, is defined as:
- * The 2D circular Gaussian distribution centered at (x0, x0)
+ * with standard deviations along each axis, σ, is defined as:
+ * The 2D Gaussian distribution centered at (x0, y0) with standard deviations along each
* axis, σX and σY, is defined as:
- * The covariance matrix, Σ, of such a distribution is expressed as:
- * The covariance matrix, Σ, of such a distribution is expressed as:
+ * 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:
- * The 2D circular standard Gaussian distribution centered at (x0, x0)
+ * with standard deviation along both axes, σ, is defined as:
+ * The 2D circular Gaussian distribution centered at (x0, x0) with standard deviations along each
- * axis, σ, is defined as:
- * The 2D circular Gaussian distribution centered at (x0, x0)
+ * with standard deviations along each axis, σ, is defined as:
+ * The 2D Gaussian distribution centered at (x0, y0) with standard deviations along each
* axis, σX and σY, is defined as:
- * The covariance matrix, Σ, of such a distribution is expressed as:
- * The covariance matrix, Σ, of such a distribution is expressed as:
+ * The covariance matrix, Σ, of such a distribution is expressed as:
+ * 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 + reiθ 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 + reiθ is
+ * given by:
+ * 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 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:
+ * 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:
+ * 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:
+ *
- * 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 @@
/**
*
- * 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.
+ *
+ * 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.
*
*
- * 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) {
*
*
- * 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.
+ *
+ * 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.
*
*
- *
*/
@@ -186,12 +190,13 @@ public abstract class Schur
- *
* @param rng Random number generator to use when performing random exceptional shifts.
@@ -273,8 +278,10 @@ public Schur
- * 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}.
*
*
- *
*
*
@@ -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).
*
- *
*/
@@ -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).
*
- *
* @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).
*
- *
* @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 @@
*
*
*
@@ -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).
*
- *
*/
@@ -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).
*
- *
- * @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).
*
- *
*/
@@ -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).
*
- *
* @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 @@
/**
*
- *
* @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).
*
- *
* @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
/**
- * Usage:
- *
*
*
- * 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:
*
- *
*
- * Usage:
*
*
*
- * 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:
*
*
@@ -172,9 +182,10 @@ public U solve(U b) {
/**
- *
*
Usage:
- *
*
*
- * 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:
*
- *
*
- *
- *
- * 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:
- *
*
*
- * 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:
*
- *
*
* Implementation Notes:
*
- * 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
- * which is easily solved by back-substitution on R. In the real case, QH simply
- * becomes QH.
+ * ⇒ Rx = QHb
+ * or RX = QHB
+ *
*
- * ⇒ (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
- *
- *
- * 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:
*
*
*
* 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:
*
- * 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
+ *
+ *
+ *
+ * which is easily solved by back-substitution on R. In the real case,
+ * QH simply
+ * becomes QT.
*
* @param
+ * 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
- * which is easily solved by back-substitution on R. In the real case, QH simply
- * becomes QT.
+ * ⇒ Rx = QHb
+ * or RX = QHB
+ *
*
- * ⇒ (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
- *
@@ -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) {
/**
- *
- *
- * 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:
- *
*
*
- * 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:
*
- *
*
* Implementation Notes:
*
- * 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
+ *
+ *
+ *
+ * which is easily solved by back-substitution on R.
+ *
+ * @see ComplexLstsqSolver
*/
public class RealLstsqSolver extends LstsqSolver
+ * 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
- * which is easily solved by back-substitution on R. In the real case, QT simply
- * becomes QT.
+ * ⇒ Rx = QTb
+ * or RX = QTB
+ *
*
- * ⇒ (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
- *
- *
*/
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.
*
- * Supported Operations:
*
*
*
* Usage Examples:
@@ -78,7 +80,7 @@
* }
*
*
- * {@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) {
/**
- *
*
- *
*
@@ -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() {
/**
- *
- * 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) {
/**
- *
- * 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) {
/**
- *
- * 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) {
/**
- *
- * 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) {
/**
- *
- * x' = R(α, β, γ)x
- * = RZ(γ)RY(β)RX(α)x
+ *
+ * x' = R(α, β, γ)x
+ * = Rz(γ)Ry(β)Rx(α)x
*
*
- * x' = Ru(θ)x
+ *
+ * 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) {
/**
- *
- * x' = RE(α, β, γ)x
- * = RZ(γ)RX(β)RZ(α)x
+ *
+ * x' = RE(α, β, γ)x
+ * = Rz(γ)Rx(β)Rz(α)x
*
*
- * f(x, y) = 1/(2π) exp[ -1/2 (x2 + y2) ]
+ *
+ * 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.
*
- *
- * f(x, y) = 1/(2πσ2) exp[ -1/(2σ2) ((x - x0)2 + (y - x0)2) ]
+ *
+ * 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) {
*
*
+ *
* 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.
*
- *
- * Σ = [ 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
+ *
+ * Σ = [ σ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
/**
*
- * f(x, y) = 1/(2π) exp[ -1/2 (x2 + y2) ]
+ *
+ * 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.
*
- *
- * f(x, y) = 1/(2πσ2) exp[ -1/(2σ2) ((x - x0)2 + (y - x0)2) ]
+ *
+ * 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) {
*
*
+ *
* 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.
*
- *
- * Σ = [ 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
+ *
+ * Σ = [ σ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
- *
+ *
* @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);
* 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 #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.
+ *
+ * {@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);}
+ * Σ = [ σ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
+ * f(z) = { 1 / [π (router2 - rinner2)] for rinner ≤ |z - (x + yi)| < router, 0 otherwise.
+ *
+ *
+ *
+ *
+ * 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
+ * f(x) = 1 / (2πσ2)1/2 exp[ - (x - μ)2 / (2σ2) ]
+ *
+ *
+ *
+ * @see RealUniform
+ * @see Complex128BiGaussian
*/
public class RealGaussian extends Distribution
+ * 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