蒙特卡罗(可能是模拟退火?)单位球面上N个相互排斥点的方法c++
Monte Carlo (Possibly Simulated Annealing?) Method For N Mutually Repelling Points on a Unit Sphere C++
我需要在c++中创建一个算法来使用蒙特卡罗方法模拟球体上相互排斥的点。到目前为止,我得到的是:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <time.h>
#include <stdlib.h>
using namespace std;
int main()
{
int a,f,g,n,m,i,j,k,r,s;
double p,q,Energy,energy,y[101][4],x[101][4],Length,Distance;
clock_t t1,t2;
t1=clock();
/* set the number of points */
n=12;
/* check that there are no more than 100 points */
if(n>100){
cout << n << " is too many points for me :-( n";
exit(0);
}
/* reset the random number generator */
srand((unsigned)time(0));
for (i=1;i<=n;i++){
x[i][1]=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0;
x[i][2]=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0;
x[i][3]=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0;
Length=sqrt(pow(x[i][1],2)+pow(x[i][2],2)+pow(x[i][3],2));
for (k=1;k<=3;k++){
x[i][k]=x[i][k]/Length;
}
}
/* calculate the energy */
Energy=0.0;
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
Distance=sqrt(pow(x[i][1]-x[j][1],2)+pow(x[i][2]-x[j][2],2)
+pow(x[i][3]-x[j][3],2));
Energy=Energy+1.0/Distance;
}
}
/* Save Original Points */
for(i=1;i<=n;i++){
y[i][1]=x[i][1];
y[i][2]=x[i][2];
y[i][3]=x[i][3];
}
/* Loop for random points m times*/
m=10;
if (m>100){
cout << "The m="<< m << " loop is inefficient...lessen m n";
exit(0);
}
a=1;
while(a<m){
/* assign random points */
for (i=1;i<=n;i++){
x[i][1]=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0;
x[i][2]=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0;
x[i][3]=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0;
Length=sqrt(pow(x[i][1],2)+pow(x[i][2],2)+pow(x[i][3],2));
for (k=1;k<=3;k++){
x[i][k]=x[i][k]/Length;
}
}
/* calculate the energy */
energy=0.0;
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
Distance=sqrt(pow(x[i][1]-x[j][1],2)+pow(x[i][2]-x[j][2],2)
+pow(x[i][3]-x[j][3],2));
energy=energy+1.0/Distance;
}
}
if(energy<Energy)
for(i=1;i<=n;i++){
for(j=1;j<=3;j++){
Energy=energy;
y[i][j]=x[i][j];
}
}
else
for(i=1;i<=n;i++){
for(j=1;j<=3;j++){
energy=Energy;
x[i][j]=y[i][j];
}
}
a=a+1;
}
/* Output the best random energy */
cout << "Energy=" << Energy << "n";
m=10;
a=1;
while(a<m){
/* Choose random point to move */
g=(rand() % n)+1;
/* Choose a p small to give q in a range -p <= q <= p */
p=0.1;
/* q is how much I am moving the random point by */
q=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0*p;
/* Move the point by q */
for(j=1;j<=3;j++){
x[g][j]=((x[g][j])+q);
}
/* Bring it back onto sphere */
Length=sqrt(pow(x[g][1],2)+pow(x[g][2],2)+pow(x[g][3],2));
for (k=1;k<=3;k++){
x[g][k]=x[g][k]/Length;
}
/* Calculate the new energy */
energy=0.0;
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
Distance=sqrt(pow(x[i][1]-x[j][1],2)+pow(x[i][2]-x[j][2],2)
+pow(x[i][3]-x[j][3],2));
energy=energy+1.0/Distance;
}
}
/* Choose best energy and therefore best point */
if (energy<Energy)
Energy=energy,x[g][1]=y[g][1],x[g][2]=y[g][2],x[g][3]=y[g][3];
else
energy=Energy,y[g][1]=x[g][1],y[g][2]=x[g][2],y[g][3]=x[g][3];
a=a+1;
}
/* Output the best single shift energy */
cout << "Energy=" << Energy << "n";
/* Set fail count to 0 */
s=0;
f=0;
r=1;
**p=0.1;**
/* Maximum distance to move the random point */
while (**p>0.00001**) {
/* Number of loops to do */
while (**r<3000**) {
g=(rand() % n)+1;
/* q is how much I am moving the random point by -p<=q<=p*/
q=((rand()*1.0)/(1.0*RAND_MAX)-0.5)*2.0*p;
/* Move the point by q */
for(j=1;j<=3;j++){
x[g][j]=((x[g][j])+q);
}
/* Bring it back onto sphere */
Length=sqrt(pow(x[g][1],2)+pow(x[g][2],2)+pow(x[g][3],2));
for (k=1;k<=3;k++){
x[g][k]=x[g][k]/Length;
}
/* Calculate the new energy */
energy=0.0;
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
Distance=sqrt(pow(y[i][1]-y[j][1],2)+pow(y[i][2]-y[j][2],2)
+pow(y[i][3]-y[j][3],2));
energy=energy+1.0/Distance;
}
}
/* Choose best energy and therefore best point */
if (energy<Energy)
Energy=energy,x[g][1]=y[g][1],x[g][2]=y[g][2],x[g][3]=y[g][3],s=s+1;
else
energy=Energy,y[g][1]=x[g][1],y[g][2]=x[g][2],y[g][3]=x[g][3],f=f+1;
r=r+1;
}
**/* Calculate percentage fails */
if ((100.0*(f/r))>50.0)
p=(p-0.00001);
else
p=p;**
r=0;
}
cout << "Overall Success Rate = " << ((s*1.0)/((s+f)*1.0))*100 << "%" << "n";
cout << "Energy=" << fixed << setprecision(10) << Energy << "n";
ofstream Bestpointssofar ("Bestpointssofar");
for(i=1;i<=n;i++){
Bestpointssofar << y[i][1] << " " << y[i][2] << " " << y[i][3] << "n";
}
Bestpointssofar.close();
t2=clock();
float diff ((float)t2-(float)t1);
float seconds = diff / CLOCKS_PER_SEC;
cout << fixed << setprecision(2) << "Run time: " << seconds << "(s)" << "n";
return 0;
}
我认为这是可以的(注意我基本上是在尽量减少能量函数),但我想使它更准确/使它运行得更快。要做到这一点,我认为我应该改变p的值,while循环条件或如何在代码末尾改变p。(所有这些都在*…*我试图鼓励他们让你明白我的意思。大约是代码的四分之三)。我已经坐了几个小时试图改变这些情况,但没有任何效果。对于n=12(球面上的12个点),我的能量应该是49.16525306,但实际上我只能得到50.5到54.0之间的能量。我知道这是相对较好的,但我希望它更准确(即使它确实需要一些时间)。如果可能的话,我也希望成功率能提高(我的总体成功率绝对令人震惊)。
如果有人有任何想法,我将非常感谢你的帮助!谢谢,a .
(注意:如果你想运行代码,你必须去掉两个*。
首先,你看起来像一个聪明的科学家/数学家,正在尝试做一些编程。我是一名物理学家,根据我的经验,这些人是最糟糕的程序员;如果可能的话,向有经验的程序员寻求帮助。
第二个,看看这个代码(重复,参见第一个):
/* Move the point by q */
for(j=1;j<=3;j++){
x[g][j]=((x[g][j])+q);
}
你对三个坐标的修改量相同,这意味着你总是沿着(1,1,1)射线移动一个点。如果每次修改一个坐标,结果会得到改善。
第三,在最后一个循环中(这是花费大部分时间的一个),你的逻辑有点混乱——你修改了x,但随后使用y计算能量。结果仍然很好,因为在循环结束时也有x和y的转置,但是纠正这个可以提高结果的准确性。
第四,这是一个大的,当你扰动一个点然后重新计算能量,你重新计算所有点的贡献;只有一个点改变了,这意味着大多数点对没有改变,不需要重新计算。相反,在选择一个点之后,可以这样计算该点的贡献:
double oldEnergy = 0.0;
for(i=1;i<=n;i++)
{
if(i!=g)
{
Distance=myDistance(x[i], x[g]);
oldEnergy += 1.0/Distance;
}
}
扰动后再计算,比较。这使得计算从O(n2)到O(n),这使得它更快。
当我做这些修改(并使p收敛速度快10倍,因为我不是很有耐心)我的能量为49.1652530576
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 枚举环境变量的惯用C++14/C++17方法
- 初始化具有非默认构造函数的std::数组项的更好方法