Skip to content

Commit 597917e

Browse files
committed
Add direct residual function support to NonlinearObjectiveModel and related interfaces
1 parent 44e41dc commit 597917e

File tree

3 files changed

+528
-107
lines changed

3 files changed

+528
-107
lines changed

src/Numerics/Optimization/IObjectiveModel.cs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,55 @@
33

44
namespace MathNet.Numerics.Optimization
55
{
6+
/// <summary>
7+
/// Interface for objective model evaluation, providing access to optimization-related values
8+
/// </summary>
69
public interface IObjectiveModelEvaluation
710
{
11+
/// <summary>
12+
/// Creates a new instance of the objective model with the same function but not the same state
13+
/// </summary>
14+
/// <returns>A new instance of an objective model</returns>
815
IObjectiveModel CreateNew();
916

1017
/// <summary>
1118
/// Get the y-values of the observations.
19+
/// May be null when using direct residual functions.
1220
/// </summary>
1321
Vector<double> ObservedY { get; }
1422

1523
/// <summary>
1624
/// Get the values of the weights for the observations.
25+
/// May be null when using direct residual functions.
1726
/// </summary>
1827
Matrix<double> Weights { get; }
1928

2029
/// <summary>
2130
/// Get the y-values of the fitted model that correspond to the independent values.
31+
/// Only applicable when using model functions, may be null when using direct residual functions.
2232
/// </summary>
2333
Vector<double> ModelValues { get; }
2434

35+
/// <summary>
36+
/// Get the residual values at the current parameters.
37+
/// For model functions, this is (y - f(x;p)) possibly weighted.
38+
/// For direct residual functions, this is the raw output of the residual function.
39+
/// </summary>
40+
Vector<double> Residuals { get; }
41+
2542
/// <summary>
2643
/// Get the values of the parameters.
2744
/// </summary>
2845
Vector<double> Point { get; }
2946

3047
/// <summary>
31-
/// Get the residual sum of squares.
48+
/// Get the residual sum of squares, calculated as F(p) = 1/2 * ∑(residuals²).
3249
/// </summary>
3350
double Value { get; }
3451

3552
/// <summary>
36-
/// Get the Gradient vector. G = J'(y - f(x; p))
53+
/// Get the Gradient vector. G = J'(y - f(x; p)) for model functions,
54+
/// or G = J'r for direct residual functions.
3755
/// </summary>
3856
Vector<double> Gradient { get; }
3957

@@ -54,21 +72,51 @@ public interface IObjectiveModelEvaluation
5472

5573
/// <summary>
5674
/// Get the degree of freedom.
75+
/// For model functions: (number of observations - number of parameters + number of fixed parameters)
76+
/// For direct residual functions: uses explicit observation count or residual vector length if not provided.
5777
/// </summary>
5878
int DegreeOfFreedom { get; }
5979

80+
/// <summary>
81+
/// Indicates whether gradient information is supported
82+
/// </summary>
6083
bool IsGradientSupported { get; }
84+
85+
/// <summary>
86+
/// Indicates whether Hessian information is supported
87+
/// </summary>
6188
bool IsHessianSupported { get; }
6289
}
6390

91+
/// <summary>
92+
/// Interface for objective model that can be minimized
93+
/// </summary>
6494
public interface IObjectiveModel : IObjectiveModelEvaluation
6595
{
96+
/// <summary>
97+
/// Set parameters and optionally specify which parameters should be fixed
98+
/// </summary>
99+
/// <param name="initialGuess">The initial values of parameters</param>
100+
/// <param name="isFixed">Optional list specifying which parameters are fixed (true) or free (false)</param>
66101
void SetParameters(Vector<double> initialGuess, List<bool> isFixed = null);
67102

103+
/// <summary>
104+
/// Evaluates the objective model at the specified parameters
105+
/// </summary>
106+
/// <param name="parameters">Parameters at which to evaluate</param>
68107
void EvaluateAt(Vector<double> parameters);
69108

109+
/// <summary>
110+
/// Creates a copy of this objective model with the same state
111+
/// </summary>
112+
/// <returns>A copy of the objective model</returns>
70113
IObjectiveModel Fork();
71114

115+
/// <summary>
116+
/// Converts this objective model to an objective function for optimization.
117+
/// Creates a function that calculates 1/2 * sum(residuals²) to be minimized.
118+
/// </summary>
119+
/// <returns>An IObjectiveFunction that can be used with general optimization algorithms</returns>
72120
IObjectiveFunction ToObjectiveFunction();
73121
}
74122
}

src/Numerics/Optimization/ObjectiveFunction.cs

Lines changed: 99 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,17 @@ public static IScalarObjectiveFunction ScalarSecondDerivative(Func<double, doubl
116116
}
117117

