├── .gitignore ├── COPYING.txt ├── README.md ├── Settings.StyleCop ├── csnumerics.png ├── csnumerics.sln ├── csnumerics.tests ├── Issues │ └── GH1.cs ├── Optimizers │ ├── BobyqaTests.cs │ ├── CobylaTests.cs │ └── LincoaTests.cs ├── Properties │ └── AssemblyInfo.cs └── csnumerics.tests.csproj ├── csnumerics.unity.sln ├── csnumerics.unity └── csnumerics.unity.csproj ├── csnumerics ├── NET35 │ └── Zip.cs ├── Optimizers │ ├── Bobyqa.cs │ ├── Cobyla.cs │ ├── IOptimizer.cs │ ├── IQuadraticModelOptimizer.cs │ ├── ITrustRegionOptimizer.cs │ ├── OptimizationStatus.cs │ ├── OptimizationSummary.cs │ └── lincoa.cs ├── csnumerics.csproj └── csnumerics.snk └── packages └── repositories.config /.gitignore: -------------------------------------------------------------------------------- 1 | [Oo]bj 2 | [Bb]in 3 | [Pp]ackages 4 | *.suo 5 | *.user 6 | 7 | .vscode 8 | .vs 9 | InternalTrace.*.log 10 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CSNumerics logo 2 | 3 | # CSNumerics 4 | 5 | Portable numerical algorithms in C# 6 | 7 | Copyright (c) 2012-2022 Anders Gustafsson, Cureos AB. Licensed under the GNU Lesser General Public License version 3.
8 | 9 | [![NuGet](https://img.shields.io/nuget/v/csnumerics.svg)](https://www.nuget.org/packages/csnumerics/) 10 | [![NuGet](https://img.shields.io/nuget/dt/csnumerics.svg)](https://www.nuget.org/packages/csnumerics/) 11 | [![Build status](https://ci.appveyor.com/api/projects/status/2msksh7auurc4hu4?svg=true)](https://ci.appveyor.com/project/anders9ustafsson/csnumerics) 12 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cureos/csnumerics?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 13 | 14 | ## Usage 15 | 16 | *CSNumerics* is a .NET Standard 1.0 and 2.0 class library of various numerical algorithms written in C#. 17 | 18 | It currently consists of C# implementations of Michael J.D. Powell's optimization algorithms: 19 | 20 | * [BOBYQA](https://github.com/cureos/csnumerics/wiki/BOBYQA) for minimizing a nonlinear objective function subject to variable bounds. 21 | * [LINCOA](https://github.com/cureos/csnumerics/wiki/LINCOA) for minimizing a nonlinear objective function subject to linear constraints. 22 | * [COBYLA](https://github.com/cureos/csnumerics/wiki/COBYLA) for minimizing a nonlinear objective function subject to nonlinear constraints. 23 | 24 | Use *NuGet* to include [CSNumerics](https://www.nuget.org/packages/csnumerics) in your application. 25 | -------------------------------------------------------------------------------- /Settings.StyleCop: -------------------------------------------------------------------------------- 1 | 2 | 3 | False 4 | 5 | 6 | -------------------------------------------------------------------------------- /csnumerics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cureos/csnumerics/6adcffc8884b76037e6dee15e32ca0bffee71862/csnumerics.png -------------------------------------------------------------------------------- /csnumerics.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30110.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csnumerics", "csnumerics\csnumerics.csproj", "{75A1F6A6-7753-4B6C-B8FD-B1896C37038C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csnumerics.tests", "csnumerics.tests\csnumerics.tests.csproj", "{1CDAECB0-0D30-43FB-8529-E3BE44461B66}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {75A1F6A6-7753-4B6C-B8FD-B1896C37038C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {75A1F6A6-7753-4B6C-B8FD-B1896C37038C}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {75A1F6A6-7753-4B6C-B8FD-B1896C37038C}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {75A1F6A6-7753-4B6C-B8FD-B1896C37038C}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {1CDAECB0-0D30-43FB-8529-E3BE44461B66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {1CDAECB0-0D30-43FB-8529-E3BE44461B66}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {1CDAECB0-0D30-43FB-8529-E3BE44461B66}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {1CDAECB0-0D30-43FB-8529-E3BE44461B66}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /csnumerics.tests/Issues/GH1.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | using System; 23 | using System.Linq; 24 | using Cureos.Numerics.Optimizers; 25 | using NUnit.Framework; 26 | 27 | namespace Cureos.Numerics.Issues 28 | { 29 | [TestFixture] 30 | public class GH1 31 | { 32 | #region Unit tests 33 | 34 | [Test, Ignore("Constraints violated")] 35 | public void Cobyla_FindMinimum_ConstraintsShouldBeSatisfied() 36 | { 37 | var x0 = new[] { 0.705, 0.0075, 0.075, 0, 0.0375, 0, 0.05, 0.125 }; 38 | var cobyla = new Cobyla(x0.Length, 3 + x0.Length, Calcfc) 39 | { 40 | MaximumFunctionCalls = 100000, 41 | TrustRegionRadiusStart = 1.0, 42 | TrustRegionRadiusEnd = 1.0e-6, 43 | PrintLevel = 1, 44 | Logger = Console.Out 45 | }; 46 | 47 | var summary = cobyla.FindMinimum(x0); 48 | Assert.AreEqual(OptimizationStatus.Normal, summary.Status); 49 | Assert.IsTrue(summary.G.All(c => c >= -1.0e-6)); 50 | } 51 | 52 | #endregion 53 | 54 | #region Private methods 55 | 56 | private static void Calcfc(int n, int m, double[] x, out double f, double[] con) 57 | { 58 | for (var i = 0; i < x.Length; i++) 59 | { 60 | con[i] = x[i]; 61 | } 62 | 63 | var sum = 0.0; 64 | for (var i = 0; i < n; i++) 65 | { 66 | sum += x[i]; 67 | } 68 | con[n] = sum - 0.9999; 69 | con[n + 1] = 1.0001 - sum; 70 | 71 | double[][] matrix = 72 | { 73 | new[] { -0.25, -0.25, 0.75, 0.75, -0.25, -0.25, 0.75, 0.75 }, 74 | new[] { 0.0, -0.8, 0.0, 0.2, 0.0, -0.8, 0.0, 0.2 }, 75 | new[] { 0.0, 0.0, 0.0, 0.0, -0.6, -0.6, 0.4, 0.4 }, 76 | new[] { 0.0, 0.0, -0.7, -0.7, 0.0, 0.0, 0.3, 0.3 }, 77 | new[] { 0.0, 0.0, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5 }, 78 | new[] { -0.05, -0.05, 0.0, 0.0, 0.95, 0.95, 0.0, 0.0 }, 79 | new[] { -0.01, 0.99, 0.0, 0.0, -0.01, 0.99, 0.0, 0.0 } 80 | }; 81 | var matrix_m_x = new double[matrix.GetLength(0)]; 82 | sum = 0; 83 | for (var i = 0; i < matrix.GetLength(0); i++) 84 | { 85 | for (var j = 0; j < matrix[i].Length; j++) 86 | { 87 | matrix_m_x[i] = matrix_m_x[i] + matrix[i][j] * x[j]; 88 | } 89 | sum += Math.Abs(matrix_m_x[i]); 90 | } 91 | con[n + 2] = 0.06651 - sum; 92 | 93 | var entropy = 0.0; 94 | for (var i = 0; i < n; i++) 95 | { 96 | var d = x[i]; 97 | if (d <= 0.0) 98 | { 99 | continue; 100 | } 101 | entropy -= d * Math.Log(d, 2.0); 102 | } 103 | 104 | f = -entropy; 105 | } 106 | 107 | #endregion 108 | } 109 | } -------------------------------------------------------------------------------- /csnumerics.tests/Optimizers/BobyqaTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | using System; 23 | using System.Collections; 24 | using System.IO; 25 | using System.Linq; 26 | using NUnit.Framework; 27 | 28 | namespace Cureos.Numerics.Optimizers 29 | { 30 | [TestFixture] 31 | public class BobyqaTests 32 | { 33 | #region Fields 34 | 35 | private const double TOL = 1.0e-5; 36 | 37 | #endregion 38 | 39 | #region Unit tests 40 | 41 | [Test] 42 | public void FindMinimum_IntermedRosenbrock_ReturnsValidMinimum() 43 | { 44 | var optimizer = new Bobyqa( 45 | 2, 46 | (n, x) => 10.0 * Math.Pow(x[0] * x[0] - x[1], 2.0) + Math.Pow(1.0 + x[0], 2.0)); 47 | var summary = optimizer.FindMinimum(new[] { 1.0, -1.0 }); 48 | 49 | Assert.AreEqual(-1.0, summary.X[0], TOL); 50 | Assert.AreEqual(1.0, summary.X[1], TOL); 51 | } 52 | 53 | [Test] 54 | public void FindMinimum_HS04_ReturnsValidMinimum() 55 | { 56 | var optimizer = new Bobyqa(2, (n, x) => Math.Pow(x[0] + 1.0, 3.0) / 3.0 + x[1], new[] { 1.0, 0.0 }, null) 57 | { 58 | InterpolationConditions = 4 59 | }; 60 | var result = optimizer.FindMinimum(new[] { 1.125, 0.125 }); 61 | 62 | Assert.AreEqual(1.0, result.X[0], TOL); 63 | Assert.AreEqual(0.0, result.X[1], TOL); 64 | } 65 | 66 | [Test] 67 | public void FindMinimum_HS05_ReturnsValidMinimum() 68 | { 69 | var optimizer = new Bobyqa( 70 | 2, 71 | (n, x) => Math.Sin(x[0] + x[1]) + Math.Pow(x[0] - x[1], 2.0) - 1.5 * x[0] + 2.5 * x[1] + 1, 72 | new[] { -1.5, -3.0 }, 73 | new[] { 4.0, 3.0 }); 74 | var result = optimizer.FindMinimum(new[] { 0.0, 0.0 }); 75 | 76 | Assert.AreEqual(0.5 - Math.PI / 3.0, result.X[0], TOL); 77 | Assert.AreEqual(-0.5 - Math.PI / 3.0, result.X[1], TOL); 78 | } 79 | 80 | [TestCase(5, 16)] 81 | [TestCase(5, 21)] 82 | [TestCase(10, 26)] 83 | [TestCase(10, 41)] 84 | public void FindMinimum_BobyqaTestCase_ReturnStatusNormal(int m, int npt) 85 | { 86 | // Test problem for BOBYQA, the objective function being the sum of 87 | // the reciprocals of all pairwise distances between the points P_I, 88 | // I=1,2,...,M in two dimensions, where M=N/2 and where the components 89 | // of P_I are X(2*I-1) and X(2*I). Thus each vector X of N variables 90 | // defines the M points P_I. The initial X gives equally spaced points 91 | // on a circle. Four different choices of the pairs (N,NPT) are tried, 92 | // namely (10,16), (10,21), (20,26) and (20,41). Convergence to a local 93 | // minimum that is not global occurs in both the N=10 cases. The details 94 | // of the results are highly sensitive to computer rounding errors. The 95 | // choice IPRINT=2 provides the current X and optimal F so far whenever 96 | // RHO is reduced. The bound constraints of the problem require every 97 | // component of X to be in the interval [-1,1]. 98 | 99 | var n = 2 * m; 100 | var x0 = new double[n]; 101 | var xl = new double[n]; 102 | var xu = new double[n]; 103 | 104 | const double bdl = -1.0; 105 | const double bdu = 1.0; 106 | for (var i = 0; i < n; ++i) 107 | { 108 | xl[i] = bdl; 109 | xu[i] = bdu; 110 | } 111 | 112 | Console.WriteLine("{0}2D output with M ={1,4}, N ={2,4} and NPT ={3,4}", Environment.NewLine, m, n, npt); 113 | 114 | for (var j = 1; j <= m; ++j) 115 | { 116 | var temp = 2.0 * Math.PI * j / m; 117 | x0[2 * j - 2] = Math.Cos(temp); 118 | x0[2 * j - 1] = Math.Sin(temp); 119 | } 120 | 121 | const int iprint = 2; 122 | const int maxfun = 500000; 123 | const double rhobeg = 1.0E-1; 124 | const double rhoend = 1.0E-6; 125 | 126 | var optimizer = new Bobyqa(n, this.BobyqaTestCalfun, xl, xu) 127 | { 128 | InterpolationConditions = npt, 129 | TrustRegionRadiusStart = rhobeg, 130 | TrustRegionRadiusEnd = rhoend, 131 | PrintLevel = iprint, 132 | MaximumFunctionCalls = maxfun 133 | }; 134 | 135 | const OptimizationStatus expected = OptimizationStatus.Normal; 136 | var actual = optimizer.FindMinimum(x0).Status; 137 | Assert.AreEqual(expected, actual); 138 | } 139 | 140 | public double BobyqaTestCalfun(int n, double[] x) 141 | { 142 | var f = 0.0; 143 | for (var i = 4; i <= n; i += 2) 144 | { 145 | for (var j = 2; j <= i - 2; j += 2) 146 | { 147 | var temp = Math.Max(Math.Pow(x[i - 2] - x[j - 2], 2.0) + Math.Pow(x[i - 1] - x[j - 1], 2.0), 1.0e-6); 148 | f += 1.0 / Math.Sqrt(temp); 149 | } 150 | } 151 | return f; 152 | } 153 | 154 | [TestCase(13, 78), Ignore("Accuracy")] 155 | public void FindMinimum_ConstrainedRosenWithAdditionalInterpolationPoints_ReturnsValidMinimum(int n, int maxAdditionalPoints) 156 | { 157 | var xl = Enumerable.Repeat(-1.0, n).ToArray(); 158 | var xu = Enumerable.Repeat(2.0, n).ToArray(); 159 | var expected = Enumerable.Repeat(1.0, n).ToArray(); 160 | 161 | var optimizer = new Bobyqa(n, this.Rosen, xl, xu) 162 | { 163 | TrustRegionRadiusEnd = 1.0e-8, 164 | MaximumFunctionCalls = 3000, 165 | Logger = Console.Out 166 | }; 167 | for (var num = 1; num <= maxAdditionalPoints; ++num) 168 | { 169 | Console.WriteLine("\nNumber of additional points = {0}", num); 170 | optimizer.InterpolationConditions = 2 * n + 1 + num; 171 | var result = optimizer.FindMinimum(Enumerable.Repeat(0.1, n).ToArray()); 172 | 173 | CollectionAssert.AreEqual(expected, result.X, new DoubleComparer(1.0e-6)); 174 | } 175 | } 176 | 177 | [Test] 178 | public void FindMinimum_LogOutput_OutputNonEmpty() 179 | { 180 | const int n = 9; 181 | var optimizer = new Bobyqa(n, this.Rosen) { Logger = Console.Out }; 182 | using (var logger = new StringWriter()) 183 | { 184 | optimizer.Logger = logger; 185 | optimizer.FindMinimum(Enumerable.Repeat(0.1, n).ToArray()); 186 | Assert.Greater(logger.ToString().Length, 0); 187 | } 188 | } 189 | 190 | [Test] 191 | public void FindMinimum_LogOutputToConsole_OutputNonEmpty() 192 | { 193 | const int n = 9; 194 | var optimizer = new Bobyqa(n, this.Rosen) { Logger = Console.Out }; 195 | optimizer.FindMinimum(Enumerable.Repeat(0.1, n).ToArray()); 196 | } 197 | 198 | public double Rosen(int n, double[] x) 199 | { 200 | var f = 0.0; 201 | for (var i = 0; i < n - 1; ++i) 202 | f += 1e2 * (x[i] * x[i] - x[i + 1]) * (x[i] * x[i] - x[i + 1]) + (x[i] - 1.0) * (x[i] - 1.0); 203 | return f; 204 | } 205 | 206 | #endregion 207 | } 208 | 209 | internal class DoubleComparer : IComparer 210 | { 211 | private readonly double _tol; 212 | 213 | internal DoubleComparer(double tol) 214 | { 215 | _tol = tol; 216 | } 217 | 218 | internal int Compare(double x, double y) 219 | { 220 | return Math.Abs(x - y) <= _tol ? 0 : x.CompareTo(y); 221 | } 222 | 223 | int IComparer.Compare(object x, object y) 224 | { 225 | return Compare((double)x, (double)y); 226 | } 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /csnumerics.tests/Optimizers/CobylaTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | //------------------------------------------------------------------------------ 23 | // Main program of test problems in Report DAMTP 1992/NA5. 24 | //------------------------------------------------------------------------------ 25 | 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Linq; 30 | using NUnit.Framework; 31 | 32 | namespace Cureos.Numerics.Optimizers 33 | { 34 | [TestFixture] 35 | public class CobylaTests 36 | { 37 | #region FIELDS 38 | 39 | private const double rhobeg = 0.5; 40 | private const double rhoend1 = 1.0e-6; 41 | private const double rhoend2 = 1.0e-8; 42 | private const int maxfun = 3500; 43 | 44 | #endregion 45 | 46 | #region AUTO-IMPLEMENTED PROPERTIES 47 | 48 | private static IEnumerable> TestCases 49 | { 50 | get 51 | { 52 | yield return 53 | Tuple.Create("1 (Simple quadratic)", (CalcfcDelegate)calcfc1, 2, 0, new[] {-1.0, 0.0}, 1.0e-5); 54 | yield return 55 | Tuple.Create("2 (2D unit circle calculation)", (CalcfcDelegate)calcfc2, 2, 1, 56 | new[] {Math.Sqrt(0.5), -Math.Sqrt(0.5)}, 1.0e-5); 57 | yield return 58 | Tuple.Create("3 (3D ellipsoid calculation)", (CalcfcDelegate)calcfc3, 3, 1, 59 | new[] {1.0 / Math.Sqrt(3.0), 1.0 / Math.Sqrt(6.0), -1.0 / 3.0}, 1.0e-5); 60 | yield return 61 | Tuple.Create("4 (Weak Rosenbrock)", (CalcfcDelegate)calcfc4, 2, 0, new[] {-1.0, 1.0}, 2.0e-5); 62 | yield return 63 | Tuple.Create("5 (Intermediate Rosenbrock)", (CalcfcDelegate)calcfc5, 2, 0, new[] {-1.0, 1.0}, 2.0e-4) 64 | ; 65 | yield return 66 | Tuple.Create("6 (Equation (9.1.15) in Fletcher's book)", (CalcfcDelegate)calcfc6, 2, 2, 67 | new[] {Math.Sqrt(0.5), Math.Sqrt(0.5)}, 1.0e-6); 68 | yield return 69 | Tuple.Create("7 (Equation (14.4.2) in Fletcher)", (CalcfcDelegate)calcfc7, 3, 3, 70 | new[] {0.0, -3.0, -3.0}, 1.0e-8); 71 | yield return 72 | Tuple.Create("8 (Rosen-Suzuki)", (CalcfcDelegate)calcfc8, 4, 3, 73 | new[] {0.0, 1.0, 2.0, -1.0}, 1.0e-5); 74 | yield return 75 | Tuple.Create("9 (Hock and Schittkowski 100)", (CalcfcDelegate)calcfc9, 7, 4, 76 | new[] { 2.330499, 1.951372, -0.4775414, 4.365726, -0.624487, 1.038131, 1.594227 }, 1.0e-5); 77 | yield return 78 | Tuple.Create("10 (Hexagon area)", (CalcfcDelegate)calcfc10, 9, 14, 79 | new[] { 0.688341, 0.725387, -0.284033, 0.958814, 0.688341, 0.725387, -0.284033, 0.958814, 0.0 }, 80 | 1.0e-5); 81 | } 82 | } 83 | 84 | #endregion 85 | 86 | #region METHODS 87 | 88 | [TestCaseSource("TestCases")] 89 | public void TestProblem(Tuple testCase) 90 | { 91 | var problem = testCase.Item1; 92 | var calcfc = testCase.Item2; 93 | var n = testCase.Item3; 94 | var m = testCase.Item4; 95 | var xopt = testCase.Item5; 96 | var accepted = testCase.Item6; 97 | 98 | Console.WriteLine("{0}Output from test problem {1}", Environment.NewLine, problem); 99 | 100 | var error1 = RunTestProblem(calcfc, n, m, rhoend1, xopt); 101 | Assert.Less(error1, accepted); 102 | var error2 = RunTestProblem(calcfc, n, m, rhoend2, xopt); 103 | Assert.That(error2, Is.LessThan(error1).Within(1.0e-8)); 104 | } 105 | 106 | public double RunTestProblem(CalcfcDelegate calcfc, int n, int m, double rhoend, double[] xopt) 107 | { 108 | var timer = new Stopwatch(); 109 | timer.Restart(); 110 | var optimizer = new Cobyla(n, m, calcfc) 111 | { 112 | MaximumFunctionCalls = maxfun, 113 | TrustRegionRadiusStart = rhobeg, 114 | TrustRegionRadiusEnd = rhoend 115 | }; 116 | var result = optimizer.FindMinimum(Enumerable.Repeat(1.0, n).ToArray()); 117 | timer.Stop(); 118 | 119 | Assert.That(result.Status, 120 | Is.EqualTo(OptimizationStatus.Normal).Or.EqualTo(OptimizationStatus.MAXFUN_Reached)); 121 | 122 | var error = xopt.Select((xo, i) => Math.Pow(xo - result.X[i], 2.0)).Sum(); 123 | Console.WriteLine("{0}Least squares error in variables = {1,16:E6}", Environment.NewLine, error); 124 | Console.WriteLine("Elapsed time for optimization = {0} ms", timer.ElapsedMilliseconds); 125 | 126 | return error; 127 | } 128 | 129 | /// 130 | /// Minimization of a simple quadratic function of two variables. 131 | /// 132 | public static void calcfc1(int n, int m, double[] x, out double f, double[] con) 133 | { 134 | f = 10.0 * Math.Pow(x[0] + 1.0, 2.0) + Math.Pow(x[1], 2.0); 135 | } 136 | 137 | /// 138 | /// Easy two dimensional minimization in unit circle. 139 | /// 140 | public static void calcfc2(int n, int m, double[] x, out double f, double[] con) 141 | { 142 | f = x[0] * x[1]; 143 | con[0] = 1.0 - x[0] * x[0] - x[1] * x[1]; 144 | } 145 | 146 | /// 147 | /// Easy three dimensional minimization in ellipsoid. 148 | /// 149 | public static void calcfc3(int n, int m, double[] x, out double f, double[] con) 150 | { 151 | f = x[0] * x[1] * x[2]; 152 | con[0] = 1.0 - x[0] * x[0] - 2.0 * x[1] * x[1] - 3.0 * x[2] * x[2]; 153 | } 154 | 155 | /// 156 | /// Weak version of Rosenbrock's problem. 157 | /// 158 | public static void calcfc4(int n, int m, double[] x, out double f, double[] con) 159 | { 160 | f = Math.Pow(x[0] * x[0] - x[1], 2.0) + Math.Pow(1.0 + x[0], 2.0); 161 | } 162 | 163 | /// 164 | /// Intermediate version of Rosenbrock's problem. 165 | /// 166 | public static void calcfc5(int n, int m, double[] x, out double f, double[] con) 167 | { 168 | f = 10.0 * Math.Pow(x[0] * x[0] - x[1], 2.0) + Math.Pow(1.0 + x[0], 2.0); 169 | } 170 | 171 | /// 172 | /// This problem is taken from Fletcher's book Practical Methods of 173 | /// Optimization and has the equation number (9.1.15). 174 | /// 175 | public static void calcfc6(int n, int m, double[] x, out double f, double[] con) 176 | { 177 | f = -x[0] - x[1]; 178 | con[0] = x[1] - x[0] * x[0]; 179 | con[1] = 1.0 - x[0] * x[0] - x[1] * x[1]; 180 | } 181 | 182 | /// 183 | /// This problem is taken from Fletcher's book Practical Methods of 184 | /// Optimization and has the equation number (14.4.2). 185 | /// 186 | public static void calcfc7(int n, int m, double[] x, out double f, double[] con) 187 | { 188 | f = x[2]; 189 | con[0] = 5.0 * x[0] - x[1] + x[2]; 190 | con[1] = x[2] - x[0] * x[0] - x[1] * x[1] - 4.0 * x[1]; 191 | con[2] = x[2] - 5.0 * x[0] - x[1]; 192 | } 193 | 194 | /// 195 | /// This problem is taken from page 66 of Hock and Schittkowski's book Test 196 | /// Examples for Nonlinear Programming Codes. It is their test problem Number 197 | /// 43, and has the name Rosen-Suzuki. 198 | /// 199 | public static void calcfc8(int n, int m, double[] x, out double f, double[] con) 200 | { 201 | f = x[0] * x[0] + x[1] * x[1] + 2.0 * x[2] * x[2] + x[3] * x[3] - 5.0 * x[0] - 5.0 * x[1] - 21.0 * x[2] + 202 | 7.0 * x[3]; 203 | con[0] = 8.0 - x[0] * x[0] - x[1] * x[1] - x[2] * x[2] - x[3] * x[3] - x[0] + x[1] - x[2] + x[3]; 204 | con[1] = 10.0 - x[0] * x[0] - 2.0 * x[1] * x[1] - x[2] * x[2] - 2.0 * x[3] * x[3] + x[0] + x[3]; 205 | con[2] = 5.0 - 2.0 * x[0] * x[0] - x[1] * x[1] - x[2] * x[2] - 2.0 * x[0] + x[1] + x[3]; 206 | } 207 | 208 | /// 209 | /// This problem is taken from page 111 of Hock and Schittkowski's 210 | /// book Test Examples for Nonlinear Programming Codes. It is their 211 | /// test problem Number 100. 212 | /// 213 | public static void calcfc9(int n, int m, double[] x, out double f, double[] con) 214 | { 215 | f = Math.Pow(x[0] - 10.0, 2.0) + 5.0 * Math.Pow(x[1] - 12.0, 2.0) + Math.Pow(x[2], 4.0) + 216 | 3.0 * Math.Pow(x[3] - 11.0, 2.0) + 10.0 * Math.Pow(x[4], 6.0) + 7.0 * x[5] * x[5] + Math.Pow(x[6], 4.0) - 217 | 4.0 * x[5] * x[6] - 10.0 * x[5] - 8.0 * x[6]; 218 | con[0] = 127.0 - 2.0 * x[0] * x[0] - 3.0 * Math.Pow(x[1], 4.0) - x[2] - 4.0 * x[3] * x[3] - 5.0 * x[4]; 219 | con[1] = 282.0 - 7.0 * x[0] - 3.0 * x[1] - 10.0 * x[2] * x[2] - x[3] + x[4]; 220 | con[2] = 196.0 - 23.0 * x[0] - x[1] * x[1] - 6.0 * x[5] * x[5] + 8.0 * x[6]; 221 | con[3] = -4.0 * x[0] * x[0] - x[1] * x[1] + 3.0 * x[0] * x[1] - 2.0 * x[2] * x[2] - 5.0 * x[5] + 11.0 * x[6]; 222 | } 223 | 224 | /// 225 | /// This problem is taken from page 415 of Luenberger's book Applied 226 | /// Nonlinear Programming. It is to maximize the area of a hexagon of 227 | /// unit diameter. 228 | /// 229 | public static void calcfc10(int n, int m, double[] x, out double f, double[] con) 230 | { 231 | f = -0.5 * (x[0] * x[3] - x[1] * x[2] + x[2] * x[8] - x[4] * x[8] + x[4] * x[7] - x[5] * x[6]); 232 | con[0] = 1.0 - x[2] * x[2] - x[3] * x[3]; 233 | con[1] = 1.0 - x[8] * x[8]; 234 | con[2] = 1.0 - x[4] * x[4] - x[5] * x[5]; 235 | con[3] = 1.0 - x[0] * x[0] - Math.Pow(x[1] - x[8], 2.0); 236 | con[4] = 1.0 - Math.Pow(x[0] - x[4], 2.0) - Math.Pow(x[1] - x[5], 2.0); 237 | con[5] = 1.0 - Math.Pow(x[0] - x[6], 2.0) - Math.Pow(x[1] - x[7], 2.0); 238 | con[6] = 1.0 - Math.Pow(x[2] - x[4], 2.0) - Math.Pow(x[3] - x[5], 2.0); 239 | con[7] = 1.0 - Math.Pow(x[2] - x[6], 2.0) - Math.Pow(x[3] - x[7], 2.0); 240 | con[8] = 1.0 - x[6] * x[6] - Math.Pow(x[7] - x[8], 2.0); 241 | con[9] = x[0] * x[3] - x[1] * x[2]; 242 | con[10] = x[2] * x[8]; 243 | con[11] = -x[4] * x[8]; 244 | con[12] = x[4] * x[7] - x[5] * x[6]; 245 | con[13] = x[8]; 246 | } 247 | 248 | [Test] 249 | public void FindMinimum_LogOutputToConsole_VisualInspection() 250 | { 251 | var optimizer = new Cobyla(9, 14, calcfc10) { PrintLevel = 2, Logger = Console.Out }; 252 | optimizer.FindMinimum(Enumerable.Repeat(1.0, 9).ToArray()); 253 | } 254 | 255 | #endregion 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /csnumerics.tests/Optimizers/LincoaTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | using System; 23 | using NUnit.Framework; 24 | 25 | namespace Cureos.Numerics.Optimizers 26 | { 27 | [TestFixture] 28 | public class LincoaTests 29 | { 30 | #region FIELDS 31 | 32 | private double _fmax; 33 | 34 | #endregion 35 | 36 | #region Unit tests 37 | 38 | [TestCase(15, 0.01)] 39 | [TestCase(30, 0.001)] 40 | [TestCase(45, 0.001)] 41 | public void FindMinimum_PtsinTet_YieldsExpectedValue(int npt, double tol) 42 | { 43 | // Set some constants. 44 | const int n = 12; 45 | 46 | // Set the data points. 47 | const int np = 50; 48 | var sumx = 0.0; 49 | var sumy = 0.0; 50 | var sumz = 0.0; 51 | 52 | var xp = new double[50]; 53 | var yp = new double[50]; 54 | var zp = new double[50]; 55 | for (var j = 0; j < np; ++j) 56 | { 57 | var theta = j * Math.PI / (np - 1.0); 58 | xp[j] = Math.Cos(theta) * Math.Cos(2.0 * theta); 59 | sumx += xp[j]; 60 | yp[j] = Math.Sin(theta) * Math.Cos(2.0 * theta); 61 | sumy += yp[j]; 62 | zp[j] = Math.Sin(2.0 * theta); 63 | sumz += zp[j]; 64 | } 65 | sumx /= np; 66 | sumy /= np; 67 | sumz /= np; 68 | for (var j = 0; j < np; ++j) 69 | { 70 | xp[j] -= sumx; 71 | yp[j] -= sumy; 72 | zp[j] -= sumz; 73 | } 74 | 75 | // Set the linear constraints. 76 | const int m = 4 * np; 77 | var a = new double[m, n]; 78 | var b = new double[m]; 79 | for (var k = 0; k < m; ++k) 80 | { 81 | b[k] = 1.0; 82 | for (var i = 0; i < n; ++i) 83 | a[k, i] = 0.0; 84 | } 85 | for (var j = 0; j < np; ++j) 86 | { 87 | for (var i = 0; i < 4; ++i) 88 | { 89 | var k = 4 * j + i; 90 | var iw = 3 * i; 91 | a[k, iw] = xp[j]; 92 | a[k, iw + 1] = yp[j]; 93 | a[k, iw + 2] = zp[j]; 94 | } 95 | } 96 | 97 | // Set the initial vector of variables. 98 | var xs = 0.0; 99 | var ys = 0.0; 100 | var zs = 0.0; 101 | var ss = 0.0; 102 | for (var j = 0; j < np; ++j) 103 | { 104 | xs = Math.Min(xs, xp[j]); 105 | ys = Math.Min(ys, yp[j]); 106 | zs = Math.Min(zs, zp[j]); 107 | ss = Math.Max(ss, xp[j] + yp[j] + zp[j]); 108 | } 109 | 110 | var x = new double[12]; 111 | x[0] = 1.0 / xs; 112 | x[4] = 1.0 / ys; 113 | x[8] = 1.0 / zs; 114 | x[9] = 1.0 / ss; 115 | x[10] = 1.0 / ss; 116 | x[11] = 1.0 / ss; 117 | 118 | this._fmax = Math.Pow(ss - xs - ys - zs, 3.0) / 6.0; 119 | 120 | // Call of LINCOA, which provides the printing given at the end of this note. 121 | const double rhobeg = 1.0; 122 | const double rhoend = 1.0E-6; 123 | const int iprint = 1; 124 | const int maxfun = 10000; 125 | 126 | var lincoa = new Lincoa(this.PtsinTet, a, b) 127 | { 128 | InterpolationConditions = npt, 129 | TrustRegionRadiusStart = rhobeg, 130 | TrustRegionRadiusEnd = rhoend, 131 | MaximumFunctionCalls = maxfun, 132 | PrintLevel = iprint, 133 | Logger = Console.Out 134 | }; 135 | var result = lincoa.FindMinimum(x); 136 | 137 | const double expected = 2.761; 138 | var actual = result.F; 139 | Assert.AreEqual(expected, actual, tol); 140 | } 141 | 142 | public double PtsinTet(int n, double[] x, bool isXFeasible) 143 | { 144 | var v12 = x[0] * x[4] - x[3] * x[1]; 145 | var v13 = x[0] * x[7] - x[6] * x[1]; 146 | var v14 = x[0] * x[10] - x[9] * x[1]; 147 | var v23 = x[3] * x[7] - x[6] * x[4]; 148 | var v24 = x[3] * x[10] - x[9] * x[4]; 149 | var v34 = x[6] * x[10] - x[9] * x[7]; 150 | var del1 = v23 * x[11] - v24 * x[8] + v34 * x[5]; 151 | if (del1 <= 0.0) return this._fmax; 152 | var del2 = -v34 * x[2] - v13 * x[11] + v14 * x[8]; 153 | if (del2 <= 0.0) return this._fmax; 154 | var del3 = -v14 * x[5] + v24 * x[2] + v12 * x[11]; 155 | if (del3 <= 0.0) return this._fmax; 156 | var del4 = -v12 * x[8] + v13 * x[5] - v23 * x[2]; 157 | if (del4 <= 0.0) return this._fmax; 158 | var temp = Math.Pow(del1 + del2 + del3 + del4, 3.0) / (del1 * del2 * del3 * del4); 159 | return Math.Min(temp / 6.0, this._fmax); 160 | } 161 | 162 | #endregion 163 | 164 | [TestCase(2, -100, -300)] 165 | public void FindMinimum_EasyFun_YieldsExpectedValue(int dim, double minVal, double expect) 166 | { 167 | var constraintMatrix = new double[dim,dim]; 168 | var constraintVals = new double[dim]; 169 | for (int i = 0; i < dim; i++) 170 | { 171 | constraintMatrix[i, i] = -1; 172 | constraintVals[i] = -minVal; 173 | } 174 | 175 | var lincoa = new Lincoa(EasyFun, constraintMatrix, constraintVals) 176 | { 177 | TrustRegionRadiusStart = 1, 178 | TrustRegionRadiusEnd = 0.01, 179 | MaximumFunctionCalls = 10000, 180 | PrintLevel = 3, 181 | Logger = Console.Out 182 | }; 183 | var result = lincoa.FindMinimum(new double[dim]); 184 | 185 | var actual = result.F; 186 | Assert.AreEqual(expect, actual, 0.1); 187 | 188 | } 189 | 190 | public double EasyFun(int n, double[] x, bool isXFeasible) 191 | { 192 | double total = 0; 193 | for (var i = 0; i < x.Length; i++) 194 | { 195 | total += (i + 1)*x[i]; 196 | } 197 | return total; 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /csnumerics.tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2014, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | using System.Reflection; 23 | using System.Runtime.InteropServices; 24 | 25 | // General Information about an assembly is controlled through the following 26 | // set of attributes. Change these attribute values to modify the information 27 | // associated with an assembly. 28 | [assembly: AssemblyTitle("csnumerics.tests")] 29 | [assembly: AssemblyDescription("Unit tests for CSNumerics assembly")] 30 | [assembly: AssemblyConfiguration("")] 31 | [assembly: AssemblyCompany("Cureos AB")] 32 | [assembly: AssemblyProduct("CSNumerics")] 33 | [assembly: AssemblyCopyright("Copyright © 2014 Cureos AB")] 34 | [assembly: AssemblyTrademark("CSNumerics")] 35 | [assembly: AssemblyCulture("")] 36 | 37 | // Setting ComVisible to false makes the types in this assembly not visible 38 | // to COM components. If you need to access a type in this assembly from 39 | // COM, set the ComVisible attribute to true on that type. 40 | [assembly: ComVisible(false)] 41 | 42 | // The following GUID is for the ID of the typelib if this project is exposed to COM 43 | [assembly: Guid("e1a60c16-e42e-4ab6-ba2e-6887d5a0719a")] 44 | 45 | // Version information for an assembly consists of the following four values: 46 | // 47 | // Major Version 48 | // Minor Version 49 | // Build Number 50 | // Revision 51 | // 52 | // You can specify all the values or you can default the Build and Revision Numbers 53 | // by using the '*' as shown below: 54 | // [assembly: AssemblyVersion("1.0.*")] 55 | [assembly: AssemblyVersion("0.8.0.0")] 56 | [assembly: AssemblyFileVersion("0.8.0.0")] 57 | -------------------------------------------------------------------------------- /csnumerics.tests/csnumerics.tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net462 5 | disable 6 | disable 7 | false 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | all 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /csnumerics.unity.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csnumerics.unity", "csnumerics.unity\csnumerics.unity.csproj", "{1653BD71-936D-444B-9B95-C0EDB0F2128D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {1653BD71-936D-444B-9B95-C0EDB0F2128D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {1653BD71-936D-444B-9B95-C0EDB0F2128D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {1653BD71-936D-444B-9B95-C0EDB0F2128D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {1653BD71-936D-444B-9B95-C0EDB0F2128D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /csnumerics.unity/csnumerics.unity.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1653BD71-936D-444B-9B95-C0EDB0F2128D} 8 | Library 9 | Properties 10 | Cureos.Numerics 11 | CSNumerics 12 | v3.5 13 | 512 14 | Unity Subset v3.5 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | true 35 | 36 | 37 | ..\csnumerics\csnumerics.snk 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | NET35\Zip.cs 46 | 47 | 48 | Optimizers\Bobyqa.cs 49 | 50 | 51 | Optimizers\Cobyla.cs 52 | 53 | 54 | Optimizers\IOptimizer.cs 55 | 56 | 57 | Optimizers\IQuadraticModelOptimizer.cs 58 | 59 | 60 | Optimizers\ITrustRegionOptimizer.cs 61 | 62 | 63 | Optimizers\Lincoa.cs 64 | 65 | 66 | Optimizers\OptimizationStatus.cs 67 | 68 | 69 | Optimizers\OptimizationSummary.cs 70 | 71 | 72 | Properties\AssemblyInfo.cs 73 | 74 | 75 | 76 | 83 | -------------------------------------------------------------------------------- /csnumerics/NET35/Zip.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace System.Linq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Returns a projection of tuples, where each tuple contains the N-th element 27 | /// from each of the argument sequences. 28 | /// 29 | /// 30 | /// If the two input sequences are of different lengths, the result sequence 31 | /// is terminated as soon as the shortest input sequence is exhausted. 32 | /// This operator uses deferred execution and streams its results. 33 | /// 34 | /// 35 | /// 36 | /// int[] numbers = { 1, 2, 3 }; 37 | /// string[] letters = { "A", "B", "C", "D" }; 38 | /// var zipped = numbers.Zip(letters, (n, l) => n + l); 39 | /// 40 | /// The zipped variable, when iterated over, will yield "1A", "2B", "3C", in turn. 41 | /// 42 | /// Type of elements in first sequence 43 | /// Type of elements in second sequence 44 | /// Type of elements in result sequence 45 | /// First sequence 46 | /// Second sequence 47 | /// Function to apply to each pair of elements 48 | /// 49 | /// A sequence that contains elements of the two input sequences, 50 | /// combined by . 51 | /// 52 | 53 | public static IEnumerable Zip(this IEnumerable first, 54 | IEnumerable second, Func resultSelector) 55 | { 56 | if (first == null) throw new ArgumentNullException("first"); 57 | if (second == null) throw new ArgumentNullException("second"); 58 | if (resultSelector == null) throw new ArgumentNullException("resultSelector"); 59 | 60 | return ZipImpl(first, second, resultSelector); 61 | } 62 | 63 | static IEnumerable ZipImpl( 64 | IEnumerable first, 65 | IEnumerable second, 66 | Func resultSelector) 67 | { 68 | using (var e1 = first.GetEnumerator()) 69 | using (var e2 = second.GetEnumerator()) 70 | { 71 | while (e1.MoveNext()) 72 | { 73 | if (e2.MoveNext()) 74 | yield return resultSelector(e1.Current, e2.Current); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /csnumerics/Optimizers/Cobyla.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | * 21 | * Remarks: 22 | * 23 | * The original Fortran 77 version of this code was by Michael Powell (M.J.D.Powell @ damtp.cam.ac.uk) 24 | * The Fortran 90 version was by Alan Miller (Alan.Miller @ vic.cmis.csiro.au). Latest revision - 30 October 1998 25 | */ 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.IO; 30 | 31 | namespace Cureos.Numerics.Optimizers 32 | { 33 | // ReSharper disable InconsistentNaming 34 | 35 | #region DELEGATES 36 | 37 | /// 38 | /// Signature for the objective and constraints function evaluation method used in minimization. 39 | /// 40 | /// Number of variables. 41 | /// Number of constraints. 42 | /// Variable values to be employed in function and constraints calculation. 43 | /// Calculated objective function value. 44 | /// Calculated function values of the constraints. 45 | public delegate void CalcfcDelegate(int n, int m, double[] x, out double f, double[] con); 46 | 47 | #endregion 48 | 49 | /// 50 | /// Constrained Optimization BY Linear Approximation for .NET 51 | /// 52 | /// COBYLA2 is an implementation of Powell�s nonlinear derivative�free constrained optimization that uses 53 | /// a linear approximation approach. The algorithm is a sequential trust�region algorithm that employs linear 54 | /// approximations to the objective and constraint functions, where the approximations are formed by linear 55 | /// interpolation at n + 1 points in the space of the variables and tries to maintain a regular�shaped simplex 56 | /// over iterations. 57 | /// 58 | /// It solves nonsmooth NLP with a moderate number of variables (about 100). Inequality constraints only. 59 | /// 60 | /// The initial point X is taken as one vertex of the initial simplex with zero being another, so, X should 61 | /// not be entered as the zero vector. 62 | /// 63 | public class Cobyla : ITrustRegionOptimizer 64 | { 65 | #region FIELDS 66 | 67 | private readonly int _n; 68 | private readonly int _m; 69 | private readonly CalcfcDelegate _calcfc; 70 | 71 | private int _maxfun; 72 | private int _iprint; 73 | 74 | private double _rhobeg; 75 | private double _rhoend; 76 | 77 | private TextWriter _logger; 78 | 79 | private static readonly string LF = Environment.NewLine; 80 | private static readonly string IterationResultFormatter = LF + "NFVALS = {0,5} F = {1,13:E6} MAXCV = {2,13:E6}"; 81 | 82 | #endregion 83 | 84 | /// 85 | /// Minimizes the objective function F with respect to a set of inequality constraints CON, 86 | /// and returns the optimal variable array. F and CON may be non-linear, and should preferably be smooth. 87 | /// 88 | /// Number of variables. 89 | /// Number of constraints. 90 | /// Method for calculating objective function and constraints. 91 | public Cobyla(int n, int m, CalcfcDelegate calcfc) 92 | { 93 | _n = n; 94 | _m = m; 95 | _calcfc = calcfc; 96 | 97 | _rhobeg = 0.5; 98 | _rhoend = 1.0e-6; 99 | _iprint = 1; 100 | _maxfun = 10000; 101 | _logger = null; 102 | } 103 | 104 | #region PROPERTIES 105 | 106 | /// 107 | /// Gets or sets the number of maximum function calls. 108 | /// 109 | public int MaximumFunctionCalls 110 | { 111 | get 112 | { 113 | return this._maxfun; 114 | } 115 | set 116 | { 117 | this._maxfun = value; 118 | } 119 | } 120 | 121 | /// 122 | /// Gets or sets the print level to the logger. 123 | /// 124 | public int PrintLevel 125 | { 126 | get 127 | { 128 | return this._iprint; 129 | } 130 | set 131 | { 132 | this._iprint = value; 133 | } 134 | } 135 | 136 | /// 137 | /// Gets or sets the logger to which the optimizer log information should be sent. 138 | /// 139 | public TextWriter Logger 140 | { 141 | get 142 | { 143 | return this._logger; 144 | } 145 | set 146 | { 147 | this._logger = value; 148 | } 149 | } 150 | 151 | /// 152 | /// Gets or sets the final value of the trust region radius. 153 | /// 154 | public double TrustRegionRadiusStart 155 | { 156 | get 157 | { 158 | return this._rhobeg; 159 | } 160 | set 161 | { 162 | this._rhobeg = value; 163 | } 164 | } 165 | 166 | /// 167 | /// Gets or sets the start value of the trust region radius. 168 | /// 169 | public double TrustRegionRadiusEnd 170 | { 171 | get 172 | { 173 | return this._rhoend; 174 | } 175 | set 176 | { 177 | this._rhoend = value; 178 | } 179 | } 180 | 181 | #endregion 182 | 183 | #region METHODS 184 | 185 | /// 186 | /// Find a local minimum of provided objective function satisfying the nonlinear constraints. 187 | /// 188 | /// Initial variable array. 189 | /// Summary of the optimization result. 190 | public OptimizationSummary FindMinimum(double[] x0) 191 | { 192 | var nf = _maxfun; 193 | var status = COBYLA(_calcfc, _n, _m, x0, _rhobeg, _rhoend, _iprint, ref nf, _logger); 194 | 195 | double f; 196 | var con = new double[_m]; 197 | _calcfc(_n, _m, x0, out f, con); 198 | 199 | return new OptimizationSummary(status, nf, x0, f, con); 200 | } 201 | 202 | private static OptimizationStatus COBYLA( 203 | CalcfcDelegate calcfc, 204 | int n, 205 | int m, 206 | double[] x, 207 | double rhobeg, 208 | double rhoend, 209 | int iprint, 210 | ref int iters, 211 | TextWriter logger) 212 | { 213 | // This subroutine minimizes an objective function F(X) subject to M 214 | // inequality constraints on X, where X is a vector of variables that has 215 | // N components. The algorithm employs linear approximations to the 216 | // objective and constraint functions, the approximations being formed by 217 | // linear interpolation at N+1 points in the space of the variables. 218 | // We regard these interpolation points as vertices of a simplex. The 219 | // parameter RHO controls the size of the simplex and it is reduced 220 | // automatically from RHOBEG to RHOEND. For each RHO the subroutine tries 221 | // to achieve a good vector of variables for the current size, and then 222 | // RHO is reduced until the value RHOEND is reached. Therefore RHOBEG and 223 | // RHOEND should be set to reasonable initial changes to and the required 224 | // accuracy in the variables respectively, but this accuracy should be 225 | // viewed as a subject for experimentation because it is not guaranteed. 226 | // The subroutine has an advantage over many of its competitors, however, 227 | // which is that it treats each constraint individually when calculating 228 | // a change to the variables, instead of lumping the constraints together 229 | // into a single penalty function. The name of the subroutine is derived 230 | // from the phrase Constrained Optimization BY Linear Approximations. 231 | 232 | // The user must set the values of N, M, RHOBEG and RHOEND, and must 233 | // provide an initial vector of variables in X. Further, the value of 234 | // IPRINT should be set to 0, 1, 2 or 3, which controls the amount of 235 | // printing during the calculation. Specifically, there is no output if 236 | // IPRINT=0 and there is output only at the end of the calculation if 237 | // IPRINT=1. Otherwise each new value of RHO and SIGMA is printed. 238 | // Further, the vector of variables and some function information are 239 | // given either when RHO is reduced or when each new value of F(X) is 240 | // computed in the cases IPRINT=2 or IPRINT=3 respectively. Here SIGMA 241 | // is a penalty parameter, it being assumed that a change to X is an 242 | // improvement if it reduces the merit function 243 | // F(X)+SIGMA*MAX(0.0, - C1(X), - C2(X),..., - CM(X)), 244 | // where C1,C2,...,CM denote the constraint functions that should become 245 | // nonnegative eventually, at least to the precision of RHOEND. In the 246 | // printed output the displayed term that is multiplied by SIGMA is 247 | // called MAXCV, which stands for 'MAXimum Constraint Violation'. The 248 | // argument ITERS is an integer variable that must be set by the user to a 249 | // limit on the number of calls of CALCFC, the purpose of this routine being 250 | // given below. The value of ITERS will be altered to the number of calls 251 | // of CALCFC that are made. 252 | 253 | // In order to define the objective and constraint functions, we require 254 | // a subroutine that has the name and arguments 255 | // SUBROUTINE CALCFC (N,M,X,F,CON) 256 | // DIMENSION X(:),CON(:) . 257 | // The values of N and M are fixed and have been defined already, while 258 | // X is now the current vector of variables. The subroutine should return 259 | // the objective and constraint functions at X in F and CON(1),CON(2), 260 | // ...,CON(M). Note that we are trying to adjust X so that F(X) is as 261 | // small as possible subject to the constraint functions being nonnegative. 262 | 263 | // Local variables 264 | var mpp = m + 2; 265 | 266 | // Internal base-1 X array 267 | var xinout = new double[n + 1]; 268 | Array.Copy(x, 0, xinout, 1, n); 269 | 270 | // Internal representation of the objective and constraints calculation method, 271 | // accounting for that X and CON arrays in the cobylb method are base-1 arrays. 272 | var fcalcfc = new CalcfcDelegate( 273 | (int nn, int mm, double[] xx, out double f, double[] con) => 274 | { 275 | var ixx = new double[nn]; 276 | Array.Copy(xx, 1, ixx, 0, nn); 277 | var ocon = new double[mm]; 278 | calcfc(nn, mm, ixx, out f, ocon); 279 | Array.Copy(ocon, 0, con, 1, mm); 280 | }); 281 | 282 | var status = COBYLB(fcalcfc, n, m, mpp, xinout, rhobeg, rhoend, iprint, ref iters, logger); 283 | 284 | Array.Copy(xinout, 1, x, 0, n); 285 | 286 | return status; 287 | } 288 | 289 | private static OptimizationStatus COBYLB( 290 | CalcfcDelegate calcfc, 291 | int n, 292 | int m, 293 | int mpp, 294 | double[] x, 295 | double rhobeg, 296 | double rhoend, 297 | int iprint, 298 | ref int maxfun, 299 | TextWriter logger) 300 | { 301 | // N.B. Arguments CON, SIM, SIMI, DATMAT, A, VSIG, VETA, SIGBAR, DX, W & IACT 302 | // have been removed. 303 | 304 | // Set the initial values of some parameters. The last column of SIM holds 305 | // the optimal vertex of the current simplex, and the preceding N columns 306 | // hold the displacements from the optimal vertex to the other vertices. 307 | // Further, SIMI holds the inverse of the matrix that is contained in the 308 | // first N columns of SIM. 309 | 310 | // Local variables 311 | 312 | const double alpha = 0.25; 313 | const double beta = 2.1; 314 | const double gamma = 0.5; 315 | const double delta = 1.1; 316 | 317 | double f, resmax, total; 318 | 319 | var np = n + 1; 320 | var mp = m + 1; 321 | var rho = rhobeg; 322 | var parmu = 0.0; 323 | 324 | var iflag = false; 325 | var ifull = false; 326 | var parsig = 0.0; 327 | var prerec = 0.0; 328 | var prerem = 0.0; 329 | 330 | var con = new double[1 + mpp]; 331 | var sim = new double[1 + n, 1 + np]; 332 | var simi = new double[1 + n, 1 + n]; 333 | var datmat = new double[1 + mpp, 1 + np]; 334 | var a = new double[1 + n, 1 + mp]; 335 | var vsig = new double[1 + n]; 336 | var veta = new double[1 + n]; 337 | var sigbar = new double[1 + n]; 338 | var dx = new double[1 + n]; 339 | var w = new double[1 + n]; 340 | 341 | if (iprint >= 2 && logger != null) logger.WriteLine(LF + "The initial value of RHO is {0,13:F6} and PARMU is set to zero.", rho); 342 | 343 | var nfvals = 0; 344 | var temp = 1.0 / rho; 345 | 346 | for (var i = 1; i <= n; ++i) 347 | { 348 | sim[i, np] = x[i]; 349 | sim[i, i] = rho; 350 | simi[i, i] = temp; 351 | } 352 | 353 | var jdrop = np; 354 | var ibrnch = false; 355 | 356 | OptimizationStatus status; 357 | 358 | // Make the next call of the user-supplied subroutine CALCFC. These 359 | // instructions are also used for calling CALCFC during the iterations of 360 | // the algorithm. 361 | 362 | L_40: 363 | if (nfvals >= maxfun && nfvals > 0) 364 | { 365 | if (iprint >= 1 && logger != null) logger.WriteLine(LF + "Return from subroutine COBYLA because the MAXFUN limit has been reached."); 366 | status = OptimizationStatus.MAXFUN_Reached; 367 | goto L_600; 368 | } 369 | 370 | ++nfvals; 371 | 372 | calcfc(n, m, x, out f, con); 373 | resmax = 0.0; 374 | for (var k = 1; k <= m; ++k) resmax = Math.Max(resmax, -con[k]); 375 | 376 | if ((nfvals == iprint - 1 || iprint == 3) && logger != null) 377 | { 378 | logger.WriteLine(IterationResultFormatter, nfvals, f, resmax); 379 | logger.WriteLine("X = {0}", x.PART(1, n).FORMAT()); 380 | } 381 | 382 | con[mp] = f; 383 | con[mpp] = resmax; 384 | if (ibrnch) goto L_440; 385 | 386 | // Set the recently calculated function values in a column of DATMAT. This 387 | // array has a column for each vertex of the current simplex, the entries of 388 | // each column being the values of the constraint functions (if any) 389 | // followed by the objective function and the greatest constraint violation 390 | // at the vertex. 391 | 392 | for (var i = 1; i <= mpp; ++i) datmat[i, jdrop] = con[i]; 393 | 394 | if (nfvals <= np) 395 | { 396 | 397 | // Exchange the new vertex of the initial simplex with the optimal vertex if 398 | // necessary. Then, if the initial simplex is not complete, pick its next 399 | // vertex and calculate the function values there. 400 | 401 | if (jdrop <= n) 402 | { 403 | if (datmat[mp, np] <= f) 404 | { 405 | x[jdrop] = sim[jdrop, np]; 406 | } 407 | else 408 | { 409 | sim[jdrop, np] = x[jdrop]; 410 | for (var k = 1; k <= mpp; ++k) 411 | { 412 | datmat[k, jdrop] = datmat[k, np]; 413 | datmat[k, np] = con[k]; 414 | } 415 | for (var k = 1; k <= jdrop; ++k) 416 | { 417 | sim[jdrop, k] = -rho; 418 | temp = 0.0; 419 | for (var i = k; i <= jdrop; ++i) temp -= simi[i, k]; 420 | simi[jdrop, k] = temp; 421 | } 422 | } 423 | } 424 | if (nfvals <= n) 425 | { 426 | jdrop = nfvals; 427 | x[jdrop] += rho; 428 | goto L_40; 429 | } 430 | } 431 | 432 | ibrnch = true; 433 | 434 | // Identify the optimal vertex of the current simplex. 435 | 436 | L_140: 437 | var phimin = datmat[mp, np] + parmu * datmat[mpp, np]; 438 | var nbest = np; 439 | 440 | for (var j = 1; j <= n; ++j) 441 | { 442 | temp = datmat[mp, j] + parmu * datmat[mpp, j]; 443 | if (temp < phimin) 444 | { 445 | nbest = j; 446 | phimin = temp; 447 | } 448 | else if (temp == phimin && parmu == 0.0 && datmat[mpp, j] < datmat[mpp, nbest]) 449 | { 450 | nbest = j; 451 | } 452 | } 453 | 454 | // Switch the best vertex into pole position if it is not there already, 455 | // and also update SIM, SIMI and DATMAT. 456 | 457 | if (nbest <= n) 458 | { 459 | for (var i = 1; i <= mpp; ++i) 460 | { 461 | temp = datmat[i, np]; 462 | datmat[i, np] = datmat[i, nbest]; 463 | datmat[i, nbest] = temp; 464 | } 465 | for (var i = 1; i <= n; ++i) 466 | { 467 | temp = sim[i, nbest]; 468 | sim[i, nbest] = 0.0; 469 | sim[i, np] += temp; 470 | 471 | var tempa = 0.0; 472 | for (var k = 1; k <= n; ++k) 473 | { 474 | sim[i, k] -= temp; 475 | tempa -= simi[k, i]; 476 | } 477 | simi[nbest, i] = tempa; 478 | } 479 | } 480 | 481 | // Make an error return if SIGI is a poor approximation to the inverse of 482 | // the leading N by N submatrix of SIG. 483 | 484 | var error = 0.0; 485 | for (var i = 1; i <= n; ++i) 486 | { 487 | for (var j = 1; j <= n; ++j) 488 | { 489 | temp = DOT_PRODUCT(simi.ROW(i).PART(1, n), sim.COL(j).PART(1, n)) - (i == j ? 1.0 : 0.0); 490 | error = Math.Max(error, Math.Abs(temp)); 491 | } 492 | } 493 | if (error > 0.1) 494 | { 495 | if (iprint >= 1 && logger != null) 496 | logger.WriteLine( 497 | LF + "Return from subroutine COBYLA because rounding errors are becoming damaging."); 498 | status = OptimizationStatus.X_RoundingErrorsPreventUpdate; 499 | goto L_600; 500 | } 501 | 502 | // Calculate the coefficients of the linear approximations to the objective 503 | // and constraint functions, placing minus the objective function gradient 504 | // after the constraint gradients in the array A. The vector W is used for 505 | // working space. 506 | 507 | for (var k = 1; k <= mp; ++k) 508 | { 509 | con[k] = -datmat[k, np]; 510 | for (var j = 1; j <= n; ++j) w[j] = datmat[k, j] + con[k]; 511 | 512 | for (var i = 1; i <= n; ++i) 513 | { 514 | a[i, k] = (k == mp ? -1.0 : 1.0) * DOT_PRODUCT(w.PART(1, n), simi.COL(i).PART(1, n)); 515 | } 516 | } 517 | 518 | // Calculate the values of sigma and eta, and set IFLAG = 0 if the current 519 | // simplex is not acceptable. 520 | 521 | iflag = true; 522 | parsig = alpha * rho; 523 | var pareta = beta * rho; 524 | 525 | for (var j = 1; j <= n; ++j) 526 | { 527 | var wsig = 0.0; 528 | for (var k = 1; k <= n; ++k) wsig += simi[j, k] * simi[j, k]; 529 | var weta = 0.0; 530 | for (var k = 1; k <= n; ++k) weta += sim[k, j] * sim[k, j]; 531 | vsig[j] = 1.0 / Math.Sqrt(wsig); 532 | veta[j] = Math.Sqrt(weta); 533 | if (vsig[j] < parsig || veta[j] > pareta) iflag = false; 534 | } 535 | 536 | // If a new vertex is needed to improve acceptability, then decide which 537 | // vertex to drop from the simplex. 538 | 539 | if (!ibrnch && !iflag) 540 | { 541 | jdrop = 0; 542 | temp = pareta; 543 | for (var j = 1; j <= n; ++j) 544 | { 545 | if (veta[j] > temp) 546 | { 547 | jdrop = j; 548 | temp = veta[j]; 549 | } 550 | } 551 | if (jdrop == 0) 552 | { 553 | for (var j = 1; j <= n; ++j) 554 | { 555 | if (vsig[j] < temp) 556 | { 557 | jdrop = j; 558 | temp = vsig[j]; 559 | } 560 | } 561 | } 562 | 563 | // Calculate the step to the new vertex and its sign. 564 | 565 | temp = gamma * rho * vsig[jdrop]; 566 | for (var k = 1; k <= n; ++k) dx[k] = temp * simi[jdrop, k]; 567 | var cvmaxp = 0.0; 568 | var cvmaxm = 0.0; 569 | 570 | total = 0.0; 571 | for (var k = 1; k <= mp; ++k) 572 | { 573 | total = DOT_PRODUCT(a.COL(k).PART(1, n), dx.PART(1, n)); 574 | if (k < mp) 575 | { 576 | temp = datmat[k, np]; 577 | cvmaxp = Math.Max(cvmaxp, -total - temp); 578 | cvmaxm = Math.Max(cvmaxm, total - temp); 579 | } 580 | } 581 | var dxsign = parmu * (cvmaxp - cvmaxm) > 2.0 * total ? -1.0 : 1.0; 582 | 583 | // Update the elements of SIM and SIMI, and set the next X. 584 | 585 | temp = 0.0; 586 | for (var i = 1; i <= n; ++i) 587 | { 588 | dx[i] = dxsign * dx[i]; 589 | sim[i, jdrop] = dx[i]; 590 | temp += simi[jdrop, i] * dx[i]; 591 | } 592 | for (var k = 1; k <= n; ++k) simi[jdrop, k] /= temp; 593 | 594 | for (var j = 1; j <= n; ++j) 595 | { 596 | if (j != jdrop) 597 | { 598 | temp = DOT_PRODUCT(simi.ROW(j).PART(1, n), dx.PART(1, n)); 599 | for (var k = 1; k <= n; ++k) simi[j, k] -= temp * simi[jdrop, k]; 600 | } 601 | x[j] = sim[j, np] + dx[j]; 602 | } 603 | goto L_40; 604 | } 605 | 606 | // Calculate DX = x(*)-x(0). 607 | // Branch if the length of DX is less than 0.5*RHO. 608 | 609 | TRSTLP(n, m, a, con, rho, dx, out ifull); 610 | if (!ifull) 611 | { 612 | temp = 0.0; 613 | for (var k = 1; k <= n; ++k) temp += dx[k] * dx[k]; 614 | if (temp < 0.25 * rho * rho) 615 | { 616 | ibrnch = true; 617 | goto L_550; 618 | } 619 | } 620 | 621 | // Predict the change to F and the new maximum constraint violation if the 622 | // variables are altered from x(0) to x(0) + DX. 623 | 624 | total = 0.0; 625 | var resnew = 0.0; 626 | con[mp] = 0.0; 627 | for (var k = 1; k <= mp; ++k) 628 | { 629 | total = con[k] - DOT_PRODUCT(a.COL(k).PART(1, n), dx.PART(1, n)); 630 | if (k < mp) resnew = Math.Max(resnew, total); 631 | } 632 | 633 | // Increase PARMU if necessary and branch back if this change alters the 634 | // optimal vertex. Otherwise PREREM and PREREC will be set to the predicted 635 | // reductions in the merit function and the maximum constraint violation 636 | // respectively. 637 | 638 | prerec = datmat[mpp, np] - resnew; 639 | var barmu = prerec > 0.0 ? total / prerec : 0.0; 640 | if (parmu < 1.5 * barmu) 641 | { 642 | parmu = 2.0 * barmu; 643 | if (iprint >= 2 && logger != null) logger.WriteLine(LF + "Increase in PARMU to {0,13:F6}", parmu); 644 | var phi = datmat[mp, np] + parmu * datmat[mpp, np]; 645 | for (var j = 1; j <= n; ++j) 646 | { 647 | temp = datmat[mp, j] + parmu * datmat[mpp, j]; 648 | if (temp < phi || (temp == phi && parmu == 0.0 && datmat[mpp, j] < datmat[mpp, np])) goto L_140; 649 | } 650 | } 651 | prerem = parmu * prerec - total; 652 | 653 | // Calculate the constraint and objective functions at x(*). 654 | // Then find the actual reduction in the merit function. 655 | 656 | for (var k = 1; k <= n; ++k) x[k] = sim[k, np] + dx[k]; 657 | ibrnch = true; 658 | goto L_40; 659 | 660 | L_440: 661 | var vmold = datmat[mp, np] + parmu * datmat[mpp, np]; 662 | var vmnew = f + parmu * resmax; 663 | var trured = vmold - vmnew; 664 | if (parmu == 0.0 && f == datmat[mp, np]) 665 | { 666 | prerem = prerec; 667 | trured = datmat[mpp, np] - resmax; 668 | } 669 | 670 | // Begin the operations that decide whether x(*) should replace one of the 671 | // vertices of the current simplex, the change being mandatory if TRURED is 672 | // positive. Firstly, JDROP is set to the index of the vertex that is to be 673 | // replaced. 674 | 675 | var ratio = trured <= 0.0 ? 1.0 : 0.0; 676 | jdrop = 0; 677 | for (var j = 1; j <= n; ++j) 678 | { 679 | temp = Math.Abs(DOT_PRODUCT(simi.ROW(j).PART(1, n), dx.PART(1, n))); 680 | if (temp > ratio) 681 | { 682 | jdrop = j; 683 | ratio = temp; 684 | } 685 | sigbar[j] = temp * vsig[j]; 686 | } 687 | 688 | // Calculate the value of ell. 689 | 690 | var edgmax = delta * rho; 691 | var l = 0; 692 | for (var j = 1; j <= n; ++j) 693 | { 694 | if (sigbar[j] >= parsig || sigbar[j] >= vsig[j]) 695 | { 696 | temp = veta[j]; 697 | if (trured > 0.0) 698 | { 699 | temp = 0.0; 700 | for (var k = 1; k <= n; ++k) temp += Math.Pow(dx[k] - sim[k, j], 2.0); 701 | temp = Math.Sqrt(temp); 702 | } 703 | if (temp > edgmax) 704 | { 705 | l = j; 706 | edgmax = temp; 707 | } 708 | } 709 | } 710 | if (l > 0) jdrop = l; 711 | if (jdrop == 0) goto L_550; 712 | 713 | // Revise the simplex by updating the elements of SIM, SIMI and DATMAT. 714 | 715 | temp = 0.0; 716 | for (var i = 1; i <= n; ++i) 717 | { 718 | sim[i, jdrop] = dx[i]; 719 | temp += simi[jdrop, i] * dx[i]; 720 | } 721 | for (var k = 1; k <= n; ++k) simi[jdrop, k] /= temp; 722 | for (var j = 1; j <= n; ++j) 723 | { 724 | if (j != jdrop) 725 | { 726 | temp = DOT_PRODUCT(simi.ROW(j).PART(1, n), dx.PART(1, n)); 727 | for (var k = 1; k <= n; ++k) simi[j, k] -= temp * simi[jdrop, k]; 728 | } 729 | } 730 | for (var k = 1; k <= mpp; ++k) datmat[k, jdrop] = con[k]; 731 | 732 | // Branch back for further iterations with the current RHO. 733 | 734 | if (trured > 0.0 && trured >= 0.1 * prerem) goto L_140; 735 | 736 | L_550: 737 | if (!iflag) 738 | { 739 | ibrnch = false; 740 | goto L_140; 741 | } 742 | 743 | // Otherwise reduce RHO if it is not at its least value and reset PARMU. 744 | 745 | if (rho > rhoend) 746 | { 747 | double cmin = 0.0, cmax = 0.0; 748 | 749 | rho *= 0.5; 750 | if (rho <= 1.5 * rhoend) rho = rhoend; 751 | if (parmu > 0.0) 752 | { 753 | var denom = 0.0; 754 | for (var k = 1; k <= mp; ++k) 755 | { 756 | cmin = datmat[k, np]; 757 | cmax = cmin; 758 | for (var i = 1; i <= n; ++i) 759 | { 760 | cmin = Math.Min(cmin, datmat[k, i]); 761 | cmax = Math.Max(cmax, datmat[k, i]); 762 | } 763 | if (k <= m && cmin < 0.5 * cmax) 764 | { 765 | temp = Math.Max(cmax, 0.0) - cmin; 766 | denom = denom <= 0.0 ? temp : Math.Min(denom, temp); 767 | } 768 | } 769 | if (denom == 0.0) 770 | { 771 | parmu = 0.0; 772 | } 773 | else if (cmax - cmin < parmu * denom) 774 | { 775 | parmu = (cmax - cmin) / denom; 776 | } 777 | } 778 | if (logger != null) 779 | { 780 | if (iprint >= 2) logger.WriteLine(LF + "Reduction in RHO to {0,13:E6} and PARMU = {1,13:E6}", rho, parmu); 781 | if (iprint == 2) 782 | { 783 | logger.WriteLine(IterationResultFormatter, nfvals, datmat[mp, np], datmat[mpp, np]); 784 | logger.WriteLine("X = {0}", sim.COL(np).PART(1, n).FORMAT()); 785 | } 786 | } 787 | goto L_140; 788 | } 789 | 790 | // Return the best calculated values of the variables. 791 | 792 | status = OptimizationStatus.Normal; 793 | if (iprint >= 1 && logger != null) logger.WriteLine(LF + "Normal return from subroutine COBYLA"); 794 | if (ifull) goto L_620; 795 | 796 | L_600: 797 | for (var k = 1; k <= n; ++k) x[k] = sim[k, np]; 798 | f = datmat[mp, np]; 799 | resmax = datmat[mpp, np]; 800 | 801 | L_620: 802 | if (iprint >= 1 && logger != null) 803 | { 804 | logger.WriteLine(IterationResultFormatter, nfvals, f, resmax); 805 | logger.WriteLine("X = {0}", x.PART(1, n).FORMAT()); 806 | } 807 | 808 | maxfun = nfvals; 809 | 810 | return status; 811 | } 812 | 813 | private static void TRSTLP(int n, int m, double[,] a, double[] b, double rho, double[] dx, out bool ifull) 814 | { 815 | // N.B. Arguments Z, ZDOTA, VMULTC, SDIRN, DXNEW, VMULTD & IACT have been removed. 816 | 817 | // This subroutine calculates an N-component vector DX by applying the 818 | // following two stages. In the first stage, DX is set to the shortest 819 | // vector that minimizes the greatest violation of the constraints 820 | // A(1,K)*DX(1)+A(2,K)*DX(2)+...+A(N,K)*DX(N) .GE. B(K), K = 2,3,...,M, 821 | // subject to the Euclidean length of DX being at most RHO. If its length is 822 | // strictly less than RHO, then we use the resultant freedom in DX to 823 | // minimize the objective function 824 | // -A(1,M+1)*DX(1) - A(2,M+1)*DX(2) - ... - A(N,M+1)*DX(N) 825 | // subject to no increase in any greatest constraint violation. This 826 | // notation allows the gradient of the objective function to be regarded as 827 | // the gradient of a constraint. Therefore the two stages are distinguished 828 | // by MCON .EQ. M and MCON .GT. M respectively. It is possible that a 829 | // degeneracy may prevent DX from attaining the target length RHO. Then the 830 | // value IFULL = 0 would be set, but usually IFULL = 1 on return. 831 | 832 | // In general NACT is the number of constraints in the active set and 833 | // IACT(1),...,IACT(NACT) are their indices, while the remainder of IACT 834 | // contains a permutation of the remaining constraint indices. Further, Z 835 | // is an orthogonal matrix whose first NACT columns can be regarded as the 836 | // result of Gram-Schmidt applied to the active constraint gradients. For 837 | // J = 1,2,...,NACT, the number ZDOTA(J) is the scalar product of the J-th 838 | // column of Z with the gradient of the J-th active constraint. DX is the 839 | // current vector of variables and here the residuals of the active 840 | // constraints should be zero. Further, the active constraints have 841 | // nonnegative Lagrange multipliers that are held at the beginning of 842 | // VMULTC. The remainder of this vector holds the residuals of the inactive 843 | // constraints at DX, the ordering of the components of VMULTC being in 844 | // agreement with the permutation of the indices of the constraints that is 845 | // in IACT. All these residuals are nonnegative, which is achieved by the 846 | // shift RESMAX that makes the least residual zero. 847 | 848 | // Initialize Z and some other variables. The value of RESMAX will be 849 | // appropriate to DX = 0, while ICON will be the index of a most violated 850 | // constraint if RESMAX is positive. Usually during the first stage the 851 | // vector SDIRN gives a search direction that reduces all the active 852 | // constraint violations by one simultaneously. 853 | 854 | // Local variables 855 | 856 | ifull = true; 857 | 858 | double temp; 859 | 860 | var nactx = 0; 861 | var resold = 0.0; 862 | 863 | var z = new double[1 + n, 1 + n]; 864 | var zdota = new double[2 + m]; 865 | var vmultc = new double[2 + m]; 866 | var sdirn = new double[1 + n]; 867 | var dxnew = new double[1 + n]; 868 | var vmultd = new double[2 + m]; 869 | var iact = new int[2 + m]; 870 | 871 | var mcon = m; 872 | var nact = 0; 873 | for (var i = 1; i <= n; ++i) 874 | { 875 | z[i, i] = 1.0; 876 | dx[i] = 0.0; 877 | } 878 | 879 | var icon = 0; 880 | var resmax = 0.0; 881 | if (m >= 1) 882 | { 883 | for (var k = 1; k <= m; ++k) 884 | { 885 | if (b[k] > resmax) 886 | { 887 | resmax = b[k]; 888 | icon = k; 889 | } 890 | } 891 | for (var k = 1; k <= m; ++k) 892 | { 893 | iact[k] = k; 894 | vmultc[k] = resmax - b[k]; 895 | } 896 | } 897 | if (resmax == 0.0) goto L_480; 898 | 899 | // End the current stage of the calculation if 3 consecutive iterations 900 | // have either failed to reduce the best calculated value of the objective 901 | // function or to increase the number of active constraints since the best 902 | // value was calculated. This strategy prevents cycling, but there is a 903 | // remote possibility that it will cause premature termination. 904 | 905 | L_60: 906 | var optold = 0.0; 907 | var icount = 0; 908 | 909 | L_70: 910 | var optnew = mcon == m ? resmax : -DOT_PRODUCT(dx.PART(1, n), a.COL(mcon).PART(1, n)); 911 | 912 | if (icount == 0 || optnew < optold) 913 | { 914 | optold = optnew; 915 | nactx = nact; 916 | icount = 3; 917 | } 918 | else if (nact > nactx) 919 | { 920 | nactx = nact; 921 | icount = 3; 922 | } 923 | else 924 | { 925 | --icount; 926 | } 927 | if (icount == 0) goto L_490; 928 | 929 | // If ICON exceeds NACT, then we add the constraint with index IACT(ICON) to 930 | // the active set. Apply Givens rotations so that the last N-NACT-1 columns 931 | // of Z are orthogonal to the gradient of the new constraint, a scalar 932 | // product being set to zero if its nonzero value could be due to computer 933 | // rounding errors. The array DXNEW is used for working space. 934 | 935 | if (icon <= nact) goto L_260; 936 | var kk = iact[icon]; 937 | for (var k = 1; k <= n; ++k) dxnew[k] = a[k, kk]; 938 | var tot = 0.0; 939 | 940 | { 941 | var k = n; 942 | while (k > nact) 943 | { 944 | var sp = 0.0; 945 | var spabs = 0.0; 946 | for (var i = 1; i <= n; ++i) 947 | { 948 | temp = z[i, k] * dxnew[i]; 949 | sp += temp; 950 | spabs += Math.Abs(temp); 951 | } 952 | var acca = spabs + 0.1 * Math.Abs(sp); 953 | var accb = spabs + 0.2 * Math.Abs(sp); 954 | if (spabs >= acca || acca >= accb) sp = 0.0; 955 | if (tot == 0.0) 956 | { 957 | tot = sp; 958 | } 959 | else 960 | { 961 | var kp = k + 1; 962 | temp = Math.Sqrt(sp * sp + tot * tot); 963 | var alpha = sp / temp; 964 | var beta = tot / temp; 965 | tot = temp; 966 | for (var i = 1; i <= n; ++i) 967 | { 968 | temp = alpha * z[i, k] + beta * z[i, kp]; 969 | z[i, kp] = alpha * z[i, kp] - beta * z[i, k]; 970 | z[i, k] = temp; 971 | } 972 | } 973 | --k; 974 | } 975 | } 976 | 977 | // Add the new constraint if this can be done without a deletion from the 978 | // active set. 979 | 980 | if (tot != 0.0) 981 | { 982 | ++nact; 983 | zdota[nact] = tot; 984 | vmultc[icon] = vmultc[nact]; 985 | vmultc[nact] = 0.0; 986 | goto L_210; 987 | } 988 | 989 | // The next instruction is reached if a deletion has to be made from the 990 | // active set in order to make room for the new active constraint, because 991 | // the new constraint gradient is a linear combination of the gradients of 992 | // the old active constraints. Set the elements of VMULTD to the multipliers 993 | // of the linear combination. Further, set IOUT to the index of the 994 | // constraint to be deleted, but branch if no suitable index can be found. 995 | 996 | var ratio = -1.0; 997 | { 998 | var k = nact; 999 | do 1000 | { 1001 | var zdotv = 0.0; 1002 | var zdvabs = 0.0; 1003 | 1004 | for (var i = 1; i <= n; ++i) 1005 | { 1006 | temp = z[i, k] * dxnew[i]; 1007 | zdotv = zdotv + temp; 1008 | zdvabs = zdvabs + Math.Abs(temp); 1009 | } 1010 | var acca = zdvabs + 0.1 * Math.Abs(zdotv); 1011 | var accb = zdvabs + 0.2 * Math.Abs(zdotv); 1012 | if (zdvabs < acca && acca < accb) 1013 | { 1014 | temp = zdotv / zdota[k]; 1015 | if (temp > 0.0 && iact[k] <= m) 1016 | { 1017 | var tempa = vmultc[k] / temp; 1018 | if (ratio < 0.0 || tempa < ratio) ratio = tempa; 1019 | } 1020 | 1021 | if (k >= 2) 1022 | { 1023 | var kw = iact[k]; 1024 | for (var i = 1; i <= n; ++i) dxnew[i] -= temp * a[i, kw]; 1025 | } 1026 | vmultd[k] = temp; 1027 | } 1028 | else 1029 | { 1030 | vmultd[k] = 0.0; 1031 | } 1032 | } 1033 | while (--k > 0); 1034 | } 1035 | if (ratio < 0.0) goto L_490; 1036 | 1037 | // Revise the Lagrange multipliers and reorder the active constraints so 1038 | // that the one to be replaced is at the end of the list. Also calculate the 1039 | // new value of ZDOTA(NACT) and branch if it is not acceptable. 1040 | 1041 | for (var k = 1; k <= nact; ++k) vmultc[k] = Math.Max(0.0, vmultc[k] - ratio * vmultd[k]); 1042 | if (icon < nact) 1043 | { 1044 | var isave = iact[icon]; 1045 | var vsave = vmultc[icon]; 1046 | var k = icon; 1047 | do 1048 | { 1049 | var kp = k + 1; 1050 | var kw = iact[kp]; 1051 | var sp = DOT_PRODUCT(z.COL(k).PART(1, n), a.COL(kw).PART(1, n)); 1052 | temp = Math.Sqrt(sp * sp + zdota[kp] * zdota[kp]); 1053 | var alpha = zdota[kp] / temp; 1054 | var beta = sp / temp; 1055 | zdota[kp] = alpha * zdota[k]; 1056 | zdota[k] = temp; 1057 | for (var i = 1; i <= n; ++i) 1058 | { 1059 | temp = alpha * z[i, kp] + beta * z[i, k]; 1060 | z[i, kp] = alpha * z[i, k] - beta * z[i, kp]; 1061 | z[i, k] = temp; 1062 | } 1063 | iact[k] = kw; 1064 | vmultc[k] = vmultc[kp]; 1065 | k = kp; 1066 | } 1067 | while (k < nact); 1068 | iact[k] = isave; 1069 | vmultc[k] = vsave; 1070 | } 1071 | temp = DOT_PRODUCT(z.COL(nact).PART(1, n), a.COL(kk).PART(1, n)); 1072 | if (temp == 0.0) goto L_490; 1073 | zdota[nact] = temp; 1074 | vmultc[icon] = 0.0; 1075 | vmultc[nact] = ratio; 1076 | 1077 | // Update IACT and ensure that the objective function continues to be 1078 | // treated as the last active constraint when MCON>M. 1079 | 1080 | L_210: 1081 | iact[icon] = iact[nact]; 1082 | iact[nact] = kk; 1083 | if (mcon > m && kk != mcon) 1084 | { 1085 | var k = nact - 1; 1086 | var sp = DOT_PRODUCT(z.COL(k).PART(1, n), a.COL(kk).PART(1, n)); 1087 | temp = Math.Sqrt(sp * sp + zdota[nact] * zdota[nact]); 1088 | var alpha = zdota[nact] / temp; 1089 | var beta = sp / temp; 1090 | zdota[nact] = alpha * zdota[k]; 1091 | zdota[k] = temp; 1092 | for (var i = 1; i <= n; ++i) 1093 | { 1094 | temp = alpha * z[i, nact] + beta * z[i, k]; 1095 | z[i, nact] = alpha * z[i, k] - beta * z[i, nact]; 1096 | z[i, k] = temp; 1097 | } 1098 | iact[nact] = iact[k]; 1099 | iact[k] = kk; 1100 | temp = vmultc[k]; 1101 | vmultc[k] = vmultc[nact]; 1102 | vmultc[nact] = temp; 1103 | } 1104 | 1105 | // If stage one is in progress, then set SDIRN to the direction of the next 1106 | // change to the current vector of variables. 1107 | 1108 | if (mcon > m) goto L_320; 1109 | kk = iact[nact]; 1110 | temp = (DOT_PRODUCT(sdirn.PART(1, n), a.COL(kk).PART(1, n)) - 1.0) / zdota[nact]; 1111 | for (var k = 1; k <= n; ++k) sdirn[k] -= temp * z[k, nact]; 1112 | goto L_340; 1113 | 1114 | // Delete the constraint that has the index IACT(ICON) from the active set. 1115 | 1116 | L_260: 1117 | if (icon < nact) 1118 | { 1119 | var isave = iact[icon]; 1120 | var vsave = vmultc[icon]; 1121 | var k = icon; 1122 | do 1123 | { 1124 | var kp = k + 1; 1125 | kk = iact[kp]; 1126 | var sp = DOT_PRODUCT(z.COL(k).PART(1, n), a.COL(kk).PART(1, n)); 1127 | temp = Math.Sqrt(sp * sp + zdota[kp] * zdota[kp]); 1128 | var alpha = zdota[kp] / temp; 1129 | var beta = sp / temp; 1130 | zdota[kp] = alpha * zdota[k]; 1131 | zdota[k] = temp; 1132 | for (var i = 1; i <= n; ++i) 1133 | { 1134 | temp = alpha * z[i, kp] + beta * z[i, k]; 1135 | z[i, kp] = alpha * z[i, k] - beta * z[i, kp]; 1136 | z[i, k] = temp; 1137 | } 1138 | iact[k] = kk; 1139 | vmultc[k] = vmultc[kp]; 1140 | k = kp; 1141 | } 1142 | while (k < nact); 1143 | 1144 | iact[k] = isave; 1145 | vmultc[k] = vsave; 1146 | } 1147 | --nact; 1148 | 1149 | // If stage one is in progress, then set SDIRN to the direction of the next 1150 | // change to the current vector of variables. 1151 | 1152 | if (mcon > m) goto L_320; 1153 | temp = DOT_PRODUCT(sdirn.PART(1, n), z.COL(nact + 1).PART(1, n)); 1154 | for (var k = 1; k <= n; ++k) sdirn[k] -= temp * z[k, nact + 1]; 1155 | goto L_340; 1156 | 1157 | // Pick the next search direction of stage two. 1158 | 1159 | L_320: 1160 | temp = 1.0 / zdota[nact]; 1161 | for (var k = 1; k <= n; ++k) sdirn[k] = temp * z[k, nact]; 1162 | 1163 | // Calculate the step to the boundary of the trust region or take the step 1164 | // that reduces RESMAX to zero. The two statements below that include the 1165 | // factor 1.0E-6 prevent some harmless underflows that occurred in a test 1166 | // calculation. Further, we skip the step if it could be zero within a 1167 | // reasonable tolerance for computer rounding errors. 1168 | 1169 | L_340: 1170 | var dd = rho * rho; 1171 | var sd = 0.0; 1172 | var ss = 0.0; 1173 | for (var i = 1; i <= n; ++i) 1174 | { 1175 | if (Math.Abs(dx[i]) >= 1.0E-6 * rho) dd -= dx[i] * dx[i]; 1176 | sd += dx[i] * sdirn[i]; 1177 | ss += sdirn[i] * sdirn[i]; 1178 | } 1179 | if (dd <= 0.0) goto L_490; 1180 | temp = Math.Sqrt(ss * dd); 1181 | if (Math.Abs(sd) >= 1.0E-6 * temp) temp = Math.Sqrt(ss * dd + sd * sd); 1182 | var stpful = dd / (temp + sd); 1183 | var step = stpful; 1184 | if (mcon == m) 1185 | { 1186 | var acca = step + 0.1 * resmax; 1187 | var accb = step + 0.2 * resmax; 1188 | if (step >= acca || acca >= accb) goto L_480; 1189 | step = Math.Min(step, resmax); 1190 | } 1191 | 1192 | // Set DXNEW to the new variables if STEP is the steplength, and reduce 1193 | // RESMAX to the corresponding maximum residual if stage one is being done. 1194 | // Because DXNEW will be changed during the calculation of some Lagrange 1195 | // multipliers, it will be restored to the following value later. 1196 | 1197 | for (var k = 1; k <= n; ++k) dxnew[k] = dx[k] + step * sdirn[k]; 1198 | if (mcon == m) 1199 | { 1200 | resold = resmax; 1201 | resmax = 0.0; 1202 | for (var k = 1; k <= nact; ++k) 1203 | { 1204 | kk = iact[k]; 1205 | temp = b[kk] - DOT_PRODUCT(a.COL(kk).PART(1, n), dxnew.PART(1, n)); 1206 | resmax = Math.Max(resmax, temp); 1207 | } 1208 | } 1209 | 1210 | // Set VMULTD to the VMULTC vector that would occur if DX became DXNEW. A 1211 | // device is included to force VMULTD(K) = 0.0 if deviations from this value 1212 | // can be attributed to computer rounding errors. First calculate the new 1213 | // Lagrange multipliers. 1214 | 1215 | { 1216 | var k = nact; 1217 | L_390: 1218 | var zdotw = 0.0; 1219 | var zdwabs = 0.0; 1220 | for (var i = 1; i <= n; ++i) 1221 | { 1222 | temp = z[i, k] * dxnew[i]; 1223 | zdotw += temp; 1224 | zdwabs += Math.Abs(temp); 1225 | } 1226 | var acca = zdwabs + 0.1 * Math.Abs(zdotw); 1227 | var accb = zdwabs + 0.2 * Math.Abs(zdotw); 1228 | if (zdwabs >= acca || acca >= accb) zdotw = 0.0; 1229 | vmultd[k] = zdotw / zdota[k]; 1230 | if (k >= 2) 1231 | { 1232 | kk = iact[k]; 1233 | for (var i = 1; i <= n; ++i) dxnew[i] -= vmultd[k] * a[i, kk]; 1234 | --k; 1235 | goto L_390; 1236 | } 1237 | if (mcon > m) vmultd[nact] = Math.Max(0.0, vmultd[nact]); 1238 | } 1239 | 1240 | // Complete VMULTC by finding the new constraint residuals. 1241 | 1242 | for (var k = 1; k <= n; ++k) dxnew[k] = dx[k] + step * sdirn[k]; 1243 | if (mcon > nact) 1244 | { 1245 | var kl = nact + 1; 1246 | for (var k = kl; k <= mcon; ++k) 1247 | { 1248 | kk = iact[k]; 1249 | var total = resmax - b[kk]; 1250 | var sumabs = resmax + Math.Abs(b[kk]); 1251 | for (var i = 1; i <= n; ++i) 1252 | { 1253 | temp = a[i, kk] * dxnew[i]; 1254 | total += temp; 1255 | sumabs += Math.Abs(temp); 1256 | } 1257 | var acca = sumabs + 0.1 * Math.Abs(total); 1258 | var accb = sumabs + 0.2 * Math.Abs(total); 1259 | if (sumabs >= acca || acca >= accb) total = 0.0; 1260 | vmultd[k] = total; 1261 | } 1262 | } 1263 | 1264 | // Calculate the fraction of the step from DX to DXNEW that will be taken. 1265 | 1266 | ratio = 1.0; 1267 | icon = 0; 1268 | for (var k = 1; k <= mcon; ++k) 1269 | { 1270 | if (vmultd[k] < 0.0) 1271 | { 1272 | temp = vmultc[k] / (vmultc[k] - vmultd[k]); 1273 | if (temp < ratio) 1274 | { 1275 | ratio = temp; 1276 | icon = k; 1277 | } 1278 | } 1279 | } 1280 | 1281 | // Update DX, VMULTC and RESMAX. 1282 | 1283 | temp = 1.0 - ratio; 1284 | for (var k = 1; k <= n; ++k) dx[k] = temp * dx[k] + ratio * dxnew[k]; 1285 | for (var k = 1; k <= mcon; ++k) vmultc[k] = Math.Max(0.0, temp * vmultc[k] + ratio * vmultd[k]); 1286 | if (mcon == m) resmax = resold + ratio * (resmax - resold); 1287 | 1288 | // If the full step is not acceptable then begin another iteration. 1289 | // Otherwise switch to stage two or end the calculation. 1290 | 1291 | if (icon > 0) goto L_70; 1292 | if (step == stpful) return; 1293 | 1294 | L_480: 1295 | mcon = m + 1; 1296 | icon = mcon; 1297 | iact[mcon] = mcon; 1298 | vmultc[mcon] = 0.0; 1299 | goto L_60; 1300 | 1301 | // We employ any freedom that may be available to reduce the objective 1302 | // function before returning a DX whose length is less than RHO. 1303 | 1304 | L_490: 1305 | if (mcon == m) goto L_480; 1306 | ifull = false; 1307 | } 1308 | 1309 | private static double DOT_PRODUCT(double[] lhs, double[] rhs) 1310 | { 1311 | var sum = 0.0; 1312 | for (var i = 0; i < lhs.Length; ++i) sum += lhs[i] * rhs[i]; 1313 | return sum; 1314 | } 1315 | 1316 | #endregion 1317 | } 1318 | 1319 | #region EXTENSION METHODS CLASS 1320 | 1321 | internal static class CobylaExtensionMethods 1322 | { 1323 | internal static T[] ROW(this T[,] src, int rowidx) 1324 | { 1325 | var cols = src.GetLength(1); 1326 | var dest = new T[cols]; 1327 | for (var col = 0; col < cols; ++col) dest[col] = src[rowidx, col]; 1328 | return dest; 1329 | } 1330 | 1331 | internal static T[] COL(this T[,] src, int colidx) 1332 | { 1333 | var rows = src.GetLength(0); 1334 | var dest = new T[rows]; 1335 | for (var row = 0; row < rows; ++row) dest[row] = src[row, colidx]; 1336 | return dest; 1337 | } 1338 | 1339 | internal static T[] PART(this IList src, int from, int to) 1340 | { 1341 | var dest = new T[to - from + 1]; 1342 | var destidx = 0; 1343 | for (var srcidx = from; srcidx <= to; ++srcidx, ++destidx) dest[destidx] = src[srcidx]; 1344 | return dest; 1345 | } 1346 | 1347 | internal static string FORMAT(this double[] x) 1348 | { 1349 | var xStr = new string[x.Length]; 1350 | for (var i = 0; i < x.Length; ++i) xStr[i] = String.Format("{0,13:F6}", x[i]); 1351 | return String.Concat(xStr); 1352 | } 1353 | } 1354 | 1355 | // ReSharper restore InconsistentNaming 1356 | 1357 | #endregion 1358 | } 1359 | -------------------------------------------------------------------------------- /csnumerics/Optimizers/IOptimizer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | using System.IO; 23 | 24 | namespace Cureos.Numerics.Optimizers 25 | { 26 | /// 27 | /// General interface for optimizers in the CS Numerics class library. 28 | /// 29 | interface IOptimizer 30 | { 31 | #region PROPERTIES 32 | 33 | /// 34 | /// Gets or sets the number of maximum function calls. 35 | /// 36 | int MaximumFunctionCalls { get; set; } 37 | 38 | /// 39 | /// Gets or sets the print level to the logger. 40 | /// 41 | int PrintLevel { get; set; } 42 | 43 | /// 44 | /// Gets or sets the logger to which the optimizer log information should be sent. 45 | /// 46 | TextWriter Logger { get; set; } 47 | 48 | #endregion 49 | 50 | #region METHODS 51 | 52 | /// 53 | /// Find a local minimum of provided objective function satisfying the provided linear constraints. 54 | /// 55 | /// Initial variable array. 56 | /// Summary of the optimization result. 57 | OptimizationSummary FindMinimum(double[] x0); 58 | 59 | #endregion 60 | } 61 | } -------------------------------------------------------------------------------- /csnumerics/Optimizers/IQuadraticModelOptimizer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | namespace Cureos.Numerics.Optimizers 23 | { 24 | /// 25 | /// Interface for derivative-free optimizers following the basic principles of M.J.D. Powell's 26 | /// quadratic model trust region optimizers. 27 | /// 28 | interface IQuadraticModelOptimizer : ITrustRegionOptimizer 29 | { 30 | /// 31 | /// Gets or sets the number of interpolation conditions. 32 | /// 33 | int InterpolationConditions { get; set; } 34 | } 35 | } -------------------------------------------------------------------------------- /csnumerics/Optimizers/ITrustRegionOptimizer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | namespace Cureos.Numerics.Optimizers 23 | { 24 | /// 25 | /// Interface for derivative-free optimizers following the basic principles of M.J.D. Powell's trust region optimizers. 26 | /// 27 | internal interface ITrustRegionOptimizer : IOptimizer 28 | { 29 | /// 30 | /// Gets or sets the final value of the trust region radius. 31 | /// 32 | double TrustRegionRadiusStart { get; set; } 33 | 34 | /// 35 | /// Gets or sets the start value of the trust region radius. 36 | /// 37 | double TrustRegionRadiusEnd { get; set; } 38 | } 39 | } -------------------------------------------------------------------------------- /csnumerics/Optimizers/OptimizationStatus.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | namespace Cureos.Numerics.Optimizers 23 | { 24 | /// 25 | /// Optimization status codes. 26 | /// 27 | public enum OptimizationStatus 28 | { 29 | // ReSharper disable InconsistentNaming 30 | 31 | /* 32 | * Common 33 | */ 34 | 35 | /// 36 | /// Optimization successfully completed. 37 | /// 38 | Normal, 39 | 40 | /// 41 | /// Too few variables. 42 | /// 43 | N_TooSmall, 44 | 45 | /// 46 | /// Invalid number of interpolation conditions. 47 | /// 48 | NPT_OutOfRange, 49 | 50 | /// 51 | /// Specified maximum number of function evaluations must exceed number of interpolation conditions. 52 | /// 53 | MAXFUN_NotLargerThan_NPT, 54 | 55 | /// 56 | /// Maximum number of iterations (function/constraints evaluations) reached during optimization. 57 | /// 58 | MAXFUN_Reached, 59 | 60 | /// 61 | /// Size of rounding error is becoming damaging, terminating prematurely. 62 | /// 63 | X_RoundingErrorsPreventUpdate, 64 | 65 | /* 66 | * LINCOA specific 67 | */ 68 | 69 | /// 70 | /// Constraint gradient is too small. 71 | /// 72 | ConstraintGradientIsZero, 73 | 74 | /// 75 | /// Denominator in updating formula is too small. 76 | /// 77 | UpdatingFormulaDenominatorZero, 78 | 79 | /* 80 | * BOBYQA specific 81 | */ 82 | 83 | /// 84 | /// Insufficient number of variable bounds. 85 | /// 86 | VariableBoundsArrayTooShort, 87 | 88 | /// 89 | /// Invalid variable bounds specification. 90 | /// 91 | InvalidBoundsSpecification, 92 | 93 | /// 94 | /// Distance between lower and upper bound is insufficient for one or more variables. 95 | /// 96 | BoundsRangeTooSmall, 97 | 98 | /// 99 | /// Denominator cancellation. 100 | /// 101 | DenominatorCancellation, 102 | 103 | /// 104 | /// Reduction of trust-region step failed. 105 | /// 106 | TrustRegionStepReductionFailure 107 | 108 | // ReSharper enable InconsistentNaming 109 | } 110 | } -------------------------------------------------------------------------------- /csnumerics/Optimizers/OptimizationSummary.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2022, Cureos AB. 3 | * All rights reserved. 4 | * http://www.cureos.com 5 | * 6 | * This file is part of CSNumerics. 7 | * 8 | * CSNumerics is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * CSNumerics is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with CSNumerics. If not, see . 20 | */ 21 | 22 | namespace Cureos.Numerics.Optimizers 23 | { 24 | /// 25 | /// Summary of output from optimization. 26 | /// 27 | public class OptimizationSummary 28 | { 29 | #region CONSTRUCTORS 30 | 31 | /// 32 | /// Initializes an instance of the optimization summary. 33 | /// 34 | /// Status of the completed optimization. 35 | /// Number of function evaluations. 36 | /// Optimized variable array. 37 | /// Optimal value of the objective function. 38 | /// If defined, values of constraint functions at optimum. 39 | internal OptimizationSummary(OptimizationStatus status, int nf, double[] x, double f, double[] g = null) 40 | { 41 | Status = status; 42 | Evals = nf; 43 | X = x; 44 | F = f; 45 | G = g; 46 | } 47 | 48 | #endregion 49 | 50 | #region PROPERTIES 51 | 52 | /// 53 | /// Gets the status of the completed optimization. 54 | /// 55 | public OptimizationStatus Status { get; private set; } 56 | 57 | /// 58 | /// Gets the number of function evaluations. 59 | /// 60 | public int Evals { get; private set; } 61 | 62 | /// 63 | /// Gets the optimized variable array. 64 | /// 65 | public double[] X { get; private set; } 66 | 67 | /// 68 | /// Gets the optimal value of the objective function. 69 | /// 70 | public double F { get; private set; } 71 | 72 | /// 73 | /// Gets the values of the constraint functions at optimum, if defined. 74 | /// 75 | public double[] G { get; private set; } 76 | 77 | #endregion 78 | } 79 | } -------------------------------------------------------------------------------- /csnumerics/csnumerics.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard1.0;netstandard2.0 5 | disable 6 | disable 7 | true 8 | csnumerics.snk 9 | true 10 | 11 | 12 | 13 | Cureos 14 | Copyright © 2012-2022 Cureos 15 | Portable numerics library written in C# 16 | CSNumerics 17 | CSNumerics 18 | 1.0.2 19 | en 20 | 21 | 22 | 23 | csnumerics 24 | Anders Gustafsson, Cureos 25 | CSNumerics is a .NET Standard class library of various numerical algorithms written in C#. 26 | 27 | It currently consists of C# implementations of Michael J.D. Powell's optimization algorithms BOBYQA, LINCOA and COBYLA. 28 | true 29 | LGPL-3.0-or-later 30 | https://github.com/cureos/csnumerics 31 | csnumerics.png 32 | numerics optimization cobyla bobyqa lincoa dotnet dotnetstandard 33 | true 34 | true 35 | true 36 | snupkg 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /csnumerics/csnumerics.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cureos/csnumerics/6adcffc8884b76037e6dee15e32ca0bffee71862/csnumerics/csnumerics.snk -------------------------------------------------------------------------------- /packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------