不可重复的2D矢量问题

时间:2010-07-04 14:08:35

标签: c++

我正在编写一个小程序来计算物理问题,但是我在从二维数组中擦除元素时遇到了问题。我正在使用XCode编译(所以GDB)。

问题总是出现在walker.erase(walker.begin()+ loacationInArray)部分(在void diffuseWalkers函数中),并且总是经过不同数量的函数调用。所以有时,“热化”循环可能会运行50次,有时则会一直运行。我经常收到一个EXC_BAD_ACCESS错误,偶尔会出现malloc错误。

任何帮助都会非常感激,因为我已经尝试了所有的东西而且真的看不出我做错了什么。我已经发布了以下代码。名为'heliumHeader.h'的头文件包含一些对我的问题不重要的数学函数。

    #include "heliumHeader.h"


    void copyVectorInformation(vector<double>& walker, vector<double>& walkerTemp);
    void diffuseWalker(double beta, double a, double alpha, int locationInArray, vector<double>& walker, double dt, 
           double& trialEnergy, int& numberOfWalkers, int targetNumberOfWalkers);
    using namespace std;

    int main(){


 srand(time(NULL));

 double s=0.; //inter-molecular distance
 double beta = 0.15;
 double alpha = 2.;
 double dt=0.1; 
 int numberOfWalkers = 1; //number of particles
 int targetNumberOfWalkers = numberOfWalkers;

 //2D-vectors to hold information
 vector<vector<double> > walker(numberOfWalkers,6); 

 //solve for a
 double a = 1.;
 for(int i=0; i<20;i++)
  a = 1./(1.+exp(-s/a));

 //set up sums
 double localEnergy, trialEnergy, localEnergy2, trialEnergy2;
 localEnergy = trialEnergy = localEnergy2 = trialEnergy2 = 0.;

 //put the walkers randomly in space & get the energy of that configuration
 for(int i=0; i<walker.size(); i++){
  for(int j=0; j<6; j++)
   walker[i][j]=randomPositiveNegative();
  localEnergy += calculateEnergy(beta, alpha, a, walker[i]);
 }

 localEnergy /= numberOfWalkers;

 double beforeEnergy = localEnergy;
 cout << "local energy of random " << localEnergy << endl;
 trialEnergy = -2.903;

 //move the walkers
 for(int thermalisationCounter = 1; thermalisationCounter<1000; thermalisationCounter++){
  for(int i=0; i<walker.size(); i++)
   diffuseWalker(beta, a, alpha, i, walker[i], dt, trialEnergy, numberOfWalkers, targetNumberOfWalkers);
  cout << thermalisationCounter << endl;
 }

 //recalculate the local energy
 for(int i=0; i<walker.size(); i++){
  for(int j=0; j<6; j++)
   localEnergy += calculateEnergy(beta, alpha, a, walker[i]);
 }

 localEnergy /= numberOfWalkers;

 for(int numberOfSteps = 1; numberOfSteps<1000; numberOfSteps++){
  for(int i=0; i<walker.size(); i++)
   diffuseWalker(beta, a, alpha, i, walker[i], dt, trialEnergy, numberOfWalkers, targetNumberOfWalkers);
  cout << numberOfSteps << endl;
 }

 //get initial energy of random positiions
 for(int i=0; i<walker.size(); i++)
  localEnergy += calculateEnergy(beta, alpha, a, walker[i]);

 localEnergy /= numberOfWalkers;

 cout << "before energy " << beforeEnergy << " local energy " << localEnergy << 
 " trial energy " << trialEnergy << " number " << numberOfWalkers << endl;

 return 0;
    }


    void copyVectorInformation(vector<double>& walker, vector<double>& walkerTemp){
     for(int i=0; i<6; i++)
      walkerTemp[i] = walker[i];
    }//end of copyVectorInformation

    void diffuseWalker(double beta, double a, double alpha, int locationInArray, vector<double>& walker, double dt, 
           double& trialEnergy, int& numberOfWalkers, int targetNumberOfWalkers){

 vector<double> driftFunction(6);
 vector<double> walkerTemp(6); //temporary store of information

 //copy the walker information over
 copyVectorInformation(walker, walkerTemp);

 //get the drift functions
 calculateDriftFunctions(beta, alpha, a, walker, driftFunction);

 //get the old local energy
 double preMoveLocalEnergy = calculateEnergy(beta, alpha, a, walker);

 //move the walker
 for(int j=0; j<6;j++)
  walker[j] += 0.5*dt*driftFunction[j] + randomGauss()*sqrt(dt);

 //caclulate the local energy of the new position
 double postMoveLocalEnergy = calculateEnergy(beta, alpha, a, walker);

 //calculate the weight, q and branching ration s
 double q = exp(-dt*(0.5*(postMoveLocalEnergy + preMoveLocalEnergy) - trialEnergy));
 double s = q+randomPositive();

 if(int(s)<1){
  //kill the walker 
  walker.erase(walker.begin()+locationInArray);
  numberOfWalkers--;
 }
 else{
  //reproduce walker int(s) number of times
  for(int k=0; k<int(s); k++){
   walker.push_back(walker[locationInArray]);
   numberOfWalkers++;
  }
 }

 //update the trial energy
 trialEnergy += 0.2*log((double)targetNumberOfWalkers/(double)numberOfWalkers);

    }//end of diffuse walkers

4 个答案:

答案 0 :(得分:1)

你有:

 if(int(s)<1){
  //kill the walker 
  walker.erase(walker.begin()+locationInArray);
  numberOfWalkers--;
 }

假设

(int(s) < 1)

总是如此(总是擦除)然后

 //move the walkers
 for(int thermalisationCounter = 1; thermalisationCounter<1000; thermalisationCounter++){
  for(int i=0; i<walker.size(); i++)
   diffuseWalker(beta, a, alpha, i, walker[i], dt, trialEnergy, numberOfWalkers, targetNumberOfWalkers);
  cout << thermalisationCounter << endl;
 }

将删除所有对角线元素。这是你的意图吗?也许您将行索引与列索引(或1D与2D)混合在一起?

无论如何,问题是locationInArray太大了,你正在删除不再在向量中的项目。

答案 1 :(得分:0)

我认为你的问题在于矢量的大小是动态的。当你打电话给.erase时,你看起来像是在循环中。如果你在中间擦掉一些东西,并继续在元素中循环,那么随之而来的奇怪就会让我感到惊讶。

答案 2 :(得分:0)

我认为你正在从错误的向量中删除。在main函数walker中是2D向量。在diffuseWalker中,您正在从已传递到函数的walker中删除,该函数是双向的一维向量。您在这里使用locationInArray并递减numberOfWalkers这对于1D walker没有意义 - 看起来您想要实际从2D矢量中删除。我建议为2D和1D矢量使用不同的名称,以避免这样的混淆。

答案 3 :(得分:0)

是的 - 非常感谢。这是真的,我正在删除数组的诊断元素,我在另一个程序中做了一个小得多的玩具示例。

我通过将函数传递给完整的2D向量来解决它,因此当我擦除walker(walker.begin()+locationInArray)时,迭代器引用i向量的第一个索引“walker[i][j]”。之前,当我刚刚将它作为1D向量(基本上是'j'索引片段)传递时,如果'locationInArray&gt; = 6'为0&lt;&lt; 0&lt; = j&lt; = 5。

非常感谢你的回答。