Skip to content

Commit bdb6beb

Browse files
committed
Extended basic OptimizationTests to include publicly available test functions from Wikipedia.
1 parent c23fc50 commit bdb6beb

File tree

1 file changed

+279
-7
lines changed

1 file changed

+279
-7
lines changed

Src/ILGPU.Algorithms.Tests/OptimizationTests.cs

Lines changed: 279 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using ILGPU.Tests;
2121
using System.Linq;
2222
using System.Numerics;
23+
using System.Runtime.CompilerServices;
2324
using Xunit;
2425
using Xunit.Abstractions;
2526

@@ -34,11 +35,18 @@ public abstract partial class OptimizationTests : TestBase
3435
protected OptimizationTests(ITestOutputHelper output, TestContext testContext)
3536
: base(output, testContext)
3637
{ }
37-
38+
3839
#if NET7_0_OR_GREATER
39-
40+
4041
#region Objectives
41-
42+
43+
public interface IPredefineTestFunction
44+
{
45+
float Result { get; }
46+
float[] LowerBounds { get; }
47+
float[] UpperBounds { get; }
48+
}
49+
4250
public readonly record struct DistanceF32x2(float Constant) :
4351
IOptimizationFunction<Float32x2, float, float>
4452
{
@@ -60,7 +68,271 @@ public float Evaluate(
6068
public bool CurrentIsBetter(float current, float proposed) =>
6169
current <= proposed;
6270
}
63-
71+
72+
/// <summary>
73+
/// Represents the Himmelblau function:
74+
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
75+
/// </summary>
76+
public readonly record struct HimmelblauFunction :
77+
IOptimizationFunction<Float32x2, float, float>,
78+
IPredefineTestFunction
79+
{
80+
private static readonly float[] GlobalLowerBounds = new float[]
81+
{
82+
-5.0f, -5.0f
83+
};
84+
85+
private static readonly float[] GlobalUpperBounds = new float[]
86+
{
87+
5.0f, 5.0f
88+
};
89+
90+
/// <summary>
91+
/// The optimal result.
92+
/// </summary>
93+
public const float GlobalResult = 0.0f;
94+
95+
/// <summary>
96+
/// Evaluates the Himmelblau function.
97+
/// </summary>
98+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
99+
public static float Evaluate(float x, float y)
100+
{
101+
float first = (x * x + y - 11);
102+
float second = (x + y * y - 7);
103+
return first * first + second * second;
104+
}
105+
106+
public float Result => GlobalResult;
107+
public float[] LowerBounds => GlobalLowerBounds;
108+
public float[] UpperBounds => GlobalUpperBounds;
109+
110+
public float Evaluate(
111+
LongIndex1D index,
112+
Index1D dimension,
113+
SingleVectorView<Float32x2> positionView)
114+
{
115+
var first = positionView[0];
116+
return Evaluate(first.X, first.Y);
117+
}
118+
119+
public bool CurrentIsBetter(float current, float proposed) =>
120+
current < proposed;
121+
}
122+
123+
/// <summary>
124+
/// Represents the Easom function:
125+
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
126+
/// </summary>
127+
public readonly record struct EasomFunction :
128+
IOptimizationFunction<Float32x2, float, float>,
129+
IPredefineTestFunction
130+
{
131+
private static readonly float[] GlobalLowerBounds = new float[]
132+
{
133+
-100.0f, -100.0f
134+
};
135+
136+
private static readonly float[] GlobalUpperBounds = new float[]
137+
{
138+
100.0f, 100.0f
139+
};
140+
141+
/// <summary>
142+
/// The optimal result.
143+
/// </summary>
144+
public const float GlobalResult = -1.0f;
145+
146+
public float Result => GlobalResult;
147+
public float[] LowerBounds => GlobalLowerBounds;
148+
public float[] UpperBounds => GlobalUpperBounds;
149+
150+
/// <summary>
151+
/// Evaluates the Easom function.
152+
/// </summary>
153+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
154+
public static float Evaluate(float x, float y)
155+
{
156+
float xPart = x - XMath.PI;
157+
float yPart = y - XMath.PI;
158+
return -XMath.Cos(x) * XMath.Cos(y) *
159+
XMath.Exp(-(xPart * xPart + yPart * yPart));
160+
}
161+
public float Evaluate(
162+
LongIndex1D index,
163+
Index1D dimension,
164+
SingleVectorView<Float32x2> positionView)
165+
{
166+
var first = positionView[0];
167+
return Evaluate(first.X, first.Y);
168+
}
169+
170+
public bool CurrentIsBetter(float current, float proposed) =>
171+
current < proposed;
172+
}
173+
174+
/// <summary>
175+
/// Represents the Shaffer function N4:
176+
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
177+
/// </summary>
178+
public readonly record struct ShafferFunction4 :
179+
IOptimizationFunction<Float32x2, float, float>,
180+
IPredefineTestFunction
181+
{
182+
private static readonly float[] GlobalLowerBounds = new float[]
183+
{
184+
-100.0f, -100.0f
185+
};
186+
187+
private static readonly float[] GlobalUpperBounds = new float[]
188+
{
189+
100.0f, 100.0f
190+
};
191+
192+
/// <summary>
193+
/// The optimal result.
194+
/// </summary>
195+
public const float GlobalResult = 0.292579f;
196+
197+
public float Result => GlobalResult;
198+
public float[] LowerBounds => GlobalLowerBounds;
199+
public float[] UpperBounds => GlobalUpperBounds;
200+
201+
/// <summary>
202+
/// Evaluates the Shaffer function.
203+
/// </summary>
204+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
205+
public static float Evaluate(float x, float y)
206+
{
207+
float cos = XMath.Cos(XMath.Sin(XMath.Abs(x * x - y * y)));
208+
float nominator = cos * cos - 0.5f;
209+
float denominator = 1 + 0.001f * (x * x + y * y);
210+
return 0.5f + nominator / (denominator * denominator);
211+
}
212+
public float Evaluate(
213+
LongIndex1D index,
214+
Index1D dimension,
215+
SingleVectorView<Float32x2> positionView)
216+
{
217+
var first = positionView[0];
218+
return Evaluate(first.X, first.Y);
219+
}
220+
221+
public bool CurrentIsBetter(float current, float proposed) =>
222+
current < proposed;
223+
}
224+
225+
/// <summary>
226+
/// Represents the Rosenbrock function constrained to a disk
227+
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
228+
/// </summary>
229+
public readonly record struct RosenbrockDisk :
230+
IOptimizationFunction<Float32x2, float, float>,
231+
IPredefineTestFunction
232+
{
233+
private static readonly float[] GlobalLowerBounds = new float[]
234+
{
235+
-1.5f, -1.5f
236+
};
237+
238+
private static readonly float[] GlobalUpperBounds = new float[]
239+
{
240+
1.5f, 1.5f
241+
};
242+
243+
/// <summary>
244+
/// The optimal result.
245+
/// </summary>
246+
public const float GlobalResult = 0.0f;
247+
248+
public float Result => GlobalResult;
249+
public float[] LowerBounds => GlobalLowerBounds;
250+
public float[] UpperBounds => GlobalUpperBounds;
251+
252+
/// <summary>
253+
/// Evaluates the constrained Rosenbrock function.
254+
/// </summary>
255+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
256+
public static float Evaluate(float x, float y)
257+
{
258+
float xMin = 1.0f - x;
259+
float x2 = x * x;
260+
float result = xMin * xMin + 100.0f * (y - x2) * (y - x2);
261+
if (x * x + y * y <= 2.0f)
262+
return result;
263+
return float.MaxValue;
264+
}
265+
266+
public float Evaluate(
267+
LongIndex1D index,
268+
Index1D dimension,
269+
SingleVectorView<Float32x2> positionView)
270+
{
271+
var first = positionView[0];
272+
return Evaluate(first.X, first.Y);
273+
}
274+
275+
public bool CurrentIsBetter(float current, float proposed) =>
276+
current < proposed;
277+
}
278+
279+
/// <summary>
280+
/// Represents the Gomez and Levy function:
281+
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
282+
/// </summary>
283+
public readonly record struct GomezAndLevyFunction :
284+
IOptimizationFunction<Float32x2, float, float>,
285+
IPredefineTestFunction
286+
{
287+
private static readonly float[] GlobalLowerBounds = new float[]
288+
{
289+
-1.0f, -1.0f
290+
};
291+
292+
private static readonly float[] GlobalUpperBounds = new float[]
293+
{
294+
0.75f, 1.0f
295+
};
296+
297+
/// <summary>
298+
/// The optimal result.
299+
/// </summary>
300+
public const float GlobalResult = -1.031628453f;
301+
302+
public float Result => GlobalResult;
303+
public float[] LowerBounds => GlobalLowerBounds;
304+
public float[] UpperBounds => GlobalUpperBounds;
305+
306+
/// <summary>
307+
/// Evaluates the constrained Gomez and Levy function.
308+
/// </summary>
309+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
310+
public static float Evaluate(float x, float y)
311+
{
312+
float x2 = x * x;
313+
float x4 = x2 * x2;
314+
float y2 = y * y;
315+
float y4 = y2 * y2;
316+
float result = 4.0f * x2 + 2.1f * x4 + 1.0f / 3.0f * x4 * x2 +
317+
x * y - 4.0f * y2 + 4.0f * y4;
318+
float sin = XMath.Sin(2.0f * XMath.PI * y);
319+
float conditionValue = -XMath.Sin(4.0f * XMath.PI * x) + 2.0f * sin * sin;
320+
return conditionValue < 1.5f ? result : float.MaxValue;
321+
}
322+
323+
public float Evaluate(
324+
LongIndex1D index,
325+
Index1D dimension,
326+
SingleVectorView<Float32x2> positionView)
327+
{
328+
var first = positionView[0];
329+
return Evaluate(first.X, first.Y);
330+
}
331+
332+
public bool CurrentIsBetter(float current, float proposed) =>
333+
current < proposed;
334+
}
335+
64336
#endregion
65337

66338
#region MemberData
@@ -129,7 +401,7 @@ public static TheoryData<
129401

130402
#endregion
131403

132-
[SkippableTheory()]
404+
[SkippableTheory]
133405
[MemberData(nameof(TestData))]
134406
public void ParticleSwarmOptimization<
135407
TFunc,
@@ -157,7 +429,7 @@ public void ParticleSwarmOptimization<
157429
Skip.If(
158430
Accelerator.AcceleratorType == AcceleratorType.CPU &&
159431
optimizerConfig.NumIterations * optimizerConfig.NumParticles > 2048);
160-
432+
161433
const int Seed = 24404699;
162434
using var pso = new PSO<
163435
TNumericType,
@@ -185,7 +457,7 @@ public void ParticleSwarmOptimization<
185457
best,
186458
optimizerConfig.NumIterations);
187459
stream.Synchronize();
188-
460+
189461
// Check result
190462
Assert.True(
191463
result.Result - delta <= expected,

0 commit comments

Comments
 (0)