Ising 1-Dimensional C - program - c

i am trying to simulate the Ising Model 1-D. This model consists in a chain of spin (100 spins) and using the Mont Carlo - Metropolis to accept the flip of a spin if the energy of the system (unitary) goes down or if it will be less than a random number.
In the correct program, both the energy the magnetization go to zero, and we have the results as a Gaussian (graphics of Energyor the magnetization by the number of Monte Carlo steps).
I have done some work but i think my random generator isn't correctt for this, and i don't know how/where to implement the boundary conditions: the last spin of the chain is the first one.
I need help to finish it. Any help will be welcome. Thank you.
I am pasting my C program down:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h> //necessary for function time()
#define LENGTH 100 //size of the chain of spins
#define TEMP 2 // Temperature in units of J
#define WARM 200 // Termalização
#define MCS 20000 //Monte Carlo Steps
void start( int spin[])
{
/* starts with all the spins 1 */
int i;
for (i = 0 ; i < 100; i++)
{
spin[i] = 1;
}
}
double energy( int spin[]) //of the change function J=1
{
int i;
double energyX=0;// because the begining Energy = -J*sum (until 100) =-100,
for (i = 0;i<100;i++)
energyX=energyX-spin[i]*spin[i+1];
return(energyX);
}
int randnum(){
int num;
srand(time(NULL));
/* srand(time(NULL)) objectives to initiate the random number generator
with the value of the function time(NULL). This is calculated as being the
total of seconds passed since january first of 1970 until the present date.
So, this way, for each execution the value of the "seed" will be different.
*/
srand(time(NULL));
//picking one spin randomly zero to 100
num=rand() % 100;
printf("num = %d ", num);
return num;
}
void montcarlo( int spin[])
{
int i,j,num;
double prob;
double energyA, energyB; // A -> old energy and B -> the new energy
int rnum1,rnum2;
prob=exp(-(energyB-energyA)/TEMP);
energyA = 0;
energyB = 0;
for (i = 0;i<100;i++)
{
for (j = 0;j<100;j++)
{
energyA=energy(spin);
rnum1=randnum();
rnum2=randnum(); // i think they will give me different numbers
spin[rnum1] = -spin[rnum1]; //flip of the randomly selected spin
energyB = energyB-spin[j]*spin[j+1];
if ((energyB-energyA<0)||((energyB-energyA>0)&&(rnum2>prob))){ // using rnum2 not to be correlated if i used rnum1
spin[rnum1]=spin[rnum1];} // keep the flip
else if((energyB-energyA>0)&&(rnum2<prob))
spin[rnum1]=-spin[rnum1]; // unflip
}
}
}
int Mag_Moment( int spin[] ) // isso é momento magnetico
{
int i;
int mag;
for (i = 0 ; i < 100; i++)
{
mag = mag + spin[i];
}
return(mag);
}
int main()
{
// starting the spin's chain
int spin[100];//the vector goes til LENGHT=100
int i,num,j;
int itime;
double mag_moment;
start(spin);
double energy_chain=0;
energy_chain=energy(spin); // that will give me -100 in the begining
printf("energy_chain starts with %f", energy_chain);// initially it gives -100
/*Warming it makes the spins not so ordered*/
for (i = 1 ; i <= WARM; i++)
{
itime = i;
montcarlo(spin);
}
printf("Configurtion after warming %d \n", itime);
for (j = 0 ; j < LENGTH; j++)
{
printf("%d",spin[j]);
}
printf("\n");
energy_chain=energy(spin); // new energy after the warming
/*openning a file to save the values of energy and magnet moment of the chain*/
FILE *fp; // declaring the file for the energy
FILE *fp2;// declaring the file for the mag moment
fp=fopen("energy_chain.txt","w");
fp2=fopen("mag_moment.txt","w");
int pures;// net value of i
int a;
/* using Monte Carlo metropolis for the whole chain */
for (i = (WARM + 1) ; i <= MCS; i++)
{
itime=i;//saving the i step for the final printf.
pures = i-(WARM+1);
montcarlo(spin);
energy_chain = energy_chain + energy(spin);// the spin chain is moodified by void montcarlo
mag_moment = mag_moment + Mag_Moment(spin);
a=pures%10000;// here i select a value to save in a txt file for 10000 steps to produce graphs
if (a==0){
fprintf(fp,"%.12f\n",energy_chain); // %.12f just to give a great precision
fprintf(fp2,"%.12f\n",mag_moment);
}
}
fclose(fp); // closing the files
fclose(fp2);
/* Finishing -- Printing */
printf("energy_chain = %.12f\n", energy_chain);
printf("mag_moment = %.12f \n", mag_moment);
printf("Temperature = %d,\n Size of the system = 100 \n", TEMP);
printf("Warm steps = %d, Montcarlo steps = %d \n", WARM , MCS);
printf("Configuration in time %d \n", itime);
for (j = 0 ; j < 100; j++)
{
printf("%d",spin[j]);
}
printf("\n");
return 0;
}