118118
/// <summary>
119-
/// objective model with a user supplied jacobian for non-linear least squares regression.
119+
/// Creates an objective model with a user-supplied model function and Jacobian for non-linear least squares regression.
120+
/// Uses the form F(p) = 1/2 * sum(w_i * (y_i - f(x_i; p))^2) where f(x; p) is the model function.
120121
/// </summary>
121-
public static IObjectiveModel NonlinearModel(Func<Vector<double>, Vector<double>, Vector<double>> function,
122+
/// <param name="function">The model function f(x; p) that maps from x to y given parameters p</param>
123+
/// <param name="derivatives">The Jacobian of the model function with respect to parameters</param>
124+
/// <param name="observedX">The observed x values</param>
125+
/// <param name="observedY">The observed y values</param>
126+
/// <param name="weight">Optional weights for the observations</param>
127+
/// <returns>An objective model configured for the specified model and observations</returns>
128+
public static IObjectiveModel NonlinearModel(
129+
Func<Vector<double>, Vector<double>, Vector<double>> function,
122130
Func<Vector<double>, Vector<double>, Matrix<double>> derivatives,
123131
Vector<double> observedX, Vector<double> observedY, Vector<double> weight = null)
124132
{
@@ -128,9 +136,17 @@ public static IObjectiveModel NonlinearModel(Func<Vector<double>, Vector<double>
128136
}
129137

130138
/// <summary>
131-
/// Objective model for non-linear least squares regression.
139+
/// Creates an objective model for non-linear least squares regression with numerical differentiation.
140+
/// Uses the form F(p) = 1/2 * sum(w_i * (y_i - f(x_i; p))^2) where f(x; p) is the model function.
132141
/// </summary>
133-
public static IObjectiveModel NonlinearModel(Func<Vector<double>, Vector<double>, Vector<double>> function,
142+
/// <param name="function">The model function f(x; p) that maps from x to y given parameters p</param>
143+
/// <param name="observedX">The observed x values</param>
144+
/// <param name="observedY">The observed y values</param>
145+
/// <param name="weight">Optional weights for the observations</param>
146+
/// <param name="accuracyOrder">Accuracy order for numerical differentiation (1-6)</param>
147+
/// <returns>An objective model configured for the specified model and observations</returns>
148+
public static IObjectiveModel NonlinearModel(
149+
Func<Vector<double>, Vector<double>, Vector<double>> function,
134150
Vector<double> observedX, Vector<double> observedY, Vector<double> weight = null,
135151
int accuracyOrder = 2)
136152
{
@@ -140,9 +156,18 @@ public static IObjectiveModel NonlinearModel(Func<Vector<double>, Vector<double>
140156
}
141157

142158
/// <summary>
143-
/// Objective model with a user supplied jacobian for non-linear least squares regression.
159+
/// Creates an objective model with a user-supplied model function and Jacobian for non-linear least squares regression.
160+
/// This overload accepts scalar x values with function f(p, x) and converts them to vector operations internally.
161+
/// Uses the form F(p) = 1/2 * sum(w_i * (y_i - f(p, x_i))^2).
144162
/// </summary>
145-
public static IObjectiveModel NonlinearModel(Func<Vector<double>, double, double> function,
163+
/// <param name="function">The model function f(p, x) that maps from scalar x to y given parameters p</param>
164+
/// <param name="derivatives">The derivatives of the model function with respect to parameters</param>
165+
/// <param name="observedX">The observed x values</param>
166+
/// <param name="observedY">The observed y values</param>
167+
/// <param name="weight">Optional weights for the observations</param>
168+
/// <returns>An objective model configured for the specified model and observations</returns>
169+
public static IObjectiveModel NonlinearModel(
170+
Func<Vector<double>, double, double> function,
146171
Func<Vector<double>, double, Vector<double>> derivatives,
147172
Vector<double> observedX, Vector<double> observedY, Vector<double> weight = null)
148173
{
@@ -174,9 +199,18 @@ Matrix<double> Prime(Vector<double> point, Vector<double> x)
174199
}
175200

176201
/// <summary>
177-
/// Objective model for non-linear least squares regression.
202+
/// Creates an objective model for non-linear least squares regression with numerical differentiation.
203+
/// This overload accepts scalar x values with function f(p, x) and converts them to vector operations internally.
204+
/// Uses the form F(p) = 1/2 * sum(w_i * (y_i - f(p, x_i))^2).
178205
/// </summary>
179-
public static IObjectiveModel NonlinearModel(Func<Vector<double>, double, double> function,
206+
/// <param name="function">The model function f(p, x) that maps from scalar x to y given parameters p</param>
207+
/// <param name="observedX">The observed x values</param>
208+
/// <param name="observedY">The observed y values</param>
209+
/// <param name="weight">Optional weights for the observations</param>
210+
/// <param name="accuracyOrder">Accuracy order for numerical differentiation (1-6)</param>
211+
/// <returns>An objective model configured for the specified model and observations</returns>
212+
public static IObjectiveModel NonlinearModel(
213+
Func<Vector<double>, double, double> function,
180214
Vector<double> observedX, Vector<double> observedY, Vector<double> weight = null,
181215
int accuracyOrder = 2)
182216
{
@@ -197,9 +231,35 @@ Vector<double> Func(Vector<double> point, Vector<double> x)
197231
}
198232

199233
/// <summary>
200-
/// Objective function with a user supplied jacobian for nonlinear least squares regression.
234+
/// Creates an objective model from a direct residual function for non-linear optimization.
235+
/// Uses the form F(p) = 1/2 * sum(r_i(p)^2) where r(p) is the residual function.
201236
/// </summary>
202-
public static IObjectiveFunction NonlinearFunction(Func<Vector<double>, Vector<double>, Vector<double>> function,
237+
/// <param name="residualFunction">Function that calculates residuals directly from parameters</param>
238+
/// <param name="jacobian">Optional Jacobian of the residual function</param>
239+
/// <param name="observationCount">Number of observations for degree of freedom calculations (optional)</param>
240+
/// <param name="accuracyOrder">Accuracy order for numerical differentiation (1-6)</param>
241+
/// <returns>An objective model configured for the specified residual function</returns>
242+
public static IObjectiveModel NonlinearModel(
243+
Func<Vector<double>, Vector<double>> residualFunction,
244+
Func<Vector<double>, Matrix<double>> jacobian = null,
245+
int? observationCount = null,
246+
int accuracyOrder = 2)
247+
{
248+
return new NonlinearObjectiveModel(residualFunction, jacobian, accuracyOrder, observationCount);
249+
}
250+
251+
/// <summary>
252+
/// Creates an objective function with a user-supplied model function and Jacobian for non-linear least squares regression.
253+
/// Uses the form F(p) = 1/2 * sum(w_i * (y_i - f(x_i; p))^2) where f(x; p) is the model function.
254+
/// </summary>
255+
/// <param name="function">The model function f(x; p) that maps from x to y given parameters p</param>
256+
/// <param name="derivatives">The Jacobian of the model function with respect to parameters</param>
257+
/// <param name="observedX">The observed x values</param>
258+
/// <param name="observedY">The observed y values</param>
259+
/// <param name="weight">Optional weights for the observations</param>
260+
/// <returns>An objective function configured for the specified model and observations</returns>
261+
public static IObjectiveFunction NonlinearFunction(
262+
Func<Vector<double>, Vector<double>, Vector<double>> function,
203263
Func<Vector<double>, Vector<double>, Matrix<double>> derivatives,
204264
Vector<double> observedX, Vector<double> observedY, Vector<double> weight = null)
205265
{
@@ -209,16 +269,42 @@ public static IObjectiveFunction NonlinearFunction(Func<Vector<double>, Vector<d
209269
}
210270

211271
/// <summary>
212-
/// Objective function for nonlinear least squares regression.
213-
/// The numerical jacobian with accuracy order is used.
272+
/// Creates an objective function for non-linear least squares regression with numerical differentiation.
273+
/// Uses the form F(p) = 1/2 * sum(w_i * (y_i - f(x_i; p))^2) where f(x; p) is the model function.
214274
/// </summary>
215-
public static IObjectiveFunction NonlinearFunction(Func<Vector<double>, Vector<double>, Vector<double>> function,
275+
/// <param name="function">The model function f(x; p) that maps from x to y given parameters p</param>
276+
/// <param name="observedX">The observed x values</param>
277+
/// <param name="observedY">The observed y values</param>
278+
/// <param name="weight">Optional weights for the observations</param>
279+
/// <param name="accuracyOrder">Accuracy order for numerical differentiation (1-6)</param>
280+
/// <returns>An objective function configured for the specified model and observations</returns>
281+
public static IObjectiveFunction NonlinearFunction(
282+
Func<Vector<double>, Vector<double>, Vector<double>> function,
216283
Vector<double> observedX, Vector<double> observedY, Vector<double> weight = null,
217284
int accuracyOrder = 2)
218285
{
219286
var objective = new NonlinearObjectiveModel(function, null, accuracyOrder: accuracyOrder);
220287
objective.SetObserved(observedX, observedY, weight);
221288
return objective.ToObjectiveFunction();
222289
}
290+
291+
/// <summary>
292+
/// Creates an objective function from a direct residual function for non-linear optimization.
293+
/// Uses the form F(p) = 1/2 * sum(r_i(p)^2) where r(p) is the residual function.
294+
/// </summary>
295+
/// <param name="residualFunction">Function that calculates residuals directly from parameters</param>
296+
/// <param name="jacobian">Optional Jacobian of the residual function</param>
297+
/// <param name="observationCount">Number of observations for degree of freedom calculations (optional)</param>
298+
/// <param name="accuracyOrder">Accuracy order for numerical differentiation (1-6)</param>
299+
/// <returns>An objective function configured for the specified residual function</returns>
300+
public static IObjectiveFunction NonlinearFunction(
301+
Func<Vector<double>, Vector<double>> residualFunction,
302+
Func<Vector<double>, Matrix<double>> jacobian = null,
303+
int? observationCount = null,
304+
int accuracyOrder = 2)
305+
{
306+
var objective = new NonlinearObjectiveModel(residualFunction, jacobian, accuracyOrder, observationCount);
307+
return objective.ToObjectiveFunction();
308+
}
223309
}
224310
}

0 commit comments

Comments
 (0)