Files
ensmallen/tests/pso_test.cpp
T

395 lines
10 KiB
C++

/**
* @file pso_test.cpp
* @author Suryoday Basak
* @author Chintan Soni
*
* Test file for PSO optimizer.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <ensmallen.hpp>
#include "catch.hpp"
using namespace ens;
using namespace ens::test;
using namespace std;
/**
* Test the PSO optimizer on the Sphere Function. Use arma::mat.
*/
TEST_CASE("LBestPSOSphereFunctionTest", "[PSOTest]")
{
SphereFunction f(4);
LBestPSO s;
arma::mat coords = f.GetInitialPoint<arma::mat>();
if (!s.Optimize(f, coords))
FAIL("LBest PSO optimization reported failure for Sphere Function.");
double finalValue = f.Evaluate(coords);
REQUIRE(finalValue <= 1e-5);
for (size_t j = 0; j < 4; ++j)
REQUIRE(coords(j) <= 1e-3);
}
/**
* Test the PSO optimizer on the Sphere Function. Use arma::fmat.
*/
TEST_CASE("LBestPSOSphereFunctionFMatTest", "[PSOTest]")
{
SphereFunction f(4);
LBestPSO s;
arma::fmat coords = f.GetInitialPoint<arma::fmat>();
if (!s.Optimize(f, coords))
FAIL("LBest PSO optimization reported failure for Sphere Function.");
double finalValue = f.Evaluate(coords);
REQUIRE(finalValue <= 1e-5);
for (size_t j = 0; j < 4; ++j)
REQUIRE(coords(j) <= 1e-3);
}
/**
* Test the PSO optimizer on the Rosenbrock Function. Use arma::mat.
*/
TEST_CASE("LBestPSORosenbrockTest","[PSOTest]")
{
RosenbrockFunction f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(50);
upperBound.fill(60);
// We allow a few trials.
for (size_t trial = 0; trial < 3; ++trial)
{
LBestPSO s(250, lowerBound, upperBound, 3000, 600, 1e-30, 2.05, 2.05);
arma::vec coordinates = f.GetInitialPoint();
const double result = s.Optimize(f, coordinates);
if (trial != 2)
{
if (result != Approx(0.0).margin(0.03))
continue;
if (coordinates(0) != Approx(1.0).margin(0.02))
continue;
if (coordinates(1) != Approx(1.0).margin(0.02))
continue;
}
REQUIRE(result == Approx(0.0).margin(0.03));
REQUIRE(coordinates(0) == Approx(1.0).margin(0.02));
REQUIRE(coordinates(1) == Approx(1.0).margin(0.02));
}
}
/**
* Test the PSO optimizer on the Rosenbrock Function. Use arma::fmat.
*/
TEST_CASE("LBestPSORosenbrockFMatTest","[PSOTest]")
{
RosenbrockFunction f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(50);
upperBound.fill(60);
// We allow a few trials.
for (size_t trial = 0; trial < 5; ++trial)
{
LBestPSO s(250, lowerBound, upperBound, 5000, 600, 1e-30, 2.05, 2.05);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
const double result = s.Optimize(f, coordinates);
if (trial != 4)
{
if (result != Approx(0.0).margin(0.03))
continue;
if (coordinates(0) != Approx(1.0).margin(0.03))
continue;
if (coordinates(1) != Approx(1.0).margin(0.03))
continue;
}
REQUIRE(result == Approx(0.0).margin(0.03));
REQUIRE(coordinates(0) == Approx(1.0).margin(0.03));
REQUIRE(coordinates(1) == Approx(1.0).margin(0.03));
}
}
/**
* Test the PSO optimizer on the Rosenbrock function with lowerBound and
* upperbound of type double.
*/
TEST_CASE("LBestPSORosenbrockDoubleTest","[PSOTest]")
{
RosenbrockFunction f;
// Setting bounds for the initial swarm population.
double lowerBound = 50;
double upperBound = 60;
// We allow a few trials.
for (size_t trial = 0; trial < 3; ++trial)
{
LBestPSO s(250, lowerBound, upperBound, 5000, 400, 1e-30, 2.05, 2.05);
arma::vec coordinates = f.GetInitialPoint();
const double result = s.Optimize(f, coordinates);
if (trial != 2)
{
if (result != Approx(0.0).margin(1e-3))
continue;
if (coordinates(0) != Approx(1.0).epsilon(1e-2))
continue;
if (coordinates(1) != Approx(1.0).epsilon(1e-2))
continue;
}
REQUIRE(result == Approx(0.0).margin(0.005));
REQUIRE(coordinates(0) == Approx(1.0).margin(0.005));
REQUIRE(coordinates(1) == Approx(1.0).margin(0.005));
}
}
/**
* Test the PSO optimizer on Cross-in-Tray Function.
*/
TEST_CASE("LBestPSOCrossInTrayFunctionTest", "[PSOTest]")
{
CrossInTrayFunction f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(-1);
upperBound.fill(1);
// We allow many trials---sometimes this can have trouble converging.
for (size_t trial = 0; trial < 15; ++trial)
{
LBestPSO s(500, lowerBound, upperBound, 6000, 400, 1e-30, 2.05, 2.05);
arma::mat coordinates = arma::mat("10; 10");
const double result = s.Optimize(f, coordinates);
if (trial != 14)
{
if (std::isinf(result) || std::isnan(result))
continue;
if (result != Approx(-2.06261).margin(0.01))
continue;
if (abs(coordinates(0)) != Approx(1.34941).margin(0.01))
continue;
if (abs(coordinates(1)) != Approx(1.34941).margin(0.01))
continue;
}
REQUIRE(result == Approx(-2.06261).margin(0.01));
REQUIRE(abs(coordinates(0)) == Approx(1.34941).margin(0.01));
REQUIRE(abs(coordinates(1)) == Approx(1.34941).margin(0.01));
}
}
/**
* Test the PSO optimizer on the Ackley Function.
*/
TEST_CASE("LBestPSOAckleyFunctionTest", "[PSOTest]")
{
AckleyFunction f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(4);
upperBound.fill(5);
LBestPSO s(64, lowerBound, upperBound);
arma::mat coordinates = arma::mat("5; 5");
const double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(0).margin(0.01));
REQUIRE(coordinates(0) == Approx(0).margin(0.01));
REQUIRE(coordinates(1) == Approx(0).margin(0.01));
}
/**
* Test the PSO optimizer on the Beale Function.
*/
TEST_CASE("LBestPSOBealeFunctionTest", "[PSOTest]")
{
BealeFunction f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(3);
upperBound.fill(4);
LBestPSO s(64, lowerBound, upperBound);
arma::mat coordinates = arma::mat("4.5; 4.5");
const double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(0).margin(0.01));
REQUIRE(coordinates(0) == Approx(3).margin(0.01));
REQUIRE(coordinates(1) == Approx(0.5).margin(0.01));
}
/**
* Test the PSO optimizer on the Goldstein-Price Function.
*/
TEST_CASE("LBestPSOGoldsteinPriceFunctionTest", "[PSOTest]")
{
GoldsteinPriceFunction f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(1.6);
upperBound.fill(2);
// Allow a few trials in case of failure.
for (size_t trial = 0; trial < 10; ++trial)
{
LBestPSO s(64, lowerBound, upperBound);
arma::mat coordinates = arma::mat("1; 0");
s.Optimize(f, coordinates);
if (trial != 9)
{
if (coordinates(0) != Approx(0).margin(0.01))
continue;
if (coordinates(1) != Approx(-1).margin(0.01))
continue;
}
REQUIRE(coordinates(0) == Approx(0).margin(0.01));
REQUIRE(coordinates(1) == Approx(-1).margin(0.01));
}
}
/**
* Test the PSO optimizer on the Levi Function.
*/
TEST_CASE("LBestPSOLevyFunctionN13Test", "[PSOTest]")
{
LevyFunctionN13 f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(-10);
upperBound.fill(-9);
LBestPSO s(64, lowerBound, upperBound);
arma::mat coordinates = arma::mat("3; 3");
s.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(1).margin(0.01));
REQUIRE(coordinates(1) == Approx(1).margin(0.01));
}
/**
* Test the PSO optimizer on the Himmelblau Function.
*/
TEST_CASE("LBestPSOHimmelblauFunctionTest", "[PSOTest]")
{
HimmelblauFunction f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(0);
upperBound.fill(1);
LBestPSO s(64, lowerBound, upperBound);
arma::mat coordinates = arma::mat("2; 1");
s.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(3.0).margin(0.01));
REQUIRE(coordinates(1) == Approx(2.0).margin(0.01));
}
/**
* Test the PSO optimizer on the Three-hump Camel Function.
*/
TEST_CASE("LBestPSOThreeHumpCamelFunctionTest", "[PSOTest]")
{
ThreeHumpCamelFunction f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(-5);
upperBound.fill(-4);
LBestPSO s(64, lowerBound, upperBound);
arma::mat coordinates = arma::mat("2; 2");
s.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0).margin(0.01));
REQUIRE(coordinates(1) == Approx(0).margin(0.01));
}
/**
* Test the PSO optimizer on Schaffer Function N.2.
*/
TEST_CASE("LBestPSOSchafferFunctionN2Test", "[PSOTest]")
{
SchafferFunctionN2 f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(40);
upperBound.fill(50);
LBestPSO s(500, lowerBound, upperBound);
arma::mat coordinates = arma::mat("10; 10");
s.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0).margin(0.01));
REQUIRE(coordinates(1) == Approx(0).margin(0.01));
}
// TODO: With future improvements in metaheuristic optimisers in ensmallen,
// try to optimize this function.
/**
* Test the PSO optimizer on Schaffer function N.4.
*/
/*
TEST_CASE("LBestPSOScafferFunctionN4Test", "[PSOTest]")
{
SchafferFunctionN4 f;
// Setting bounds for the initial swarm population.
arma::vec lowerBound(2);
arma::vec upperBound(2);
lowerBound.fill(-0.01);
upperBound.fill(1.5);
LBestPSO s(25000, lowerBound, upperBound, 4000, 40, 1e-40, 1.5, 1.0);
arma::mat coordinates = arma::mat("0; 10");
const double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(0.292579).margin(0.1));
REQUIRE(coordinates(0) == Approx(0).margin(0.1));
REQUIRE(abs(coordinates(1)) == Approx(1.25313).margin(0.1));
}
*/