you should call srand(time(NULL)); only once in your program. Every time you call this in the same second you will get the same sequence of random numbers. So it is very likely that both calls to randnum will give you the same number.
Just add srand(time(NULL)); at the begin of main and remove it elsewhere.

I see a number of bugs in this code, I think. The first one is the re-seeding of the srand() each loop which has already been addressed. Many of the loops go beyond the array bounds, such as:
for (ii = 0;ii<100;ii++)
{
energyX = energyX - spin[ii]*spin[ii+1];
}
This will give you spin[99]*spin[100] for the last loop, for which is out of bounds. That is kind of peppered throughout the code. Also, I noticed the probability rnum2 is an int but compared as if it's supposed to be a double. I think dividing the rnum2 by 100 will give a reasonable probability.
rnum2 = (randnum()/100.0); // i think they will give me different numbers
The initial probability used to calculate the spin is, prob=exp(-(energyB-energyA)/TEMP); but both energy values are not initialized, maybe this is intentional, but I think it would be better to just use rand(). The Mag_Moment() function never initializes the return value, so you wind up with a return value that is garbage. Can you point me to the algorithm you are trying to reproduce? I'm just curious.

Related

Exactly one high card in a 6 card hand using simulations

So I've got a probability problem that (out of pure boredom) I decided to try and solve using simulations.
Problem: What is the probability of drawing exactly one high card in a 6 card hand.
Now, this problem is specifically about some game that's played in my country so for some weird reason there are 21 high cards, but that's not important.
Solving this problem by hand, using basic combinatorics I got:
And now, here's the way I simulated it in C:
The main function:
int main(void)
{
srand(time(0));
int deck[52];
int i;
for(i = 0; i<21; i++) deck[i] = 1;
for(i = 21; i<52; i++) deck[i] = 0;
int n;
printf("# of simulations: ");
scanf("%d", &n);
int memo[52];
int hits = 0;
for(i = 0; i<n; i++){
clear_memo(memo);
hits += simulate(deck, memo);
}
printf("Result: %lf\n", (double)hits/n);
}
So the deck is an array of 52 numbers where the first 21 have the value 1 (high cards) and the other 31 elements have the value 0 (low cards).
The memo will be sent to the simulation function each time to keep track of which cards have already been drawn. The memo also gets reset every time using the clear_memo function which does nothing but set all the values to zero.
Then it calls the simulation functions and counts the hits.
Here's the simulation function:
int simulate(int * deck, int * memo){
//I draw the first card separetly in order to initialize the had_high variable
int index = ( rand() % 52 );
int card = deck[index];
int had_high = (card == 1);
memo[index] = 1;
//printf("%d ", index);
int i = 1;
while(i < 6){
int draw = (rand() % 52);
//printf("%d ", draw);
if(memo[draw]) continue;
index = draw;
card = deck[index];
memo[index] = 1;
if(card){
if(had_high) { //meaning there are 2 high cards, no hit
//printf("\n");
return 0;
}
had_high = 1; //if not, then this is the first high card
}
i++;
}
printf("\n");
return had_high; //the function would've reached this point even if all the cards had been low
//therefore I return had_high instead of just 1
}
The simulation function itself works, I've tested it separately a lot of times and there seem to be no problems with it.
However, when I run the program with a high number of simulations (100k or 1m) the result is always approx. 0.175 which is not what I got with my by hand calculation.
I am reasonably certain that my by hand calculation is correct (but correct me if I'm wrong there as well).
If I'm right about the by hand calculations then there must be something wrong with how I simulated this event. One of my thoughts was that it had something to do with the rand function and how it's pseudo-random, but I really don't know as it is very hard to test anything that works with random numbers.
Any ideas?
Thanks.
EDIT:
As per request of klutt:
void clear_memo(int * memo){
int i = 0;
for(;i<52;i++) memo[i] = 0;
}
My program gives the same result as yours - about 0.175
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
int deck[52];
int successes = 0;
srand((unsigned)time(NULL));
for(int run = 0; run < 100000; run++) {
for(int n = 0; n<52; n++) {
deck[n] = n;
}
int cards = 52;
int highs = 0;
for(int n=0; n<6; n++) {
int index = rand() % cards;
if(deck[index ] < 21) {
highs++;
}
deck[index] = deck[--cards];
}
if(highs == 1) {
successes++;
}
}
printf("Probability of drawing exactly one high card = %f\n", successes / 100000.0);
}
But the combinatrics are wrong in two ways:
There are only 31 "low" cards in the pack so the expression should be
21 31 30 29 28 27
__ . __ . __ . __ . __ . __ = 0.02921
52 51 50 49 48 47
Secondly, any of the 6 draws can be a "high", not just the first, so
multiply the chance by 6.
0.02921 * 6 = 0.1752
Your calculation is wrong
What you are calculating is the probability that the first card is high and all of the rest are low. Or at least it seams that you're trying to do so. You're slightly off. It should be (21/52)*(31/51)*(30/50)*(29/49)*(28/48)*(27/47) = 0.02921...
You should multiply this by 6, since the high card can appear anywhere. Then you have the probability for exactly one high, which is 0.17526
rand() % n has a non-uniform distribution
That being said, be aware that the random generator in C is not very good to use in this way. Depending on how you use it it can get a horrible distribution. If you are using C++, you can use:
std::random_device rd;
std::default_random_engine generator(rd());
std::uniform_int_distribution<int> distribution(0,51);
int index = distribution(generator);
In simulations like this, this may have a huge effect. In this case it had a small effect. I tested both the standard rand() method and the C++ variant and ran the simulation 4 times with 10 million iterations each time:
Using rand() % 52:
Result: 0.175141
Result: 0.175074
Result: 0.175318
Result: 0.175506
Using distribution(generator):
Result: 0.175197
Result: 0.175225
Result: 0.175228
Result: 0.175293
As you can see, the deviation is smaller. So if accuracy matters, either consider switching to C++ and use those methods, or find a way to get a good distribution. And if you are doing a simulation to numerically calculate a probability, then it does matter.

