/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * */ #ifndef INCLUDED_SCCOMP_SOURCE_PARTICLESWARM_HXX #define INCLUDED_SCCOMP_SOURCE_PARTICLESWARM_HXX #include #include #include struct Particle { Particle(size_t nDimensionality) : mVelocity(nDimensionality) , mPosition(nDimensionality) , mCurrentFitness(std::numeric_limits::lowest()) , mBestPosition(nDimensionality) , mBestFitness(std::numeric_limits::lowest()) { } std::vector mVelocity; std::vector mPosition; double mCurrentFitness; std::vector mBestPosition; double mBestFitness; }; template class ParticleSwarmOptimizationAlgorithm { private: // inertia static constexpr double constWeight = 0.729; // cognitive coefficient static constexpr double c1 = 1.49445; // social coefficient static constexpr double c2 = 1.49445; static constexpr double constAcceptedPrecision = 0.000000001; DataProvider& mrDataProvider; size_t mnNumOfParticles; std::vector maSwarm; std::random_device maRandomDevice; std::mt19937 maGenerator; size_t mnDimensionality; std::uniform_real_distribution<> maRandom01; std::vector maBestPosition; double mfBestFitness; int mnGeneration; int mnLastChange; public: ParticleSwarmOptimizationAlgorithm(DataProvider& rDataProvider, size_t nNumOfParticles) : mrDataProvider(rDataProvider) , mnNumOfParticles(nNumOfParticles) , maGenerator(maRandomDevice()) , mnDimensionality(mrDataProvider.getDimensionality()) , maRandom01(0.0, 1.0) , maBestPosition(mnDimensionality) , mfBestFitness(std::numeric_limits::lowest()) , mnGeneration(0) , mnLastChange(0) { } std::vector const& getResult() { return maBestPosition; } int getGeneration() { return mnGeneration; } int getLastChange() { return mnLastChange; } void initialize() { mnGeneration = 0; mnLastChange = 0; maSwarm.clear(); mfBestFitness = std::numeric_limits::lowest(); for (size_t i = 0; i < mnNumOfParticles; i++) { maSwarm.emplace_back(mnDimensionality); Particle& rParticle = maSwarm.back(); mrDataProvider.initializeVariables(rParticle.mPosition, maGenerator); mrDataProvider.initializeVariables(rParticle.mVelocity, maGenerator); for (size_t k = 0; k < mnDimensionality; k++) { rParticle.mPosition[k] = mrDataProvider.clampVariable(k, rParticle.mPosition[k]); } rParticle.mCurrentFitness = mrDataProvider.calculateFitness(rParticle.mPosition); for (size_t k = 0; k < mnDimensionality; k++) { rParticle.mPosition[k] = mrDataProvider.clampVariable(k, rParticle.mPosition[k]); } std::copy(rParticle.mPosition.begin(), rParticle.mPosition.end(), rParticle.mBestPosition.begin()); rParticle.mBestFitness = rParticle.mCurrentFitness; if (rParticle.mCurrentFitness > mfBestFitness) { mfBestFitness = rParticle.mCurrentFitness; std::copy(rParticle.mPosition.begin(), rParticle.mPosition.end(), maBestPosition.begin()); } } } bool next() { bool bBestChanged = false; for (Particle& rParticle : maSwarm) { double fRandom1 = maRandom01(maGenerator); double fRandom2 = maRandom01(maGenerator); for (size_t k = 0; k < mnDimensionality; k++) { rParticle.mVelocity[k] = (constWeight * rParticle.mVelocity[k]) + (c1 * fRandom1 * (rParticle.mBestPosition[k] - rParticle.mPosition[k])) + (c2 * fRandom2 * (maBestPosition[k] - rParticle.mPosition[k])); mrDataProvider.clampVariable(k, rParticle.mVelocity[k]); rParticle.mPosition[k] += rParticle.mVelocity[k]; rParticle.mPosition[k] = mrDataProvider.clampVariable(k, rParticle.mPosition[k]); } rParticle.mCurrentFitness = mrDataProvider.calculateFitness(rParticle.mPosition); if (rParticle.mCurrentFitness > rParticle.mBestFitness) { rParticle.mBestFitness = rParticle.mCurrentFitness; std::copy(rParticle.mPosition.begin(), rParticle.mPosition.end(), rParticle.mBestPosition.begin()); } if (rParticle.mCurrentFitness > mfBestFitness) { if (std::abs(rParticle.mCurrentFitness - mfBestFitness) > constAcceptedPrecision) { bBestChanged = true; mnLastChange = mnGeneration; } std::copy(rParticle.mPosition.begin(), rParticle.mPosition.end(), maBestPosition.begin()); mfBestFitness = rParticle.mCurrentFitness; } } mnGeneration++; return bBestChanged; } }; #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */