0

I am currently learning c++ and was trying to write code that will find the minima of a function. I have put my starting points in vectors p0,p1,p2 and stored those set of points in a vector which I have called pmatrix.

I am trying to pass this pmatrix as an argument when I am creating an object of the simplex class. When I wrote the code below my hope was that I had correctly passed the pmatrix, by reference, into the constructor properly as no errors came up.

However, after calling the evaluate method which changes pmatrix, printing the values inside and outside of the class definition, it has not changed in the main scope and somewhere 2 separate copies of pmatrix exist. How do I make sure that the changes the methods do to pmatrix act on the one I have defined in the main scope?


#include <iostream>
#include <vector>

class Simplex {
    std::vector<std::vector<double>> pmatrix;
    double (*F)(double x_0,double x_1);

    public:
        Simplex(std::vector<std::vector<double>> &pmatrix,double (*func)(double,double)){
            this->pmatrix = pmatrix;
            F=func;
        }

        void evaluate(){
           for (int i=0; i<pmatrix.size();i++){
               std::vector<double> p_i;
               p_i=pmatrix[i];
               p_i[p_i.size()-1]=F(p_i[0],p_i[1]);
               pmatrix[i]=p_i;


            }
        }
        void test(){
            std::cout<<"pmatrix[i][2] elements inside the class def is "<<pmatrix[0][2]<<" "<<pmatrix[1][2]<<" "<<pmatrix[2][2]<<"\n";




        }

};
//defining rosenbrocks parabolic valley
double rpv (double x1, double x0){
    return 100*(x0-(x1*x1))*(x0-(x1*x1))+(1-x0)*(1-x0);
}
int main()
{
    std::vector<double> p0 = {0,0,1};
    std::vector<double> p1 = {2,0,2};
    std::vector<double> p2 = {0,2,3};
    std::vector<std::vector<double>> pmatrix = {p0,p1,p2};

    Simplex simplex(pmatrix,rpv);
    simplex.evaluate();

    std::cout<<"pmatrix[i][2] elements from pmatrix in main "<<pmatrix[0][2]<<" "<<pmatrix[1][2]<<" "<<pmatrix[2][2]<<"\n";
    simplex.test();



return 1;
}

output

pmatrix[i][2] elements from pmatrix in main 1 2 3
pmatrix[i][2] elements inside the class def is 1 1601 401
8
  • unrelated to your problem: if your points have 3 coordinates then consider creating a struct Point { int x, y, z; } and then have std::vector<Point>. Commented Apr 20, 2020 at 20:15
  • Apart from readability, is there any benefit to doing so? Commented Apr 20, 2020 at 20:24
  • @V.Jain Readability is an important part of your code. Keep it simple, and whenever you can combine such things into a struct, it is a good idea to do so. Commented Apr 20, 2020 at 20:28
  • @V.Jain Also, you can using the following statement: using PointsMatrix = std::vector<Point> to make it even tidier! Commented Apr 20, 2020 at 20:30
  • @Kerek I don't recommend that. Why is Point.push_back()? It doesn't make sense. Commented Apr 20, 2020 at 20:46

2 Answers 2

1

Make Simplex::pmatrix a reference, and initialize it in your constructor's member initializer list. References need to be assigned their referent on construction, so by the time you're in the body of your constructor it's too late; all members have been default constructed already.

That's what the member initializer list is for. You should get into the habit of using it even when not forced in situations like these.

class Simplex {
    std::vector<std::vector<double>>& pmatrix; // <-- this is a ref now
    double (*F)(double x_0,double x_1);

    public:
        Simplex(std::vector<std::vector<double>> &otherpmatrix,
                double (*func)(double,double))
        : pmatrix(otherpmatrix)
        , F(func)
        { }

    // other various Simplex things...
}

This should be fine as long as you manage the lifetimes of Simplex and pmatrix and ensure that pmatrix isn't destroyed before Simplex.

Sign up to request clarification or add additional context in comments.

9 Comments

Can you clarify on your syntax, I tried to change my simplex class as you suggested by changing the line: std::vector<std::vector<double>> pmatrix; to std::vector<std::vector<double>> &pmatrix; Simplex(std::vector<std::vector<double>> pmatrix,double (*func)(double,double)) to Simplex(std::vector<std::vector<double>> &otherpmatrix,double (*func)(double,double)) and this->pmatrix=pmatrix; to this->pmatrix=otherpmatrix;. This gives me an error.
I appreciate that comment is difficult to read, if you could edit your answer so that I can compile the code with error I would appreciate it.
What error did you get? Note that I'm using an initialization list (the stuff between : and { after the function parameters.
The name change to otherpmatrix was just so I could keep the member variable and parameter separate in my head. I don't like function parameters having the same name as member variables. Feel free to keep it as pmatrix if you like.
Because only a reference can reference another variable. Your pmatrix wasn't originally a reference. It was a pmatrix. A pmatrix can't reference a pmatrix. Only a pmatrix& can reference a pmatrix. The other option is to to have your Simplex be responsible for constructing the pmatrix, and then you can pull a reference to it in your main. But the original needs to be somewhere. They can't both be pmatrix and they can't both be pmatrix&.
|
0

It really depends on who is the owner of pmatrix. If it only uses pmatrix, I would use:

std::vector<Point>& pmatrix;

And pass it as reference in the ctor. It is also possible to keep it as a pointer, which means that it can be nullptr, and we don't own it.

On the case where there is no one true owner, and it should be shared, you should use std::shared_ptr which means that it won't be destroyed while in use in the Simplex:

struct Point
{
    double x;
    double y;
    double z;
};

using PointList = std::vector<Point>;

using FunctionPtr = double(*)(double, double);

class Simplex 
{
    std::shared_ptr<PointList> pmatrix;
    FunctionPtr F; // find a better name for it!

public:
    Simplex(const std::shared_ptr<PointList>& otherpmatrix,
            FunctionPtr func) : 
        pmatrix(otherpmatrix), 
        F(func)
    {
    }
};

double rpv (double x1, double x0){
    return 100*(x0-(x1*x1))*(x0-(x1*x1))+(1-x0)*(1-x0);
}

int main()
{
    auto pmatrix = std::shared_ptr<PointList>(new PointList());
    pmatrix->push_back({0,0,1});
    pmatrix->push_back({2,0,2});
    pmatrix->push_back({0,2,3});

    Simplex simplex(pmatrix, &rpv);
}

This denotes that you have a shared ownership of this object.

1 Comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.