What is wrong with my hash function?

I'm trying to create a hash table. Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define N 19
#define c1 3
#define c2 5
#define m 3000
int efort;
int h_table[N];
int h(int k, int i)
{
return (k + i*c1 + i*i*c2) % N;
}
void init()
{
for (int i = 0; i < N; i++)
h_table[i] = -1;
}
void insert(int k)
{
int position, i;
i = 0;
do
{
position = h(k, i);
printf("\n Position %d \n", position);
if (h_table[position] == -1)
{
h_table[position] = k;
printf("Inserted :elem %d at %d \n", h_table[position], position);
break;
}
else
{
i += 1;
}
} while (i != N);
}
void print(int n)
{
printf("\nTable content: \n");
for (int i = 0; i < n; i++)
{
printf("%d ", h_table[i]);
}
}
void test()
{
int a[100];
int b[100];
init();
memset(b, -1, 100);
srand(time(NULL));
for (int i = 0; i < N; i++)
{
a[i] = rand() % (3000 + 1 - 2000) + 2000;
}
for (int i = 0; i < N ; i++)
{
insert(a[i]);
}
print(N);
}
int main()
{
test();
return 0;
}
Hash ("h") function and "insert" function are took from "Introduction to algorithms" book (Cormen).I don't know what is happening with the h function or insert function. Sometimes it fills completely my array, but sometimes it doesn't. That means it doesn't work good. What am I doing wrong?
In short, you are producing repeating values for position often enough to prevent h_table[] from being populated after only N attempts...
The pseudo-random number generator is not guaranteed to produce a set of unique numbers, nor is your h(...) function guaranteed to produce a mutually exclusive set of position values. It is likely that you are generating the same position enough times that you run out of loops before all 19 positions have been generated. The question how many times must h(...) be called on average before you are likely to get the value of an unused position? should be answered. This may help to direct you to the problem.
As an experiment, I increased the looping indexes from N to 100 in all but the h(...) function (so as not to overrun h_table[] ). And as expected the first 5 positions filled immediately. The next one filled after 3 more tries. The next one 10 tries later, and so on, until by the end of 100 tries, there were still some unwritten positions.
On the next run, all table positions were filled.
2 possible solutions:
1) Modify hash to improve probability of unique values.
2) Increase iterations to populate h_table
A good_hash_function() % N may repeat itself in N re-hashes. A good hash looks nearly random in its output even though it is deterministic. So in N tries it might not loop through all the array elements.
After failing to find a free array element after a number of tries, say N/3 tries, recommend a different approach. Just look for the next free element.

