I am trying to devellop a small option pricer using win32 API.
To do that I use monte carlo simulation to compute the price of a call option but there is a mistake in my simulation and I don't see where.
Someone can tell me why the two prices are different ?
The price for a call with the black and scholes formula is 6.84 but the one given by the monte carlo simulation is 7.54.
(There is no error in the price from the black and scholes formula)
This is the code :
std::vector<double> vecteur_pas(double T) {
std::vector<double> pas;
pas.push_back(0);
double x = T / nb_pas;
for (int i = 1; i <= nb_pas; i++) {
pas.push_back(pas[i-1] + x);
}
return pas;
std::vector <double> NormalRnd() {
std::vector <double> brow;
brow.push_back(0);
double unif_1, unif_2;
for (int i = 0; i < nb_pas; i++) {
unif_1 = (double(rand() + 0.5)) / (double(RAND_MAX) + 1.0);
unif_2 = (double(rand() + 0.5)) / (double(RAND_MAX) + 1.0);
brow.push_back(sqrt(-2 * log(unif_1)) * cos(2 * M_PI * unif_2));
}
return brow;
std::vector<double> MBG(double S, double mu, double vol, double T) {
std::vector<double> traj;
traj.push_back(S);
std::vector <double> b =NormalRnd();
std::vector<double> pas = vecteur_pas(T);
double drift = 0.0;
double diffusion = 0.0;
for (int i = 1; i <= nb_pas; i++) {
drift = (mu - 0.5 * pow(vol, 2)) * (pas[i]-pas[i-1]);
diffusion = vol * b[i] * sqrt(pas[i] - pas[i - 1]);
traj.push_back(traj[i - 1] * exp(drift + diffusion));
}
return traj;
The MBG function is called in a loop after :
for (int i = 0; i < 100000; i++)
{
if ((i % 1000) == 0)
{
SendDlgItemMessage(Calcul, IDE_PB, PBM_STEPIT, 0, 0);
}
vector<double> proc_prix = MBG(actif.S, actif.r, actif.v, actif.T);
double last_value = proc_prix[proc_prix.size() - 1];
Prime = Prime + std::max(last_value - actif.K, 0.0);
}
Prime = Prime / 100000;
This is the output
Related
How to create a Gaussian kernel by only specifying its width w (3,5,7,9...), and without specifying its variance sigma?
In other word, how to adapt sigma so that the Gaussian distribution 'fits well' w?
I would be interested in a C++ implementation:
void create_gaussian_kernel(int w, std::vector<std::vector<float>>& kernel)
{
kernel = std::vector<std::vector<float>>(w, std::vector<float>(w, 0.f)); // 2D array of size w x w
const Scalar sigma = 1.0; // how to adapt sigma to w ???
const int hw = (w-1)/2; // half width
for(int di = -hw; di <= +hw; ++di)
{
const int i = hw + di;
for(int dj = -hw; dj <= +hw; ++dj)
{
const int j = hw + dj;
kernel[i][j] = gauss2D(di, dj, sigma);
}
}
}
Everything I see on the Internet use a fixed size w and a fixed variance sigma :
geeksforgeeks.org/gaussian-filter-generation-c/
tutorialspoint.com/gaussian-filter-generation-in-cplusplus
stackoverflow.com/a/8204880/5317819
stackoverflow.com/q/42186498/5317819
stackoverflow.com/a/54615770/5317819
I found a simple (arbitrary) relation between sigma and w.
I want the next value outside the kernel (along one axis) below a very small value epsilon:
exp( - (half_width + 1)^2 / (2 * sigma^2) ) < epsilon
with half_width the kernel 'half width'.
The result is
sigma^2 = - (half_width + 1)^2 / (2 * log(epsilon))
I use the following c++ code:
#include <vector>
#include <cmath>
#include <cassert>
using Matrix = std::vector<std::vector<float>>;
// compute sigma^2 that 'fit' the kernel half width
float compute_squared_variance(int half_width, float epsilon = 0.001)
{
assert(0 < epsilon && epsilon < 1); // small value required
return - (half_width + 1.0) * (half_width + 1.0) / 2.0 / std::log(epsilon);
}
float gaussian_exp(float y, float x, float sigma2)
{
assert(0 < sigma2);
return std::exp( - (x*x + y*y) / (2 * sigma2) );
}
// create a Gaussian kernel of size 2*half_width+1 x 2*half_width+1
Matrix make_gaussian_kernel(int half_width)
{
if(half_width <= 0)
{
// kernel of size 1 x 1
Matrix kernel(1, std::vector<float>(1, 1.0));
return kernel;
}
Matrix kernel(2*half_width+1, std::vector<float>(2*half_width+1, 0.0));
const float sigma2 = compute_squared_variance(half_width, 0.1);
float sum = 0;
for(int di = -half_width; di <= +half_width; ++di)
{
const int i = half_width + di;
for(int dj = -half_width; dj <= +half_width; ++dj)
{
const int j = half_width + dj;
kernel[i][j] = gaussian_exp(di, dj, sigma2);
sum += kernel[i][j];
}
}
assert(0 < sum);
// normalize
for(int i=0; i<2*half_width+1; ++i)
{
for(int j=0; j<2*half_width+1; ++j)
{
kernel[i][j] /= sum;
}
}
return kernel;
}
For the function below, I would not add the noise (Inoise in the code below) in every time step but, for example, only in every second time step. So while dt=0.0025 serves as the time step for the numerical integration, I would, for example, add Inoise only in every second time step (i.e. in 0.005 steps).
What is the best way to insert this into my existing function?
runs = 1000;
t_end = 5;
dt = 0.0025;
t_steps = t_end/dt;
for(int j=0; j<runs; j++){
double vT = v0;
double mT = m0;
double hT = h0;
double nT = n0;
for(int i=0; i<t_steps; i++){
double IStim = 0.0;
if ((delay / dt <= (double)i) && ((double)i <= (delay + duration) / dt))
IStim = I;
mT = (mT + dt * alphaM(vT)) / (1.0 + dt * (alphaM(vT) + betaM(vT)));
hT = (hT + dt * alphaH(vT)) / (1.0 + dt * (alphaH(vT) + betaH(vT)));
nT = (nT + dt * alphaN(vT)) / (1.0 + dt * (alphaN(vT) + betaN(vT)));
const double iNa = gNa * pow(mT, 3.0) * hT * (vT - vNa);
const double iK = gK * pow(nT, 4.0) * (vT - vK);
const double iL = gL * (vT-vL);
const double Inoise = (doubleRand() * knoise * sqrt(gNa * A));
const double IIon = ((iNa + iK + iL) * A) + Inoise;
vT += ((-IIon + IStim) / C) * dt;
voltage[i] = vT;
if(vT > 60.0) {
count++;
break;
}
}
}
return count;
}
You could accumulate the elapsed time and only add the noise once enough steps have passed:
double elapsedTime = 0;
double INoiseThreshold = 0.005;
for(int j=0; j<runs; j++){
//...
for(int i=0; i<t_steps; i++){
//...
double Inoise = 0;
elapsedTime += dt;
if(elapsedTime >= INoiseThreshold){
Inoise = (doubleRand() * knoise * sqrt(gNa * A));
elapsedTime = 0;
}
const double IIon = ((iNa + iK + iL) * A) + Inoise;
//...
}
}
return count;
Instead of comparing the floating point numbers directly, you could check if their differences are within an small epsilon to allow for rounding errors.
Instead of making the value of Inoise dependent on the condition, you could make the presence in the IIon formula dependent e.g.:
const double IIon = ((iNa + iK + iL) * A) + (elapsedTime >= INoiseThreshold) ? Inoise : 0;
just remember to reset elapsedTime once it surpassed the threshold.
I wrote the code in C++ which solves the time-dependent 1D Schrodinger equation for the anharmonic potential V = x^2/2 + lambda*x^4, using Thomas algorithm. My code is working and I animate the results in Mathematica, to check what is going on. I test the code against the known solution for the harmonic potential (I put lambda = 0), but the animation shows that abs(Psi) is changing with time, and I know that is not correct for the harmonic potential. Actually, I see that in one point it time it becomes constant, but before that is oscillating.
So I understand that I need to have constant magnitude of the wave function over the time interval, but I don't know how to do it, or where am I doing mistake.
Here is my code and the animation for 100 time steps and 100 points on the grid.
#include <iostream>
#include <iomanip>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <complex>
#include <fstream>
using namespace std;
// Mandatory parameters
const int L = 1; //length of domain in x direction
const int tmax = 10; //end time
const int nx = 100, nt = 100; //number of the grid points and time steps respectively
double lambda; //dictates the shape of the potential (we can use lambda = 0.0
// to test the code against the known solution for the harmonic
// oscillator)
complex<double> I(0.0, 1.0); //imaginary unit
// Derived parameters
double delta_x = 1. / (nx - 1);
//spacing between the grid points
double delta_t = 1. / (nt - 1);
//the time step
double r = delta_t / (delta_x * delta_x); //used to simplify expressions for
// the coefficients of the lhs and
// rhs of the matrix eqn
// Algorithm for solving the tridiagonal matrix system
vector<complex<double> > thomas_algorithm(vector<double>& a,
vector<complex<double> >& b,
vector<double>& c,
vector<complex<double> >& d)
{
// Temporary wave function
vector<complex<double> > y(nx + 1, 0.0);
// Modified matrix coefficients
vector<complex<double> > c_prime(nx + 1, 0.0);
vector<complex<double> > d_prime(nx + 1, 0.0);
// This updates the coefficients in the first row
c_prime[0] = c[0] / b[0];
d_prime[0] = d[0] / b[0];
// Create the c_prime and d_prime coefficients in the forward sweep
for (int i = 1; i < nx + 1; i++)
{
complex<double> m = 1.0 / (b[i] - a[i] * c_prime[i - 1]);
c_prime[i] = c[i] * m;
d_prime[i] = (d[i] - a[i] * d_prime[i - 1]) * m;
}
// This gives the value of the last equation in the system
y[nx] = d_prime[nx];
// This is the reverse sweep, used to update the solution vector
for (int i = nx - 1; i > 0; i--)
{
y[i] = d_prime[i] - c_prime[i] * y[i + 1];
}
return y;
}
void calc()
{
// First create the vectors to store the coefficients
vector<double> a(nx + 1, 1.0);
vector<complex<double> > b(nx + 1, 0.0);
vector<double> c(nx + 1, 1.0);
vector<complex<double> > d(nx + 1, 0.0);
vector<complex<double> > psi(nx + 1, 0.0);
vector<complex<double> > phi(nx + 1, 0.0);
vector<double> V(nx + 1, 0.0);
vector<double> x(nx + 1, 0);
vector<vector<complex<double> > > PSI(nt + 1,
vector<complex<double> >(nx + 1,
0.0));
vector<double> prob(nx + 1, 0);
// We don't have the first member of the left diagonal and the last member
// of the right diagonal
a[0] = 0.0;
c[nx] = 0.0;
for (int i = 0; i < nx + 1; i++)
{
x[i] = (-nx / 2) + i; // Values on the x axis
// Eigenfunction of the harmonic oscillator in the ground state
phi[i] = exp(-pow(x[i] * delta_x, 2) / 2) / (pow(M_PI, 0.25));
// Anharmonic potential
V[i] = pow(x[i] * delta_x, 2) / 2 + lambda * pow(x[i] * delta_x, 4);
// The main diagonal coefficients
b[i] = 2.0 * I / r - 2.0 + V[i] * delta_x * delta_x;
}
double sum0 = 0.0;
for (int i = 0; i < nx + 1; i++)
{
PSI[0][i] = phi[i]; // Initial condition for the wave function
sum0 += abs(pow(PSI[0][i], 2)); // Needed for the normalization
}
sum0 = sum0 * delta_x;
for (int i = 0; i < nx + 1; i++)
{
PSI[0][i] = PSI[0][i] / sqrt(sum0); // Normalization of the initial
// wave function
}
for (int j = 0; j < nt; j++)
{
PSI[j][0] = 0.0;
PSI[j][nx] = 0.0; // Boundary conditions for the wave function
d[0] = 0.0;
d[nx] = 0.0; // Boundary conditions for the rhs
// Fill in the current time step vector d representing the rhs
for (int i = 1; i < nx + 1; i++)
{
d[i] = PSI[j][i + 1]
+ (2.0 - 2.0 * I / r - V[i] * delta_x * delta_x) * PSI[j][i]
+ PSI[j][i - 1];
}
// Now solve the tridiagonal system
psi = thomas_algorithm(a, b, c, d);
for (int i = 1; i < nx; i++)
{
PSI[j + 1][i] = psi[i]; // Assign values to the wave function
}
for (int i = 0; i < nx + 1; i++)
{
// Probability density of the wave function in the next time step
prob[i] = abs(PSI[j + 1][i] * conj(PSI[j + 1][i]));
}
double sum = 0.0;
for (int i = 0; i < nx + 1; i++)
{
sum += prob[i] * delta_x;
}
for (int i = 0; i < nx + 1; i++)
{
// Normalization of the wave function in the next time step
PSI[j + 1][i] /= sqrt(sum);
}
}
// Opening files for writing the results
ofstream file_psi_re, file_psi_imag, file_psi_abs, file_potential,
file_phi0;
file_psi_re.open("psi_re.dat");
file_psi_imag.open("psi_imag.dat");
file_psi_abs.open("psi_abs.dat");
for (int i = 0; i < nx + 1; i++)
{
file_psi_re << fixed << x[i] << " ";
file_psi_imag << fixed << x[i] << " ";
file_psi_abs << fixed << x[i] << " ";
for (int j = 0; j < nt + 1; j++)
{
file_psi_re << fixed << setprecision(6) << PSI[j][i].real() << " ";
file_psi_imag << fixed << setprecision(6) << PSI[j][i].imag()
<< " ";
file_psi_abs << fixed << setprecision(6) << abs(PSI[j][i]) << " ";
}
file_psi_re << endl;
file_psi_imag << endl;
file_psi_abs << endl;
}
}
int main(int argc, char **argv)
{
calc();
return 0;
}
The black line is abs(psi), the red one is Im(psi) and the blue one is Re(psi).
(Bear in mind that my computational physics course was ten years ago now)
You say you are solving a time-dependent system, but I don't see any time-dependence (even if lambda != 0). In the Schrodinger Equation, if the potential function does not depend on time then the different equation is called separable because you can solve the time component and spatial component of the differential equation separately.
The general solution in that case is just the solution to the time-independent Schrodinger Equation multiplied by exp(-iE/h_bar). When you plot the magnitude of the probability that term just becomes 1 and so the probability doesn't change over time. In these cases people quite typically just ignore the time component altogether.
All this is to say that since your potential function doesn't depend on time then you aren't solving a time-dependent Schrodinger Equation. The Tridiagonal Matrix Algorithm can only be used to solve ordinary differential equations, whereas if your potential depended on time you would have a partial differential equation and would need a different method to solve it. Also as a result of that plotting the probability density over time is rarely interesting.
As for why your potential is not constant, numerical methods for finding eigenvalues and eigenvectors rarely produce the normalised eigenvectors naturally, so are you manually normalising your eigenvector before computing your probabilities?
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am writing a molecular dynamics program to create an lattice and populate it with atoms/molecules. These then are given random velocities and the system is initialized. Then throughout time the molecules interact with each other and exert forces on each other.
I've tried to make my program as readable as possible.
My issue is when the code is run, the values of everything I'm interested in, mainly the vectors _tempreture, _pressure, _totalEnergy, _interactionEnergy, _kineticEnergy all seem to converge (after 5 runs) to certain values. These values then do not change throughout the rest of the runs and sometimes will randomly spike, then drop back down.
I can't figure out the unexpected behavior of my code, and I've been looking at it hours upon hours. I hoping one of you bright guys will be able to help me.
//in MD.h
#ifndef MD_H
#define MD_H
#include <iostream>
#include <random>
#include <time.h>
#include <vector>
#include <string>
#include <fstream>
class MD{
public:
MD();
~MD();
void initLatice();
void simulate(int _runs);
void wrtieToFile(std::string fileName);
double randomValue(double upper, double lower);
private:
double _nMolecules;
double _estKineticEnergy;
double _dt;
double _density;
bool _tempscale;
double _energyCorrection;
double _pressureCorrection;
double _nFCC = 4;
double _truncationSeperation;
double _sidelength;
double _pi = 3.142;
std::vector<double> x_data, y_data, z_data;
std::vector<double> _vX, _vY, _vZ;
std::vector<double> _xPos, _yPos, _zPos;
std::vector<double> _totalEnergy, _kineticEnergy, _interactionEnergy, _pressure, _tempreture;
std::vector<double> _radialDist, _radialDistCoord;
};
#endif
in case anyone is wondering the next file doesn't contain the definition for writeToFile, I decided not to paste it on here to save space.
//in MD.cpp
#include "MD.h"
MD::MD() : _radialDist(201, 0.0), _radialDistCoord(201, 0.0) {
_dt = 0.005;
_density = 1.0;
_tempscale = true;
_nMolecules = pow(_nFCC, 3) * 4;
x_data = { 0.25, 0.75, 0.75, 0.25 };
y_data = { 0.25, 0.75, 0.25, 0.75 };
z_data = { 0.25, 0.25, 0.75, 0.75 };
_sidelength = pow((_nFCC / _density), 1. / 3.);
_truncationSeperation = 2.5;
if (_truncationSeperation > _sidelength / 2.0)
_truncationSeperation = _sidelength / 2.0;
_energyCorrection = (8.0 * _pi * _density)*(1.0 / (9.0 * pow(_truncationSeperation, 9)) - 1 / (3.0 * pow(_truncationSeperation, 3)));
_pressureCorrection = (16.0 * _pi * pow(_density, 2))*(2.0 / (9.0 * pow(_truncationSeperation, 9)) - 1 / (3.0 * pow(_truncationSeperation, 3)));
}
MD::~MD(){}
double MD::randomValue(double upper, double lower)
{
double returnValue;
do{
returnValue = upper + (rand() / (RAND_MAX / (lower - upper)));
} while (returnValue > upper || returnValue < lower);
return returnValue;
}
void MD::initLatice(){
int count = 0;
double x_init = 0, y_init = 0, z_init = 0;
double _tempreture = 1.0;
_estKineticEnergy = 0.5 * (3.0 * _nMolecules - 4.0) * _tempreture;
srand(time(NULL));
for (int i = 0; i < 4; i++){
for (int a = 1; a <= _nFCC; a++){
for (int b = 1; b <= _nFCC; b++){
for (int c = 1; c <= _nFCC; c++){
_xPos.push_back(_sidelength*(a - 1 + x_data[i]) / _nFCC);
_vX.push_back(randomValue(0.5, -0.5));
x_init += _vX[count] / _nMolecules;
_yPos.push_back(_sidelength*(b - 1 + y_data[i]) / _nFCC);
_vY.push_back(randomValue(0.5, -0.5));
y_init += _vY[count] / _nMolecules;
_zPos.push_back(_sidelength*(c - 1 + z_data[i]) / _nFCC);
_vZ.push_back(randomValue(0.5, -0.5));
z_init += _vZ[count] / _nMolecules;
count++;
}
}
}
}
double velocityScale = 0, kineticEnergy = 0;
for (int i = 0; i < _nMolecules; i++){
_vX[i] -= x_init;
_vY[i] -= y_init;
_vZ[i] -= z_init;
kineticEnergy += 0.5 * (pow(_vX[i], 2) + pow(_vY[i], 2) + pow(_vZ[i], 2));
}
velocityScale = sqrt(_estKineticEnergy / kineticEnergy);
for (int i = 0; i < _nMolecules; i++){
_vX[i] = _vX[i] * velocityScale;
_vY[i] = _vY[i] * velocityScale;
_vZ[i] = _vZ[i] * velocityScale;
}
}
void MD::simulate(int _runs){
double force = 0;
double seperationSquared = 0;
double interactionEnergy = 0;
double kineticEnergy = 0;
double pressure = 0;
for (int run = 0; run <= _runs; run++){
interactionEnergy = 0;
pressure = 0;
std::vector<double> force_x(256, 0.0);
std::vector<double> force_y(256, 0.0);
std::vector<double> force_z(256, 0.0);
for (int i = 0; i < _nMolecules - 1; i++){
double xI = _xPos[i], yI = _yPos[i], zI = _zPos[i];
for (int j = i + 1; j < _nMolecules; j++){
double x = xI - _xPos[j];
double y = yI - _yPos[j];
double z = zI - _zPos[j];
if (x > _sidelength / 2.0)
x -= _sidelength;
if (y > _sidelength / 2.0)
y -= _sidelength;
if (z > _sidelength / 2.0)
z -= _sidelength;
if (x < -_sidelength / 2.0)
x += _sidelength;
if (y < -_sidelength / 2.0)
y += _sidelength;
if (z < -_sidelength / 2.0)
z += _sidelength;
seperationSquared = pow(x, 2) + pow(y, 2) + pow(z, 2);
if (seperationSquared <= (pow(_truncationSeperation, 2))){
interactionEnergy += 4. * ((1. / pow(seperationSquared, 6)) - (1. / pow(seperationSquared, 3)));
force = 24. * ((2. / pow(seperationSquared, 7)) - (1. / pow(seperationSquared, 4)));
force_x[i] += x * force;
force_y[i] += y * force;
force_z[i] += z * force;
force_x[j] -= x * force;
force_y[j] -= y * force;
force_z[j] -= z * force;
pressure += force * seperationSquared;
int histCounter = ceil(sqrt(seperationSquared) * (200.0/_truncationSeperation));
_radialDist[histCounter] += 1.0;
}
}
}
//thermostating
double velocityScale = 0;
if (_tempscale == true){
kineticEnergy = 0;
for (int i = 0; i < _nMolecules; i++)
kineticEnergy += 0.5 * (pow(_vX[i], 2) + pow(_vY[i], 2) + pow(_vZ[i], 2));
velocityScale = sqrt(_estKineticEnergy / kineticEnergy);
}
else { velocityScale = 1.0; }
kineticEnergy = 0;
//applying verlets leapfrog algorithm
for (int i = 0; i < _nMolecules; i++){
_vX[i] = _vX[i] * velocityScale + force_x[i] * _dt;
_xPos[i] += _vX[i] * _dt;
_vY[i] = _vY[i] * velocityScale + force_y[i] * _dt;
_yPos[i] += _vY[i] * _dt;
_vZ[i] = _vZ[i] * velocityScale + force_z[i] * _dt;
_zPos[i] += _vZ[i] * _dt;
kineticEnergy += 0.5 * (pow(_vX[i], 2) + pow(_vY[i], 2) + pow(_vZ[i], 2));
//check if the particle is still within the box
if (_xPos[i] > _sidelength)
_xPos[i] -= _sidelength;
if (_yPos[i] > _sidelength)
_yPos[i] -= _sidelength;
if (_zPos[i] > _sidelength)
_zPos[i] -= _sidelength;
if (_xPos[i] < 0.0)
_xPos[i] += _sidelength;
if (_yPos[i] < 0.0)
_yPos[i] += _sidelength;
if (_zPos[i] < 0.0)
_zPos[i] += _sidelength;
}
_kineticEnergy.push_back(kineticEnergy / _nMolecules);
_interactionEnergy.push_back((interactionEnergy / _nMolecules) + _energyCorrection);
_totalEnergy.push_back(_kineticEnergy[run] + _interactionEnergy[run]);
if (_tempscale == true)
_tempreture.push_back(_nMolecules * 2. * _kineticEnergy[run] / (3.0 * _nMolecules - 4.0));
else
_tempreture.push_back(_nMolecules * 2. * _kineticEnergy[run] / (3.0 * _nMolecules - 3.0));
_pressure.push_back((2.0 * _kineticEnergy[run] * _nMolecules + pressure) / (3.0*(pow(_sidelength, 3) + _pressureCorrection)));
}
for (int i = 1; i <= 200; i++){
double r = i * _truncationSeperation / 200.0;
_radialDistCoord[i] = _radialDistCoord[i - 1] + 2.0 * _radialDist[i] * 10 / _runs / _nMolecules;
_radialDist[i] = _radialDist[i] / (2.0*_pi*r*r*(_truncationSeperation/200.0)*_density*_runs*_nMolecules);
}
}
and finally...
//in main.cpp
#include "MD.h"
int main(){
MD myMD;
myMD.initLatice();
myMD.simulate(400);
std::string fileName = "myFile.txt";
myMD.wrtieToFile(fileName);
return 0;
}
Many thanks!
I have written a global version of Particle Swarm Optimization algorithm in C++.
I tried to write it exactly as same as my MATLAB PSO code that have written before, but this code generates different and so worst answers.
The MATLAB code is:
clear all;
numofdims = 30;
numofparticles = 50;
c1 = 2;
c2 = 2;
numofiterations = 1000;
V = zeros(50, 30);
initialpop = V;
Vmin = zeros(30, 1);
Vmax = Vmin;
Xmax = ones(30, 1) * 100;
Xmin = -Xmax;
pbestfits = zeros(50, 1);
worsts = zeros(50, 1);
bests = zeros(50, 1);
meanfits = zeros(50, 1);
pbests = zeros(50, 30);
initialpop = Xmin + (Xmax - Xmin) .* rand(numofparticles, numofdims);
X = initialpop;
fitnesses = testfunc1(X);
[minfit, minfitidx] = min(fitnesses);
gbestfit = minfit;
gbest = X(minfitidx, :);
for i = 1:numofdims
Vmax(i) = 0.2 * (Xmax(i) - Xmin(i));
Vmin(i) = -Vmax(i);
end
for t = 1:1000
w = 0.9 - 0.7 * (t / numofiterations);
for i = 1:numofparticles
if(fitnesses(i) < pbestfits(i))
pbestfits(i) = fitnesses(i);
pbests(i, :) = X(i, :);
end
end
for i = 1:numofparticles
for j = 1:numofdims
V(i, j) = min(max((w * V(i, j) + rand * c1 * (pbests(i, j) - X(i, j))...
+ rand * c2 * (gbest(j) - X(i, j))), Vmin(j)), Vmax(j));
X(i, j) = min(max((X(i, j) + V(i, j)), Xmin(j)), Xmax(j));
end
end
fitnesses = testfunc1(X);
[minfit, minfitidx] = min(fitnesses);
if(minfit < gbestfit)
gbestfit = minfit;
gbest = X(minfitidx, :);
end
worsts(t) = max(fitnesses);
bests(t) = gbestfit;
meanfits(t) = mean(fitnesses);
end
In which, testfunc1 is:
function [out] = testfunc1(R)
out = sum(R .^ 2, 2);
end
The C++ code is:
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <ctime>
#define rand_01 ((float)rand() / (float)RAND_MAX)
const int numofdims = 30;
const int numofparticles = 50;
using namespace std;
void fitnessfunc(float X[numofparticles][numofdims], float fitnesses[numofparticles])
{
memset(fitnesses, 0, sizeof (float) * numofparticles);
for(int i = 0; i < numofparticles; i++)
{
for(int j = 0; j < numofdims; j++)
{
fitnesses[i] += (pow(X[i][j], 2));
}
}
}
float mean(float inputval[], int vallength)
{
int addvalue = 0;
for(int i = 0; i < vallength; i++)
{
addvalue += inputval[i];
}
return (float)(addvalue / vallength);
}
void PSO(int numofiterations, float c1, float c2,
float Xmin[numofdims], float Xmax[numofdims], float initialpop[numofparticles][numofdims],
float worsts[], float meanfits[], float bests[], float *gbestfit, float gbest[numofdims])
{
float V[numofparticles][numofdims] = {0};
float X[numofparticles][numofdims];
float Vmax[numofdims];
float Vmin[numofdims];
float pbests[numofparticles][numofdims];
float pbestfits[numofparticles];
float fitnesses[numofparticles];
float w;
float minfit;
int minfitidx;
memcpy(X, initialpop, sizeof(float) * numofparticles * numofdims);
fitnessfunc(X, fitnesses);
minfit = *min_element(fitnesses, fitnesses + numofparticles);
minfitidx = min_element(fitnesses, fitnesses + numofparticles) - fitnesses;
*gbestfit = minfit;
memcpy(gbest, X[minfitidx], sizeof(float) * numofdims);
for(int i = 0; i < numofdims; i++)
{
Vmax[i] = 0.2 * (Xmax[i] - Xmin[i]);
Vmin[i] = -Vmax[i];
}
for(int t = 0; t < 1000; t++)
{
w = 0.9 - 0.7 * (float) (t / numofiterations);
for(int i = 0; i < numofparticles; i++)
{
if(fitnesses[i] < pbestfits[i])
{
pbestfits[i] = fitnesses[i];
memcpy(pbests[i], X[i], sizeof(float) * numofdims);
}
}
for(int i = 0; i < numofparticles; i++)
{
for(int j = 0; j < numofdims; j++)
{
V[i][j] = min(max((w * V[i][j] + rand_01 * c1 * (pbests[i][j] - X[i][j])
+ rand_01 * c2 * (gbest[j] - X[i][j])), Vmin[j]), Vmax[j]);
X[i][j] = min(max((X[i][j] + V[i][j]), Xmin[j]), Xmax[j]);
}
}
fitnessfunc(X, fitnesses);
minfit = *min_element(fitnesses, fitnesses + numofparticles);
minfitidx = min_element(fitnesses, fitnesses + numofparticles) - fitnesses;
if(minfit < *gbestfit)
{
*gbestfit = minfit;
memcpy(gbest, X[minfitidx], sizeof(float) * numofdims);
}
worsts[t] = *max_element(fitnesses, fitnesses + numofparticles);
bests[t] = *gbestfit;
meanfits[t] = mean(fitnesses, numofparticles);
}
}
int main()
{
time_t t;
srand((unsigned) time(&t));
float xmin[30], xmax[30];
float initpop[50][30];
float worsts[1000], bests[1000];
float meanfits[1000];
float gbestfit;
float gbest[30];
for(int i = 0; i < 30; i++)
{
xmax[i] = 100;
xmin[i] = -100;
}
for(int i = 0; i < 50; i++)
for(int j = 0; j < 30; j++)
{
initpop[i][j] = rand() % (100 + 100 + 1) - 100;
}
PSO(1000, 2, 2, xmin, xmax, initpop, worsts, meanfits, bests, &gbestfit, gbest);
cout<<"fitness: "<<gbestfit<<endl;
return 0;
}
I have debugged two codes many times but can not find the difference which makes answers different.
It is making me crazy!
May you help me please?
Update:
Please consider that, the function mean is just used for reporting some information and is not used in the optimization procedure.
You've got integer division in the following line
w = 0.9 - 0.7 * (float) (t / numofiterations);
w will be 0.2 for every iteration, change it to
w = 0.9 - 0.7 * t / numofiterations;
The first multiplication will automatically promote t to a double the division should then promote numof iterations to a double.
The parenthesis means it will be done first and therefore not be promoted as wo integers is involved in the division.
This could be a mistake in function mean:
return (float)(addvalue / vallength);
This is integer division, so the result is truncated down, then cast to float. It is unlikely this is what you want.