├── .gitattributes ├── 978-1-4842-6796-7.jpg ├── errata.md ├── README.md ├── Contributing.md ├── LICENSE.txt ├── HelloNM.java ├── Chapter1.java ├── Chapter3.java ├── Chapter4.java ├── Chapter11.java ├── Chapter7.java ├── Chapter5.java ├── Chapter8.java ├── Chapter6Integration.java ├── Chapter6Differentiation.java ├── Chapter9.java └── Chapter13.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /978-1-4842-6796-7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/numerical-methods-using-java/HEAD/978-1-4842-6796-7.jpg -------------------------------------------------------------------------------- /errata.md: -------------------------------------------------------------------------------- 1 | # Errata for *Numerical Methods Using Java* 2 | 3 | On **page xx** [Summary of error]: 4 | 5 | Details of error here. Highlight key pieces in **bold**. 6 | 7 | *** 8 | 9 | On **page xx** [Summary of error]: 10 | 11 | Details of error here. Highlight key pieces in **bold**. 12 | 13 | *** -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Numerical Methods Using Java*](https://link.springer.com/book/10.1007/978-1-4842-6797-4) by Haksun Li (Apress, 2022). 4 | 5 | [comment]: #cover 6 | ![Cover image](978-1-4842-6796-7.jpg) 7 | 8 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 9 | 10 | ## Releases 11 | 12 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 13 | 14 | ## Contributions 15 | 16 | See the file Contributing.md for more information on how you can contribute to this repository. -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Freeware License, some rights reserved 2 | 3 | Copyright (c) 2022 Haksun Li 4 | 5 | Permission is hereby granted, free of charge, to anyone obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to work with the Software within the limits of freeware distribution and fair use. 8 | This includes the rights to use, copy, and modify the Software for personal use. 9 | Users are also allowed and encouraged to submit corrections and modifications 10 | to the Software for the benefit of other users. 11 | 12 | It is not allowed to reuse, modify, or redistribute the Software for 13 | commercial use in any way, or for a user’s educational materials such as books 14 | or blog articles without prior permission from the copyright holder. 15 | 16 | The above copyright notice and this permission notice need to be included 17 | in all copies or substantial portions of the software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | 27 | 28 | -------------------------------------------------------------------------------- /HelloNM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.algebra.linear.vector.doubles.Vector; 26 | import dev.nm.algebra.linear.vector.doubles.dense.DenseVector; 27 | 28 | /** 29 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 30 | * 31 | * @author haksunli 32 | * @see 33 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 34 | * https://nm.dev/ 35 | */ 36 | public class HelloNM { 37 | 38 | public static void main(String[] args) { 39 | System.out.println("Hello NM!"); 40 | 41 | Vector v = new DenseVector(1., 2., 3.); 42 | System.out.println(v); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Chapter1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Numerical Method Inc. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.algebra.linear.matrix.doubles.Matrix; 26 | import dev.nm.algebra.linear.matrix.doubles.matrixtype.dense.DenseMatrix; 27 | import dev.nm.algebra.linear.matrix.doubles.operation.Inverse; 28 | import dev.nm.algebra.linear.vector.doubles.Vector; 29 | import dev.nm.algebra.linear.vector.doubles.dense.DenseVector; 30 | 31 | /** 32 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 33 | * 34 | * @author haksunli 35 | * @see 36 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 37 | * https://nm.dev/ 38 | */ 39 | public class Chapter1 { 40 | 41 | public static void main(String[] args) { 42 | System.out.println("Chapter 1 demos"); 43 | 44 | Chapter1 chapter1 = new Chapter1(); 45 | 46 | chapter1.invert_matrix(); 47 | chapter1.innerProductDemo(); 48 | chapter1.a_vector(); 49 | } 50 | 51 | public void a_vector() { 52 | Vector v = new DenseVector(1., 2., 3.); 53 | System.out.println(v); 54 | } 55 | 56 | public void innerProductDemo() { 57 | System.out.println("dot product of two vectors"); 58 | 59 | Vector v1 = new DenseVector(new double[]{1., 2.}); 60 | Vector v2 = new DenseVector(new double[]{3., 4.}); 61 | double product = v1.innerProduct(v2); 62 | System.out.println(product); 63 | } 64 | 65 | public void invert_matrix() { 66 | System.out.println("invert a matrix"); 67 | 68 | Matrix A = new DenseMatrix( 69 | new double[][]{ 70 | {1, 2, 3}, 71 | {6, 5, 4}, 72 | {8, 7, 9} 73 | }); 74 | 75 | Matrix Ainv = new Inverse(A); 76 | System.out.println(Ainv); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Chapter3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.analysis.function.polynomial.Polynomial; 26 | import dev.nm.analysis.function.polynomial.root.PolyRoot; 27 | import dev.nm.analysis.function.rn2r1.univariate.AbstractUnivariateRealFunction; 28 | import dev.nm.analysis.function.rn2r1.univariate.UnivariateRealFunction; 29 | import dev.nm.analysis.root.univariate.BisectionRoot; 30 | import dev.nm.analysis.root.univariate.BrentRoot; 31 | import dev.nm.analysis.root.univariate.HalleyRoot; 32 | import dev.nm.analysis.root.univariate.NewtonRoot; 33 | import dev.nm.analysis.root.univariate.NoRootFoundException; 34 | import dev.nm.number.complex.Complex; 35 | import java.util.Arrays; 36 | import java.util.List; 37 | 38 | /** 39 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 40 | * 41 | * @author haksunli 42 | * @see 43 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 44 | * https://nm.dev/ 45 | */ 46 | public class Chapter3 { 47 | 48 | public static void main(String[] args) throws Exception { 49 | System.out.println("Chapter 3 demos"); 50 | 51 | Chapter3 chapter3 = new Chapter3(); 52 | chapter3.define_functions(); 53 | chapter3.solve_root_for_polynomial_1(); 54 | chapter3.solve_root_for_polynomial_2(); 55 | chapter3.solve_root_using_bisection_method(); 56 | chapter3.solve_root_using_Brent_method(); 57 | chapter3.solve_root_using_Netwon_method(); 58 | chapter3.solve_root_using_Hally_method(); 59 | } 60 | 61 | public void define_functions() { 62 | System.out.println("defining functions"); 63 | 64 | Polynomial p = new Polynomial(1, -10, 35, -50, 24); 65 | System.out.println("p(1) = " + p.evaluate(1.)); 66 | 67 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 68 | @Override 69 | public double evaluate(double x) { 70 | return Math.sin(x) * x - 3; 71 | } 72 | }; 73 | System.out.println("f(1) = " + f.evaluate(1.)); 74 | } 75 | 76 | public void solve_root_for_polynomial_1() { 77 | System.out.println("solve root for polynomial"); 78 | 79 | Polynomial p = new Polynomial(1, -10, 35, -50, 24); 80 | PolyRoot solver = new PolyRoot(); 81 | List roots = solver.solve(p); 82 | System.out.println(Arrays.toString(roots.toArray())); 83 | } 84 | 85 | public void solve_root_for_polynomial_2() { 86 | System.out.println("solve root for polynomial with complex root"); 87 | 88 | Polynomial p = new Polynomial(1, 0, 1); // x^2 + 1 = 0 89 | PolyRoot solver = new PolyRoot(); 90 | List roots0 = solver.solve(p); 91 | System.out.println(Arrays.toString(roots0.toArray())); 92 | List roots1 = PolyRoot.getComplexRoots(roots0); 93 | System.out.println(Arrays.toString(roots1.toArray())); 94 | } 95 | 96 | public void solve_root_using_bisection_method() throws NoRootFoundException { 97 | System.out.println("solve root using bisection method"); 98 | 99 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 100 | @Override 101 | public double evaluate(double x) { 102 | return x * Math.sin(x) - 3; // x * six(x) - 3 = 0 103 | } 104 | }; 105 | 106 | BisectionRoot solver = new BisectionRoot(1e-8, 30); 107 | double root = solver.solve(f, 12., 14.); 108 | double fx = f.evaluate(root); 109 | System.out.println(String.format("f(%f) = %f", root, fx)); 110 | } 111 | 112 | public void solve_root_using_Brent_method() { 113 | System.out.println("solve root using Brent's method"); 114 | 115 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 116 | @Override 117 | public double evaluate(double x) { 118 | return x * x - 3; // x^2 - 3 = 0 119 | } 120 | }; 121 | 122 | BrentRoot solver = new BrentRoot(1e-8, 10); 123 | double root = solver.solve(f, 0., 4.); 124 | double fx = f.evaluate(root); 125 | System.out.println(String.format("f(%f) = %f", root, fx)); 126 | } 127 | 128 | public void solve_root_using_Netwon_method() throws NoRootFoundException { 129 | System.out.println("solve root using Newton's method using the first order derivatie"); 130 | 131 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 132 | @Override 133 | public double evaluate(double x) { 134 | return x * x + 4 * x - 5; // x^2 +4x - 5 = 0 135 | } 136 | }; 137 | 138 | UnivariateRealFunction df = new AbstractUnivariateRealFunction() { 139 | @Override 140 | public double evaluate(double x) { 141 | return 2 * x + 4; // 2x + 4 142 | } 143 | }; 144 | 145 | NewtonRoot solver = new NewtonRoot(1e-8, 5); 146 | double root = solver.solve(f, df, 5.); 147 | double fx = f.evaluate(root); 148 | System.out.println(String.format("f(%f) = %f", root, fx)); 149 | } 150 | 151 | public void solve_root_using_Hally_method() throws NoRootFoundException { 152 | System.out.println("solve root using Hally's method using the first and second order derivaties"); 153 | 154 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 155 | @Override 156 | public double evaluate(double x) { 157 | return x * x + 4 * x - 5; // x^2 +4x - 5 = 0 158 | } 159 | }; 160 | 161 | UnivariateRealFunction df = new AbstractUnivariateRealFunction() { 162 | @Override 163 | public double evaluate(double x) { 164 | return 2 * x + 4; // 2x + 4 165 | } 166 | }; 167 | 168 | UnivariateRealFunction d2f = new AbstractUnivariateRealFunction() { 169 | @Override 170 | public double evaluate(double x) { 171 | return 2; // 2 172 | } 173 | }; 174 | 175 | HalleyRoot solver = new HalleyRoot(1e-8, 3); 176 | double root = solver.solve(f, df, d2f, 5.); 177 | double fx = f.evaluate(root); 178 | 179 | System.out.println(String.format("f(%f) = %f", root, fx)); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /Chapter4.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.algebra.linear.vector.doubles.Vector; 26 | import dev.nm.algebra.linear.vector.doubles.dense.DenseVector; 27 | import dev.nm.analysis.function.rn2r1.AbstractBivariateRealFunction; 28 | import dev.nm.analysis.function.rn2r1.AbstractRealScalarFunction; 29 | import dev.nm.analysis.function.rn2r1.AbstractTrivariateRealFunction; 30 | import dev.nm.analysis.function.rn2r1.BivariateRealFunction; 31 | import dev.nm.analysis.function.rn2r1.RealScalarFunction; 32 | import dev.nm.analysis.function.rn2r1.TrivariateRealFunction; 33 | import dev.nm.analysis.function.rn2rm.AbstractRealVectorFunction; 34 | import dev.nm.analysis.function.rn2rm.RealVectorFunction; 35 | import dev.nm.analysis.root.multivariate.NewtonSystemRoot; 36 | import dev.nm.analysis.root.univariate.NoRootFoundException; 37 | import java.util.Arrays; 38 | 39 | /** 40 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 41 | * 42 | * @author haksunli 43 | * @see 44 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 45 | * https://nm.dev/ 46 | */ 47 | public class Chapter4 { 48 | 49 | public static void main(String[] args) throws Exception { 50 | System.out.println("Chapter 4 demos"); 51 | 52 | Chapter4 chapter4 = new Chapter4(); 53 | chapter4.define_multivariate_functions(); 54 | chapter4.define_multivariate_vector_function(); 55 | chapter4.solve_system_of_two_equations(); 56 | chapter4.solve_system_of_equations(); 57 | } 58 | 59 | public void define_multivariate_functions() { 60 | System.out.println("define multivariate functions"); 61 | 62 | RealScalarFunction f1 = new AbstractRealScalarFunction(3) { 63 | @Override 64 | public Double evaluate(Vector x) { 65 | double x1 = x.get(1); 66 | double x2 = x.get(2); 67 | double x3 = x.get(3); 68 | return 2 * x1 * x1 + x2 * x2 - x3; 69 | } 70 | }; 71 | System.out.println("f1(1,2,3) = " + f1.evaluate(new DenseVector(1, 2, 3))); 72 | 73 | TrivariateRealFunction f2 = new AbstractTrivariateRealFunction() { 74 | @Override 75 | public double evaluate(double x1, double x2, double x3) { 76 | return 2 * x1 * x1 + x2 * x2 - x3; 77 | } 78 | }; 79 | System.out.println("f2(1,2,3) = " + f2.evaluate(new DenseVector(1, 2, 3))); 80 | } 81 | 82 | public void define_multivariate_vector_function() { 83 | System.out.println("define multivariate vector function"); 84 | 85 | TrivariateRealFunction f1 = new AbstractTrivariateRealFunction() { 86 | @Override 87 | public double evaluate(double x, double y, double z) { 88 | return Math.pow(x, 2) + Math.pow(y, 3) - z - 6; 89 | } 90 | }; 91 | TrivariateRealFunction f2 = new AbstractTrivariateRealFunction() { 92 | @Override 93 | public double evaluate(double x, double y, double z) { 94 | return 2 * x + 9 * y - z - 17; 95 | } 96 | }; 97 | TrivariateRealFunction f3 = new AbstractTrivariateRealFunction() { 98 | @Override 99 | public double evaluate(double x, double y, double z) { 100 | return Math.pow(x, 4) + 5 * y + 6 * z - 29; 101 | } 102 | }; 103 | RealScalarFunction[] F = new TrivariateRealFunction[]{f1, f2, f3}; 104 | 105 | Vector x = new DenseVector(1.5, 2.5, 3.5); 106 | double f1_x = F[0].evaluate(x); 107 | double f2_x = F[1].evaluate(x); 108 | double f3_x = F[2].evaluate(x); 109 | double[] F_x = new double[]{f1_x, f2_x, f3_x}; 110 | System.out.println("F(x) = " + Arrays.toString(F_x)); 111 | 112 | RealVectorFunction G = new AbstractRealVectorFunction(3, 3) { 113 | @Override 114 | public Vector evaluate(Vector v) { 115 | double x = v.get(1); 116 | double y = v.get(2); 117 | double z = v.get(3); 118 | 119 | double g1 = Math.pow(x, 2) + Math.pow(y, 3) - z - 6; 120 | double g2 = 2 * x + 9 * y - z - 17; 121 | double g3 = Math.pow(x, 4) + 5 * y + 6 * z - 29; 122 | 123 | Vector g = new DenseVector(g1, g2, g3); 124 | return g; 125 | } 126 | }; 127 | Vector Gx = G.evaluate(x); 128 | System.out.println("G(x) = " + Gx); 129 | } 130 | 131 | public void solve_system_of_two_equations() throws NoRootFoundException { 132 | System.out.println("solve a system of two equations"); 133 | 134 | BivariateRealFunction f1 = new AbstractBivariateRealFunction() { 135 | @Override 136 | public double evaluate(double x, double y) { 137 | return 3 * x + y * y - 12; 138 | } 139 | }; 140 | BivariateRealFunction f2 = new AbstractBivariateRealFunction() { 141 | @Override 142 | public double evaluate(double x, double y) { 143 | return x * x + y - 4; 144 | } 145 | }; 146 | BivariateRealFunction[] F = new BivariateRealFunction[]{f1, f2}; 147 | 148 | NewtonSystemRoot solver = new NewtonSystemRoot(1e-8, 10); 149 | Vector initial = new DenseVector(new double[]{0, 0}); // (0, 0) 150 | Vector root = solver.solve(F, initial); 151 | 152 | System.out.println(String.format("f(%s) = (%f, %f)", root.toString(), f1.evaluate(root), f2.evaluate(root))); 153 | } 154 | 155 | public void solve_system_of_equations() throws NoRootFoundException { 156 | System.out.println("solve a system of equations"); 157 | 158 | RealVectorFunction G = new AbstractRealVectorFunction(3, 3) { 159 | @Override 160 | public Vector evaluate(Vector v) { 161 | double x = v.get(1); 162 | double y = v.get(2); 163 | double z = v.get(3); 164 | 165 | double g1 = Math.pow(x, 2) + Math.pow(y, 3) - z - 6; 166 | double g2 = 2 * x + 9 * y - z - 17; 167 | double g3 = Math.pow(x, 4) + 5 * y + 6 * z - 29; 168 | 169 | Vector g = new DenseVector(g1, g2, g3); 170 | return g; 171 | } 172 | }; 173 | 174 | NewtonSystemRoot solver = new NewtonSystemRoot(1e-8, 15); 175 | Vector initial = new DenseVector(new double[]{0, 0, 0}); // (0, 0, 0) 176 | Vector root = solver.solve(G, initial); 177 | 178 | System.out.println(String.format("f(%s) = %s", root.toString(), G.evaluate(root).toString())); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /Chapter11.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.algebra.linear.vector.doubles.Vector; 26 | import dev.nm.algebra.linear.vector.doubles.dense.DenseVector; 27 | import dev.nm.analysis.function.rn2r1.AbstractBivariateRealFunction; 28 | import dev.nm.analysis.function.rn2r1.AbstractRealScalarFunction; 29 | import dev.nm.analysis.function.rn2r1.RealScalarFunction; 30 | import dev.nm.misc.algorithm.stopcondition.AfterIterations; 31 | import dev.nm.misc.algorithm.stopcondition.StopCondition; 32 | import dev.nm.solver.IterativeSolution; 33 | import dev.nm.solver.multivariate.constrained.constraint.general.GeneralEqualityConstraints; 34 | import dev.nm.solver.multivariate.constrained.constraint.general.GeneralLessThanConstraints; 35 | import dev.nm.solver.multivariate.constrained.general.penaltymethod.PenaltyMethodMinimizer; 36 | import dev.nm.solver.multivariate.constrained.integer.IPProblem; 37 | import dev.nm.solver.multivariate.constrained.integer.IPProblemImpl1; 38 | import dev.nm.solver.multivariate.constrained.problem.ConstrainedOptimProblemImpl1; 39 | import dev.nm.solver.multivariate.geneticalgorithm.minimizer.deoptim.DEOptim; 40 | import dev.nm.solver.multivariate.geneticalgorithm.minimizer.deoptim.Rand1Bin; 41 | import dev.nm.solver.multivariate.geneticalgorithm.minimizer.deoptim.constrained.IntegralConstrainedCellFactory; 42 | import dev.nm.solver.multivariate.geneticalgorithm.minimizer.simplegrid.SimpleCellFactory; 43 | import dev.nm.solver.multivariate.geneticalgorithm.minimizer.simplegrid.SimpleGridMinimizer; 44 | import dev.nm.solver.multivariate.unconstrained.IterativeMinimizer; 45 | import dev.nm.solver.multivariate.unconstrained.annealing.GeneralizedSimulatedAnnealingMinimizer; 46 | import dev.nm.solver.multivariate.unconstrained.c2.quasinewton.BFGSMinimizer; 47 | import dev.nm.solver.problem.C2OptimProblemImpl; 48 | import dev.nm.solver.problem.OptimProblem; 49 | import dev.nm.stat.random.rng.univariate.RandomLongGenerator; 50 | import dev.nm.stat.random.rng.univariate.uniform.UniformRNG; 51 | 52 | /** 53 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 54 | * 55 | * @author haksunli 56 | * @see 57 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 58 | * https://nm.dev/ 59 | */ 60 | public class Chapter11 { 61 | 62 | public static void main(String[] args) throws Exception { 63 | System.out.println("Chapter 11 demos"); 64 | 65 | Chapter11 chapter11 = new Chapter11(); 66 | chapter11.penalty_method(); 67 | chapter11.genetic_algorithm(); 68 | chapter11.differential_evolution(); 69 | chapter11.simulated_annealing(); 70 | } 71 | 72 | public void simulated_annealing() throws Exception { 73 | System.out.println("simulated annealing"); 74 | 75 | // the objective function to minimize 76 | final RealScalarFunction f 77 | = new AbstractRealScalarFunction(2) { 78 | 79 | @Override 80 | public Double evaluate(Vector x) { 81 | double x1 = x.get(1); 82 | double x2 = x.get(2); 83 | // (4 - 2.1*x(1)^2 + x(1)^4/3)*x(1)^2 84 | double term1 85 | = (4.0 - 2.1 * Math.pow(x1, 2.0) + Math.pow(x1, 4.0) / 3.0) 86 | * Math.pow(x1, 2.0); 87 | // x(1)*x(2) 88 | double term2 = x1 * x2; 89 | // (-4 + 4*x(2)^2)*x(2)^2 90 | double term3 = (-4.0 + 4.0 * Math.pow(x2, 2.0)) * Math.pow(x2, 2.0); 91 | return term1 + term2 + term3; 92 | } 93 | }; 94 | 95 | // construct an optimization problem 96 | final OptimProblem problem = new OptimProblem() { 97 | 98 | @Override 99 | public RealScalarFunction f() { 100 | return f; 101 | } 102 | 103 | @Override 104 | public int dimension() { 105 | return 2; 106 | } 107 | }; 108 | 109 | // stop after 5000 iterations 110 | StopCondition stopCondition = new AfterIterations(5000); 111 | // an instance of a simulated annealing solver 112 | IterativeMinimizer solver 113 | = new GeneralizedSimulatedAnnealingMinimizer( 114 | 2, // dimension of the objective function 115 | stopCondition 116 | ); 117 | IterativeSolution soln = solver.solve(problem); 118 | Vector x0 = new DenseVector(0.5, 0.5); // the initial guess 119 | Vector xmin = soln.search(x0); 120 | double fxmin = f.evaluate(xmin); // the mimimum 121 | System.out.println(String.format("f(%s) = %f", xmin, fxmin)); 122 | } 123 | 124 | public void differential_evolution() throws Exception { 125 | System.out.println("Differential Evolution"); 126 | 127 | // the objective function to minimize 128 | RealScalarFunction f 129 | = new AbstractBivariateRealFunction() { 130 | @Override 131 | public double evaluate(double x, double y) { 132 | return (x - 1) * (x - 1) + (y - 3) * (y - 3); // (x - 1)^2 + (y - 3)^2 133 | } 134 | }; 135 | 136 | // construct an integer programming problem 137 | final IPProblem problem 138 | // both x and y need to be integers 139 | = new IPProblemImpl1(f, null, null, new int[]{1, 2}, 0); 140 | 141 | // a uniform random number generator 142 | final RandomLongGenerator rng = new UniformRNG(); 143 | rng.seed(123456798L); 144 | 145 | // construct an instance of a genetic algorithm solver 146 | DEOptim solver = new DEOptim( 147 | () -> new IntegralConstrainedCellFactory( 148 | new Rand1Bin(0.5, 0.5, rng), // the DE operator 149 | new IntegralConstrainedCellFactory.SomeIntegers(problem)), // specify the integral constraints 150 | rng, // a uniform random number generator 151 | 1e-15, // a precision parameter 152 | 100, // the maximum number of iterations 153 | 20 // the maximum number of iterations of no improvement 154 | ); 155 | 156 | IterativeSolution soln = solver.solve(problem); 157 | Vector xmin = soln.search(new Vector[]{ 158 | // the boundaries: [-10, 10], [-10, 10] 159 | new DenseVector(-10.0, 10.0), 160 | new DenseVector(10.0, -10.0), 161 | new DenseVector(10.0, 10.0), 162 | new DenseVector(-10.0, -10.0) 163 | }); 164 | double fxmin = f.evaluate(xmin); // the mimimum 165 | System.out.println(String.format("f(%s) = %f", xmin, fxmin)); 166 | } 167 | 168 | public void genetic_algorithm() throws Exception { 169 | System.out.println("genetic algorithm"); 170 | 171 | // the objective function to minimize 172 | RealScalarFunction f 173 | = new AbstractBivariateRealFunction() { 174 | @Override 175 | public double evaluate(double x, double y) { 176 | return x * x + y * y; // x^2 + y^2 177 | } 178 | }; 179 | 180 | // a uniform random number generator 181 | RandomLongGenerator rng = new UniformRNG(); 182 | rng.seed(123456798L); 183 | 184 | // construct an instance of the genetic algorithm solver 185 | SimpleGridMinimizer solver 186 | = new SimpleGridMinimizer( 187 | // define the encodinng, crossover and mutation operator 188 | () -> new SimpleCellFactory( 189 | 0.1, // the convergence rate 190 | rng), 191 | rng, // source of randomness for the GA 192 | 1e-15, // a precision parameter 193 | 500, // the maximum number of iterations 194 | 500 // the maximum number of iterations of no improvement 195 | ); 196 | 197 | // run the solver to solve the optimization problem 198 | IterativeSolution soln 199 | = solver.solve(new C2OptimProblemImpl(f)); 200 | Vector xmin = soln.search(new Vector[]{ // the minimizer 201 | // the boundaries: [-10, 10], [-10, 10] 202 | new DenseVector(-10.0, 10.0), 203 | new DenseVector(10.0, -10.0), 204 | new DenseVector(10.0, 10.0), 205 | new DenseVector(-10.0, -10.0) 206 | }); 207 | double fxmin = f.evaluate(xmin); // the mimimum 208 | System.out.println(String.format("f(%s) = %f", xmin, fxmin)); 209 | } 210 | 211 | public void penalty_method() throws Exception { 212 | System.out.println("penalty method"); 213 | 214 | RealScalarFunction f = new AbstractBivariateRealFunction() { 215 | @Override 216 | public double evaluate(double x, double y) { 217 | // f = (x+1)^2 + (y+1)^2 218 | return (x + 1) * (x + 1) + (y + 1) * (y + 1); 219 | } 220 | }; 221 | 222 | RealScalarFunction c1 = new AbstractBivariateRealFunction() { 223 | @Override 224 | public double evaluate(double x, double y) { 225 | // y = 0 226 | return y; 227 | } 228 | }; 229 | 230 | RealScalarFunction c2 = new AbstractBivariateRealFunction() { 231 | @Override 232 | public double evaluate(double x, double y) { 233 | // x >= 1 234 | return 1 - x; 235 | } 236 | }; 237 | 238 | ConstrainedOptimProblemImpl1 problem 239 | = new ConstrainedOptimProblemImpl1( 240 | f, 241 | new GeneralEqualityConstraints(c1), // y = 0 242 | new GeneralLessThanConstraints(c2)); // x >= 1 243 | 244 | double M = 1e30; // the penalty factor 245 | PenaltyMethodMinimizer optim 246 | = new PenaltyMethodMinimizer( 247 | PenaltyMethodMinimizer.DEFAULT_PENALTY_FUNCTION_FACTORY, 248 | M, 249 | // the solver to solve the equivalent unconstrained optimization problem 250 | new BFGSMinimizer(false, 1e-8, 200) 251 | ); 252 | IterativeSolution soln = optim.solve(problem); 253 | 254 | Vector xmin = soln.search( // the minimizer 255 | new DenseVector(new double[]{0, 0}) // an initial guess 256 | ); 257 | double fxmin = f.evaluate(xmin); // the mimimum 258 | System.out.println(String.format("f(%s) = %f", xmin, fxmin)); 259 | 260 | // alternatively 261 | System.out.println(String.format("f(%s) = %f", soln.minimizer(), soln.minimum())); 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /Chapter7.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.algebra.linear.vector.doubles.Vector; 26 | import dev.nm.algebra.linear.vector.doubles.dense.DenseVector; 27 | import dev.nm.analysis.differentialequation.ode.ivp.problem.DerivativeFunction; 28 | import dev.nm.analysis.differentialequation.ode.ivp.problem.ODE1stOrder; 29 | import dev.nm.analysis.differentialequation.ode.ivp.solver.EulerMethod; 30 | import dev.nm.analysis.differentialequation.ode.ivp.solver.ODESolution; 31 | import dev.nm.analysis.differentialequation.ode.ivp.solver.ODESolver; 32 | import dev.nm.analysis.differentialequation.ode.ivp.solver.multistep.adamsbashforthmoulton.ABMPredictorCorrector1; 33 | import dev.nm.analysis.differentialequation.ode.ivp.solver.multistep.adamsbashforthmoulton.ABMPredictorCorrector2; 34 | import dev.nm.analysis.differentialequation.ode.ivp.solver.multistep.adamsbashforthmoulton.ABMPredictorCorrector3; 35 | import dev.nm.analysis.differentialequation.ode.ivp.solver.multistep.adamsbashforthmoulton.ABMPredictorCorrector4; 36 | import dev.nm.analysis.differentialequation.ode.ivp.solver.multistep.adamsbashforthmoulton.ABMPredictorCorrector5; 37 | import dev.nm.analysis.differentialequation.ode.ivp.solver.multistep.adamsbashforthmoulton.AdamsBashforthMoulton; 38 | import dev.nm.analysis.differentialequation.ode.ivp.solver.rungekutta.RungeKutta; 39 | import dev.nm.analysis.differentialequation.ode.ivp.solver.rungekutta.RungeKutta1; 40 | import dev.nm.analysis.differentialequation.ode.ivp.solver.rungekutta.RungeKutta2; 41 | import dev.nm.analysis.differentialequation.ode.ivp.solver.rungekutta.RungeKutta3; 42 | import dev.nm.analysis.differentialequation.ode.ivp.solver.rungekutta.RungeKuttaStepper; 43 | import dev.nm.analysis.function.rn2r1.univariate.AbstractUnivariateRealFunction; 44 | import dev.nm.analysis.function.rn2r1.univariate.UnivariateRealFunction; 45 | import dev.nm.analysis.function.rn2rm.AbstractRealVectorFunction; 46 | import dev.nm.analysis.function.rn2rm.RealVectorFunction; 47 | import java.io.IOException; 48 | import static java.lang.Math.exp; 49 | 50 | /** 51 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 52 | * 53 | * @author haksunli 54 | * @see 55 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 56 | * https://nm.dev/ 57 | */ 58 | public class Chapter7 { 59 | 60 | public static void main(String[] args) throws IOException { 61 | System.out.println("Chapter 7 demos"); 62 | 63 | Chapter7 chapter7 = new Chapter7(); 64 | chapter7.EulerMethod(); 65 | chapter7.RungeKutta(); 66 | chapter7.ABM(); 67 | chapter7.system_of_ODEs(); 68 | chapter7.higher_order_ODEs(); 69 | } 70 | 71 | private void higher_order_ODEs() { 72 | System.out.println("solve a higher-order ODE using Euler's method"); 73 | 74 | // define the equivalent system of ODEs to solve 75 | DerivativeFunction dY = new DerivativeFunction() { 76 | 77 | @Override 78 | public Vector evaluate(double t, Vector v) { 79 | double y_1 = v.get(1); 80 | double y_2 = v.get(2); 81 | 82 | double dy_1 = y_2; 83 | double dy_2 = y_2 + 6. * y_1; 84 | return new DenseVector(new double[]{dy_1, dy_2}); 85 | } 86 | 87 | @Override 88 | public int dimension() { 89 | return 2; 90 | } 91 | }; 92 | // initial condition, y1(0) = 1, y2(0) = 2 93 | Vector Y0 = new DenseVector(1., 2.); 94 | 95 | double t0 = 0, t1 = 1.; // solution domain 96 | double h = 0.1; // step size 97 | 98 | // the analytical solution 99 | UnivariateRealFunction f 100 | = new AbstractUnivariateRealFunction() { 101 | @Override 102 | public double evaluate(double t) { 103 | double f = 0.8 * exp(3. * t); 104 | f += 0.2 * exp(-2. * t); 105 | return f; 106 | } 107 | }; 108 | 109 | // define an IVP 110 | ODE1stOrder ivp = new ODE1stOrder(dY, Y0, t0, t1); 111 | // construt an ODE solver using Euler's method 112 | // ODESolver solver = new EulerMethod(h); 113 | // construt an ODE solver using the third order Runge-Kutta formula 114 | RungeKuttaStepper stepper3 = new RungeKutta3(); 115 | ODESolver solver = new RungeKutta(stepper3, h); 116 | 117 | // solve the ODE 118 | ODESolution soln = solver.solve(ivp); 119 | // print out the solution function, y, at discrete points 120 | double[] t = soln.x(); 121 | Vector[] v = soln.y(); 122 | for (int i = 0; i < t.length; ++i) { 123 | double y1 = v[i].get(1); // the numerical solution 124 | System.out.println(String.format( 125 | "y(%f) = %f vs %f", 126 | t[i], 127 | y1, 128 | f.evaluate(t[i]) 129 | )); 130 | } 131 | } 132 | 133 | private void system_of_ODEs() { 134 | System.out.println("solve a system of ODEs using Euler's method"); 135 | 136 | // define the system of ODEs to solve 137 | DerivativeFunction dY = new DerivativeFunction() { 138 | 139 | @Override 140 | public Vector evaluate(double t, Vector v) { 141 | double x = v.get(1); 142 | double y = v.get(2); 143 | 144 | double dx = 3. * x - 4. * y; 145 | double dy = 4. * x - 7. * y; 146 | return new DenseVector(new double[]{dx, dy}); 147 | } 148 | 149 | @Override 150 | public int dimension() { 151 | return 2; 152 | } 153 | }; 154 | // initial condition, x0=y0=1 155 | Vector Y0 = new DenseVector(1., 1.); 156 | 157 | double x0 = 0, x1 = 1.; // solution domain 158 | double h = 0.1; // step size 159 | 160 | // the analytical solution 161 | RealVectorFunction F 162 | = new AbstractRealVectorFunction(1, 2) { 163 | @Override 164 | public Vector evaluate(Vector v) { 165 | double t = v.get(1); 166 | double x = 2. / 3 * exp(t) + 1. / 3 * exp(-5. * t); 167 | double y = 1. / 3 * exp(t) + 2. / 3 * exp(-5. * t); 168 | return new DenseVector(x, y); 169 | } 170 | }; 171 | 172 | // define an IVP 173 | ODE1stOrder ivp = new ODE1stOrder(dY, Y0, x0, x1); 174 | // construt an ODE solver using Euler's method 175 | ODESolver solver = new EulerMethod(h); 176 | // solve the ODE 177 | ODESolution soln = solver.solve(ivp); 178 | // print out the solution function, y, at discrete points 179 | double[] t = soln.x(); 180 | Vector[] v = soln.y(); 181 | for (int i = 0; i < t.length; ++i) { 182 | System.out.println(String.format( 183 | "y(%f) = %s vs %s", 184 | t[i], 185 | v[i], 186 | F.evaluate(new DenseVector(t[i])) 187 | )); 188 | } 189 | } 190 | 191 | private void ABM() { 192 | System.out.println("solve an ODE using Adams-Bashforth methods"); 193 | 194 | // define the ODE to solve 195 | DerivativeFunction dy = new DerivativeFunction() { 196 | 197 | @Override 198 | public Vector evaluate(double x, Vector v) { 199 | double y = v.get(1); 200 | double dy = y - x + 1; 201 | return new DenseVector(dy); 202 | } 203 | 204 | @Override 205 | public int dimension() { 206 | return 1; 207 | } 208 | }; 209 | // initial condition, y0=1 210 | Vector y0 = new DenseVector(1.); 211 | 212 | double x0 = 0, x1 = 1.; // solution domain 213 | double h = 0.1; // step size 214 | 215 | // the analytical solution 216 | UnivariateRealFunction y = new AbstractUnivariateRealFunction() { 217 | @Override 218 | public double evaluate(double x) { 219 | double y = exp(x) + x; 220 | return y; 221 | } 222 | }; 223 | 224 | // define an IVP 225 | ODE1stOrder ivp = new ODE1stOrder(dy, y0, x0, x1); 226 | 227 | // using first order Adams-Bashforth formula 228 | ODESolver solver1 = new AdamsBashforthMoulton(new ABMPredictorCorrector1(), h); 229 | ODESolution soln1 = solver1.solve(ivp); 230 | 231 | // using second order Adams-Bashforth formula 232 | ODESolver solver2 = new AdamsBashforthMoulton(new ABMPredictorCorrector2(), h); 233 | ODESolution soln2 = solver2.solve(ivp); 234 | 235 | // using third order Adams-Bashforth formula 236 | ODESolver solver3 = new AdamsBashforthMoulton(new ABMPredictorCorrector3(), h); 237 | ODESolution soln3 = solver3.solve(ivp); 238 | 239 | // using forth order Adams-Bashforth formula 240 | ODESolver solver4 = new AdamsBashforthMoulton(new ABMPredictorCorrector4(), h); 241 | ODESolution soln4 = solver4.solve(ivp); 242 | 243 | // using fifth order Adams-Bashforth formula 244 | ODESolver solver5 = new AdamsBashforthMoulton(new ABMPredictorCorrector5(), h); 245 | ODESolution soln5 = solver5.solve(ivp); 246 | 247 | double[] x = soln1.x(); 248 | Vector[] y1 = soln1.y(); 249 | Vector[] y2 = soln2.y(); 250 | Vector[] y3 = soln3.y(); 251 | Vector[] y4 = soln4.y(); 252 | Vector[] y5 = soln5.y(); 253 | for (int i = 0; i < x.length; ++i) { 254 | double yx = y.evaluate(x[i]); // the analytical solution 255 | double diff1 = yx - y1[i].get(1); // the first order error 256 | double diff2 = yx - y2[i].get(1); // the second order error 257 | double diff3 = yx - y3[i].get(1); // the third order error 258 | double diff4 = yx - y4[i].get(1); // the forth order error 259 | double diff5 = yx - y5[i].get(1); // the fifth order error 260 | System.out.println( 261 | String.format("y(%f) = %s (%.16f); = %s (%.16f); = %s (%.16f); = %s (%.16f); = %s (%.16f)", 262 | x[i], y1[i], diff1, 263 | y2[i], diff2, 264 | y3[i], diff3, 265 | y4[i], diff4, 266 | y5[i], diff5 267 | )); 268 | } 269 | } 270 | 271 | private void RungeKutta() { 272 | System.out.println("solve an ODE using Runge-Kutta methods"); 273 | 274 | // define the ODE to solve 275 | DerivativeFunction dy = new DerivativeFunction() { 276 | 277 | @Override 278 | public Vector evaluate(double x, Vector v) { 279 | double y = v.get(1); 280 | double dy = y - x + 1; 281 | return new DenseVector(dy); 282 | } 283 | 284 | @Override 285 | public int dimension() { 286 | return 1; 287 | } 288 | }; 289 | // initial condition, y0=1 290 | Vector y0 = new DenseVector(1.); 291 | 292 | double x0 = 0, x1 = 1.; // solution domain 293 | double h = 0.1; // step size 294 | 295 | // the analytical solution 296 | UnivariateRealFunction y = new AbstractUnivariateRealFunction() { 297 | @Override 298 | public double evaluate(double x) { 299 | double y = exp(x) + x; 300 | return y; 301 | } 302 | }; 303 | 304 | // define an IVP 305 | ODE1stOrder ivp = new ODE1stOrder(dy, y0, x0, x1); 306 | 307 | // using first order Runge-Kutta formula 308 | RungeKuttaStepper stepper1 = new RungeKutta1(); 309 | ODESolver solver1 = new RungeKutta(stepper1, h); 310 | ODESolution soln1 = solver1.solve(ivp); 311 | 312 | // using second order Runge-Kutta formula 313 | RungeKuttaStepper stepper2 = new RungeKutta2(); 314 | ODESolver solver2 = new RungeKutta(stepper2, h); 315 | ODESolution soln2 = solver2.solve(ivp); 316 | 317 | // using third order Runge-Kutta formula 318 | RungeKuttaStepper stepper3 = new RungeKutta3(); 319 | ODESolver solver3 = new RungeKutta(stepper3, h); 320 | ODESolution soln3 = solver3.solve(ivp); 321 | 322 | double[] x = soln1.x(); 323 | Vector[] y1 = soln1.y(); 324 | Vector[] y2 = soln2.y(); 325 | Vector[] y3 = soln3.y(); 326 | for (int i = 0; i < x.length; ++i) { 327 | double yx = y.evaluate(x[i]); // the analytical solution 328 | double diff1 = yx - y1[i].get(1); // the first order error 329 | double diff2 = yx - y2[i].get(1); // the second order error 330 | double diff3 = yx - y3[i].get(1); // the third order error 331 | System.out.println( 332 | String.format("y(%f) = %s (%.16f); = %s (%.16f); = %s (%.16f)", 333 | x[i], y1[i], diff1, 334 | y2[i], diff2, 335 | y3[i], diff3 336 | )); 337 | } 338 | } 339 | 340 | private void EulerMethod() { 341 | System.out.println("solve an ODE using Euler's method"); 342 | 343 | // define the ODE to solve 344 | DerivativeFunction dy = new DerivativeFunction() { 345 | 346 | @Override 347 | public Vector evaluate(double x, Vector y) { 348 | 349 | Vector dy = y.scaled(-2. * x); 350 | return dy.add(1); // y' = 1 - 2xy 351 | } 352 | 353 | @Override 354 | public int dimension() { 355 | return 1; 356 | } 357 | }; 358 | // initial condition, y0=0 359 | Vector y0 = new DenseVector(0.); 360 | 361 | double x0 = 0, x1 = 1.; // solution domain 362 | double h = 0.1; // step size 363 | 364 | // define an IVP 365 | ODE1stOrder ivp = new ODE1stOrder(dy, y0, x0, x1); 366 | // construt an ODE solver using Euler's method 367 | ODESolver solver = new EulerMethod(h); 368 | // solve the ODE 369 | ODESolution soln = solver.solve(ivp); 370 | // print out the solution function, y, at discrete points 371 | double[] x = soln.x(); 372 | Vector[] y = soln.y(); 373 | for (int i = 0; i < x.length; ++i) { 374 | System.out.println(String.format("y(%f) = %s", x[i], y[i])); 375 | } 376 | } 377 | 378 | } 379 | -------------------------------------------------------------------------------- /Chapter5.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import java.io.BufferedWriter; 26 | import java.io.FileWriter; 27 | import java.io.IOException; 28 | 29 | import dev.nm.algebra.linear.vector.doubles.dense.DenseVector; 30 | import dev.nm.analysis.curvefit.LeastSquares; 31 | import dev.nm.analysis.curvefit.interpolation.bivariate.BicubicInterpolation; 32 | import dev.nm.analysis.curvefit.interpolation.bivariate.BicubicSpline; 33 | import dev.nm.analysis.curvefit.interpolation.bivariate.BilinearInterpolation; 34 | import dev.nm.analysis.curvefit.interpolation.bivariate.BivariateArrayGrid; 35 | import dev.nm.analysis.curvefit.interpolation.bivariate.BivariateGrid; 36 | import dev.nm.analysis.curvefit.interpolation.bivariate.BivariateGridInterpolation; 37 | import dev.nm.analysis.curvefit.interpolation.bivariate.BivariateRegularGrid; 38 | import dev.nm.analysis.curvefit.interpolation.multivariate.MultivariateArrayGrid; 39 | import dev.nm.analysis.curvefit.interpolation.multivariate.RecursiveGridInterpolation; 40 | import dev.nm.analysis.curvefit.interpolation.univariate.CubicHermite; 41 | import dev.nm.analysis.curvefit.interpolation.univariate.CubicSpline; 42 | import dev.nm.analysis.curvefit.interpolation.univariate.Interpolation; 43 | import dev.nm.analysis.curvefit.interpolation.univariate.LinearInterpolation; 44 | import dev.nm.analysis.curvefit.interpolation.univariate.NewtonPolynomial; 45 | import dev.nm.analysis.function.rn2r1.RealScalarFunction; 46 | import dev.nm.analysis.function.rn2r1.univariate.UnivariateRealFunction; 47 | import dev.nm.analysis.function.tuple.OrderedPairs; 48 | import dev.nm.analysis.function.tuple.SortedOrderedPairs; 49 | import dev.nm.misc.datastructure.MultiDimensionalArray; 50 | import java.io.File; 51 | import static java.lang.Math.log; 52 | 53 | /** 54 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 55 | * 56 | * @author haksunli 57 | * @see 58 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 59 | * https://nm.dev/ 60 | */ 61 | public class Chapter5 { 62 | 63 | public static void main(String[] args) throws IOException { 64 | System.out.println("Chapter 5 demos"); 65 | 66 | Chapter5 chapter5 = new Chapter5(); 67 | chapter5.least_square_curve_fitting(); 68 | chapter5.linear_interpolation(); 69 | chapter5.cubic_Hermite_interpolation(); 70 | chapter5.cubic_spline_interpolation(); 71 | chapter5.newton_polynomial_interpolation(); 72 | chapter5.bivariate_interpolation(); 73 | chapter5.bivariate_interpolation_using_derivatives(); 74 | chapter5.multivariate_interpolation(); 75 | } 76 | 77 | public void least_square_curve_fitting() { 78 | System.out.println("least square curve fitting"); 79 | 80 | // the data set 81 | OrderedPairs data = new SortedOrderedPairs( 82 | new double[]{0., 1., 2., 3., 4., 5.}, 83 | new double[]{0., 1., 1.414, 1.732, 2., 2.236} 84 | ); 85 | 86 | LeastSquares ls = new LeastSquares(2); 87 | UnivariateRealFunction f = ls.fit(data); 88 | System.out.println(String.format("f(%.0f)=%f", 0., f.evaluate(0.))); // f(0) = 0.09 89 | System.out.println(String.format("f(%.0f)=%f", 1., f.evaluate(1.))); // f(1) = 0.82 90 | System.out.println(String.format("f(%.0f)=%f", 2., f.evaluate(2.))); // f(2) = 1.39 91 | System.out.println(String.format("f(%.0f)=%f", 3., f.evaluate(3.))); // f(3) = 1.81 92 | System.out.println(String.format("f(%.0f)=%f", 4., f.evaluate(4.))); // f(4) = 2.07 93 | System.out.println(String.format("f(%.0f)=%f", 5., f.evaluate(5.))); // f(5) = 2.17 94 | } 95 | 96 | public void linear_interpolation() throws IOException { 97 | System.out.println("linear interpolation"); 98 | 99 | // the data set 100 | OrderedPairs data = new SortedOrderedPairs( 101 | new double[]{0., 0.7, 1.4, 2.1, 2.8, 3.5, 4.2, 4.9, 5.6, 6.3}, 102 | new double[]{0., 0.644218, 0.98545, 0.863209, 0.334988, -0.350783, -0.871576, -0.982453, -0.631267, 0.0168139} 103 | ); 104 | LinearInterpolation li = new LinearInterpolation(); 105 | UnivariateRealFunction f = li.fit(data); 106 | System.out.println(f.evaluate(2)); // f(2) = 0.880672 107 | System.out.println(f.evaluate(3)); // f(3) = 0.139053 108 | 109 | plot(f, 100, 0, 6.5, "./plots/chapter5/figure_5_6/f_sample.txt"); 110 | } 111 | 112 | public void cubic_Hermite_interpolation() throws IOException { 113 | System.out.println("cubic_Hermite interpolation"); 114 | 115 | // the data set 116 | OrderedPairs data = new SortedOrderedPairs( 117 | new double[]{0., 0.7, 1.4, 2.1, 2.8, 3.5, 4.2, 4.9, 5.6, 6.3}, 118 | new double[]{0., 0.644218, 0.98545, 0.863209, 0.334988, -0.350783, -0.871576, -0.982453, -0.631267, 0.0168139} 119 | ); 120 | CubicHermite spline = new CubicHermite(CubicHermite.Tangents.CATMULL_ROM); 121 | // CubicHermite spline = new CubicHermite(CubicHermite.Tangents.FINITE_DIFFERENCE); 122 | UnivariateRealFunction f = spline.fit(data); 123 | System.out.println(f.evaluate(2)); // f(2) = 0.906030 124 | System.out.println(f.evaluate(3)); // f(3) = 0.145727 125 | 126 | plot(f, 100, 0, 6.3, "./plots/chapter5/figure_5_7/f_sample.txt"); 127 | plot(f, 100, 0.7, 2.1, "./plots/chapter5/figure_5_8/f_sample.txt"); 128 | } 129 | 130 | public void cubic_spline_interpolation() throws IOException { 131 | System.out.println("cubic spline interpolation"); 132 | 133 | // the data set 134 | OrderedPairs data = new SortedOrderedPairs( 135 | new double[]{0., 1., 2., 3., 4., 5.}, 136 | new double[]{0., 3.5, 5., 3., 1., 4.} 137 | ); 138 | CubicSpline cs1 = CubicSpline.natural(); 139 | UnivariateRealFunction f1 = cs1.fit(data); 140 | plot(f1, 100, 0, 5, "./plots/chapter5/figure_5_9/natural_cspline_sample.txt"); 141 | 142 | CubicSpline cs2 = CubicSpline.clamped(); 143 | UnivariateRealFunction f2 = cs2.fit(data); 144 | plot(f2, 100, 0, 5, "./plots/chapter5/figure_5_9/clamped_cspline_sample.txt"); 145 | 146 | CubicSpline cs3 = CubicSpline.notAKnot(); 147 | UnivariateRealFunction f3 = cs3.fit(data); 148 | plot(f3, 100, 0, 5, "./plots/chapter5/figure_5_9/notaknot_cspline_sample.txt"); 149 | } 150 | 151 | public void newton_polynomial_interpolation() throws IOException { 152 | System.out.println("Newton polynomial interpolation"); 153 | 154 | // 2 data points, linear form 155 | OrderedPairs data1 = new SortedOrderedPairs( 156 | new double[]{1., 3.}, 157 | new double[]{log(1.), log(3.)} 158 | ); 159 | Interpolation np1 = new NewtonPolynomial(); 160 | UnivariateRealFunction f1 = np1.fit(data1); 161 | plot(f1, 100, 1, 3, "./plots/chapter5/figure_5_10/linear_newton_sample.txt"); 162 | 163 | // 3 data points, quadratic form 164 | OrderedPairs data2 = new SortedOrderedPairs( 165 | new double[]{1., 2., 3.}, 166 | new double[]{log(1.), log(2.), log(3.)} 167 | ); 168 | Interpolation np2 = new NewtonPolynomial(); 169 | UnivariateRealFunction f2 = np2.fit(data2); 170 | plot(f2, 100, 1, 3, "./plots/chapter5/figure_5_11/quadratic_newton_sample.txt"); 171 | 172 | // comparison between Newton polynomial and cubic spline 173 | OrderedPairs data3 = new SortedOrderedPairs( 174 | new double[]{1., 2., 3., 4., 5., 6., 7.}, 175 | new double[]{3., 4., 2., 5., 4., 3., 6.} 176 | ); 177 | Interpolation np3 = new NewtonPolynomial(); 178 | UnivariateRealFunction f3_1 = np3.fit(data3); 179 | plot(f3_1, 500, 1, 7, "./plots/chapter5/figure_5_12/newton_sample.txt"); 180 | 181 | Interpolation cs = CubicSpline.natural(); 182 | UnivariateRealFunction f3_2 = cs.fit(data3); 183 | plot(f3_2, 500, 1, 7, "./plots/chapter5/figure_5_12/cspline_sample.txt"); 184 | } 185 | 186 | public void bivariate_interpolation() throws IOException { 187 | System.out.println("bivariate interpolation"); 188 | 189 | BivariateGrid grids = new BivariateArrayGrid( 190 | new double[][]{ 191 | {1, 1, 1}, // z(1, 1) = 1, z(1, 2) = 1, z(1, 3) = 1 192 | {2, 4, 8}, // z(2, 1) = 2, z(2, 2) = 4, z(2, 3) = 8 193 | {3, 9, 27} // z(3, 1) = 3, z(3, 2) = 9, z(3, 3) = 27 194 | }, 195 | new double[]{1, 2, 3}, // x 196 | new double[]{1, 2, 3} // y 197 | ); 198 | 199 | BivariateGridInterpolation bl = new BilinearInterpolation(); 200 | RealScalarFunction f1 = bl.interpolate(grids); // f3(1.5, 1.5) = 2.0 201 | System.out.println(f1.evaluate(new DenseVector(new double[]{1.5, 1.5}))); 202 | 203 | BivariateGridInterpolation bs = new BicubicSpline(); 204 | RealScalarFunction f2 = bs.interpolate(grids); // f2(1.5, 1.5) = 1.8828125 205 | System.out.println(f2.evaluate(new DenseVector(new double[]{1.5, 1.5}))); 206 | 207 | BivariateGridInterpolation bi = new BicubicInterpolation(); 208 | RealScalarFunction f3 = bi.interpolate(grids); // f1(1.5, 1.5) = 1.90625 209 | System.out.println(f3.evaluate(new DenseVector(new double[]{1.5, 1.5}))); 210 | 211 | plot(f3, 30, new double[]{1, 3}, new double[]{1, 3}, "./plots/chapter5/figure_5_13/bicspline_sample.txt"); 212 | } 213 | 214 | public void bivariate_interpolation_using_derivatives() throws IOException { 215 | System.out.println("bivariate interpolation using derivatives"); 216 | 217 | // derivatives and answers from Michael Flanagan's library 218 | double[][] z = new double[][]{ 219 | {1.0, 3.0, 5.0}, 220 | {2.0, 4.0, 8.0}, 221 | {9.0, 10.0, 11.0} 222 | }; 223 | 224 | final double[][] dx = new double[][]{ 225 | {6.0, 2.0, 2.0}, 226 | {6.0, 7.0, 8.0}, 227 | {6.0, 12.0, 14.0} 228 | }; 229 | final double[][] dy = new double[][]{ 230 | {8.0, 8.0, 8.0}, 231 | {16.0, 12.0, 8.0}, 232 | {4.0, 4.0, 4.0} 233 | }; 234 | final double[][] dxdy = new double[][]{ 235 | {16.0, 8.0, 0.0}, 236 | {-4.0, -4.0, -4.0}, 237 | {-24.0, -16.0, -8.0} 238 | }; 239 | 240 | BicubicInterpolation.PartialDerivatives deriv 241 | = new BicubicInterpolation.PartialDerivatives() { 242 | @Override 243 | public double dx(BivariateGrid grid, int i, int j) { 244 | return getDeriv(dx, i, j); // for some reason the y-axis is written in reverse... 245 | } 246 | 247 | @Override 248 | public double dy(BivariateGrid grid, int i, int j) { 249 | return getDeriv(dy, i, j); 250 | } 251 | 252 | @Override 253 | public double dxdy(BivariateGrid grid, int i, int j) { 254 | return getDeriv(dxdy, i, j); 255 | } 256 | 257 | private double getDeriv(double[][] dx, int i, int j) { 258 | return dx[i][2 - j]; 259 | } 260 | }; 261 | 262 | BivariateGridInterpolation interpolation = new BicubicInterpolation(deriv); 263 | BivariateGrid grid = new BivariateRegularGrid(z, 0.0, 0.0, 0.5, 0.25); 264 | RealScalarFunction f = interpolation.interpolate(grid); 265 | 266 | System.out.println(f.evaluate(new DenseVector(0.0, 0.0))); // 1.0 267 | 268 | System.out.println(f.evaluate(new DenseVector(0.0, 0.125))); // 2.0 269 | System.out.println(f.evaluate(new DenseVector(0.0, 0.25))); // 3.0 270 | System.out.println(f.evaluate(new DenseVector(0.0, 0.375))); // 4.0 271 | System.out.println(f.evaluate(new DenseVector(0.0, 0.5))); // 5.0 272 | 273 | System.out.println(f.evaluate(new DenseVector(0.25, 0.0))); // 1.125 274 | System.out.println(f.evaluate(new DenseVector(0.25, 0.125))); // 2.078125 275 | System.out.println(f.evaluate(new DenseVector(0.25, 0.25))); // 3.1875 276 | System.out.println(f.evaluate(new DenseVector(0.25, 0.375))); // 4.765625 277 | System.out.println(f.evaluate(new DenseVector(0.25, 0.5))); // 6.5 278 | 279 | System.out.println(f.evaluate(new DenseVector(0.5, 0.0))); // 2.0 280 | System.out.println(f.evaluate(new DenseVector(0.5, 0.125))); // 2.875 281 | System.out.println(f.evaluate(new DenseVector(0.5, 0.25))); // 4.0 282 | System.out.println(f.evaluate(new DenseVector(0.5, 0.375))); // 5.875 283 | System.out.println(f.evaluate(new DenseVector(0.5, 0.5))); // 8.0 284 | 285 | System.out.println(f.evaluate(new DenseVector(0.75, 0.0))); // 5.125 286 | System.out.println(f.evaluate(new DenseVector(0.75, 0.125))); // 5.828125 287 | System.out.println(f.evaluate(new DenseVector(0.75, 0.25))); // 6.6875 288 | System.out.println(f.evaluate(new DenseVector(0.75, 0.375))); // 8.015625 289 | System.out.println(f.evaluate(new DenseVector(0.75, 0.5))); // 9.5 290 | 291 | System.out.println(f.evaluate(new DenseVector(1.0, 0.0))); // 9.0 292 | System.out.println(f.evaluate(new DenseVector(1.0, 0.125))); // 9.5 293 | System.out.println(f.evaluate(new DenseVector(1.0, 0.25))); // 10.0 294 | System.out.println(f.evaluate(new DenseVector(1.0, 0.375))); // 10.5 295 | System.out.println(f.evaluate(new DenseVector(1.0, 0.5))); // 11.0 296 | } 297 | 298 | public void multivariate_interpolation() { 299 | // the data set 300 | MultiDimensionalArray mda 301 | = new MultiDimensionalArray<>(2, 2, 2); 302 | mda.set(1., 0, 0, 0); // mda[0][0][0] = 1. 303 | mda.set(2., 1, 0, 0); 304 | mda.set(3., 0, 1, 0); 305 | mda.set(4., 0, 0, 1); 306 | mda.set(5., 1, 1, 0); 307 | mda.set(6., 1, 0, 1); 308 | mda.set(7., 0, 1, 1); 309 | mda.set(8., 1, 1, 1); 310 | 311 | MultivariateArrayGrid mvGrid = new MultivariateArrayGrid( 312 | mda, 313 | new double[]{1, 2}, 314 | new double[]{1, 2}, 315 | new double[]{1, 2} 316 | ); 317 | RecursiveGridInterpolation rgi 318 | = new RecursiveGridInterpolation(new LinearInterpolation()); 319 | RealScalarFunction f = rgi.interpolate(mvGrid); 320 | System.out.println(f.evaluate(new DenseVector(new double[]{1.5, 1.5, 1.5}))); // f(1.5, 1.5, 1.5) = 4.5 321 | } 322 | 323 | /** 324 | * Export sample points to plot a function curve. 325 | * 326 | * @param f the function to plot 327 | * @param nSamples number of sample points 328 | * @param rangeStart start of the plotting range 329 | * @param rangeEnd end of the plotting range 330 | * @param filename export file name 331 | * @throws IOException 332 | */ 333 | private void plot( 334 | UnivariateRealFunction f, 335 | int nSamples, 336 | double rangeStart, 337 | double rangeEnd, 338 | String filename 339 | ) throws IOException { 340 | File file = new File(filename); 341 | if (!file.getParentFile().exists()) { 342 | file.getParentFile().mkdirs(); 343 | } 344 | file.createNewFile(); 345 | try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { 346 | double gridSize = (rangeEnd - rangeStart) / (nSamples - 1); 347 | double x = rangeStart; 348 | for (int i = 0; i < nSamples; i++) { 349 | writer.write(String.format("%f %f\n", x, f.evaluate(x))); 350 | // writer.write(new StringBuilder().append(x).append(" ").append(f.evaluate(x)).toString()); 351 | // writer.newLine(); 352 | x += gridSize; 353 | } 354 | } 355 | } 356 | 357 | /** 358 | * Export sample points to plot a bivariate function surface. 359 | * 360 | * @param f the function to plot 361 | * @param nSamples number of sample points 362 | * @param rangeX plotting range of x 363 | * @param rangeY plotting range of y 364 | * @param filename export file name 365 | * @throws IOException 366 | */ 367 | private void plot( 368 | RealScalarFunction f, 369 | int nSamples, 370 | double[] rangeX, 371 | double[] rangeY, 372 | String filename 373 | ) throws IOException { 374 | File file = new File(filename); 375 | if (!file.getParentFile().exists()) { 376 | file.getParentFile().mkdirs(); 377 | } 378 | file.createNewFile(); 379 | try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { 380 | double gridSizeX = (rangeX[1] - rangeX[0]) / (nSamples - 1); 381 | double gridSizeY = (rangeY[1] - rangeY[0]) / (nSamples - 1); 382 | double x = rangeX[0]; 383 | for (int i = 0; i < nSamples; i++) { 384 | double y = rangeY[0]; 385 | for (int j = 0; j < nSamples; j++) { 386 | writer.write(String.format("%f %f %s\n", x, y, f.evaluate(new DenseVector(x, y)).toString())); 387 | // writer.write(new StringBuilder().append(x).append(" ").append(y).append(" ").append(f.evaluate(new DenseVector(x, y))).toString()); 388 | // writer.newLine(); 389 | y += gridSizeY; 390 | } 391 | x += gridSizeX; 392 | } 393 | } 394 | } 395 | 396 | } 397 | -------------------------------------------------------------------------------- /Chapter8.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.algebra.linear.vector.doubles.Vector; 26 | import dev.nm.analysis.differentialequation.pde.finitedifference.PDESolutionGrid2D; 27 | import dev.nm.analysis.differentialequation.pde.finitedifference.PDESolutionTimeSpaceGrid1D; 28 | import dev.nm.analysis.differentialequation.pde.finitedifference.PDESolutionTimeSpaceGrid2D; 29 | import dev.nm.analysis.differentialequation.pde.finitedifference.elliptic.dim2.IterativeCentralDifference; 30 | import dev.nm.analysis.differentialequation.pde.finitedifference.elliptic.dim2.PoissonEquation2D; 31 | import dev.nm.analysis.differentialequation.pde.finitedifference.hyperbolic.dim1.ExplicitCentralDifference1D; 32 | import dev.nm.analysis.differentialequation.pde.finitedifference.hyperbolic.dim1.WaveEquation1D; 33 | import dev.nm.analysis.differentialequation.pde.finitedifference.hyperbolic.dim2.ExplicitCentralDifference2D; 34 | import dev.nm.analysis.differentialequation.pde.finitedifference.hyperbolic.dim2.WaveEquation2D; 35 | import dev.nm.analysis.differentialequation.pde.finitedifference.parabolic.dim1.heatequation.CrankNicolsonHeatEquation1D; 36 | import dev.nm.analysis.differentialequation.pde.finitedifference.parabolic.dim1.heatequation.HeatEquation1D; 37 | import dev.nm.analysis.differentialequation.pde.finitedifference.parabolic.dim2.AlternatingDirectionImplicitMethod; 38 | import dev.nm.analysis.differentialequation.pde.finitedifference.parabolic.dim2.HeatEquation2D; 39 | import dev.nm.analysis.function.rn2r1.AbstractBivariateRealFunction; 40 | import dev.nm.analysis.function.rn2r1.AbstractTrivariateRealFunction; 41 | import dev.nm.analysis.function.rn2r1.BivariateRealFunction; 42 | import dev.nm.analysis.function.rn2r1.TrivariateRealFunction; 43 | import dev.nm.analysis.function.rn2r1.univariate.AbstractUnivariateRealFunction; 44 | import dev.nm.number.DoubleUtils; 45 | import static java.lang.Math.*; 46 | 47 | /** 48 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 49 | * 50 | * @author haksunli 51 | * @see 52 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 53 | * https://nm.dev/ 54 | */ 55 | public class Chapter8 { 56 | 57 | public static void main(String[] args) { 58 | System.out.println("Chapter 8 demos"); 59 | 60 | Chapter8 chapter8 = new Chapter8(); 61 | chapter8.solve_Poisson_equation_0010(); 62 | chapter8.solve_Poisson_equation_0020(); 63 | chapter8.solve_wave_equation_1D(); 64 | chapter8.solve_wave_equation_2D(); 65 | chapter8.solve_heat_equation_1D(); 66 | chapter8.solve_heat_equation_2D(); 67 | } 68 | 69 | private void solve_heat_equation_2D() { 70 | System.out.println("solve a 2-dimensional heat equation"); 71 | 72 | // solution domain 73 | final double a = 4.0, b = 4.0; 74 | // time domain 75 | final double T = 5000; 76 | 77 | // heat equation coefficient 78 | final double beta = 1e-4; 79 | 80 | // initial condition 81 | final BivariateRealFunction f 82 | = new AbstractBivariateRealFunction() { 83 | @Override 84 | public double evaluate(double x1, double x2) { 85 | return 0.; 86 | } 87 | }; 88 | 89 | // boundary condition 90 | final TrivariateRealFunction g 91 | = new AbstractTrivariateRealFunction() { 92 | @Override 93 | public double evaluate(double t, double x, double y) { 94 | return exp(y) * cos(x) - exp(x) * cos(y); 95 | } 96 | }; 97 | final HeatEquation2D PDE = new HeatEquation2D(beta, T, a, b, f, g); 98 | 99 | AlternatingDirectionImplicitMethod adi 100 | = new AlternatingDirectionImplicitMethod(1e-5); 101 | PDESolutionTimeSpaceGrid2D soln = adi.solve(PDE, 50, 39, 39); 102 | 103 | int t = 50; 104 | int x = 1; 105 | int y = 1; 106 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 107 | t = 50; 108 | x = 1; 109 | y = 16; 110 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 111 | t = 50; 112 | x = 1; 113 | y = 31; 114 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 115 | 116 | t = 50; 117 | x = 16; 118 | y = 1; 119 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 120 | t = 50; 121 | x = 16; 122 | y = 16; 123 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 124 | t = 50; 125 | x = 16; 126 | y = 31; 127 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 128 | 129 | t = 50; 130 | x = 31; 131 | y = 1; 132 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 133 | t = 50; 134 | x = 31; 135 | y = 16; 136 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 137 | t = 50; 138 | x = 31; 139 | y = 31; 140 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 141 | } 142 | 143 | private void solve_heat_equation_1D() { 144 | System.out.println("solve a 1-dimensional heat equation"); 145 | 146 | HeatEquation1D pde = new HeatEquation1D( 147 | 1e-5, // heat equation coefficient 148 | 1., 6000., // solution domain bounds 149 | new AbstractUnivariateRealFunction() { 150 | @Override 151 | public double evaluate(double x) { 152 | return 2.0 * x + sin(2.0 * PI * x); // initial condition 153 | } 154 | }, 155 | 0., new AbstractUnivariateRealFunction() { 156 | @Override 157 | public double evaluate(double t) { 158 | return 0.; // boundary condition at x = 0 159 | } 160 | }, 161 | 0., new AbstractUnivariateRealFunction() { 162 | @Override 163 | public double evaluate(double t) { 164 | return 2.; // boundary condition at x = 6000 165 | } 166 | }); 167 | 168 | // c_k are 0 for Dirichlet boundary conditions 169 | int m = 50; 170 | int n = 39; 171 | 172 | PDESolutionTimeSpaceGrid1D soln 173 | = new CrankNicolsonHeatEquation1D().solve(pde, m, n); 174 | 175 | int t = 0; 176 | int x = 1; 177 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 178 | t = 0; 179 | x = 16; 180 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 181 | t = 0; 182 | x = 31; 183 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 184 | 185 | t = 15; 186 | x = 1; 187 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 188 | t = 15; 189 | x = 16; 190 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 191 | t = 15; 192 | x = 31; 193 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 194 | 195 | t = 30; 196 | x = 1; 197 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 198 | t = 30; 199 | x = 16; 200 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 201 | t = 30; 202 | x = 31; 203 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 204 | 205 | t = 45; 206 | x = 1; 207 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 208 | t = 45; 209 | x = 16; 210 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 211 | t = 45; 212 | x = 31; 213 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 214 | } 215 | 216 | private void solve_wave_equation_2D() { 217 | System.out.println("solve a 2-dimensional wave equation"); 218 | 219 | double c2 = 1. / 4; // wave speed squared 220 | double T = 2., a = 2., b = 2.; // the solution domain bounds 221 | WaveEquation2D pde = new WaveEquation2D( 222 | c2, T, a, b, 223 | new AbstractBivariateRealFunction() { 224 | @Override 225 | public double evaluate(double x, double y) { 226 | return 0.1 * sin(PI * x) * sin(PI * y / 2.); 227 | } 228 | }, 229 | new AbstractBivariateRealFunction() { 230 | @Override 231 | public double evaluate(double x, double y) { 232 | return 0.; 233 | } 234 | }); 235 | 236 | int m = 40; // dt = T/m 237 | int n = 39; // dx = a/n 238 | int p = 39; // dy = b/p 239 | PDESolutionTimeSpaceGrid2D soln = new ExplicitCentralDifference2D().solve(pde, m, n, p); 240 | 241 | int t = 40; // t index 242 | int x = 1; // x index 243 | int y = 1; // y index 244 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 245 | t = 40; // t index 246 | x = 1; // x index 247 | y = 16; // y index 248 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 249 | t = 40; // t index 250 | x = 1; // x index 251 | y = 31; // y index 252 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 253 | 254 | t = 40; // t index 255 | x = 16; // x index 256 | y = 1; // y index 257 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 258 | t = 40; // t index 259 | x = 16; // x index 260 | y = 16; // y index 261 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 262 | t = 40; // t index 263 | x = 16; // x index 264 | y = 31; // y index 265 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 266 | 267 | t = 40; // t index 268 | x = 31; // x index 269 | y = 1; // y index 270 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 271 | t = 40; // t index 272 | x = 31; // x index 273 | y = 16; // y index 274 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 275 | t = 40; // t index 276 | x = 31; // x index 277 | y = 31; // y index 278 | System.out.println(String.format("u(%d,%d,%d) = %f", t, x, y, soln.u(t, x, y))); 279 | } 280 | 281 | private void solve_wave_equation_1D() { 282 | System.out.println("solve a 1-dimensional wave equation"); 283 | 284 | final double c2 = 4.0; // c^2 285 | final double T = 1.0; // time upper bond 286 | final double a = 2.0; // x upper bound 287 | WaveEquation1D pde 288 | = new WaveEquation1D( 289 | c2, 290 | T, 291 | a, 292 | new AbstractUnivariateRealFunction() { 293 | @Override 294 | public double evaluate(double x) { 295 | return 0.1 * sin(PI * x); // 0.1 * sin(π x) 296 | } 297 | }, 298 | new AbstractUnivariateRealFunction() { 299 | @Override 300 | public double evaluate(double x) { 301 | return 0.2 * PI * sin(PI * x); // 0.2π * sin(π x) 302 | } 303 | }); 304 | 305 | int m = 80; // dt = T/m 306 | int n = 39; // dx = a/n 307 | PDESolutionTimeSpaceGrid1D soln = new ExplicitCentralDifference1D().solve(pde, m, n); 308 | 309 | int t = 0; // time index 310 | int x = 1; // x index 311 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 312 | t = 0; 313 | x = 16; 314 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 315 | t = 0; 316 | x = 31; 317 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 318 | 319 | t = 20; 320 | x = 1; 321 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 322 | t = 20; 323 | x = 16; 324 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 325 | t = 20; 326 | x = 31; 327 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 328 | 329 | t = 40; 330 | x = 1; 331 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 332 | t = 40; 333 | x = 16; 334 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 335 | t = 40; 336 | x = 31; 337 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 338 | 339 | t = 60; 340 | x = 1; 341 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 342 | t = 60; 343 | x = 16; 344 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 345 | t = 60; 346 | x = 31; 347 | System.out.println(String.format("u(%d,%d) = %f", t, x, soln.u(t, x))); 348 | } 349 | 350 | private void solve_Poisson_equation_0020() { 351 | System.out.println("solve a 2-dimensional Poisson equation"); 352 | 353 | BivariateRealFunction ZERO // a constant zero function, f = 0 354 | = new AbstractBivariateRealFunction() { 355 | @Override 356 | public double evaluate(double x, double y) { 357 | return 0; 358 | } 359 | 360 | @Override 361 | public Double evaluate(Vector x) { 362 | return 0.; 363 | } 364 | }; 365 | 366 | // the boundary conditions 367 | final double EPSION = 1e-8; 368 | BivariateRealFunction g = new AbstractBivariateRealFunction() { 369 | @Override 370 | public double evaluate(double x, double y) { 371 | if (DoubleUtils.isZero(x, EPSION) || DoubleUtils.isZero(y, EPSION)) { 372 | return 0; 373 | } else if (DoubleUtils.equal(x, 0.5, EPSION)) { 374 | return 200. * y; 375 | } else if (DoubleUtils.equal(y, 0.5, EPSION)) { 376 | return 200. * x; 377 | } 378 | 379 | // not reachable; don't matter 380 | return Double.NaN; 381 | } 382 | }; 383 | 384 | double a = 0.5; // width of the x-dimension 385 | double b = 0.5; // height of the y-dimension 386 | PoissonEquation2D pde = new PoissonEquation2D(a, b, ZERO, g); 387 | IterativeCentralDifference solver = new IterativeCentralDifference( 388 | EPSION, // precision 389 | 40); // max number of iterations 390 | PDESolutionGrid2D soln = solver.solve(pde, 4, 4); 391 | int k = 1, j = 1; // node indices 392 | double u_11 = soln.u(k, j); 393 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_11)); 394 | k = 1; 395 | j = 2; 396 | double u_12 = soln.u(k, j); 397 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_12)); 398 | k = 2; 399 | j = 1; 400 | double u_21 = soln.u(k, j); 401 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_21)); 402 | k = 2; 403 | j = 2; 404 | double u_22 = soln.u(k, j); 405 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_22)); 406 | k = 3; 407 | j = 3; 408 | double u_33 = soln.u(k, j); 409 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_33)); 410 | k = 4; 411 | j = 4; 412 | double u_44 = soln.u(k, j); 413 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_44)); 414 | k = 5; 415 | j = 5; 416 | double u_55 = soln.u(k, j); 417 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_55)); 418 | } 419 | 420 | private void solve_Poisson_equation_0010() { 421 | System.out.println("solve a 2-dimensional Poisson equation"); 422 | 423 | BivariateRealFunction ZERO // a constant zero function, f = 0 424 | = new AbstractBivariateRealFunction() { 425 | @Override 426 | public double evaluate(double x, double y) { 427 | return 0; 428 | } 429 | 430 | @Override 431 | public Double evaluate(Vector x) { 432 | return 0.; 433 | } 434 | }; 435 | 436 | // the boundary conditions 437 | BivariateRealFunction g = new AbstractBivariateRealFunction() { 438 | @Override 439 | public double evaluate(double x, double y) { 440 | return log((1. + x) * (1. + x) + y * y); 441 | } 442 | }; 443 | 444 | double a = 1.; // width of the x-dimension 445 | double b = 1.; // height of the y-dimension 446 | PoissonEquation2D pde = new PoissonEquation2D(a, b, ZERO, g); 447 | IterativeCentralDifference solver = new IterativeCentralDifference( 448 | 1e-8, // precision 449 | 40); // max number of iterations 450 | PDESolutionGrid2D soln = solver.solve(pde, 2, 2); 451 | int k = 1, j = 1; // node indices 452 | double u_11 = soln.u(k, j); // x = 0.3, y = 0.3 453 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_11)); 454 | k = 1; 455 | j = 2; 456 | double u_12 = soln.u(k, j); // x = 0.3, y = 0.6 457 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_12)); 458 | k = 2; 459 | j = 1; 460 | double u_21 = soln.u(k, j); // x = 0.6, y = 0.3 461 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_21)); 462 | k = 2; 463 | j = 2; 464 | double u_22 = soln.u(k, j); // x = 0.6, y = 0.6 465 | System.out.println(String.format("u_%d,%d = u(%f,%f): %f", k, j, soln.x(k), soln.y(j), u_22)); 466 | } 467 | 468 | } 469 | -------------------------------------------------------------------------------- /Chapter6Integration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.analysis.function.polynomial.Polynomial; 26 | import dev.nm.analysis.function.rn2r1.univariate.AbstractUnivariateRealFunction; 27 | import dev.nm.analysis.function.rn2r1.univariate.UnivariateRealFunction; 28 | import dev.nm.analysis.integration.univariate.riemann.ChangeOfVariable; 29 | import dev.nm.analysis.integration.univariate.riemann.Integrator; 30 | import dev.nm.analysis.integration.univariate.riemann.IterativeIntegrator; 31 | import dev.nm.analysis.integration.univariate.riemann.gaussian.GaussChebyshevQuadrature; 32 | import dev.nm.analysis.integration.univariate.riemann.gaussian.GaussHermiteQuadrature; 33 | import dev.nm.analysis.integration.univariate.riemann.gaussian.GaussLaguerreQuadrature; 34 | import dev.nm.analysis.integration.univariate.riemann.gaussian.GaussLegendreQuadrature; 35 | import dev.nm.analysis.integration.univariate.riemann.newtoncotes.NewtonCotes; 36 | import dev.nm.analysis.integration.univariate.riemann.newtoncotes.NewtonCotes.Type; 37 | import dev.nm.analysis.integration.univariate.riemann.newtoncotes.Romberg; 38 | import dev.nm.analysis.integration.univariate.riemann.newtoncotes.Simpson; 39 | import dev.nm.analysis.integration.univariate.riemann.newtoncotes.Trapezoidal; 40 | import dev.nm.analysis.integration.univariate.riemann.substitution.DoubleExponential; 41 | import dev.nm.analysis.integration.univariate.riemann.substitution.DoubleExponential4HalfRealLine; 42 | import dev.nm.analysis.integration.univariate.riemann.substitution.DoubleExponential4RealLine; 43 | import dev.nm.analysis.integration.univariate.riemann.substitution.Exponential; 44 | import dev.nm.analysis.integration.univariate.riemann.substitution.InvertingVariable; 45 | import dev.nm.analysis.integration.univariate.riemann.substitution.MixedRule; 46 | import dev.nm.analysis.integration.univariate.riemann.substitution.PowerLawSingularity; 47 | import dev.nm.analysis.integration.univariate.riemann.substitution.StandardInterval; 48 | import java.io.IOException; 49 | import static java.lang.Math.*; 50 | 51 | /** 52 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 53 | * 54 | * @author haksunli 55 | * @see 56 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 57 | * https://nm.dev/ 58 | */ 59 | public class Chapter6Integration { 60 | 61 | public static void main(String[] args) throws IOException { 62 | System.out.println("Chapter 6 demos on integration"); 63 | 64 | Chapter6Integration chapter6 = new Chapter6Integration(); 65 | chapter6.trapezoidalRule(); 66 | chapter6.SimpsonRule(); 67 | chapter6.NewtonCotes(); 68 | chapter6.Romberg(); 69 | chapter6.Gauss_Legendre_quadrature(); 70 | chapter6.Gauss_Laguerre_quadrature(); 71 | chapter6.Gauss_Hermite_quadrature(); 72 | chapter6.Gauss_Chebyshev_quadrature(); 73 | chapter6.standard_interval_substitution(); 74 | chapter6.inverting_variable_substitution(); 75 | chapter6.exponential_substitution(); 76 | chapter6.mixed_rule_substitution(); 77 | chapter6.double_exponential_substitution(); 78 | chapter6.double_exponential_real_line_substitution(); 79 | chapter6.power_law_singularity_substitution(); 80 | } 81 | 82 | public void power_law_singularity_substitution() { 83 | System.out.println("integration by substitution using DoubleExponential4HalfRealLine"); 84 | 85 | double a = 1, b = 2; // the limits 86 | NewtonCotes integrator1 87 | = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-15, 15); 88 | ChangeOfVariable integrator2 89 | = new ChangeOfVariable( 90 | new PowerLawSingularity( 91 | PowerLawSingularity.PowerLawSingularityType.LOWER, 92 | 0.5, // gamma = 0.5 93 | a, b), 94 | integrator1); 95 | 96 | double I = integrator2.integrate( // I = 2 97 | new AbstractUnivariateRealFunction() { 98 | @Override 99 | public double evaluate(double x) { 100 | return 1 / sqrt(x - 1); 101 | } 102 | }, 103 | a, b 104 | ); 105 | 106 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 107 | } 108 | 109 | public void double_exponential_half_real_line_substitution() { 110 | System.out.println("integration by substitution using DoubleExponential4HalfRealLine"); 111 | 112 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 113 | @Override 114 | public double evaluate(double x) { 115 | return x / (exp(x) - 1); 116 | } 117 | }; 118 | 119 | double a = Double.NEGATIVE_INFINITY, b = Double.POSITIVE_INFINITY; // the limits 120 | NewtonCotes integrator 121 | = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-15, 15); 122 | ChangeOfVariable instance 123 | = new ChangeOfVariable(new DoubleExponential4HalfRealLine(f, a, b, 1), integrator); 124 | double I = instance.integrate(f, a, b); // PI * PI / 6 125 | 126 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 127 | } 128 | 129 | public void double_exponential_real_line_substitution() { 130 | System.out.println("integration by substitution using DoubleExponential4RealLine"); 131 | 132 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 133 | @Override 134 | public double evaluate(double x) { 135 | return exp(-x * x); 136 | } 137 | }; 138 | 139 | double a = Double.NEGATIVE_INFINITY, b = Double.POSITIVE_INFINITY; // the limits 140 | NewtonCotes integrator1 141 | = new NewtonCotes(3, NewtonCotes.Type.CLOSED, 1e-15, 6);//only 6 iterations! 142 | ChangeOfVariable integrator2 143 | = new ChangeOfVariable(new DoubleExponential4RealLine(f, a, b, 1), integrator1); 144 | double I = integrator2.integrate(f, a, b); // sqrt(PI) 145 | 146 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 147 | } 148 | 149 | public void double_exponential_substitution() { 150 | System.out.println("integration by substitution using DoubleExponential"); 151 | 152 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 153 | @Override 154 | public double evaluate(double x) { 155 | return log(x) * log(1 - x); 156 | } 157 | }; 158 | 159 | double a = 0., b = 1.; // the limits 160 | NewtonCotes integrator1 161 | = new NewtonCotes(2, NewtonCotes.Type.CLOSED, 1e-15, 6); // only 6 iterations! 162 | ChangeOfVariable integrator2 163 | = new ChangeOfVariable(new DoubleExponential(f, a, b, 1), integrator1); 164 | double I = integrator2.integrate(f, a, b); // I = 2 - PI * PI / 6 165 | 166 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 167 | } 168 | 169 | private void mixed_rule_substitution() { 170 | System.out.println("integration by substitution using MixedRule"); 171 | 172 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 173 | @Override 174 | public double evaluate(double x) { 175 | return exp(-x) * pow(x, -1.5) * sin(x / 2); 176 | } 177 | }; 178 | 179 | double a = 0., b = Double.POSITIVE_INFINITY; // the limits 180 | NewtonCotes integrator1 181 | = new NewtonCotes(2, NewtonCotes.Type.CLOSED, 1e-15, 7); // only 7 iteration! 182 | ChangeOfVariable integrator2 183 | = new ChangeOfVariable(new MixedRule(f, a, b, 1), integrator1); 184 | double I = integrator2.integrate(f, a, b); // I = sqrt(PI * (sqrt(5) - 2)) 185 | 186 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 187 | } 188 | 189 | private void exponential_substitution() { 190 | System.out.println("integration by substitution using Exponential"); 191 | 192 | double a = 0., b = Double.POSITIVE_INFINITY; // the limits 193 | NewtonCotes integrator1 194 | = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-15, 15); 195 | ChangeOfVariable integrator2 196 | = new ChangeOfVariable(new Exponential(a), integrator1); 197 | 198 | double I = integrator2.integrate( // I = sqrt(PI)/2 199 | new AbstractUnivariateRealFunction() { 200 | @Override 201 | public double evaluate(double x) { 202 | return sqrt(x) * exp(-x); // the original integrand 203 | } 204 | }, 205 | a, b // the original limits 206 | ); 207 | 208 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 209 | } 210 | 211 | private void inverting_variable_substitution() { 212 | System.out.println("integration by substitution using InvertingVariable"); 213 | 214 | double a = 1., b = Double.POSITIVE_INFINITY; // the limits 215 | NewtonCotes integrator1 216 | = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-15, 10); 217 | ChangeOfVariable integrator2 218 | = new ChangeOfVariable(new InvertingVariable(a, b), integrator1); 219 | 220 | double I = integrator2.integrate( // I = 1 221 | new AbstractUnivariateRealFunction() { 222 | @Override 223 | public double evaluate(double x) { 224 | return 1 / x / x; // the original integrand 225 | } 226 | }, 227 | a, b // the original limits 228 | ); 229 | 230 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 231 | } 232 | 233 | private void standard_interval_substitution() { 234 | System.out.println("integration by substitution using StandardInterval"); 235 | 236 | double a = 0., b = 10.; // the limits 237 | Integrator integrator1 238 | = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-8, 10); 239 | Integrator integrator2 240 | = new ChangeOfVariable(new StandardInterval(a, b), integrator1); 241 | 242 | double I = integrator2.integrate( 243 | new AbstractUnivariateRealFunction() { 244 | @Override 245 | public double evaluate(double t) { 246 | return t; // the original integrand 247 | } 248 | }, 249 | a, b // the original limits 250 | ); 251 | 252 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 253 | } 254 | 255 | private void Gauss_Chebyshev_quadrature() { 256 | System.out.println("integrate using the Gauss Chebyshev quadrature"); 257 | 258 | final Polynomial poly = new Polynomial(1, 2, 1); // x^2 + 2x + 1 259 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 260 | @Override 261 | public double evaluate(double x) { 262 | // second order polynomial divided by weighting can be reproduced exactly 263 | return poly.evaluate(x) / sqrt(1 - x * x); 264 | } 265 | }; 266 | 267 | // the integrators 268 | Integrator integrator1 = new Trapezoidal(1e-8, 20); // using the trapezoidal rule 269 | Integrator integrator2 = new Simpson(1e-8, 20); // using the Simpson rule 270 | Integrator integrator3 = new GaussChebyshevQuadrature(2); 271 | 272 | // the limits 273 | double a = -1., b = 1.; 274 | 275 | // the integrations 276 | double I1 = integrator1.integrate(f, a, b); 277 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the trapezoidal rule", a, b, I1)); 278 | double I2 = integrator2.integrate(f, a, b); 279 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Sampson rule", a, b, I2)); 280 | double I3 = integrator3.integrate(f, a, b); 281 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Gauss Hermite quadrature", a, b, I3)); 282 | } 283 | 284 | public void Gauss_Hermite_quadrature() { 285 | System.out.println("integrate using the Gauss Hermite quadrature"); 286 | 287 | final Polynomial poly = new Polynomial(1, 2, 1); // x^2 + 2x + 1 288 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 289 | @Override 290 | public double evaluate(double x) { 291 | return exp(-(x * x)) * poly.evaluate(x); // e^(-x^2) * (x^2 + 2x + 1) 292 | } 293 | }; 294 | 295 | // the integrators 296 | Integrator integrator1 = new Trapezoidal(1e-8, 20); // using the trapezoidal rule 297 | Integrator integrator2 = new Simpson(1e-8, 20); // using the Simpson rule 298 | Integrator integrator3 = new GaussHermiteQuadrature(2); 299 | 300 | // the limits 301 | double a = Double.NEGATIVE_INFINITY, b = Double.POSITIVE_INFINITY; 302 | 303 | // the integrations 304 | double I1 = integrator1.integrate(f, a, b); 305 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the trapezoidal rule", a, b, I1)); 306 | double I2 = integrator2.integrate(f, a, b); 307 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Sampson rule", a, b, I2)); 308 | double I3 = integrator3.integrate(f, a, b); 309 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Gauss Hermite quadrature", a, b, I3)); 310 | } 311 | 312 | private void Gauss_Laguerre_quadrature() { 313 | System.out.println("integrate using the Gauss Laguerre quadrature"); 314 | 315 | final Polynomial poly = new Polynomial(1, 2, 1); // x^2 + 2x + 1 316 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 317 | @Override 318 | public double evaluate(double x) { 319 | return exp(-x) * poly.evaluate(x); // e^-x * (x^2 + 2x + 1) 320 | } 321 | }; 322 | 323 | // the integrators 324 | Integrator integrator1 = new Trapezoidal(1e-8, 20); // using the trapezoidal rule 325 | Integrator integrator2 = new Simpson(1e-8, 20); // using the Simpson rule 326 | Integrator integrator3 = new GaussLaguerreQuadrature(2, 1e-8); 327 | 328 | // the limits 329 | double a = 0., b = Double.POSITIVE_INFINITY; 330 | 331 | // the integrations 332 | double I1 = integrator1.integrate(f, a, b); 333 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the trapezoidal rule", a, b, I1)); 334 | double I2 = integrator2.integrate(f, a, b); 335 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Sampson rule", a, b, I2)); 336 | double I3 = integrator3.integrate(f, a, b); 337 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Gauss Laguerre quadrature", a, b, I3)); 338 | } 339 | 340 | private void Gauss_Legendre_quadrature() { 341 | System.out.println("integrate using the Gauss Legendre quadrature"); 342 | 343 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 344 | @Override 345 | public double evaluate(double x) { 346 | return 4 * x * x * x + 2 * x + 1; // x^4 + x^2 + x 347 | } 348 | }; 349 | 350 | // the integrators 351 | Integrator integrator1 = new Trapezoidal(1e-8, 20); // using the trapezoidal rule 352 | Integrator integrator2 = new Simpson(1e-8, 20); // using the Simpson rule 353 | Integrator integrator3 = new GaussLegendreQuadrature(2); 354 | // the limits 355 | double a = -1., b = 1.; 356 | 357 | // the integrations 358 | double I1 = integrator1.integrate(f, a, b); 359 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the trapezoidal rule", a, b, I1)); 360 | double I2 = integrator2.integrate(f, a, b); 361 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Sampson rule", a, b, I2)); 362 | double I3 = integrator3.integrate(f, a, b); 363 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Gauss Legendre quadrature", a, b, I3)); 364 | } 365 | 366 | private void Romberg() { 367 | System.out.println("integrate using the Romberg formulas"); 368 | 369 | final UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 370 | 371 | @Override 372 | public double evaluate(double x) { 373 | return exp(2. * x) - 4. * x - 7.; 374 | } 375 | }; 376 | IterativeIntegrator integrator1 = new Trapezoidal(1e-8, 20); // using the trapezoidal rule 377 | Integrator integrator2 = new Simpson(1e-8, 20); // using the Simpson rule 378 | Integrator integrator3 = new Romberg(integrator1); 379 | // the limit 380 | double a = 0., b = 1.; 381 | // the integrations 382 | double I1 = integrator1.integrate(f, a, b); 383 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the trapezoidal rule", a, b, I1)); 384 | double I2 = integrator2.integrate(f, a, b); 385 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Simpson rule", a, b, I2)); 386 | double I3 = integrator3.integrate(f, a, b); 387 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Romberg formula", a, b, I3)); 388 | } 389 | 390 | private void NewtonCotes() { 391 | System.out.println("integrate using the Newton-Cotes formulas"); 392 | 393 | final UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 394 | 395 | @Override 396 | public double evaluate(double x) { 397 | return 4. / (1. + x * x); // 4/(1+x^2) 398 | } 399 | }; 400 | 401 | // the limit 402 | double a = 0., b = 1.; 403 | Integrator integrator1 = new Trapezoidal(1e-8, 20); // using the trapezoidal rule 404 | Integrator integrator2 = new Simpson(1e-8, 20); // using the Simpson rule 405 | Integrator integrator3 = new NewtonCotes(3, Type.CLOSED, 1e-8, 20); // using the Newton-Cotes rule 406 | Integrator integrator4 = new NewtonCotes(3, Type.OPEN, 1e-8, 20); // using the Newton-Cotes rule 407 | 408 | // the integrations 409 | double I1 = integrator1.integrate(f, a, b); 410 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the trapezoidal rule", a, b, I1)); 411 | double I2 = integrator2.integrate(f, a, b); 412 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Simpson rule", a, b, I2)); 413 | double I3 = integrator3.integrate(f, a, b); 414 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using the Newton-Cotes closed rule", a, b, I3)); 415 | double I4 = integrator4.integrate(f, a, b); 416 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %.16f, using using the Newton-Cotes open rule", a, b, I4)); 417 | } 418 | 419 | private void SimpsonRule() { 420 | System.out.println("integrate using the Simpson rule"); 421 | 422 | final UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 423 | 424 | @Override 425 | public double evaluate(double x) { 426 | return -(x * x - 4 * x + 6); // -(x^2 - 4x + 6) 427 | } 428 | }; 429 | 430 | // the limit 431 | double a = 0., b = 4.; 432 | // an integrator using the Simpson rule 433 | Integrator integrator = new Simpson(1e-8, 20); // precision, max number of iterations 434 | // the integration 435 | double I = integrator.integrate(f, a, b); 436 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 437 | } 438 | 439 | private void trapezoidalRule() { 440 | System.out.println("integrate using the trapezoidal rule"); 441 | 442 | final UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 443 | 444 | @Override 445 | public double evaluate(double x) { 446 | return -(x * x - 4 * x + 6); // -(x^2 - 4x + 6) 447 | } 448 | }; 449 | 450 | // the limit 451 | double a = 0., b = 4.; 452 | // an integrator using the trapezoidal rule 453 | Integrator integrator = new Trapezoidal(1e-8, 20); // precision, max number of iterations 454 | // the integration 455 | double I = integrator.integrate(f, a, b); 456 | System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I)); 457 | } 458 | 459 | } 460 | -------------------------------------------------------------------------------- /Chapter6Differentiation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.algebra.linear.matrix.doubles.Matrix; 26 | import dev.nm.algebra.linear.matrix.doubles.operation.MatrixMeasure; 27 | import dev.nm.algebra.linear.vector.doubles.Vector; 28 | import dev.nm.algebra.linear.vector.doubles.dense.DenseVector; 29 | import dev.nm.analysis.differentiation.Ridders; 30 | import dev.nm.analysis.differentiation.multivariate.Gradient; 31 | import dev.nm.analysis.differentiation.multivariate.GradientFunction; 32 | import dev.nm.analysis.differentiation.multivariate.Hessian; 33 | import dev.nm.analysis.differentiation.multivariate.HessianFunction; 34 | import dev.nm.analysis.differentiation.multivariate.Jacobian; 35 | import dev.nm.analysis.differentiation.multivariate.JacobianFunction; 36 | import dev.nm.analysis.differentiation.multivariate.MultivariateFiniteDifference; 37 | import dev.nm.analysis.function.special.gaussian.Gaussian; 38 | import dev.nm.analysis.differentiation.univariate.DBeta; 39 | import dev.nm.analysis.differentiation.univariate.DBetaRegularized; 40 | import dev.nm.analysis.differentiation.univariate.DErf; 41 | import dev.nm.analysis.differentiation.univariate.DGamma; 42 | import dev.nm.analysis.differentiation.univariate.DGaussian; 43 | import dev.nm.analysis.differentiation.univariate.DPolynomial; 44 | import dev.nm.analysis.differentiation.univariate.FiniteDifference; 45 | import dev.nm.analysis.function.matrix.RntoMatrix; 46 | import dev.nm.analysis.function.polynomial.Polynomial; 47 | import dev.nm.analysis.function.rn2r1.AbstractBivariateRealFunction; 48 | import dev.nm.analysis.function.rn2r1.RealScalarFunction; 49 | import dev.nm.analysis.function.rn2r1.univariate.AbstractUnivariateRealFunction; 50 | import dev.nm.analysis.function.rn2r1.univariate.UnivariateRealFunction; 51 | import dev.nm.analysis.function.rn2rm.RealVectorFunction; 52 | import dev.nm.analysis.function.special.beta.Beta; 53 | import dev.nm.analysis.function.special.beta.BetaRegularized; 54 | import dev.nm.analysis.function.special.gamma.Gamma; 55 | import dev.nm.analysis.function.special.gamma.GammaLanczosQuick; 56 | import dev.nm.analysis.function.special.gaussian.Erf; 57 | import java.io.IOException; 58 | import static java.lang.Math.*; 59 | 60 | /** 61 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 62 | * 63 | * @author haksunli 64 | * @see 65 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 66 | * https://nm.dev/ 67 | */ 68 | public class Chapter6Differentiation { 69 | 70 | public static void main(String[] args) throws IOException { 71 | System.out.println("Chapter 6 demos on differentiation"); 72 | 73 | Chapter6Differentiation chapter6 = new Chapter6Differentiation(); 74 | chapter6.df1dx1(); 75 | chapter6.df2dx2(); 76 | chapter6.dGaussian(); 77 | chapter6.dPolynomial(); 78 | chapter6.dError(); 79 | chapter6.dBeta(); 80 | chapter6.dBetaRegularized(); 81 | chapter6.dGamma(); 82 | chapter6.partial_deriatvies_0010(); 83 | chapter6.partial_deriatvies_0020(); 84 | chapter6.gradient_0010(); 85 | chapter6.gradient_0020(); 86 | chapter6.jacobian_0010(); 87 | chapter6.jacobian_0020(); 88 | chapter6.hessian_0010(); 89 | chapter6.ridder_0010(); 90 | chapter6.ridder_0020(); 91 | } 92 | 93 | public void ridder_0020() { 94 | System.out.println("comparing Ridder's method to finite difference for multivariate function"); 95 | 96 | // f = xy + 2xyz 97 | RealScalarFunction f = new RealScalarFunction() { 98 | 99 | @Override 100 | public Double evaluate(Vector v) { 101 | return v.get(1) * v.get(2) + 2 * v.get(1) * v.get(2) * v.get(3); 102 | } 103 | 104 | @Override 105 | public int dimensionOfDomain() { 106 | return 3; 107 | } 108 | 109 | @Override 110 | public int dimensionOfRange() { 111 | return 1; 112 | } 113 | }; 114 | 115 | Ridders dxy_ridder = new Ridders(f, new int[]{1, 2}); 116 | MultivariateFiniteDifference dxy // 1 + 2z 117 | // differentiate the first variable and then the second one 118 | = new MultivariateFiniteDifference(f, new int[]{1, 2}); 119 | Vector x0 = new DenseVector(1., 1., 1.); 120 | System.out.println(String.format("Dxy(%s) by Ridder = %.16f", x0, dxy_ridder.evaluate(x0))); 121 | System.out.println(String.format("Dxy(%s) by FD = %.16f", x0, dxy.evaluate(x0))); 122 | Vector x1 = new DenseVector(-100., 0., -1.5); 123 | System.out.println(String.format("Dxy(%s) by FD = %.16f", x1, dxy_ridder.evaluate(x1))); 124 | System.out.println(String.format("Dxy(%s) by FD = %.16f", x1, dxy.evaluate(x1))); 125 | 126 | //continuous function allows switching the order of differentiation by Clairaut's theorem 127 | Ridders dyx_ridder = new Ridders(f, new int[]{2, 1}); 128 | MultivariateFiniteDifference dyx // 1 + 2z 129 | // differentiate the second variable and then the first one 130 | = new MultivariateFiniteDifference(f, new int[]{2, 1}); 131 | System.out.println(String.format("Dyx(%s) by Ridder = %.16f", x0, dyx_ridder.evaluate(x0))); 132 | System.out.println(String.format("Dyx(%s) by FD = %.16f", x0, dyx.evaluate(x0))); 133 | System.out.println(String.format("Dyx(%s) by Ridder = %.16f", x1, dyx_ridder.evaluate(x1))); 134 | System.out.println(String.format("Dyx(%s) by FD = %.16f", x1, dyx.evaluate(x1))); 135 | } 136 | 137 | public void ridder_0010() { 138 | System.out.println("comparing Ridder's method to finite difference for univariate function"); 139 | 140 | UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 141 | @Override 142 | public double evaluate(double x) { 143 | return log(x); 144 | } 145 | }; 146 | 147 | double x = 0.5; 148 | for (int order = 1; order < 10; ++order) { 149 | FiniteDifference fd = new FiniteDifference(f, order, FiniteDifference.Type.CENTRAL); 150 | Ridders ridder = new Ridders(f, order); 151 | System.out.println(String.format( 152 | "%d-nd order derivative by Rideer @ %f = %.16f", order, x, ridder.evaluate(x))); 153 | System.out.println(String.format( 154 | "%d-nd order derivative by FD @ %f = %.16f", order, x, fd.evaluate(x))); 155 | } 156 | } 157 | 158 | private void hessian_0010() { 159 | System.out.println("compute the Hessian for a multivariate real-valued function"); 160 | 161 | RealScalarFunction f = new AbstractBivariateRealFunction() { 162 | @Override 163 | public double evaluate(double x, double y) { 164 | return x * y; // f = xy 165 | } 166 | }; 167 | 168 | Vector x1 = new DenseVector(1., 1.); 169 | Hessian H1 = new Hessian(f, x1); 170 | System.out.println(String.format( 171 | "the Hessian at %s = %s, the det = %f", 172 | x1, 173 | H1, 174 | MatrixMeasure.det(H1))); 175 | 176 | Vector x2 = new DenseVector(0., 0.); 177 | Hessian H2 = new Hessian(f, x2); 178 | System.out.println(String.format( 179 | "the Hessian at %s = %s, the det = %f", 180 | x2, 181 | H2, 182 | MatrixMeasure.det(H2))); 183 | 184 | RntoMatrix H = new HessianFunction(f); 185 | Matrix Hx1 = H.evaluate(x1); 186 | System.out.println(String.format( 187 | "the Hessian at %s = %s, the det = %f", 188 | x1, 189 | Hx1, 190 | MatrixMeasure.det(Hx1))); 191 | Matrix Hx2 = H.evaluate(x2); 192 | System.out.println(String.format( 193 | "the Hessian at %s = %s, the det = %f", 194 | x2, 195 | Hx2, 196 | MatrixMeasure.det(Hx2))); 197 | } 198 | 199 | private void jacobian_0020() { 200 | System.out.println("compute the Jacobian for a multivariate vector-valued function"); 201 | 202 | RealVectorFunction F = new RealVectorFunction() { 203 | @Override 204 | public Vector evaluate(Vector v) { 205 | double x1 = v.get(1); 206 | double x2 = v.get(2); 207 | double x3 = v.get(3); 208 | 209 | double f1 = 5. * x2; 210 | double f2 = 4. * x1 * x1 - 2. * sin(x2 * x3); 211 | double f3 = x2 * x3; 212 | 213 | return new DenseVector(f1, f2, f3); 214 | } 215 | 216 | @Override 217 | public int dimensionOfDomain() { 218 | return 3; 219 | } 220 | 221 | @Override 222 | public int dimensionOfRange() { 223 | return 3; 224 | } 225 | }; 226 | 227 | Vector x0 = new DenseVector(0., 0., 1.); 228 | RntoMatrix J = new JacobianFunction(F); 229 | Matrix J0 = J.evaluate(x0); 230 | System.out.println(String.format( 231 | "the Jacobian at %s = %s, the det = %f", 232 | x0, 233 | J0, 234 | MatrixMeasure.det(J0))); 235 | 236 | Vector x1 = new DenseVector(1., 2., 3.); 237 | Matrix J1 = J.evaluate(x1); 238 | System.out.println(String.format( 239 | "the Jacobian at %s = %s, the det = %f", 240 | x1, 241 | J1, 242 | MatrixMeasure.det(J1))); 243 | } 244 | 245 | private void jacobian_0010() { 246 | System.out.println("compute the Jacobian for a multivariate vector-valued function"); 247 | 248 | RealVectorFunction F = new RealVectorFunction() { 249 | @Override 250 | public Vector evaluate(Vector v) { 251 | double x = v.get(1); 252 | double y = v.get(2); 253 | 254 | double f1 = x * x * y; 255 | double f2 = 5. * x + sin(y); 256 | 257 | return new DenseVector(f1, f2); 258 | } 259 | 260 | @Override 261 | public int dimensionOfDomain() { 262 | return 2; 263 | } 264 | 265 | @Override 266 | public int dimensionOfRange() { 267 | return 2; 268 | } 269 | }; 270 | 271 | Vector x0 = new DenseVector(0., 0.); 272 | Matrix J00 = new Jacobian(F, x0); 273 | System.out.println(String.format( 274 | "the Jacobian at %s = %s, the det = %f", 275 | x0, 276 | J00, 277 | MatrixMeasure.det(J00))); 278 | 279 | RntoMatrix J = new JacobianFunction(F); // [2xy, x^2], [5, cosy] 280 | Matrix J01 = J.evaluate(x0); 281 | System.out.println(String.format( 282 | "the Jacobian at %s = %s, the det = %f", 283 | x0, 284 | J01, 285 | MatrixMeasure.det(J01))); 286 | 287 | Vector x1 = new DenseVector(1., PI); 288 | Matrix J1 = J.evaluate(x1); 289 | System.out.println(String.format( 290 | "the Jacobian at %s = %s, the det = %f", 291 | x1, 292 | J1, 293 | MatrixMeasure.det(J1))); 294 | } 295 | 296 | private void gradient_0020() { 297 | System.out.println("compute the gradient for a multivariate real-valued function"); 298 | 299 | // f = -((cos(x))^2 + (cos(y))^2)^2 300 | RealScalarFunction f = new AbstractBivariateRealFunction() { 301 | 302 | @Override 303 | public double evaluate(double x, double y) { 304 | double z = cos(x) * cos(x); 305 | z += cos(y) * cos(y); 306 | z = -z * z; 307 | return z; 308 | } 309 | }; 310 | 311 | Vector x1 = new DenseVector(0., 0.); 312 | Vector g1_0 = new Gradient(f, x1); 313 | System.out.println(String.format("gradient at %s = %s", x1, g1_0)); 314 | 315 | GradientFunction df = new GradientFunction(f); 316 | Vector g1_1 = df.evaluate(x1); 317 | System.out.println(String.format("gradient at %s = %s", x1, g1_1)); 318 | 319 | Vector x2 = new DenseVector(-1., 0.); 320 | Vector g2 = df.evaluate(x2); 321 | System.out.println(String.format("gradient at %s = %s", x2, g2)); 322 | 323 | Vector x3 = new DenseVector(1., 0.); 324 | Vector g3 = df.evaluate(x3); 325 | System.out.println(String.format("gradient at %s = %s", x3, g3)); 326 | } 327 | 328 | private void gradient_0010() { 329 | System.out.println("compute the gradient for a multivariate real-valued function"); 330 | 331 | // f = x * exp(-(x^2 + y^2)) 332 | RealScalarFunction f = new AbstractBivariateRealFunction() { 333 | 334 | @Override 335 | public double evaluate(double x, double y) { 336 | return x * exp(-(x * x + y * y)); 337 | } 338 | }; 339 | 340 | Vector x1 = new DenseVector(0., 0.); 341 | Vector g1_0 = new Gradient(f, x1); 342 | System.out.println(String.format("gradient at %s = %s", x1, g1_0)); 343 | 344 | GradientFunction df = new GradientFunction(f); 345 | Vector g1_1 = df.evaluate(x1); 346 | System.out.println(String.format("gradient at %s = %s", x1, g1_1)); 347 | 348 | Vector x2 = new DenseVector(-1., 0.); 349 | Vector g2 = df.evaluate(x2); 350 | System.out.println(String.format("gradient at %s = %s", x2, g2)); 351 | 352 | Vector x3 = new DenseVector(1., 0.); 353 | Vector g3 = df.evaluate(x3); 354 | System.out.println(String.format("gradient at %s = %s", x3, g3)); 355 | } 356 | 357 | private void partial_deriatvies_0010() { 358 | System.out.println("compute the partial derivatives for a multivariate real-valued function"); 359 | 360 | // f = x^2 + xy + y^2 361 | RealScalarFunction f = new AbstractBivariateRealFunction() { 362 | 363 | @Override 364 | public double evaluate(double x, double y) { 365 | return x * x + x * y + y * y; 366 | } 367 | }; 368 | 369 | // df/dx = 2x + y 370 | MultivariateFiniteDifference dx 371 | = new MultivariateFiniteDifference(f, new int[]{1}); 372 | System.out.println(String.format("Dxy(1.,1.) %f", dx.evaluate(new DenseVector(1., 1.)))); 373 | } 374 | 375 | private void partial_deriatvies_0020() { 376 | System.out.println("compute the partial derivatives for a multivariate real-valued function"); 377 | 378 | // f = xy + 2xyz 379 | RealScalarFunction f = new RealScalarFunction() { 380 | 381 | @Override 382 | public Double evaluate(Vector v) { 383 | return v.get(1) * v.get(2) + 2 * v.get(1) * v.get(2) * v.get(3); 384 | } 385 | 386 | @Override 387 | public int dimensionOfDomain() { 388 | return 3; 389 | } 390 | 391 | @Override 392 | public int dimensionOfRange() { 393 | return 1; 394 | } 395 | }; 396 | 397 | MultivariateFiniteDifference dxy // 1 + 2z 398 | // differentiate the first variable and then the second one 399 | = new MultivariateFiniteDifference(f, new int[]{1, 2}); 400 | System.out.println(String.format("Dxy(1.,1.,1.) %f", dxy.evaluate(new DenseVector(1., 1., 1.)))); 401 | System.out.println(String.format("Dxy(-100.,0.,-1.5) %f", dxy.evaluate(new DenseVector(-100., 0., -1.5)))); 402 | 403 | //continuous function allows switching the order of differentiation by Clairaut's theorem 404 | MultivariateFiniteDifference dyx // 1 + 2z 405 | // differentiate the second variable and then the first one 406 | = new MultivariateFiniteDifference(f, new int[]{2, 1}); 407 | System.out.println(String.format("Dyx(1.,1.,1.) %f", dyx.evaluate(new DenseVector(1., 1., 1.)))); 408 | System.out.println(String.format("Dyx(-100.,0.,-1.5) %f", dyx.evaluate(new DenseVector(-100., 0., -1.5)))); 409 | } 410 | 411 | private void dGamma() { 412 | System.out.println("compute the first order derivative for the Gamma function"); 413 | 414 | double z = 0.5; 415 | // Wikipedia: Lanczos approximation 416 | Gamma G = new GammaLanczosQuick(); 417 | DGamma dG = new DGamma(); 418 | System.out.println(String.format("Gamma(%f) = %f", z, G.evaluate(z))); 419 | System.out.println(String.format("dGamma/dz(%f) = %f", z, dG.evaluate(z))); 420 | } 421 | 422 | private void dBetaRegularized() { 423 | System.out.println("compute the first order derivative for the regularized Beta function"); 424 | 425 | double p = 0.5; 426 | double q = 2.5; 427 | BetaRegularized I = new BetaRegularized(p, q); 428 | DBetaRegularized dI = new DBetaRegularized(p, q); 429 | 430 | double x = 1.; 431 | System.out.println(String.format("BetaRegularized(%f) = %f", x, I.evaluate(x))); 432 | System.out.println(String.format("dBetaRegularized/dz(%f) = %f", x, dI.evaluate(x))); 433 | } 434 | 435 | private void dBeta() { 436 | System.out.println("compute the first order derivative for the Beta function"); 437 | 438 | double x = 1.5; 439 | double y = 2.5; 440 | Beta B = new Beta(); 441 | DBeta dB = new DBeta(); 442 | System.out.println(String.format("Beta(%f) = %f", x, B.evaluate(x, y))); 443 | System.out.println(String.format("dBeta/dz(%f) = %f", x, dB.evaluate(x, y))); 444 | } 445 | 446 | private void dError() { 447 | System.out.println("compute the first order derivative for the Error function"); 448 | 449 | double z = 0.5; 450 | Erf E = new Erf(); 451 | DErf dE = new DErf(); 452 | System.out.println(String.format("erf(%f) = %f", z, E.evaluate(z))); 453 | System.out.println(String.format("dErf/dz(%f) = %f", z, dE.evaluate(z))); 454 | } 455 | 456 | private void dPolynomial() { 457 | System.out.println("compute the first order derivative for a polynomial"); 458 | 459 | Polynomial p = new Polynomial(1, 2, 1); // x^2 + 2x + 1 460 | Polynomial dp = new DPolynomial(p); // 2x + 2 461 | double x = 1.; 462 | System.out.println(String.format("dp/dx(%f) = %f", x, dp.evaluate(x))); 463 | } 464 | 465 | private void dGaussian() { 466 | System.out.println("compute the first order derivative for the Gaussian function"); 467 | 468 | Gaussian G = new Gaussian(1., 0., 1.); // standard Gaussian 469 | DGaussian dG = new DGaussian(G); 470 | double x = -0.5; 471 | System.out.println(String.format("dG/dx(%f) = %f", x, dG.evaluate(x))); 472 | x = 0; 473 | System.out.println(String.format("dG/dx(%f) = %f", x, dG.evaluate(x))); 474 | x = 0.5; 475 | System.out.println(String.format("dG/dx(%f) = %f", x, dG.evaluate(x))); 476 | } 477 | 478 | private void df1dx1() { 479 | System.out.println("differentiate univariate functions"); 480 | 481 | final UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 482 | 483 | @Override 484 | public double evaluate(double x) { 485 | return -(x * x - 4 * x + 6); // -(x^2 - 4x + 6) 486 | } 487 | }; 488 | double x = 2.; 489 | 490 | UnivariateRealFunction df1_forward 491 | = new FiniteDifference(f, 1, FiniteDifference.Type.FORWARD); 492 | double dfdx = df1_forward.evaluate(x); // evaluate at x 493 | System.out.println(String.format("df/dx(x=%f) = %.16f using forward difference", x, dfdx)); 494 | 495 | UnivariateRealFunction df1_backward 496 | = new FiniteDifference(f, 1, FiniteDifference.Type.BACKWARD); 497 | dfdx = df1_backward.evaluate(x); // evaluate at x 498 | System.out.println(String.format("df/dx(x=%f) = %.16f using backward difference", x, dfdx)); 499 | 500 | UnivariateRealFunction df1_central 501 | = new FiniteDifference(f, 1, FiniteDifference.Type.CENTRAL); 502 | dfdx = df1_central.evaluate(x); // evaluate at x 503 | System.out.println(String.format("df/dx(x=%f) = %.16f using central difference", x, dfdx)); 504 | } 505 | 506 | private void df2dx2() { 507 | System.out.println("compute the second order derivative of univariate functions"); 508 | 509 | final UnivariateRealFunction f = new AbstractUnivariateRealFunction() { 510 | 511 | @Override 512 | public double evaluate(double x) { 513 | return -(x * x - 4 * x + 6); // -(x^2 - 4x + 6) 514 | } 515 | }; 516 | double x = 2.; 517 | 518 | System.out.println("differentiate univariate functions"); 519 | 520 | UnivariateRealFunction df1_forward 521 | = new FiniteDifference(f, 2, FiniteDifference.Type.FORWARD); 522 | double dfdx = df1_forward.evaluate(x); // evaluate at x 523 | System.out.println(String.format("d2f/dx2(x=%f) = %.16f using forward difference", x, dfdx)); 524 | 525 | UnivariateRealFunction df1_backward 526 | = new FiniteDifference(f, 2, FiniteDifference.Type.BACKWARD); 527 | dfdx = df1_backward.evaluate(x); // evaluate at x 528 | System.out.println(String.format("d2f/dx2(x=%f) = %.16f using backward difference", x, dfdx)); 529 | 530 | UnivariateRealFunction df1_central 531 | = new FiniteDifference(f, 2, FiniteDifference.Type.CENTRAL); 532 | dfdx = df1_central.evaluate(x); // evaluate at x 533 | System.out.println(String.format("d2f/d2x(x=%f) = %.16f using central difference", x, dfdx)); 534 | } 535 | 536 | } 537 | -------------------------------------------------------------------------------- /Chapter9.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.algebra.linear.matrix.doubles.Matrix; 26 | import dev.nm.algebra.linear.matrix.doubles.matrixtype.dense.DenseMatrix; 27 | import dev.nm.algebra.linear.vector.doubles.Vector; 28 | import dev.nm.algebra.linear.vector.doubles.dense.DenseVector; 29 | import dev.nm.analysis.function.matrix.RntoMatrix; 30 | import dev.nm.analysis.function.polynomial.Polynomial; 31 | import dev.nm.analysis.function.rn2r1.AbstractBivariateRealFunction; 32 | import dev.nm.analysis.function.rn2r1.RealScalarFunction; 33 | import dev.nm.analysis.function.rn2rm.RealVectorFunction; 34 | import dev.nm.analysis.function.special.gamma.LogGamma; 35 | import dev.nm.solver.IterativeSolution; 36 | import dev.nm.solver.multivariate.unconstrained.BruteForceMinimizer; 37 | import dev.nm.solver.multivariate.unconstrained.DoubleBruteForceMinimizer; 38 | import dev.nm.solver.multivariate.unconstrained.c2.conjugatedirection.ConjugateGradientMinimizer; 39 | import dev.nm.solver.multivariate.unconstrained.c2.conjugatedirection.FletcherReevesMinimizer; 40 | import dev.nm.solver.multivariate.unconstrained.c2.conjugatedirection.PowellMinimizer; 41 | import dev.nm.solver.multivariate.unconstrained.c2.conjugatedirection.ZangwillMinimizer; 42 | import dev.nm.solver.multivariate.unconstrained.c2.quasinewton.BFGSMinimizer; 43 | import dev.nm.solver.multivariate.unconstrained.c2.quasinewton.DFPMinimizer; 44 | import dev.nm.solver.multivariate.unconstrained.c2.quasinewton.HuangMinimizer; 45 | import dev.nm.solver.multivariate.unconstrained.c2.quasinewton.PearsonMinimizer; 46 | import dev.nm.solver.multivariate.unconstrained.c2.quasinewton.QuasiNewtonMinimizer; 47 | import dev.nm.solver.multivariate.unconstrained.c2.quasinewton.RankOneMinimizer; 48 | import dev.nm.solver.multivariate.unconstrained.c2.steepestdescent.FirstOrderMinimizer; 49 | import dev.nm.solver.multivariate.unconstrained.c2.steepestdescent.GaussNewtonMinimizer; 50 | import dev.nm.solver.multivariate.unconstrained.c2.steepestdescent.NewtonRaphsonMinimizer; 51 | import dev.nm.solver.multivariate.unconstrained.c2.steepestdescent.SteepestDescentMinimizer; 52 | import dev.nm.solver.problem.C2OptimProblem; 53 | import dev.nm.solver.problem.C2OptimProblemImpl; 54 | import dev.nm.solver.problem.OptimProblem; 55 | import dev.nm.root.univariate.UnivariateMinimizer; 56 | import dev.nm.root.univariate.bracketsearch.BracketSearchMinimizer; 57 | import dev.nm.root.univariate.bracketsearch.BrentMinimizer; 58 | import dev.nm.root.univariate.bracketsearch.FibonaccMinimizer; 59 | import dev.nm.root.univariate.bracketsearch.GoldenMinimizer; 60 | import static java.lang.Math.pow; 61 | import static java.lang.Math.sqrt; 62 | import java.util.ArrayList; 63 | import java.util.List; 64 | 65 | /** 66 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 67 | * 68 | * @author haksunli 69 | * @see 70 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 71 | * https://nm.dev/ 72 | */ 73 | public class Chapter9 { 74 | 75 | public static void main(String[] args) throws Exception { 76 | System.out.println("Chapter 9 demos"); 77 | 78 | Chapter9 chapter9 = new Chapter9(); 79 | chapter9.solve_by_brute_force_search_1(); 80 | chapter9.solve_by_brute_force_search_2(); 81 | chapter9.solve_by_brute_force_search_3(); 82 | chapter9.solve_by_brute_force_search_4(); 83 | chapter9.solve_loggamma_by_bracketing(); 84 | chapter9.solve_by_steepest_descent(); 85 | chapter9.solve_by_Newton_Raphson(); 86 | chapter9.solve_by_Gauss_Newton(); 87 | chapter9.solve_by_conjugate_direction_methods(); 88 | chapter9.solve_by_quasi_Newton(); 89 | } 90 | 91 | public void solve_by_brute_force_search_1() throws Exception { 92 | System.out.println("solve uniivariate function by brute force search"); 93 | 94 | // define the optimization problem using an objective function 95 | OptimProblem problem = new OptimProblem() { 96 | 97 | @Override 98 | public int dimension() { 99 | return 1; 100 | } 101 | 102 | @Override 103 | public RealScalarFunction f() { 104 | return new RealScalarFunction() { 105 | 106 | // the objective function 107 | @Override 108 | public Double evaluate(Vector v) { 109 | double x = v.get(1); 110 | Polynomial polynomial = new Polynomial(1, 0, -4); // f(x) = x^2 - 4 111 | double fx = polynomial.evaluate(x); 112 | return fx; 113 | } 114 | 115 | @Override 116 | public int dimensionOfDomain() { 117 | return 1; 118 | } 119 | 120 | @Override 121 | public int dimensionOfRange() { 122 | return 1; 123 | } 124 | }; 125 | } 126 | }; 127 | 128 | // set up the solver to use and the solution 129 | DoubleBruteForceMinimizer solver = new DoubleBruteForceMinimizer(false); 130 | BruteForceMinimizer.Solution soln = solver.solve(problem); 131 | 132 | // for brute force search, we need to explicitly enumerate the values in the domain 133 | List domain = new ArrayList<>(); 134 | domain.add(new DenseVector(-2.)); 135 | domain.add(new DenseVector(-1.)); 136 | domain.add(new DenseVector(0.)); // the minimizer 137 | domain.add(new DenseVector(1.)); 138 | domain.add(new DenseVector(2.)); 139 | soln.setDomain(domain); 140 | 141 | System.out.println(String.format("f(%s) = %f", soln.minimizer(), soln.min())); 142 | } 143 | 144 | public void solve_by_brute_force_search_2() throws Exception { 145 | System.out.println("solve multivariate function by brute force search"); 146 | 147 | OptimProblem problem = new OptimProblem() { 148 | 149 | @Override 150 | public int dimension() { 151 | return 2; 152 | } 153 | 154 | @Override 155 | public RealScalarFunction f() { 156 | return new RealScalarFunction() { 157 | 158 | @Override 159 | public Double evaluate(Vector v) { 160 | double x = v.get(1); 161 | double y = v.get(2); 162 | 163 | double fx = x * x + y * y; 164 | return fx; 165 | } 166 | 167 | @Override 168 | public int dimensionOfDomain() { 169 | return 2; 170 | } 171 | 172 | @Override 173 | public int dimensionOfRange() { 174 | return 1; 175 | } 176 | }; 177 | } 178 | }; 179 | 180 | DoubleBruteForceMinimizer bf = new DoubleBruteForceMinimizer(true); 181 | BruteForceMinimizer.Solution soln = bf.solve(problem); 182 | List domain = new ArrayList<>(); 183 | domain.add(new DenseVector(-2., -2.)); 184 | domain.add(new DenseVector(-1., -1.)); 185 | domain.add(new DenseVector(0., 0.)); // the minimizer 186 | domain.add(new DenseVector(1., 1.)); 187 | domain.add(new DenseVector(2., 2.)); 188 | soln.setDomain(domain); 189 | 190 | System.out.println(String.format("f(%s) = %f", soln.minimizer(), soln.min())); 191 | } 192 | 193 | public void solve_by_brute_force_search_3() throws Exception { 194 | System.out.println("solve uniivariate function by brute force search"); 195 | 196 | // set up the solver to use and the solution 197 | DoubleBruteForceMinimizer solver = new DoubleBruteForceMinimizer(false); 198 | BruteForceMinimizer.Solution soln 199 | = solver.solve(new C2OptimProblemImpl(new Polynomial(1, 0, -4))); // f(x) = x^2 - 4 200 | 201 | // for brute force search, we need to explicitly enumerate the values in the domain 202 | List domain = new ArrayList<>(); 203 | domain.add(new DenseVector(-2.)); 204 | domain.add(new DenseVector(-1.)); 205 | domain.add(new DenseVector(0.)); // the minimizer 206 | domain.add(new DenseVector(1.)); 207 | domain.add(new DenseVector(2.)); 208 | soln.setDomain(domain); 209 | 210 | System.out.println(String.format("f(%s) = %f", soln.minimizer(), soln.min())); 211 | } 212 | 213 | public void solve_by_brute_force_search_4() throws Exception { 214 | System.out.println("solve multivariate function by brute force search"); 215 | 216 | DoubleBruteForceMinimizer bf = new DoubleBruteForceMinimizer(true); 217 | BruteForceMinimizer.Solution soln = bf.solve( 218 | new C2OptimProblemImpl( 219 | new AbstractBivariateRealFunction() { 220 | @Override 221 | public double evaluate(double x, double y) { 222 | double fx = x * x + y * y; 223 | return fx; 224 | } 225 | })); 226 | 227 | List domain = new ArrayList<>(); 228 | domain.add(new DenseVector(-2., -2.)); 229 | domain.add(new DenseVector(-1., -1.)); 230 | domain.add(new DenseVector(0., 0.)); // the minimizer 231 | domain.add(new DenseVector(1., 1.)); 232 | domain.add(new DenseVector(2., 2.)); 233 | soln.setDomain(domain); 234 | 235 | System.out.println(String.format("f(%s) = %f", soln.minimizer(), soln.min())); 236 | } 237 | 238 | public void solve_loggamma_by_bracketing() throws Exception { 239 | System.out.println("solve loggamma function by bracketing"); 240 | 241 | LogGamma logGamma = new LogGamma(); // the log-gamma function 242 | 243 | BracketSearchMinimizer solver1 = new FibonaccMinimizer(1e-8, 15); 244 | UnivariateMinimizer.Solution soln1 = solver1.solve(logGamma); 245 | double x_min_1 = soln1.search(0, 5); 246 | System.out.println(String.format("f(%f) = %f", x_min_1, logGamma.evaluate(x_min_1))); 247 | 248 | BracketSearchMinimizer solver2 = new GoldenMinimizer(1e-8, 15); 249 | UnivariateMinimizer.Solution soln2 = solver2.solve(logGamma); 250 | double x_min_2 = soln2.search(0, 5); 251 | System.out.println(String.format("f(%f) = %f", x_min_2, logGamma.evaluate(x_min_2))); 252 | 253 | BracketSearchMinimizer solver3 = new BrentMinimizer(1e-8, 10); 254 | UnivariateMinimizer.Solution soln3 = solver3.solve(logGamma); 255 | double x_min_3 = soln3.search(0, 5); 256 | System.out.println(String.format("f(%f) = %f", x_min_3, logGamma.evaluate(x_min_3))); 257 | } 258 | 259 | public void solve_by_steepest_descent() throws Exception { 260 | System.out.println("solve multivariate function by steepest-descent"); 261 | 262 | // the objective function 263 | // the global minimizer is at x = [0,0,0,0] 264 | RealScalarFunction f = new RealScalarFunction() { 265 | 266 | @Override 267 | public Double evaluate(Vector x) { 268 | double x1 = x.get(1); 269 | double x2 = x.get(2); 270 | double x3 = x.get(3); 271 | double x4 = x.get(4); 272 | 273 | double result = pow(x1 - 4 * x2, 4); 274 | result += 12 * pow(x3 - x4, 4); 275 | result += 3 * pow(x2 - 10 * x3, 2); 276 | result += 55 * pow(x1 - 2 * x4, 2); 277 | 278 | return result; 279 | } 280 | 281 | @Override 282 | public int dimensionOfDomain() { 283 | return 4; 284 | } 285 | 286 | @Override 287 | public int dimensionOfRange() { 288 | return 1; 289 | } 290 | }; 291 | 292 | // the gradient function 293 | RealVectorFunction g = new RealVectorFunction() { 294 | 295 | @Override 296 | public Vector evaluate(Vector x) { 297 | double x1 = x.get(1); 298 | double x2 = x.get(2); 299 | double x3 = x.get(3); 300 | double x4 = x.get(4); 301 | 302 | double[] result = new double[4]; 303 | result[0] = 4 * pow(x1 - 4 * x2, 3) + 110 * (x1 - 2 * x4); 304 | result[1] = -16 * pow(x1 - 4 * x2, 3) + 6 * (x2 - 10 * x3); 305 | result[2] = 48 * pow(x3 - x4, 3) - 60 * (x2 - 10 * x3); 306 | result[3] = -48 * pow(x3 - x4, 3) - 220 * (x1 - 2 * x4); 307 | return new DenseVector(result); 308 | } 309 | 310 | @Override 311 | public int dimensionOfDomain() { 312 | return 4; 313 | } 314 | 315 | @Override 316 | public int dimensionOfRange() { 317 | return 4; 318 | } 319 | }; 320 | 321 | C2OptimProblem problem = new C2OptimProblemImpl(f, g); // only gradient information 322 | SteepestDescentMinimizer firstOrderMinimizer 323 | = new FirstOrderMinimizer( 324 | FirstOrderMinimizer.Method.IN_EXACT_LINE_SEARCH, // FirstOrderMinimizer.Method.ANALYTIC 325 | 1e-8, 326 | 40000 327 | ); 328 | IterativeSolution soln = firstOrderMinimizer.solve(problem); 329 | 330 | Vector xmin = soln.search(new DenseVector(new double[]{1, -1, -1, 1})); 331 | double f_xmin = f.evaluate(xmin); 332 | System.out.println(String.format("f(%s) = %f", xmin.toString(), f_xmin)); 333 | } 334 | 335 | public void solve_by_Newton_Raphson() throws Exception { 336 | System.out.println("solve multivariate function by Newton-Raphson"); 337 | 338 | // the objective function 339 | // the global minimizer is at x = [0,0,0,0] 340 | RealScalarFunction f = new RealScalarFunction() { 341 | 342 | @Override 343 | public Double evaluate(Vector x) { 344 | double x1 = x.get(1); 345 | double x2 = x.get(2); 346 | double x3 = x.get(3); 347 | double x4 = x.get(4); 348 | 349 | double result = pow(x1 - 4 * x2, 4); 350 | result += 12 * pow(x3 - x4, 4); 351 | result += 3 * pow(x2 - 10 * x3, 2); 352 | result += 55 * pow(x1 - 2 * x4, 2); 353 | 354 | return result; 355 | } 356 | 357 | @Override 358 | public int dimensionOfDomain() { 359 | return 4; 360 | } 361 | 362 | @Override 363 | public int dimensionOfRange() { 364 | return 1; 365 | } 366 | }; 367 | 368 | // the gradient function 369 | RealVectorFunction g = new RealVectorFunction() { 370 | 371 | @Override 372 | public Vector evaluate(Vector x) { 373 | double x1 = x.get(1); 374 | double x2 = x.get(2); 375 | double x3 = x.get(3); 376 | double x4 = x.get(4); 377 | 378 | double[] result = new double[4]; 379 | result[0] = 4 * pow(x1 - 4 * x2, 3) + 110 * (x1 - 2 * x4); 380 | result[1] = -16 * pow(x1 - 4 * x2, 3) + 6 * (x2 - 10 * x3); 381 | result[2] = 48 * pow(x3 - x4, 3) - 60 * (x2 - 10 * x3); 382 | result[3] = -48 * pow(x3 - x4, 3) - 220 * (x1 - 2 * x4); 383 | return new DenseVector(result); 384 | } 385 | 386 | @Override 387 | public int dimensionOfDomain() { 388 | return 4; 389 | } 390 | 391 | @Override 392 | public int dimensionOfRange() { 393 | return 4; 394 | } 395 | }; 396 | 397 | C2OptimProblem problem = new C2OptimProblemImpl(f, g); // use numerical Hessian 398 | SteepestDescentMinimizer newtonRaphsonMinimizer 399 | = new NewtonRaphsonMinimizer( 400 | 1e-8, 401 | 20 402 | ); 403 | IterativeSolution soln = newtonRaphsonMinimizer.solve(problem); 404 | 405 | Vector xmin = soln.search(new DenseVector(new double[]{1, -1, -1, 1})); 406 | double f_xmin = f.evaluate(xmin); 407 | System.out.println(String.format("f(%s) = %f", xmin.toString(), f_xmin)); 408 | } 409 | 410 | public void solve_by_Gauss_Newton() throws Exception { 411 | System.out.println("solve multivariate function by Gauss-Newton"); 412 | 413 | // the objective function 414 | // the global minimizer is at x = [0,0,0,0] 415 | RealVectorFunction f = new RealVectorFunction() { 416 | 417 | @Override 418 | public Vector evaluate(Vector x) { 419 | double x1 = x.get(1); 420 | double x2 = x.get(2); 421 | double x3 = x.get(3); 422 | double x4 = x.get(4); 423 | 424 | double[] fx = new double[4]; 425 | fx[0] = pow(x1 - 4 * x2, 2); 426 | fx[1] = sqrt(12) * pow(x3 - x4, 2); 427 | fx[2] = sqrt(3) * (x2 - 10 * x3); 428 | fx[3] = sqrt(55) * (x1 - 2 * x4); 429 | 430 | return new DenseVector(fx); 431 | } 432 | 433 | @Override 434 | public int dimensionOfDomain() { 435 | return 4; 436 | } 437 | 438 | @Override 439 | public int dimensionOfRange() { 440 | return 4; 441 | } 442 | }; 443 | 444 | // the Jacobian 445 | RntoMatrix J = new RntoMatrix() { 446 | 447 | @Override 448 | public Matrix evaluate(Vector x) { 449 | double x1 = x.get(1); 450 | double x2 = x.get(2); 451 | double x3 = x.get(3); 452 | double x4 = x.get(4); 453 | 454 | Matrix Jx = new DenseMatrix(4, 4); 455 | 456 | double value = 2 * (x1 - 4 * x2); 457 | Jx.set(1, 1, value); 458 | 459 | value = -8 * (x1 - 4 * x2); 460 | Jx.set(1, 2, value); 461 | 462 | value = 2 * sqrt(12) * (x3 - x4); 463 | Jx.set(2, 3, value); 464 | Jx.set(2, 4, -value); 465 | 466 | Jx.set(3, 2, sqrt(3)); 467 | Jx.set(3, 3, -10 * sqrt(3)); 468 | 469 | Jx.set(4, 1, sqrt(55)); 470 | Jx.set(4, 4, -2 * sqrt(55)); 471 | 472 | return Jx; 473 | } 474 | 475 | @Override 476 | public int dimensionOfDomain() { 477 | return 4; 478 | } 479 | 480 | @Override 481 | public int dimensionOfRange() { 482 | return 1; 483 | } 484 | }; 485 | 486 | GaussNewtonMinimizer optim1 = new GaussNewtonMinimizer(1e-8, 10); 487 | 488 | IterativeSolution soln = optim1.solve(f, J);//analytical gradient 489 | 490 | Vector xmin = soln.search(new DenseVector(new double[]{1, -1, -1, 1})); 491 | System.out.println(String.format("f(%s) = %s", xmin.toString(), f.evaluate(xmin).toString())); 492 | } 493 | 494 | public void solve_by_conjugate_direction_methods() throws Exception { 495 | System.out.println("solve multivariate function by conjugate-direction methods"); 496 | 497 | /** 498 | * The Himmelblau function: f(x) = (x1^2 + x2 - 11)^2 + (x1 + x2^2 - 499 | * 7)^2 500 | */ 501 | RealScalarFunction f = new RealScalarFunction() { 502 | @Override 503 | public Double evaluate(Vector x) { 504 | double x1 = x.get(1); 505 | double x2 = x.get(2); 506 | 507 | double result = pow(x1 * x1 + x2 - 11, 2); 508 | result += pow(x1 + x2 * x2 - 7, 2); 509 | 510 | return result; 511 | } 512 | 513 | @Override 514 | public int dimensionOfDomain() { 515 | return 2; 516 | } 517 | 518 | @Override 519 | public int dimensionOfRange() { 520 | return 1; 521 | } 522 | }; 523 | 524 | RealVectorFunction g = new RealVectorFunction() { 525 | @Override 526 | public Vector evaluate(Vector x) { 527 | double x1 = x.get(1); 528 | double x2 = x.get(2); 529 | 530 | double w1 = x1 * x1 + x2 - 11; 531 | double w2 = x1 + x2 * x2 - 7; 532 | 533 | double[] result = new double[2]; 534 | result[0] = 4 * w1 * x1 + 2 * w2; 535 | result[1] = 2 * w1 + 4 * w2 * x2; 536 | return new DenseVector(result); 537 | } 538 | 539 | @Override 540 | public int dimensionOfDomain() { 541 | return 2; 542 | } 543 | 544 | @Override 545 | public int dimensionOfRange() { 546 | return 2; 547 | } 548 | }; 549 | C2OptimProblemImpl problem = new C2OptimProblemImpl(f, g); 550 | 551 | ConjugateGradientMinimizer ConjugateGradientMinimizer 552 | = new ConjugateGradientMinimizer(1e-16, 40); 553 | IterativeSolution soln1 = ConjugateGradientMinimizer.solve(problem); 554 | Vector xmin1 = soln1.search(new DenseVector(new double[]{6, 6})); 555 | double f_xmin1 = f.evaluate(xmin1); 556 | System.out.println(String.format("f(%s) = %.16f", xmin1.toString(), f_xmin1)); 557 | 558 | ConjugateGradientMinimizer fletcherReevesMinimizer 559 | = new FletcherReevesMinimizer(1e-16, 20); 560 | IterativeSolution soln2 = fletcherReevesMinimizer.solve(problem); 561 | Vector xmin2 = soln2.search(new DenseVector(new double[]{6, 6})); 562 | double f_xmin2 = f.evaluate(xmin2); 563 | System.out.println(String.format("f(%s) = %.16f", xmin2.toString(), f_xmin2)); 564 | 565 | SteepestDescentMinimizer powellMinimizer 566 | = new PowellMinimizer(1e-16, 20); 567 | IterativeSolution soln3 = powellMinimizer.solve(problem); 568 | Vector xmin3 = soln3.search(new DenseVector(new double[]{6, 6})); 569 | double f_xmin3 = f.evaluate(xmin3); 570 | System.out.println(String.format("f(%s) = %.16f", xmin3.toString(), f_xmin3)); 571 | 572 | SteepestDescentMinimizer zangwillMinimizer 573 | = new ZangwillMinimizer(1e-16, 1e-16, 20); 574 | IterativeSolution soln4 = zangwillMinimizer.solve(problem); 575 | Vector xmin4 = soln4.search(new DenseVector(new double[]{6, 6})); 576 | double f_xmin4 = f.evaluate(xmin4); 577 | System.out.println(String.format("f(%s) = %.16f", xmin4.toString(), f_xmin4)); 578 | } 579 | 580 | public void solve_by_quasi_Newton() throws Exception { 581 | System.out.println("solve multivariate function by quasi-Newton"); 582 | 583 | /** 584 | * The Himmelblau function: f(x) = (x1^2 + x2 - 11)^2 + (x1 + x2^2 - 585 | * 7)^2 586 | */ 587 | RealScalarFunction f = new RealScalarFunction() { 588 | @Override 589 | public Double evaluate(Vector x) { 590 | double x1 = x.get(1); 591 | double x2 = x.get(2); 592 | 593 | double result = pow(x1 * x1 + x2 - 11, 2); 594 | result += pow(x1 + x2 * x2 - 7, 2); 595 | 596 | return result; 597 | } 598 | 599 | @Override 600 | public int dimensionOfDomain() { 601 | return 2; 602 | } 603 | 604 | @Override 605 | public int dimensionOfRange() { 606 | return 1; 607 | } 608 | }; 609 | 610 | RealVectorFunction g = new RealVectorFunction() { 611 | @Override 612 | public Vector evaluate(Vector x) { 613 | double x1 = x.get(1); 614 | double x2 = x.get(2); 615 | 616 | double w1 = x1 * x1 + x2 - 11; 617 | double w2 = x1 + x2 * x2 - 7; 618 | 619 | double[] result = new double[2]; 620 | result[0] = 4 * w1 * x1 + 2 * w2; 621 | result[1] = 2 * w1 + 4 * w2 * x2; 622 | return new DenseVector(result); 623 | } 624 | 625 | @Override 626 | public int dimensionOfDomain() { 627 | return 2; 628 | } 629 | 630 | @Override 631 | public int dimensionOfRange() { 632 | return 2; 633 | } 634 | }; 635 | C2OptimProblemImpl problem = new C2OptimProblemImpl(f, g); 636 | 637 | QuasiNewtonMinimizer rankOneMinimizer = new RankOneMinimizer(1e-16, 15); 638 | IterativeSolution soln1 = rankOneMinimizer.solve(problem); 639 | Vector xmin = soln1.search(new DenseVector(new double[]{6, 6})); 640 | double f_xmin = f.evaluate(xmin); 641 | System.out.println(String.format("f(%s) = %.16f", xmin.toString(), f_xmin)); 642 | 643 | QuasiNewtonMinimizer dfpMinimizer = new DFPMinimizer(1e-16, 15); 644 | IterativeSolution soln2 = dfpMinimizer.solve(problem); 645 | xmin = soln2.search(new DenseVector(new double[]{6, 6})); 646 | f_xmin = f.evaluate(xmin); 647 | System.out.println(String.format("f(%s) = %.16f", xmin.toString(), f_xmin)); 648 | 649 | QuasiNewtonMinimizer bfgsMinimizer = new BFGSMinimizer(false, 1e-16, 15); 650 | IterativeSolution soln3 = bfgsMinimizer.solve(problem); 651 | xmin = soln3.search(new DenseVector(new double[]{6, 6})); 652 | f_xmin = f.evaluate(xmin); 653 | System.out.println(String.format("f(%s) = %.16f", xmin.toString(), f_xmin)); 654 | 655 | QuasiNewtonMinimizer huangMinimizer = new HuangMinimizer(0, 1, 0, 1, 1e-16, 15); 656 | IterativeSolution soln4 = huangMinimizer.solve(problem); 657 | xmin = soln4.search(new DenseVector(new double[]{6, 6})); 658 | f_xmin = f.evaluate(xmin); 659 | System.out.println(String.format("f(%s) = %.16f", xmin.toString(), f_xmin)); 660 | 661 | QuasiNewtonMinimizer pearsonMinimizer = new PearsonMinimizer(1e-16, 15); 662 | IterativeSolution soln5 = pearsonMinimizer.solve(problem); 663 | xmin = soln5.search(new DenseVector(new double[]{6, 6})); 664 | f_xmin = f.evaluate(xmin); 665 | System.out.println(String.format("f(%s) = %.16f", xmin.toString(), f_xmin)); 666 | } 667 | 668 | } 669 | -------------------------------------------------------------------------------- /Chapter13.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) NM LTD. 3 | * https://nm.dev/ 4 | * 5 | * THIS SOFTWARE IS LICENSED, NOT SOLD. 6 | * 7 | * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE. 8 | * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE, 9 | * DO NOT USE THIS SOFTWARE. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER, 12 | * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 13 | * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS, 14 | * FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT, 15 | * TITLE AND USEFULNESS. 16 | * 17 | * IN NO EVENT AND UNDER NO LEGAL THEORY, 18 | * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE, 19 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES, 21 | * ARISING AS A RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dev.nm.nmj; 24 | 25 | import dev.nm.algebra.linear.matrix.doubles.Matrix; 26 | import dev.nm.algebra.linear.matrix.doubles.matrixtype.dense.DenseMatrix; 27 | import dev.nm.algebra.linear.vector.doubles.Vector; 28 | import dev.nm.algebra.linear.vector.doubles.dense.DenseVector; 29 | import dev.nm.analysis.function.rn2r1.univariate.AbstractUnivariateRealFunction; 30 | import dev.nm.analysis.function.rn2r1.univariate.UnivariateRealFunction; 31 | import dev.nm.analysis.function.special.gaussian.CumulativeNormalMarsaglia; 32 | import dev.nm.analysis.function.special.gaussian.Gaussian; 33 | import dev.nm.analysis.function.special.gaussian.StandardCumulativeNormal; 34 | import dev.nm.interval.RealInterval; 35 | import dev.nm.number.DoubleUtils; 36 | import dev.nm.stat.descriptive.covariance.SampleCovariance; 37 | import dev.nm.stat.descriptive.moment.Kurtosis; 38 | import dev.nm.stat.descriptive.moment.Mean; 39 | import dev.nm.stat.descriptive.moment.Skewness; 40 | import dev.nm.stat.descriptive.moment.Variance; 41 | import dev.nm.stat.distribution.univariate.BetaDistribution; 42 | import dev.nm.stat.distribution.univariate.EmpiricalDistribution; 43 | import dev.nm.stat.distribution.univariate.ExponentialDistribution; 44 | import dev.nm.stat.distribution.univariate.GammaDistribution; 45 | import dev.nm.stat.distribution.univariate.PoissonDistribution; 46 | import dev.nm.stat.distribution.univariate.ProbabilityDistribution; 47 | import dev.nm.stat.random.Estimator; 48 | import dev.nm.stat.random.rng.multivariate.MultinomialRVG; 49 | import dev.nm.stat.random.rng.multivariate.NormalRVG; 50 | import dev.nm.stat.random.rng.multivariate.RandomVectorGenerator; 51 | import dev.nm.stat.random.rng.multivariate.UniformDistributionOverBox; 52 | import dev.nm.stat.random.rng.univariate.InverseTransformSampling; 53 | import dev.nm.stat.random.rng.univariate.RandomLongGenerator; 54 | import dev.nm.stat.random.rng.univariate.RandomNumberGenerator; 55 | import dev.nm.stat.random.rng.univariate.beta.Cheng1978; 56 | import dev.nm.stat.random.rng.univariate.beta.RandomBetaGenerator; 57 | import dev.nm.stat.random.rng.univariate.exp.RandomExpGenerator; 58 | import dev.nm.stat.random.rng.univariate.exp.Ziggurat2000Exp; 59 | import dev.nm.stat.random.rng.univariate.gamma.KunduGupta2007; 60 | import dev.nm.stat.random.rng.univariate.normal.NormalRNG; 61 | import dev.nm.stat.random.rng.univariate.normal.RandomStandardNormalGenerator; 62 | import dev.nm.stat.random.rng.univariate.normal.Zignor2005; 63 | import dev.nm.stat.random.rng.univariate.poisson.Knuth1969; 64 | import dev.nm.stat.random.rng.univariate.uniform.UniformRNG; 65 | import dev.nm.stat.random.rng.univariate.uniform.linear.CompositeLinearCongruentialGenerator; 66 | import dev.nm.stat.random.rng.univariate.uniform.linear.LEcuyer; 67 | import dev.nm.stat.random.rng.univariate.uniform.linear.Lehmer; 68 | import dev.nm.stat.random.rng.univariate.uniform.linear.LinearCongruentialGenerator; 69 | import dev.nm.stat.random.rng.univariate.uniform.mersennetwister.MersenneTwister; 70 | import dev.nm.stat.random.sampler.resampler.BootstrapEstimator; 71 | import dev.nm.stat.random.sampler.resampler.bootstrap.CaseResamplingReplacement; 72 | import dev.nm.stat.random.sampler.resampler.bootstrap.block.PattonPolitisWhite2009; 73 | import dev.nm.stat.random.sampler.resampler.bootstrap.block.PattonPolitisWhite2009ForObject; 74 | import dev.nm.stat.random.variancereduction.AntitheticVariates; 75 | import dev.nm.stat.random.variancereduction.CommonRandomNumbers; 76 | import dev.nm.stat.random.variancereduction.ControlVariates; 77 | import dev.nm.stat.random.variancereduction.ImportanceSampling; 78 | import dev.nm.stat.test.distribution.normality.ShapiroWilk; 79 | import static java.lang.Math.PI; 80 | import static java.lang.Math.sin; 81 | import static java.lang.Math.sqrt; 82 | import java.util.Arrays; 83 | 84 | /** 85 | * Numerical Methods Using Java: For Data Science, Analysis, and Engineering 86 | * 87 | * @author haksunli 88 | * @see 89 | * https://www.amazon.com/Numerical-Methods-Using-Java-Engineering/dp/1484267966 90 | * https://nm.dev/ 91 | */ 92 | public class Chapter13 { 93 | 94 | public static void main(String[] args) { 95 | System.out.println("Chapter 13 demos"); 96 | 97 | Chapter13 chapter13 = new Chapter13(); 98 | chapter13.lcgs(); 99 | chapter13.MT19937(); 100 | chapter13.normal_rng(); 101 | chapter13.beta_rng(); 102 | chapter13.gamma_rng(); 103 | chapter13.Poisson_rng(); 104 | chapter13.exponential_rng(); 105 | chapter13.compute_Pi(); 106 | chapter13.normal_rvg(); 107 | chapter13.multinomial_rvg(); 108 | chapter13.empirical_rng(); 109 | chapter13.case_resampling_1(); 110 | chapter13.case_resampling_2(); 111 | chapter13.bootstrapping_methods(); 112 | chapter13.crn(); 113 | chapter13.antithetic_variates(); 114 | chapter13.control_variates(); 115 | chapter13.importance_sampling_1(); 116 | chapter13.importance_sampling_2(); 117 | } 118 | 119 | // from 120 | // https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/monte-carlo-methods-in-practice/variance-reduction-methods 121 | private void importance_sampling_2() { 122 | RandomNumberGenerator rng = new UniformRNG(); 123 | rng.seed(1234567892L); 124 | 125 | int N = 16; 126 | for (int n = 0; n < 10; ++n) { 127 | float sumUniform = 0, sumImportance = 0; 128 | for (int i = 0; i < N; ++i) { 129 | double r = rng.nextDouble(); 130 | sumUniform += sin(r * PI * 0.5); 131 | double xi = sqrt(r) * PI * 0.5; 132 | sumImportance += sin(xi) / ((8 * xi) / (PI * PI)); 133 | } 134 | sumUniform *= (PI * 0.5) / N; 135 | sumImportance *= 1.f / N; 136 | System.out.println(String.format("%f %f\n", sumUniform, sumImportance)); 137 | } 138 | } 139 | 140 | private void importance_sampling_1() { 141 | UnivariateRealFunction h = new AbstractUnivariateRealFunction() { 142 | 143 | @Override 144 | public double evaluate(double x) { 145 | return x; // the identity function 146 | } 147 | }; 148 | 149 | UnivariateRealFunction w = new AbstractUnivariateRealFunction() { 150 | private final Gaussian phi = new Gaussian(); 151 | private final StandardCumulativeNormal N = new CumulativeNormalMarsaglia(); 152 | private final double I = N.evaluate(1) - N.evaluate(0); 153 | 154 | @Override 155 | public double evaluate(double x) { 156 | double w = phi.evaluate(x) / I; // the weight 157 | return w; 158 | } 159 | }; 160 | 161 | RandomNumberGenerator rng = new UniformRNG(); 162 | rng.seed(1234567892L); 163 | 164 | ImportanceSampling is = new ImportanceSampling(h, w, rng); 165 | Estimator estimator = is.estimate(100000); 166 | System.out.println( 167 | String.format( 168 | "mean = %f, variance = %f", 169 | estimator.mean(), 170 | estimator.variance())); 171 | } 172 | 173 | private void control_variates() { 174 | UnivariateRealFunction f 175 | = new AbstractUnivariateRealFunction() { 176 | 177 | @Override 178 | public double evaluate(double x) { 179 | double fx = 1. / (1. + x); 180 | return fx; 181 | } 182 | }; 183 | 184 | UnivariateRealFunction g 185 | = new AbstractUnivariateRealFunction() { 186 | 187 | @Override 188 | public double evaluate(double x) { 189 | double gx = 1. + x; 190 | return gx; 191 | } 192 | }; 193 | 194 | RandomLongGenerator uniform = new UniformRNG(); 195 | uniform.seed(1234567891L); 196 | 197 | ControlVariates cv 198 | = new ControlVariates(f, g, 1.5, -0.4773, uniform); 199 | ControlVariates.Estimator estimator = cv.estimate(1500); 200 | System.out.println( 201 | String.format( 202 | "mean = %f, variance = %f, b = %f", 203 | estimator.mean(), 204 | estimator.variance(), 205 | estimator.b())); 206 | } 207 | 208 | private void antithetic_variates() { 209 | UnivariateRealFunction f 210 | = new AbstractUnivariateRealFunction() { 211 | 212 | @Override 213 | public double evaluate(double x) { 214 | double fx = 1. / (1. + x); 215 | return fx; 216 | } 217 | }; 218 | 219 | RandomLongGenerator uniform = new UniformRNG(); 220 | uniform.seed(1234567894L); 221 | 222 | AntitheticVariates av 223 | = new AntitheticVariates( 224 | f, 225 | uniform, 226 | AntitheticVariates.REFLECTION); 227 | Estimator estimator = av.estimate(1500); 228 | System.out.println( 229 | String.format( 230 | "mean = %f, variance = %f", 231 | estimator.mean(), 232 | estimator.variance())); 233 | } 234 | 235 | private void crn() { 236 | final UnivariateRealFunction f 237 | = new AbstractUnivariateRealFunction() { 238 | 239 | @Override 240 | public double evaluate(double x) { 241 | double fx = 2. - Math.sin(x) / x; 242 | return fx; 243 | } 244 | }; 245 | 246 | final UnivariateRealFunction g 247 | = new AbstractUnivariateRealFunction() { 248 | 249 | @Override 250 | public double evaluate(double x) { 251 | double gx = Math.exp(x * x) - 0.5; 252 | return gx; 253 | } 254 | }; 255 | 256 | RandomLongGenerator X1 = new UniformRNG(); 257 | X1.seed(1234567890L); 258 | 259 | CommonRandomNumbers crn0 260 | = new CommonRandomNumbers( 261 | f, 262 | g, 263 | X1, 264 | new AbstractUnivariateRealFunction() { // another independent uniform RNG 265 | final RandomLongGenerator X2 = new UniformRNG(); 266 | 267 | { 268 | X2.seed(246890123L); 269 | } 270 | 271 | @Override 272 | public double evaluate(double x) { 273 | return X2.nextDouble(); 274 | } 275 | }); 276 | Estimator estimator0 = crn0.estimate(100_000); 277 | System.out.println( 278 | String.format("d = %f, variance = %f", 279 | estimator0.mean(), 280 | estimator0.variance())); 281 | 282 | CommonRandomNumbers crn1 283 | = new CommonRandomNumbers(f, g, X1); // use X1 for both f and g 284 | Estimator estimator1 = crn1.estimate(100_000); 285 | System.out.println( 286 | String.format("d = %f, variance = %f", 287 | estimator1.mean(), 288 | estimator1.variance())); 289 | } 290 | 291 | /** 292 | * Constructs a dependent sequence (consisting of 0 and 1) by retaining the 293 | * last value with probability q while changing the last value with 294 | * probability 1-q. 295 | *

296 | * The simple bootstrapping method {@linkplain CaseResamplingReplacement} 297 | * will severely overestimate the occurrences of certain pattern, while 298 | * block bootstrapping method {@linkplain BlockBootstrap} gives a good 299 | * estimation of the occurrences in the original sample. All estimators over 300 | * estimate. 301 | */ 302 | private void bootstrapping_methods() { 303 | final int N = 10000; 304 | final double q = 0.70; // the probability of retaining last value 305 | 306 | UniformRNG uniformRNG = new UniformRNG(); 307 | uniformRNG.seed(1234567890L); 308 | 309 | // generate a randome series of 0s and 1s with serial correlation 310 | final double[] sample = new double[N]; 311 | sample[0] = uniformRNG.nextDouble() > 0.5 ? 1 : 0; 312 | for (int i = 1; i < N; ++i) { 313 | sample[i] = uniformRNG.nextDouble() < q ? sample[i - 1] : 1 - sample[i - 1]; 314 | } 315 | 316 | // simple case resampling with replacement method 317 | CaseResamplingReplacement simpleBoot 318 | = new CaseResamplingReplacement(sample, uniformRNG); 319 | Mean countInSimpleBootstrap = new Mean(); 320 | 321 | RandomNumberGenerator rlg = new Ziggurat2000Exp(); 322 | rlg.seed(1234567890L); 323 | 324 | // Patton-Politis-White method using stationary blocks 325 | PattonPolitisWhite2009 stationaryBlock 326 | = new PattonPolitisWhite2009( 327 | sample, 328 | PattonPolitisWhite2009ForObject.Type.STATIONARY, 329 | uniformRNG, 330 | rlg); 331 | Mean countInStationaryBlockBootstrap = new Mean(); 332 | 333 | // Patton-Politis-White method using circular blocks 334 | PattonPolitisWhite2009 circularBlock 335 | = new PattonPolitisWhite2009( 336 | sample, 337 | PattonPolitisWhite2009ForObject.Type.CIRCULAR, 338 | uniformRNG, 339 | rlg); 340 | Mean countInCircularBlockBootstrap = new Mean(); 341 | 342 | // change this line to use a different pattern 343 | final double[] pattern = new double[]{1, 0, 1, 0, 1}; 344 | 345 | final int B = 10000; 346 | for (int i = 0; i < B; ++i) { 347 | // count the number of occurrences for the pattern in the series 348 | int numberOfMatches = match(simpleBoot.newResample(), pattern); 349 | countInSimpleBootstrap.addData(numberOfMatches); 350 | 351 | // count the number of occurrences for the pattern in the series 352 | numberOfMatches = match(stationaryBlock.newResample(), pattern); 353 | countInStationaryBlockBootstrap.addData(numberOfMatches); 354 | 355 | // count the number of occurrences for the pattern in the series 356 | numberOfMatches = match(circularBlock.newResample(), pattern); 357 | countInCircularBlockBootstrap.addData(numberOfMatches); 358 | } 359 | 360 | // compare the numbers of occurrences of the pattern using different bootstrap methods 361 | int countInSample = match(sample, pattern); 362 | System.out.println("matched patterns in sample: " + countInSample); 363 | System.out.println("matched patterns in simple bootstrap: " + countInSimpleBootstrap.value()); 364 | System.out.println("matched patterns in stationary block bootstrap: " + countInStationaryBlockBootstrap.value()); 365 | System.out.println("matched patterns in circular block bootstrap: " + countInCircularBlockBootstrap.value()); 366 | } 367 | 368 | private static int match(double[] seq, double[] pattern) { 369 | int count = 0; 370 | for (int i = 0; i < seq.length - pattern.length; ++i) { 371 | if (seq[i] == pattern[0]) { 372 | double[] trunc = Arrays.copyOfRange(seq, i, i + pattern.length); 373 | if (DoubleUtils.equal(trunc, pattern, 1e-7)) { 374 | count++; 375 | } 376 | } 377 | } 378 | return count; 379 | } 380 | 381 | private void case_resampling_1() { 382 | // sample from true population 383 | double[] sample = new double[]{150., 155., 160., 165., 170.}; 384 | CaseResamplingReplacement boot = new CaseResamplingReplacement(sample); 385 | boot.seed(1234567890L); 386 | 387 | int B = 1000; 388 | double[] means = new double[B]; 389 | for (int i = 0; i < B; ++i) { 390 | double[] resample = boot.newResample(); 391 | means[i] = new Mean(resample).value(); 392 | } 393 | 394 | // estimator of population mean 395 | double mean = new Mean(means).value(); 396 | // variance of estimator; limited by sample size (regardless of how big B is) 397 | double var = new Variance(means).value(); 398 | 399 | System.out.println( 400 | String.format("mean = %f, variance of the estimated mean = %f", 401 | mean, 402 | var)); 403 | } 404 | 405 | private void case_resampling_2() { 406 | // sample from true population 407 | double[] sample = new double[]{150., 155., 160., 165., 170.}; 408 | CaseResamplingReplacement boot = new CaseResamplingReplacement(sample); 409 | boot.seed(1234567890L); 410 | 411 | int B = 1000; 412 | BootstrapEstimator estimator 413 | = new BootstrapEstimator(boot, () -> new Mean(), B); 414 | 415 | System.out.println( 416 | String.format("mean = %f, variance of the estimated mean = %f", 417 | estimator.value(), 418 | estimator.variance())); 419 | } 420 | 421 | private void empirical_rng() { 422 | // we first generate some samples from standard normal distribution 423 | RandomLongGenerator uniform = new MersenneTwister(); 424 | uniform.seed(1234567890L); 425 | 426 | RandomStandardNormalGenerator rng1 = new Zignor2005(uniform); // mean = 0, stdev = 1 427 | int N = 1000; 428 | double[] x1 = new double[N]; 429 | for (int i = 0; i < N; ++i) { 430 | x1[i] = rng1.nextDouble(); 431 | } 432 | 433 | // compute the empirical distribution function from the sample data 434 | EmpiricalDistribution dist2 = new EmpiricalDistribution(x1); 435 | 436 | // construct an RNG using inverse transform sampling method 437 | InverseTransformSampling rng2 = new InverseTransformSampling(dist2); 438 | 439 | // generate some random variates from the RNG 440 | double[] x2 = new double[N]; 441 | for (int i = 0; i < N; ++i) { 442 | x2[i] = rng2.nextDouble(); 443 | } 444 | 445 | // check the properties of the random variates 446 | Variance var = new Variance(x2); 447 | double mean = var.mean(); 448 | double stdev = var.standardDeviation(); 449 | System.out.println(String.format("mean = %f, standard deviation = %f", mean, stdev)); 450 | 451 | // check if the samples are normally distributed 452 | ShapiroWilk test = new ShapiroWilk(x2); 453 | System.out.println(String.format("ShapiroWilk statistics = %f, pValue = %f", test.statistics(), test.pValue())); 454 | } 455 | 456 | private void multinomial_rvg() { 457 | MultinomialRVG rvg 458 | = new MultinomialRVG(100_000, new double[]{0.7, 0.3}); // bin0 is 70% chance, bin1 30% chance 459 | double[] bin = rvg.nextVector(); 460 | 461 | double total = 0; 462 | for (int i = 0; i < bin.length; ++i) { 463 | total += bin[i]; 464 | } 465 | 466 | double bin0 = bin[0] / total; // bin0 percentage 467 | double bin1 = bin[1] / total; // bin0 percentage 468 | 469 | System.out.println(String.format("bin0 %% = %f, bin1 %% = %f", bin0, bin1)); 470 | } 471 | 472 | private void normal_rvg() { 473 | // mean 474 | Vector mu = new DenseVector(new double[]{-2., 2.}); 475 | // covariance matrix 476 | Matrix sigma = new DenseMatrix(new double[][]{ 477 | {1., 0.5}, 478 | {0.5, 1.} 479 | }); 480 | NormalRVG rvg = new NormalRVG(mu, sigma); 481 | rvg.seed(1234567890L); 482 | 483 | final int size = 10_000; 484 | double[][] x = new double[size][]; 485 | 486 | Mean mean1 = new Mean(); 487 | Mean mean2 = new Mean(); 488 | for (int i = 0; i < size; ++i) { 489 | double[] v = rvg.nextVector(); 490 | mean1.addData(v[0]); 491 | mean2.addData(v[1]); 492 | 493 | x[i] = v; 494 | } 495 | 496 | System.out.println(String.format("mean of X_1 = %f", mean1.value())); 497 | System.out.println(String.format("mean of X_2 = %f", mean2.value())); 498 | 499 | Matrix X = new DenseMatrix(x); 500 | SampleCovariance cov = new SampleCovariance(X); 501 | System.out.println(String.format("sample covariance = %s", cov.toString())); 502 | } 503 | 504 | private void compute_Pi() { 505 | final int N = 1_000_000; 506 | 507 | RandomVectorGenerator rvg 508 | = new UniformDistributionOverBox( 509 | new RealInterval(-1., 1.), // a unit square box 510 | new RealInterval(-1., 1.)); 511 | 512 | int N0 = 0; 513 | for (int i = 0; i < N; i++) { 514 | double[] xy = rvg.nextVector(); 515 | double x = xy[0], y = xy[1]; 516 | if (x * x + y * y <= 1.) { // check if the dot is inside a circle 517 | N0++; 518 | } 519 | } 520 | double pi = 4. * N0 / N; 521 | System.out.println("pi = " + pi); 522 | } 523 | 524 | private void exponential_rng() { 525 | int size = 500_000; 526 | 527 | RandomExpGenerator rng = new Ziggurat2000Exp(); 528 | rng.seed(634641070L); 529 | 530 | double[] x = new double[size]; 531 | for (int i = 0; i < size; ++i) { 532 | x[i] = rng.nextDouble(); 533 | } 534 | 535 | // compute the sample statistics 536 | Mean mean = new Mean(x); 537 | Variance var = new Variance(x); 538 | Skewness skew = new Skewness(x); 539 | Kurtosis kurtosis = new Kurtosis(x); 540 | 541 | // compute the theoretial statistics 542 | ProbabilityDistribution dist = new ExponentialDistribution(); 543 | 544 | // compute the theoretial statistics 545 | printStats(dist, mean, var, skew, kurtosis); 546 | } 547 | 548 | private void Poisson_rng() { 549 | final int N = 10_000; 550 | double lambda = 1; 551 | 552 | RandomNumberGenerator rng = new Knuth1969(lambda); 553 | rng.seed(123456789L); 554 | 555 | double[] x = new double[N]; 556 | for (int i = 0; i < N; ++i) { 557 | x[i] = rng.nextDouble(); 558 | } 559 | 560 | // compute the sample statistics 561 | Mean mean = new Mean(x); 562 | Variance var = new Variance(x); 563 | Skewness skew = new Skewness(x); 564 | Kurtosis kurtosis = new Kurtosis(x); 565 | 566 | // compute the theoretial statistics 567 | PoissonDistribution dist = new PoissonDistribution(lambda); 568 | 569 | // compute the theoretial statistics 570 | printStats(dist, mean, var, skew, kurtosis); 571 | } 572 | 573 | private void gamma_rng() { 574 | final int size = 1_000_000; 575 | 576 | final double k = 0.1; 577 | final double theta = 1; 578 | 579 | KunduGupta2007 rng = new KunduGupta2007(k, theta, new UniformRNG()); 580 | rng.seed(1234567895L); 581 | 582 | double[] x = new double[size]; 583 | for (int i = 0; i < size; ++i) { 584 | x[i] = rng.nextDouble(); 585 | } 586 | 587 | // compute the sample statistics 588 | Mean mean = new Mean(x); 589 | Variance var = new Variance(x); 590 | Skewness skew = new Skewness(x); 591 | Kurtosis kurtosis = new Kurtosis(x); 592 | 593 | // compute the theoretial statistics 594 | ProbabilityDistribution dist = new GammaDistribution(k, theta); 595 | 596 | // compute the theoretial statistics 597 | printStats(dist, mean, var, skew, kurtosis); 598 | } 599 | 600 | private void beta_rng() { 601 | final int size = 1_000_000; 602 | 603 | final double alpha = 0.1; 604 | final double beta = 0.2; 605 | 606 | RandomBetaGenerator rng = new Cheng1978(alpha, beta, new UniformRNG()); 607 | rng.seed(1234567890L); 608 | 609 | double[] x = new double[size]; 610 | for (int i = 0; i < size; ++i) { 611 | x[i] = rng.nextDouble(); 612 | } 613 | 614 | // compute the sample statistics 615 | Mean mean = new Mean(x); 616 | Variance var = new Variance(x); 617 | Skewness skew = new Skewness(x); 618 | Kurtosis kurtosis = new Kurtosis(x); 619 | 620 | // compute the theoretial statistics 621 | ProbabilityDistribution dist = new BetaDistribution(alpha, beta); 622 | 623 | // compare sample vs theoretical statistics 624 | printStats(dist, mean, var, skew, kurtosis); 625 | } 626 | 627 | private void normal_rng() { 628 | RandomLongGenerator uniform = new MersenneTwister(); 629 | uniform.seed(1234567890L); 630 | 631 | RandomStandardNormalGenerator rng1 = new Zignor2005(uniform); // mean = 0, stdev = 1 632 | int N = 1000; 633 | double[] arr1 = new double[N]; 634 | for (int i = 0; i < N; ++i) { 635 | arr1[i] = rng1.nextDouble(); 636 | } 637 | 638 | // check the statistics of the random samples 639 | Variance var1 = new Variance(arr1); 640 | System.out.println( 641 | String.format( 642 | "mean = %f, stdev = %f", 643 | var1.mean(), 644 | var1.standardDeviation())); 645 | 646 | NormalRNG rng2 = new NormalRNG(1., 2., rng1); // mean = 1, stdev = 2 647 | double[] arr2 = new double[N]; 648 | for (int i = 0; i < N; ++i) { 649 | arr2[i] = rng2.nextDouble(); 650 | } 651 | 652 | // check the statistics of the random samples 653 | Variance var2 = new Variance(arr2); 654 | System.out.println( 655 | String.format( 656 | "mean = %f, stdev = %f", 657 | var2.mean(), 658 | var2.standardDeviation())); 659 | } 660 | 661 | private void MT19937() { 662 | RandomLongGenerator rng = new MersenneTwister(); 663 | 664 | long startTime = System.nanoTime(); 665 | int N = 1_000_000; 666 | for (int i = 0; i < N; ++i) { 667 | rng.nextDouble(); 668 | } 669 | long endTime = System.nanoTime(); 670 | 671 | long duration = (endTime - startTime); 672 | double ms = (double) duration / 1_000_000.; // divide by 1000000 to get milliseconds 673 | System.out.println(String.format("took MT19937 %f milliseconds to generate %d random numbers", ms, N)); 674 | } 675 | 676 | private void lcgs() { 677 | System.out.println("generate randome numbers using an Lehmer RNG:"); 678 | RandomLongGenerator rng1 = new Lehmer(); 679 | rng1.seed(1234567890L); 680 | generateIntAndPrint(rng1, 10); 681 | double[] arr = generate(rng1, 10); 682 | print(arr); 683 | 684 | System.out.println("generate randome numbers using an LEcuyer RNG:"); 685 | RandomLongGenerator rng2 = new LEcuyer(); 686 | rng2.seed(1234567890L); 687 | generateIntAndPrint(rng2, 10); 688 | arr = generate(rng2, 10); 689 | print(arr); 690 | 691 | System.out.println("generate randome numbers using a composite LCG:"); 692 | RandomLongGenerator rng3 693 | = new CompositeLinearCongruentialGenerator( 694 | new LinearCongruentialGenerator[]{ 695 | (LinearCongruentialGenerator) rng1, 696 | (LinearCongruentialGenerator) rng2 697 | } 698 | ); 699 | rng3.seed(1234567890L); 700 | generateIntAndPrint(rng3, 10); 701 | arr = generate(rng3, 10); 702 | print(arr); 703 | } 704 | 705 | private static double[] generate(RandomNumberGenerator rng, int n) { 706 | double[] arr = new double[n]; 707 | for (int i = 0; i < n; i++) { 708 | arr[i] = rng.nextDouble(); 709 | } 710 | return arr; 711 | } 712 | 713 | private static void print(double[] arr) { 714 | System.out.println(Arrays.toString(arr)); 715 | } 716 | 717 | private static void generateIntAndPrint(RandomNumberGenerator rng, int n) { 718 | double[] randomNumbers = new double[n]; 719 | for (int i = 0; i < n; i++) { 720 | randomNumbers[i] = rng.nextDouble(); 721 | } 722 | System.out.println(Arrays.toString(randomNumbers)); 723 | } 724 | 725 | private void printStats( 726 | ProbabilityDistribution dist, 727 | Mean mean, 728 | Variance var, 729 | Skewness skew, 730 | Kurtosis kurtosis 731 | ) { 732 | System.out.println( 733 | String.format("theoretical mean = %f, sample mean = %f", 734 | dist.mean(), 735 | mean.value())); 736 | System.out.println( 737 | String.format("theoretical var = %f, sample var = %f", 738 | dist.variance(), 739 | var.value())); 740 | System.out.println( 741 | String.format("theoretical skew = %f, sample skew = %f", 742 | dist.skew(), 743 | skew.value())); 744 | System.out.println( 745 | String.format("theoretical kurtosis = %f, sample kurtosis = %f", 746 | dist.kurtosis(), 747 | kurtosis.value())); 748 | } 749 | } 750 | --------------------------------------------------------------------------------