How to give struct objects random not matching x and y coordinates in C?

I am trying to do my homework, which is some sort of game.
This is a part of it and I'm trying to create a function which puts 18 (9 in one team and the other 9 in another) different players on the field. player is a struct which has a name and coordinates. So I tried to write this function and had several problems. I think I have mostly fixed them, but I don't understand what's wrong with it now. Basically this function gives all the players random x and y coordinates, but as I have to make sure that they don't match, I created 2 lists x's and y's. The program takes all the players and add's their x coordinates to x's list if the current player x coordinate matches any x coordinates in x's list, then the program checks the same player's y coordinate and checks if it matches the coordinate of y of the same object in y's list. So if both x and y math, then the program runs again by recursion. The problem I get is that the coordinates I get every time I run the program are same. they don't match but they are not really random cause they don't change when I run them again.
I think I have tried all my knowledge and skills but still can't understand the problem of my code.
Can you please tell me what's wrong with this code?
void random_positions()
{
int i,j;
int xs[17],ys[17];
for(i= 0; i<9 ; i++)
{
players[i][0].x = rand() % 25;
players[i][0].y = rand() % 25;
players[i][1].x = rand() % 25;
players[i][1].y = rand() % 25;
printf("A%d x = %d y = %d \n",i+1,players[i][0].x,players[i][0].y);
printf("B%d x = %d y = %d \n",i+1,players[i][1].x,players[i][1].y);
}
for(i = 0; i < 9 ; i++)
{
xs[i] = players[i][0].x;
xs[i+8] = players[i][1].x;
ys[i] = players[i][0].y;
ys[i+8] = players[i][1].y;
for(j = 0; j <= i ; j++)
{
//printf("j%d start\n",j);
if(i != j && xs[i] == xs[j])
{
//printf("i%d start\n",j);
if(ys[i] == ys[j])
{
return random_positions();
}
//("j%d done\n",j);
}
//printf("j%d done\n",j);
}
}
}
A computer is (usually) a deterministic machine; if you run the same program twice, you will get the same answer.
A random number generator generally takes a seed, an initial value that it uses to initialize itself before it starts producing random numbers; give it a different seed, and you will get a different sequence. One way to do this is to give it the current time as a seed:
#include <stdio.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
int main ()
{
/* initialize random seed: */
srand (time(NULL));
/* generate random number between 1 and 10: */
int num = rand() % 10 + 1;
printf("%d\n", num);
return 0;
}

Need Help software is not exactly performs the required

Hello friends I need your help.
My program is such an array size 1000 where the numbers should be between 0-999. These numbers should be determined randomly (rand loop) and the number must not be repeated. Would be considered the main part, I have to count how many times I used rand().
My idea is that: one loop where it initializes all the 1000 numbers, and if in this loop they check whether the number appears twice, if the number appears twice is set it again until that not appear twice (maybe this is not the best way but ...)
It is my exercise (Here I need your help)-
#include <stdio.h>
#include <stdlib.h>
int main()
{
int const arr_size = 1000;
int i, j, c;
int arr[arr_size];
int loop = 0;
for(i = 0; i<arr_size; i++)
{
arr[i] = rand() % 1000;
loop++;
if (arr[i] == arr[i - 1])
{
arr[i] = rand() % 1000;
loop++;
}
}
printf("%d\n",loop);
}
So if anyone can give me advice on how I can make it work I appreciate your help.
Thanks.
As suggested, shuffling the set will work but other indirect statistical quantities might be of interest, such as the distribution of the loop variable as a function of the array index.
This seemed interesting so I went ahead and plotted the distribution of the loop as a function of the array index, which generally increases as i increases. Indeed, as we get near the end of the array, the chance of getting a new random number that is not already in the set decreases (and hence, the value of the loop variable increases; see the code below).
Specifically, for an array size = 1000, I recorded the non-zero values generated for loop (there were around 500 duplicates) and then made a plot vs the index.
The plot looks like this:
The code below will produce an array with the unique random values, and then calculate the value for loop. The loop values could be stored in another array and then saved for later analysis, but I didn't include that in the code below.
Again, I'm not exactly sure this fits the application, but it does return information that would not necessarily be available from an approach using a shuffle algorithm.
NOTE: some folks expressed concerns about how long this might take but it runs pretty quick, on my 2011 Macbook Pro it took a about a second for an array size of 1000. I didn't do a big-O analysis as a function of the array size, but that would be interesting too.
NOTE 2: its more elegant to use recursion for the numberInSet() function but it seemed best to keep simple.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h> /* If C99 */
const int ARR_SIZE = 1000;
/* Check if the number is in the set up to the given position: */
bool numberInSet(int number, int* theSet, int position);
int main()
{
int* arr = malloc(sizeof(int)*ARR_SIZE);
srand((unsigned int)time(NULL));
/* Intialize array with rand entries, possibly duplicates: */
for(int i = 0; i < ARR_SIZE; i++)
arr[i] = rand() % ARR_SIZE;
/* Scan the array, look for duplicate values, replace if needed: */
for(int i = 0; i < ARR_SIZE; i++) {
int loop = 0;
while ( numberInSet(arr[i], arr, i-1) ) {
arr[i] = rand() % ARR_SIZE;
loop++;
}
/* could save the loop values here, e.g., loopVals[i] = loop; */
}
for(int i = 0; i < ARR_SIZE; i++)
printf("i = %d, %d\n",i,arr[i]);
/* Free the heap memory */
free(arr);
}
bool numberInSet(int number, int* theSet, int position) {
if (position < 0)
return false;
for(int i = 0; i <= position; i++)
if (number == theSet[i])
return true;
return false;
}
To make sure all random number you get in the same program are different, you must seed once the random generator:
srand (time(NULL)); //seed the random generator
//in the loop, rand will use the seeded value
rand() % 1000

