├── .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 |
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 | [](https://www.nuget.org/packages/csnumerics/)
10 | [](https://www.nuget.org/packages/csnumerics/)
11 | [](https://ci.appveyor.com/project/anders9ustafsson/csnumerics)
12 | [](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 |
--------------------------------------------------------------------------------