Reputation:
Suppose I have a function y of n variables x[0]..x[n-1]:
y = 1 + a[0][0]*x[0] + a[1][0]*x[0]^2 + a[0][1]*x[1] + a[1][1]*x[1]^2 + ...
I want to find values of variables x[0]..x[n-1], which minimize y. This optimization task will be performed by a genetic algorithm. The basic steps of the algorithm are:
Below is the code of two classes that implement the above algorithm:
The class Solution, which describes an individual solution x[0]..x[n-1], the y value, associated with this solution, and the function y = F(x[0],..,x[n-1]).
The class Pool, which describes the pool of different solutions along with the functions of selection, breeding and mutation.
Here is the code:
class Solution
{
double *x;
double y;
double **a; // the same for all instances
int n; // the same for all instances
public:
Solution(int,double*);
~Solution();
double yFunc();
}
class Pool
{
vector<Solution> sols;
int poolSize;
// other private members
public:
Pool(int,int,double*);
~Pool();
// other public functions
}
// construct Solution
Solution::Solution(int numX,double **coef)
{
n=numX;
// allocate memory for coefficients
a = new double*[2];
for(int i=0;i<2;i++) a[i] = new double[n];
// assign coefficients
for(int i=0;i<2;i++)
for(int j=0;j<n;j++)
a[i][j] = coef[i][j];
// generate a random solution in [-1,+1] range
srand(time(0));
for(int j=0;j<n;j++)
x[j] = 2.0*(rand()/(double)RAND_MAX-0.5);
}
// destroy Solution
Solution::~Solution()
{
delete[] x;
for(int i=0;i<2;i++) delete[] a[i];
delete[] a;
}
// define optimized function
double Solution::yFunc()
{
double sum=1.0;
for(int j=0;j<n;j++)
sum += a[0][j]*x[j]+a[1][j]*x[j]*x[j];
return sum;
}
// construct Pool
Pool::Pool(int numSols, int numX, double **coef)
{
poolSize = numSols;
for(int i=0;i<poolSize;i++)
{
Solution sol = new Solution (numX,coef);
sols.push_back(sol);
}
}
I have only one question:
When I construct the pool of solutions, I create many instances of class Solution with their individual vectors x[0]..x[n-1] and the corresponding function value y. However, the a[][] coefficients of the function y = F(x[0],..,x[n-1]) and the function itself also get instantiated poolSize times even though they are the same for all solution vectors.
How can I modify the code such that only single instances of a[][],F(x[0],..,x[n-1]), and n are created? I heard about static members, but as I understand, a user is not allowed to assign their values through an external function call. These static members can only to be initialized within a class or a static Solution() function that does not except any arguments.
Even if there is a way to initialize these static members with external user-provided values, they are not multi-thread safe. So, I am looking for a way to separate the shared members of class Solution from the individual members, to avoid instantiation of the shared members poolSize times.
Upvotes: 2
Views: 1383
Reputation: 4174
Looking at what you're trying to do, it might be simpler to regard the a/n values as being something else... How about:
class Target
{
public:
double **a; // the same for all instances
int n; // the same for all instances
Target(int,double **);
~Target();
};
class Solution
{
double *x;
double y;
Target *t
public:
Solution(Target *t);
~Solution();
double yFunc();
}
class Pool
{
vector<Solution> sols;
int poolSize;
// other private members
public:
Pool(int,int,double*);
~Pool();
// other public functions
}
// construct Solution
Target::Target(int numX,double **coef)
{
n=numX;
// allocate memory for coefficients
a = new double*[2];
for(int i=0;i<2;i++) a[i] = new double[n];
// assign coefficients
for(int i=0;i<2;i++)
for(int j=0;j<n;j++)
a[i][j] = coef[i][j];
}
Solution::Solution(Target *in_t)
{
t=in_t;
// generate a random solution in [-1,+1] range
srand(time(0));
for(int j=0;j<t->n;j++)
x[j] = 2.0*(rand()/(double)RAND_MAX-0.5);
}
// destroy Solution
Target::~Target()
{
for(int i=0;i<2;i++) delete[] a[i];
delete[] a;
}
Solution::~Solution()
{
delete[] x;
}
// define optimized function
double Solution::yFunc()
{
double sum=1.0;
for(int j=0;j<t->n;j++)
sum += t->a[0][j]*x[j]+t->a[1][j]*x[j]*x[j];
return sum;
}
// construct Pool
Pool::Pool(int numSols, int numX, double **coef)
{
poolSize = numSols;
Target target(numX,coef);
for(int i=0;i<poolSize;i++)
{
Solution sol = new Solution (&target);
sols.push_back(sol);
}
}
Now you have a Target object, and a Solution, created with reference to the Target.
Upvotes: 0
Reputation: 116674
It sounds like you've picked up some C# or Java hearsay and got it confused with C++.
There is no "static constructor" feature in C++. On the other hand, there is no problem with assigning to static member variables in any of these languages. And finally, it isn't a good solution to your problem in any case!
Firstly, use std::vector
consistently wherever you are tempted to call new[]
. The whole point of std::vector
is to make manually allocated arrays unnecessary.
To actually solve your problem, you need to put the shared data in a separate object, which then all the other objects hold a pointer to. The simplest way to do this in C++ so that the shared object is deleted when no longer needed is to use boost's shared_ptr
, also known as std::tr1::shared_ptr
in current compilers/libraries.
Or for amusement, you could implement the same thing yourself. Just put an integer counter in the shared class. Every time a new client takes a pointer to the shared object of that class, they increment the counter. And in their destructor (or when they clear the pointer) then decrement the counter first. When the counter falls to zero, delete the shared object.
class SharedThing
{
int needed;
// other data
public:
SharedThing()
: needed(1) { }
SharedThing *share()
{
needed++;
return this;
}
void release()
{
if (--needed == 0)
delete this;
}
};
SharedThing *a = new SharedThing();
SharedThing *b = a->share();
SharedThing *c = b->share();
// a, b, and c all point to the same object,
// which now internally has a 'needed' count of 3
a->release(); // down to 2
b->release(); // down to 1
c->release(); // deleted
From the perspective of each local piece of code with a pointer to SharedThing
, after calling release on it, you should assume it has been deleted.
The shared_ptr
template class makes this facility reusable, so you don't have to manually call or implement share
or release
.
Update again
Based on the information you've added, it looks like the shared data has the same lifetime as an object of the class Pool
. So make Pool
the owner of it, responsible for allocating it (and setting it up) and also deleting it.
And I repeat, use std::vector<T>
, not raw new T[]
arrays.
Upvotes: 0
Reputation:
Without much experience with static members, here is how I modified my code. (The static members **a and n of Solution are initialized inside the Pool constructor)
class Solution
{
double *x;
double y;
static double **a; // the same for all instances
static int n; // the same for all instances
public:
static void StaticSet(int,double**)
Solution();
~Solution();
double yFunc();
}
// assign static variables
Solution::StaticSet(int numX,double **coef)
{
n=numX;
// allocate memory for coefficients
a = new double*[2];
for(int i=0;i<2;i++) a[i] = new double[n];
// assign coefficients
for(int i=0;i<2;i++)
for(int j=0;j<n;j++)
a[i][j] = coef[i][j];
}
// construct Solution
Solution::Solution()
{
// generate a random solution in [-1,+1] range
srand(time(0));
for(int j=0;j<n;j++)
x[j] = 2.0*(rand()/(double)RAND_MAX-0.5);
}
// construct Pool
Pool::Pool(int numSols, int numX, double **coef)
{
poolSize = numSols;
Solution::StaticSet(numX,coef);
for(int i=0;i<poolSize;i++)
sols.push_back(new Solution());
}
Is that correct?
Upvotes: 0
Reputation: 133008
I heard about static members, but as I understand, a user is not allowed to assign their values through an external function call.
Wrong.
class A
{
public:
static int x_;
static void StaticSetX(int x) { x_ = x; }
void NeedInstanceSetX(int x) { x_ = x; }
};
int main()
{
// an instance of A can access both static methods and non static
A a;
a.NeedInstanceSetX(1);
a.StaticSetX(2);
A::NeedInstanceSetX(4); // Compiler error, method not static
A::StaticSetX(3); // Ok, StaticSetX() is a static method
return 0;
}
Upvotes: 0
Reputation:
Your understanding of statics appears to be a bit off. A static variable is simply one that is shared by all instances of the class. You can access it as you would any non-static variable, but you can also access it without a class instance.
The topic is perhaps a bit broad for a SO answer, and is best addressed by a good C++ text book - which one are you using? Perhaps if you tried to modify your code to use statics and then posted questions regarding the problems you were having, we could help more.
Upvotes: 1