Getting an average from values obtained by a sensor using C

Ok so I get this code to do the averaging : (written in C )
.
.
int sum[3];
int j;
int avg;
for(;;) //infinite loop
{
for(j=0;j<3;j++){
i = ReadSensor(); // function that keeps saving sensor values as int i
sum[j]=i;
}
avg=sum[0]+sum[1]+sum[2]+sum[3];
printf("Sonar: %d \r \n", avg >> 2);
}
.
.
Is this correct ? im shifting by 2 to divide by avg / 2^(2) which is 4
The problem is im expecting a value of about 15, however I get about 8--9 .. Im not sure why this is happening ?
Basically the sensor's readings fluctuate between 15-17, I want to get an average instead of printing noise values. Is my code correct ? Then why do I get wrong outputs !?
Looks like your script only captures three values (j=0, j=1, j=2), then divides by four.
You have a few problems, here are some suggestions:
You're iterating through the inside loop 3 times, however you're saying you have 4 sensors, you should change your for loop to: for (j = 0; j < 4; j++).
sum is an array of 3 elements, yet you're accessing an element 1 past the end of the array when calculating avg (sum[3]). This will cause undefined behaviour. sum should be declared as char sum[4] for this reason and the one above.
(Optional) sum does not need to be an array in the above example, it can simply be an int.
(Optional) If you want to divide an int by 4, use the division operator. The compiler should be better at optimizing the code for your particular architecture than you.
This is how your code could now look, depending on whether you need to keep an array or not:
int sum[4];
int total, j;
for (;;)
{
total = 0; /* reset at every iteration of the outside loop */
for (j = 0; j < 4; j++) {
sum[i] = ReadSensor();
total += sum[i];
}
printf("Sonar: %d \r \n", total / 4);
}
OR
int total, j;
for (;;)
{
total = 0; /* reset at every iteration of the outside loop */
for (j = 0; j < 4; j++)
total += ReadSensor();
printf("Sonar: %d \r \n", total / 4);
}
Isn't this
avg=sum[0]+sum[1]+sum[2]+sum[3];
should be
avg=sum[0]+sum[1]+sum[2];
as the loop as well declaration int sum[3]; means we are trying to store only 3 values.
Now if you want 4 and ok with divide operator. There are the new code which should replace the mentioned lines
int sum[4];
for(j=0;j<4;j++)
avg=sum[0]+sum[1]+sum[2]+sum[3]; // this part stays the same
The number of values read from sensor is required twice. First, to control the number of iterations of for loop. Second, as the divisor of sum. Introduce a variable (say, N) to capture that.
Also, the division by shifting does not sound right, because that restricts the number of readings from the sensor to power of two.
enum { N = 4 };
sum = 0;
for( j = 0; j < N; j++) {
i = ReadSensor(); // function that keeps saving sensor values as int i
sum += i;
}
avg = sum / N;
printf( "Sonar average: %d\n", avg );

Resources