Skip to content

Commit

Permalink
Extended basic OptimizationTests to include publicly available test f…
Browse files Browse the repository at this point in the history
…unctions from Wikipedia.
  • Loading branch information
m4rs-mt committed Aug 30, 2023
1 parent a0d94a1 commit fc82eaf
Showing 1 changed file with 279 additions and 7 deletions.
286 changes: 279 additions & 7 deletions Src/ILGPU.Algorithms.Tests/OptimizationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using ILGPU.Tests;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Xunit;
using Xunit.Abstractions;

Expand All @@ -34,11 +35,18 @@ public abstract partial class OptimizationTests : TestBase
protected OptimizationTests(ITestOutputHelper output, TestContext testContext)
: base(output, testContext)
{ }

#if NET7_0_OR_GREATER

#region Objectives


public interface IPredefineTestFunction
{
float Result { get; }
float[] LowerBounds { get; }
float[] UpperBounds { get; }
}

public readonly record struct DistanceF32x2(float Constant) :
IOptimizationFunction<Float32x2, float, float>
{
Expand All @@ -60,7 +68,271 @@ public float Evaluate(
public bool CurrentIsBetter(float current, float proposed) =>
current <= proposed;
}


/// <summary>
/// Represents the Himmelblau function:
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
/// </summary>
public readonly record struct HimmelblauFunction :
IOptimizationFunction<Float32x2, float, float>,
IPredefineTestFunction
{
private static readonly float[] GlobalLowerBounds = new float[]
{
-5.0f, -5.0f
};

private static readonly float[] GlobalUpperBounds = new float[]
{
5.0f, 5.0f
};

/// <summary>
/// The optimal result.
/// </summary>
public const float GlobalResult = 0.0f;

/// <summary>
/// Evaluates the Himmelblau function.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Evaluate(float x, float y)
{
float first = (x * x + y - 11);
float second = (x + y * y - 7);
return first * first + second * second;
}

public float Result => GlobalResult;
public float[] LowerBounds => GlobalLowerBounds;
public float[] UpperBounds => GlobalUpperBounds;

public float Evaluate(
LongIndex1D index,
Index1D dimension,
SingleVectorView<Float32x2> positionView)
{
var first = positionView[0];
return Evaluate(first.X, first.Y);
}

public bool CurrentIsBetter(float current, float proposed) =>
current < proposed;
}

/// <summary>
/// Represents the Easom function:
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
/// </summary>
public readonly record struct EasomFunction :
IOptimizationFunction<Float32x2, float, float>,
IPredefineTestFunction
{
private static readonly float[] GlobalLowerBounds = new float[]
{
-100.0f, -100.0f
};

private static readonly float[] GlobalUpperBounds = new float[]
{
100.0f, 100.0f
};

/// <summary>
/// The optimal result.
/// </summary>
public const float GlobalResult = -1.0f;

public float Result => GlobalResult;
public float[] LowerBounds => GlobalLowerBounds;
public float[] UpperBounds => GlobalUpperBounds;

/// <summary>
/// Evaluates the Easom function.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Evaluate(float x, float y)
{
float xPart = x - XMath.PI;
float yPart = y - XMath.PI;
return -XMath.Cos(x) * XMath.Cos(y) *
XMath.Exp(-(xPart * xPart + yPart * yPart));
}
public float Evaluate(
LongIndex1D index,
Index1D dimension,
SingleVectorView<Float32x2> positionView)
{
var first = positionView[0];
return Evaluate(first.X, first.Y);
}

public bool CurrentIsBetter(float current, float proposed) =>
current < proposed;
}

/// <summary>
/// Represents the Shaffer function N4:
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
/// </summary>
public readonly record struct ShafferFunction4 :
IOptimizationFunction<Float32x2, float, float>,
IPredefineTestFunction
{
private static readonly float[] GlobalLowerBounds = new float[]
{
-100.0f, -100.0f
};

private static readonly float[] GlobalUpperBounds = new float[]
{
100.0f, 100.0f
};

/// <summary>
/// The optimal result.
/// </summary>
public const float GlobalResult = 0.292579f;

public float Result => GlobalResult;
public float[] LowerBounds => GlobalLowerBounds;
public float[] UpperBounds => GlobalUpperBounds;

/// <summary>
/// Evaluates the Shaffer function.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Evaluate(float x, float y)
{
float cos = XMath.Cos(XMath.Sin(XMath.Abs(x * x - y * y)));
float nominator = cos * cos - 0.5f;
float denominator = 1 + 0.001f * (x * x + y * y);
return 0.5f + nominator / (denominator * denominator);
}
public float Evaluate(
LongIndex1D index,
Index1D dimension,
SingleVectorView<Float32x2> positionView)
{
var first = positionView[0];
return Evaluate(first.X, first.Y);
}

public bool CurrentIsBetter(float current, float proposed) =>
current < proposed;
}

/// <summary>
/// Represents the Rosenbrock function constrained to a disk
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
/// </summary>
public readonly record struct RosenbrockDisk :
IOptimizationFunction<Float32x2, float, float>,
IPredefineTestFunction
{
private static readonly float[] GlobalLowerBounds = new float[]
{
-1.5f, -1.5f
};

private static readonly float[] GlobalUpperBounds = new float[]
{
1.5f, 1.5f
};

/// <summary>
/// The optimal result.
/// </summary>
public const float GlobalResult = 0.0f;

public float Result => GlobalResult;
public float[] LowerBounds => GlobalLowerBounds;
public float[] UpperBounds => GlobalUpperBounds;

/// <summary>
/// Evaluates the constrained Rosenbrock function.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Evaluate(float x, float y)
{
float xMin = 1.0f - x;
float x2 = x * x;
float result = xMin * xMin + 100.0f * (y - x2) * (y - x2);
if (x * x + y * y <= 2.0f)
return result;
return float.MaxValue;
}

public float Evaluate(
LongIndex1D index,
Index1D dimension,
SingleVectorView<Float32x2> positionView)
{
var first = positionView[0];
return Evaluate(first.X, first.Y);
}

public bool CurrentIsBetter(float current, float proposed) =>
current < proposed;
}

/// <summary>
/// Represents the Gomez and Levy function:
/// https://en.wikipedia.org/wiki/Test_functions_for_optimization
/// </summary>
public readonly record struct GomezAndLevyFunction :
IOptimizationFunction<Float32x2, float, float>,
IPredefineTestFunction
{
private static readonly float[] GlobalLowerBounds = new float[]
{
-1.0f, -1.0f
};

private static readonly float[] GlobalUpperBounds = new float[]
{
0.75f, 1.0f
};

/// <summary>
/// The optimal result.
/// </summary>
public const float GlobalResult = -1.031628453f;

public float Result => GlobalResult;
public float[] LowerBounds => GlobalLowerBounds;
public float[] UpperBounds => GlobalUpperBounds;

/// <summary>
/// Evaluates the constrained Gomez and Levy function.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Evaluate(float x, float y)
{
float x2 = x * x;
float x4 = x2 * x2;
float y2 = y * y;
float y4 = y2 * y2;
float result = 4.0f * x2 + 2.1f * x4 + 1.0f / 3.0f * x4 * x2 +
x * y - 4.0f * y2 + 4.0f * y4;
float sin = XMath.Sin(2.0f * XMath.PI * y);
float conditionValue = -XMath.Sin(4.0f * XMath.PI * x) + 2.0f * sin * sin;
return conditionValue < 1.5f ? result : float.MaxValue;
}

public float Evaluate(
LongIndex1D index,
Index1D dimension,
SingleVectorView<Float32x2> positionView)
{
var first = positionView[0];
return Evaluate(first.X, first.Y);
}

public bool CurrentIsBetter(float current, float proposed) =>
current < proposed;
}

#endregion

#region MemberData
Expand Down Expand Up @@ -129,7 +401,7 @@ public static TheoryData<

#endregion

[SkippableTheory()]
[SkippableTheory]
[MemberData(nameof(TestData))]
public void ParticleSwarmOptimization<
TFunc,
Expand Down Expand Up @@ -157,7 +429,7 @@ public void ParticleSwarmOptimization<
Skip.If(
Accelerator.AcceleratorType == AcceleratorType.CPU &&
optimizerConfig.NumIterations * optimizerConfig.NumParticles > 2048);

const int Seed = 24404699;
using var pso = new PSO<
TNumericType,
Expand Down Expand Up @@ -185,7 +457,7 @@ public void ParticleSwarmOptimization<
best,
optimizerConfig.NumIterations);
stream.Synchronize();

// Check result
Assert.True(
result.Result - delta <= expected,
Expand Down

0 comments on commit fc82eaf

Please sign in to comment.