Parallel Program with POSIX Threads Slower than Serial - c++

I know this question is a duplicate one, but I couldn't find any other topic similar to my code.
The problem statement is as followed:
There is a CSV file with 16,000 lines. A serial version of the program is extracting those rows with a price (SalePrice is a column head in the CSV) higher than a specific value (threshold) given to the program with command-line arguments and calculating their Mean and Standard Derivation which will be used for further computations.
This larger CSV file is broken into 4 CSV files for the parallel version. Each thread is assigned to one CSV file and should do the same calculations (Calculating Mean and STD of rows with price higher than a specific value named threshold in my code).
Since the data is large enough, I don't think this is because of the multithreading overhead.
I would be thankful if someone could please help me find out what part is slowing down my parallel version?
#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>
#include <iomanip>
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
using namespace std;
#define COMMA ','
#define EMPTY_STR ""
#define FILENAME "dataset.csv"
#define CLASSIFIER "GrLivArea"
#define SALE_PRICE "SalePrice"
const int MAX_THREAD_NUMBERS = 20;
int NUMBER_OF_THREADS;
int threshold;
int expensive_cnt[MAX_THREAD_NUMBERS];
vector<string> lines;
string head;
double _std;
long sum[MAX_THREAD_NUMBERS];
long ps[MAX_THREAD_NUMBERS];
long sumsq[MAX_THREAD_NUMBERS];
double mean;
int total_items;
int total_expensive_cnt;
struct Item
{
int x;
bool category;
};
vector<Item> items[MAX_THREAD_NUMBERS];
int getColNum(const string& head, const string& key)
{
int cnt = 0;
string cur = EMPTY_STR;
for (int i = 0 ; i < head.size() ; i++)
{
if (head[i] == COMMA)
{
if (cur == key)
return cnt;
cnt++;
cur = EMPTY_STR;
}
else
cur += head[i];
}
if (cur == key)
return cnt;
return -1;
}
vector<int> separateByComma(string s)
{
vector<int> res;
string cur = EMPTY_STR;
for (int i = 0 ; i < s.size() ; i++)
if (s[i] == COMMA)
{
res.push_back(stoi(cur));
cur = EMPTY_STR;
}
else
cur += s[i];
res.push_back(stoi(cur));
return res;
}
void* calcSums(void* tid)
{
long thread_id = (long)tid;
string filename = "dataset_" + to_string(thread_id) + ".csv";
ifstream fin(filename);
string head;
fin >> head;
int classifierColNum = getColNum(head, CLASSIFIER);
if (classifierColNum == -1)
{
printf("NO GrLivArea FOUND IN HEAD OF CSV\n");
exit(-1);
}
int priceColNum = getColNum(head, SALE_PRICE);
if (priceColNum == -1)
{
printf("NO SalePrice FOUND IN HEAD OF CSV\n");
exit(-1);
}
string line;
while (fin >> line)
{
vector<int> cur = separateByComma(line);
bool category = (cur[priceColNum] >= threshold);
Item item{cur[classifierColNum], category};
if (category)
{
sum[thread_id] += item.x;
sumsq[thread_id] += (item.x * item.x);
expensive_cnt[thread_id]++;
}
items[thread_id].push_back(item);
}
fin.close();
pthread_exit(NULL);
}
void calcMeanSTD()
{
string line;
for (int i = 0 ; ; i++)
{
struct stat buffer;
string name = "dataset_" + to_string(i) + ".csv";
if (!(stat (name.c_str(), &buffer) == 0))
break;
NUMBER_OF_THREADS++;
}
pthread_t threads[NUMBER_OF_THREADS];
int return_code;
for (long tid = 0 ; tid < NUMBER_OF_THREADS ; tid++)
{
return_code = pthread_create(&threads[tid], NULL, calcSums, (void*)tid);
if (return_code)
{
printf("ERROR; return code from pthread_create() is %d\n", return_code);
exit(-1);
}
}
for (long tid = 0 ; tid < NUMBER_OF_THREADS ; tid++)
{
return_code = pthread_join(threads[tid], NULL);
if (return_code)
{
printf("ERROR; return code from pthread_join() is %d\n", return_code);
exit(-1);
}
}
double total_sum = 0;
double total_sum_sq = 0;
total_expensive_cnt = 0;
total_items = 0;
for (int i = 0 ; i < NUMBER_OF_THREADS ; i++)
{
total_sum += sum[i];
total_sum_sq += sumsq[i];
total_expensive_cnt += expensive_cnt[i];
total_items += items[i].size();
}
mean = total_sum / total_expensive_cnt;
_std = sqrt((total_sum_sq - ((total_sum * total_sum) / (total_expensive_cnt))) / (total_expensive_cnt));
}
int main(int argc, char *argv[])
{
threshold = atoi(argv[1]);
calcMeanSTD();
cout << mean << " " << _std << endl;
return 0;
}
Please let me know if any part is not understandable.
Here are some run-time values:
Read CSV (Serial): 0.043268s Calculations (Serial): 0.000151s
The exact time calculation isn't much easy in the multithreaded version here since the calculations and file reading are done in the same while loop which is not separable here. There also many thread switches. Anyway, their sum is about: 0.14587s
As it can be seen, the amount of time needed to read from files is almost 300 times as doing the math calculations.

Thanks to the answers in the comment, I found out what is happening:
I tried increasing the number of rows in my CSV files to see if the parallelization is working.
The run-time values for a CSV file with 1000000 rows are:
Parallel: real 0m0.558s user 0m2.173s sys 0m0.020s
Serial: real 0m1.834s user 0m1.818s sys 0m0.016s
Since I am using 4 threads, I expect 1.834 divided by 0.558 to be near to 4 which actually is 3.28 and is fair enough.
This run-time values for smaller CSV files aren't showing these results which seems to be because of the simple math computations in my code.
The bottleneck of this code is the section where I am reading from CSV files. This section seems to be serial since it is reading from a disk.
There is also a problem of False Sharing in this code
which causes cache contention due to updates of different memory locations by different threads when these locations share the same cache line mapping. There are many solutions to this problem, for example, I can introduce padding into these arrays to make sure that elements accessed by multiple threads do not share cache lines. Or, more simply, work with thread-local variables instead of arrays, and, in the end, update the array elements only once.

Related

Is there a way to make this bruteforce password cracker faster?

So I'm pretty new to c++, and this is the second program I've ever written in it. The first program was a complete mess but it worked, this program I decided to just put all in one file. My problem is, it just runs incredibly slowly. I'm pretty sure it's because of just how many characters it has to iterate through, but the requirements are that it can crack a password of a specific length with any special characters like these. Other than the number of characters it has to go through I'm not sure what, if anything, is making it run so slowly. I'm wondering if it's something I've done that is improper and making it take so long. Is this just about how fast a password cracker like this can run?
// Password Cracker.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <thread>
#include <atomic>
#include <vector>
#include <cmath>
#include <sstream>
std::string convertToString(char*, int);
void passwordBruteForcer(std::string, long long, long long);
std::atomic<bool> isPasswordFound = false;
std::string foundString;
int main()
{
// Given some count of the amount of symbols that can exist in the password
// We will calulcate how many possible passwords there are then divide work evenly between threads
// In this case the possible symbols are all ascii codes from 32 to 126
int numOfSymbols = 95;
// Declarations;
int numberOfThreads = 8;
std::string password;
std::vector<std::thread> vecOfThreads;
// Loop waits for correct user input (problem required that password length be 5, change this if you want)
while (true)
{
// Prompting user input
std::cout << "Please enter a password of length 5 \n";
std::cout << "password: ";
std::getline(std::cin, password);
if (password.length() == 5)
{
break;
}
else
{
std::cout << "Invalid password \n";
}
}
long long amountOfPossiblePasswords = pow(numOfSymbols, password.length());
// Creates threads running brute force cracker
for (int threadNumber = 1; threadNumber <= numberOfThreads; threadNumber++)
{
long long startingNumber = (amountOfPossiblePasswords * (threadNumber - 1)) / numberOfThreads;
long long endNumber = (amountOfPossiblePasswords * threadNumber) / numberOfThreads;
long long remainder = amountOfPossiblePasswords % numberOfThreads;
if (threadNumber == numberOfThreads)
{
vecOfThreads.push_back(std::thread(passwordBruteForcer, password, startingNumber, endNumber + remainder));
}
else
{
vecOfThreads.push_back(std::thread(passwordBruteForcer, password, startingNumber, endNumber));
}
}
// Wait to join thread
for (std::thread & th : vecOfThreads)
{
if (th.joinable())
th.join();
}
// Prints the password the algorithm found
if (isPasswordFound)
{
std::cout << foundString;
}
return 0;
}
// Will go through all "printable" ASCII characters
void passwordBruteForcer(std::string passStr, long long startingNumber, long long endNumber)
{
int firstChar = 32;
int lastChar = 126;
int length = passStr.length();
int numOfChar = 95;
int numOfTries = pow(numOfChar, length);
char* guess = new char[length];
// Converts decimal to base num of chars then puts that char into array
// For ex. 0 will be first char, and a 1 will be the next char, the number that represents the amount of possible passwords
// will set this to be all lastChar
long long numToBeConvert = startingNumber;
for (int i = (length - 1); i >= 0; i--)
{
guess[i] = firstChar + (numToBeConvert % numOfChar);
numToBeConvert /= numOfChar;
}
// This creates a string based on initialized guess then tests it
std::string comparisonPasswordString = convertToString(guess, length);
if (comparisonPasswordString == passStr)
{
isPasswordFound = true;
foundString = comparisonPasswordString;
delete[] guess;
return;
}
// This loop goes from startingNumber to endNumber testing all passwords
for(long long i = startingNumber; i < endNumber; i++)
{
if (isPasswordFound == true)
{
break;
}
long long numForGuess = i;
for (int j = (length - 1); j >= 0; j--)
{
guess[j] = firstChar + (numForGuess % numOfChar);
numForGuess /= numOfChar;
}
comparisonPasswordString = convertToString(guess, length);
if (comparisonPasswordString == passStr)
{
isPasswordFound = true;
foundString = comparisonPasswordString;
break;
}
}
delete[] guess;
}
std::string convertToString(char* charArr, int length)
{
std::string convString;
for (int i = 0; i < length; i++)
{
convString.push_back(charArr[i]);
}
return convString;
}

Optimized c++ function for nth prime number execution time

I am implementing a c++ function to get Nth prime number using some predefined indices for time optimization purpose.
my code is :
// file prime.cpp
#include <iostream>
#include <time.h>
using namespace std;
/*
#define primeAt10000 104743
#define primeAt20000 224743
#define primeAt30000 350381
#define primeAt40000 479951
#define primeAt50000 611977
*/
int prime(int n){
int pos = 1,i = 1,temp;
if(n==0)
return 2;
/*
else if(n>50000){
i = primeAt50000;
pos = 50001;
}else if(n>40000){
i = primeAt40000;
pos = 40001;
}else if(n>30000){
i = primeAt30000;
pos = 30001;
}else if(n>20000){
i = primeAt20000;
pos = 20001;
}else if(n>10000){
i = primeAt10000;
pos = 10001;
}*/
while( i+=2 ){
temp = i/2+1;
for(int j = 3 ; j <= temp ; j+=2)
if(i%j == 0)
goto con;
if(pos++ >= n)
return i;
con :;
}
}
int main(int argc, char const *argv[]){
int index;
cin >> index;
clock_t start = clock();
cout << prime(index)<<endl;
cout << (clock()-start)/CLOCKS_PER_SEC<<"sec"<< endl;
return 0;
}
compiled with:
g++ prime.cpp -o prime.exe
I ran this code three times for inputs 9999, 19999 and 29999
1st run : 1sec 6sec 14sec
2nd run : 1sec 7sec 15sec
3rd run : 1sec 7sec 16sec
After enabling commented code again I ran three times with same inputes
1st run : 1sec 5sec 8sec
2nd run : 1sec 5sec 8sec
3rd run : 1sec 5sec 8sec
My question is :
Why this difference in taken time for each execution after second compilation while the loops are running everytime for ~1,25,000 times?
and
Why for input 19999 (~104743 looping times) it is much closer then the first 3 runs after first compilation (~224743 looping times)?
Difference in time for each 9999 interval is different because when we going towards larger numbers to check either it is prime or not it takes more time then smaller ones.
In other words directly We can say that the run-time of for-loop in prime() is increased because of larger value of variable temp.
when we checking for i = 101, the value of temp become 51 and for-loop will run approx 25 times.
while when we check for i = 10001, the value of temp become 5001 and for-loop will run for approx 2500 times.
this difference in run-time of for loop will increase your overall time complexity.
After some discussion with #JonathanLeffler I have further optimized this function to achieve fastest output for larger input values like for index 9999, 19689 and so on...
Now the complexity of my prime function is (N^2)/12 unlike before [it was (N^2)/8].
My new code is :
#include <iostream>
#include <time.h>
using namespace std;
#define primeAt10000 104743-7
#define primeAt20000 224743-7
#define primeAt30000 350381-7
#define primeAt40000 479951-7
#define primeAt50000 611977-7
bool checkPrime(int x){
int temp = x/2+1;
for(int j = 3 ; j <= temp ; j+=2)
if(x%j == 0)
return false;
return true;
}
int prime(int n){
int pos = 2,i = 0;
if(n==0)
return 2;
else if(n==1)
return 3;
else if(n>50000){
i = primeAt50000;
pos = 50000;
}else if(n>40000){
i = primeAt40000;
pos = 40000;
}else if(n>30000){
i = primeAt30000;
pos = 30000;
}else if(n>20000){
i = primeAt20000;
pos = 20000;
}else if(n>10000){
i = primeAt10000;
pos = 10000;
}
while( i+=6 ){
if(checkPrime(i-1))
if(pos++>=n)
return i-1;
if(checkPrime(i+1))
if(pos++>=n)
return i+1;
}
return 0;
}
int main()
{
int index;
cin >> index;
clock_t start = clock();
cout << prime(index)<<endl;
cout << (clock()-start)/(float)CLOCKS_PER_SEC<<"sec";
return 0;
}
Compiled with(as the advice of #NathanOliver && #JonathanLeffler) :
g++ -O3 -Wall -Werror -Wextra prime.cpp -o prime.exe
Now prime.exe taking 1.34, 4.83 and 7.20sec respectivly to inputs 9999, 19999 and 29999.

C++ Counting Specific Counters in Character Array from File

I'm trying to count the number of specific characters from a file. The problem I have run into is that the output is a huge number that does not match up with the amount of each letter in the file.
RainOrShine.txt
RRCSSSCSCRRRCSSSCSSRSCCRCRRCSS
SSSCCSSSCCSSSCCSSSCRCRCCSSSSSS
SSSSCSSSCSSSCRRCCCSSSSSCSSSSCS
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
string filelocation = "C:/Users/erizj/OneDrive/Documents/RainOrShine.txt";
ifstream textfile;
textfile.open(filelocation.c_str());
char weather[3][30];
int countR,countC,countS = 0;
if (!textfile)
{
cout << "Error opening the file.";
return 0;
}
else
{ // Read weather data in from file
for (int row = 0; row < 3; row++)
{
for (int col = 0; col < 30; col++)
{
textfile >> weather[row][col];
if(weather[row][col]=='R'){
countR++;
}
if(weather[row][col]=='C'){
countC++;
}
if(weather[row][col]=='S'){
countS++;
}
}
}
}
cout<<"Rainy Days during 3-Month Period: "<<countR<<endl;
cout<<"Cloudy Days during 3-Month Period: "<<countC<<endl;
cout<<"Sunny Days during 3-Month Period: "<<countS<<endl;
//cout<<"Rainy Days in June: "<<
textfile.close();
return 0;
}
Output:
Rainy Days during 3-Month Period: 4201688
Cloudy Days during 3-Month Period: 6356911
Sunny Days during 3-Month Period: 50
Does it have something to do with the counter that I set up? Thank in advance.
int countR,countC,countS = 0;
initializes countS but leaves countR and countC uninitialized.
Your program is assuming that there are a fixed number of rows and columns in the data. This could be a problem.
I suggest a more flexible approach, no assumptions about how the data is organized or the quantity of data.
Let's define a structure for our database. The data can be stored sequentially, but we need the data structure to be dynamic: std::vector.
Now to read in the data before making any analysis:
std::vector<char> database;
std::string text_line; // Easier to read in a lot of data
while (getline(data_file, text_line))
{
std::string::size_type index;
const std::string::size_type length = text_line.length();
for (index = 0; index < length; ++index)
{
const char c = text_line[index];
if ((c == 'R') || (c == 'S') || (c == 'C'))
{
database.push_back(c);
}
}
}
Since the data is read into a database, you can analyze it:
unsigned int duration = 0;
unsigned int rain_quantity = 0;
unsigned int sunny_quantity = 0;
unsigned int cloudy_quantity = 0;
// Set up the duration for the first 30 days
duration = 30;
if (database.size() < 30)
{
duration = database.size();
}
for (unsigned int index = 0; index < duration; ++index)
{
const char c = database[index];
if (c == 'C')
{
++cloudy_quantity;
}
else
{
if (c == 'R')
{
++rain_quantity;
}
else
{
++sunny_quantity;
}
}
}
You can perform other analysis without reading the data from the file.
You need to initialize all of your integer variables separately.
int countR = 0, countS = 0, countT = 0;

OpenMP, parallel for loop, Large differences in processing time

I've developed a program that reads numbers from .txt file where it will store into a vector to undergone a series of combinations and calculations to determine whether the result matches the number that I've wanted. These process will be done in multiple threads, where each thread will be in charge of handling various number of iterations within the parallel for loop.
Long story short, the processing time varies a lot when it comes to large number (e.g. 9 numbers) where the processing time could be as short as 3 minutes or it could be more than 10 minutes.
Here's the benchmark that I've tried so far:
8 numbers serial : 18.119 seconds
8 numbers multithread (first-try): 10.238 seconds
8 numbers multithread (second-try): 18.943 seconds
9 numbers serial : 458.980 seconds
9 numbers multithread (first-try): 172.347 seconds
9 numbers multithread (second-try): 519.532 seconds //Seriously?
//Another try after suggested modifications
9 numbers multithread (first-try): 297.017 seconds
9 numbers multithread (second-try): 297.85 seconds
9 numbers multithread (third-try): 304.755 seconds
9 numbers multithread (fourth-try): 396.391 seconds
So the question is, is there any possible way to improve the program (multi-thread) so that it only requires the least amount of time to shuffle/calculate the numbers?
Here's a portion of the code where parallel for loop occurs (Updated with slight modifications):
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <Windows.h>
#include <omp.h>
#define OPERATORSIZE 3
using namespace std;
int cur_target;
ofstream outFile;
string get_operator(int i) {
switch (i) {
case 0:
return "+";
case 1:
return "-";
case 2:
return "*";
case 3:
return "/";
default:
return "";
}
}
int prev_num_pos(vector<int> &cur_equation, int count) {
for (int i = count - 1; i >= 0; i--) {
if (cur_equation[i] != -1) return i + 1;
}
return 0;
}
bool nextoperator(int k, vector<int> &operator_array) {
for (int i = k - 2; i >= 0; i--) {
if (operator_array[i] < OPERATORSIZE) {
operator_array[i] += 1;
break;
}
else
operator_array[i] = 0;
switch (i) {
case 0:
return false;
}
}
return true;
}
void vector_combination(vector<int> int_list) { // Generate the number combinations from the number list
bool div_remainder = false;
int count = 0;
#pragma omp parallel for schedule(dynamic) firstprivate(div_remainder) reduction(+:count)
for (int i = 0; i < int_list.size(); ++i) {
vector<int> cur_equation, cur_temp, cur_list, operator_array;
auto list = int_list;
rotate(list.begin(), list.begin() + i, list.begin() + i + 1);
do
{
cur_list.clear();
operator_array.clear();
for (auto x : list)
cur_list.push_back(x);
for (int i = 0; i < cur_list.size() - 1; i++)
operator_array.push_back(0);
do
{
div_remainder = false;
count = 0;
cur_equation = operator_array;
cur_temp = cur_list;
for (int i = 0; i < cur_equation.size(); ++i) { // Check for equation priorities
if (cur_equation[i] == 3) {
count = i;
if (cur_temp[count] % cur_temp[count + 1] != 0) {
div_remainder = true;
break;
}
}
}
if (div_remainder)
continue;
for (int i = 0; i < cur_temp.size() - 1; ++i) {
count = -1;
if (cur_equation[i] == 2 || cur_equation[i] == 3) {
count = prev_num_pos(cur_equation, i);
}
else
continue;
if (cur_equation[i] == 2) {
cur_temp[count] *= cur_temp[i + 1];
cur_equation[i] = -1;
}
else if (cur_equation[i] == 3) {
if (cur_temp[i + 1] != 0) {
cur_temp[count] /= cur_temp[i + 1];
cur_equation[i] = -1;
}
else {
div_remainder = true;
break;
}
}
}
if (div_remainder)
continue;
for (int i = 0; i < cur_temp.size() - 1; ++i) {
switch (cur_equation[i]) {
case 0: {
cur_temp[0] += cur_temp[i + 1]; // Addition
cur_equation[i] = -1;
break;
}
case 1: { // Subtraction
cur_temp[0] -= cur_temp[i + 1];
cur_equation[i] = -i;
break;
}
}
}
if (cur_temp[0] == cur_target) {
#pragma omp critical
{
for (int i = 0; i < cur_list.size(); ++i) {
outFile << cur_list[i];
if (i < cur_list.size() - 1) { outFile << get_operator(operator_array[i]); }
}
outFile << "\n";
}
}
} while (nextoperator(cur_list.size(), operator_array));
// Send to function to undergone a list of operator combinations
} while (next_permutation(list.begin() + 1, list.end()));
}
}
int main(void) {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
vector<int> int_list;
string line;
ifstream myfile("Problem.txt");
if (myfile.is_open()) {
while (getline(myfile, line)) {
int num = stoi(line);
int_list.push_back(num);
cur_target = num;
}
}
else
cout << "Unable to open file." << endl;
myfile.close();
int_list.pop_back();
sort(int_list.begin(), int_list.end());
outFile.open("answer.txt");
vector_combination(int_list);
outFile.close();
int answer_count = 0;
myfile.open("answer.txt");
if (myfile.is_open()) {
while (getline(myfile, line)) {
++answer_count;
if (answer_count > 1)
break;
}
}
myfile.close();
if (answer_count == 0) {
outFile.open("answer.txt");
outFile << "-1" << endl;
}
outFile.close();
return 0;
}
As for the sample input, create a .txt file named "Problem.txt" with random numbers like so (The last number is the targeted result)(Updated with current sample input used for benchmark):
28
55
78
77
33
65
35
62
19
221
The hardware/software specification that the program runs on:
Processor: i5 Sandy Bridge 2500K,
Ram: 8GB,
OS: Windows 10 Professional,
IDE: Visual Studio 2015 Enterprise Edition,
Move the #pragma omp critical inside the if condition. Since cur_temp is thread private and cur_target is global read only, it is not necessary to protect the condition with a critical section.
This change drastically minimizes the direct interaction between the threads and, on my system, speeds up the parallel version consistently.
I would weakly guess the performance variations were influenced by the (seemingly random) phase shift between the loops running on different threads.
If performance variation persists, try enabling thread binding. Check the documentation of your OpenMP implementation, look for OMP_PROC_BIND, "thread pinning", "binding", or "affinity".
Apparently the runtime variance was caused by the vectors. I've checked it using performance analyzer and noticed the time spent on copying the values between vectors was not consistent. I've modified it to pointer array instead and the runtime is now improved tremendously and consistent.

C++: problem with while loop for large number of iterations (code is attached)

First of all, thank you all for helping me with my questions before.
Input 1: (CSV file) listdata (input as list of vectors)
0,44,38,42,29,26,29,18,39,29,25,18,15,18,34,31,22,12,14,22,9,27
0,0,43,37,32,30,24,25,29,16,24,30,29,9,26,8,24,8,7,12,13,15
0,0,0,21,31,32,24,21,26,23,25,23,21,18,18,19,21,11,17,11,12,10
0,0,0,0,23,27,28,24,26,20,13,19,23,22,20,16,18,11,6,12,10,7
0,0,0,0,0,17,31,26,25,24,30,25,25,15,19,8,19,13,7,16,7,4
0,0,0,0,0,0,18,22,21,31,13,30,18,15,19,14,15,13,10,9,8,7
0,0,0,0,0,0,0,20,20,17,28,25,13,18,8,18,23,11,9,19,6,7
0,0,0,0,0,0,0,0,13,12,24,11,25,15,16,12,16,17,4,9,7,8
0,0,0,0,0,0,0,0,0,21,25,7,23,23,27,20,15,22,8,9,7,10
0,0,0,0,0,0,0,0,0,0,18,21,14,14,10,19,14,9,5,11,7,3
0,0,0,0,0,0,0,0,0,0,0,25,5,15,16,19,15,8,10,12,3,11
0,0,0,0,0,0,0,0,0,0,0,0,9,16,9,12,16,8,13,10,5,5
0,0,0,0,0,0,0,0,0,0,0,0,0,29,10,10,7,16,5,6,7,9
0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,13,6,10,2,6,13,11
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,13,9,7,11,7,9
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,20,8,13
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,4,11,5,10
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,11,9,3
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,8
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
input 2 : listmoves 14630x8 entries (CSV file).
{here is couple of lines from the file:
1,2,3,4,-1,-3,-2,-4
1,2,3,5,-1,-3,-2,-5
1,2,3,6,-1,-3,-2,-6
1,2,3,7,-1,-3,-2,-7
1,2,3,8,-1,-3,-2,-8
1,2,3,9,-1,-3,-2,-9
1,2,3,10,-1,-3,-2,-10
1,2,3,11,-1,-3,-2,-11 }
Here is the code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
/*reading data files into vectors (22x22 matrix is in CSV format and 14630x8 vectors of moves in CSV format)*/
void readListData(vector< vector<short> > &vvec, const char *filename) {
ifstream dataFile;
dataFile.open(filename);
if(!dataFile.good()) {
cerr << "Could not open file '" << filename << "' for read\n";
exit(EXIT_FAILURE);
}
string line;
while (getline(dataFile, line)) {
istringstream iss(line);
vector<short> lvec;
while (!iss.eof()) {
short num;
iss >> num;
lvec.push_back(num);
char ch;
iss >> ch;
}
vvec.push_back(lvec);
}
}
/* write modified list of vectors into file at the end */
void writeListData(vector< vector <short> > &vvec, std::string filename) {
ofstream dataOutFile;
dataOutFile.open(filename.c_str());
if(!dataOutFile.good()) {
cerr << "Could not open file 'listdata.out' for write\n";
exit(EXIT_FAILURE);
}
for (vector<vector <short> >::size_type i = 0; i < vvec.size(); i++) {
vector<short>::size_type j;
for (j = 0; j < vvec[i].size() - 1; j++) {
dataOutFile << vvec[i][j] << ",";
}
dataOutFile << vvec[i][j] << endl;
}
dataOutFile.flush();
}
/* creat a toy vector for the input */
void copyVectors(const vector<vector<short> >& source, vector<vector<short> >& dest){
for(unsigned int i=0; i< source.size(); i++){
vector<short> rowSrc = source[i];
vector<short> rowDest;
for(unsigned int j=0; j< rowSrc.size(); j++){
rowDest.push_back(rowSrc[j]);
}
dest.push_back(rowDest);
}
}
int main() {
vector<vector <short> > mvec; //moves vectors
vector<vector <short> > vvecOrig; // original data vectors
readListData(vvecOrig, "listdata");
readListData(mvec, "listmoves");
const int NITERATIONS = 25; //set number of iterations
int numTables=25; //set number of outputs
vector<vector <short> > vvec;
copyVectors(vvecOrig, vvec);
for (int i=0; i<numTables; i++) {
srand((int) time(NULL));
int j = 0;
while (j < NITERATIONS) {
int movesIndex = rand() % mvec.size(); //generate random # from 0 to 14630
short a = mvec[movesIndex][0];
short b = mvec[movesIndex][1];
short c = mvec[movesIndex][2];
short d = mvec[movesIndex][3];
short e = abs(mvec[movesIndex][4]);
short f = abs(mvec[movesIndex][5]);
short g = abs(mvec[movesIndex][6]);
short h = abs(mvec[movesIndex][7]);
int x=vvec[e - 1][f - 1]-1;
int y=vvec[g - 1][h - 1]-1;
int z=vvec[a - 1][b - 1]+1;
int w=vvec[c - 1][d - 1]+1;
int x1=vvec[e - 1][f - 1];
int y1=vvec[g - 1][h - 1];
int z1=vvec[a - 1][b - 1];
int w1=vvec[c - 1][d - 1];
/*check for probability of the move */
/*if move does not create negative number in the list of vectors*/
if ((x>=0 && y>=0)) {
if (x==0 ){
x=1;
}
if(y==0){
y=1;
}
if (z==0){
z=1;
}
if (w==0){
w=1;
}
if (x1==0){
x1=1;
}
if (y1==0){
y1=1;
}
if (z1==0){
z1=1;
}
if (w1==0){
w1=1;
}
int numerator=x*y;
int denominator=z1*w1;
double probMove=numerator/denominator; //conditional probability
double prob = rand() % RAND_MAX; //generate random numer [0,1]
if ( probMove >=1 || probMove>prob) {
/*make a move if conditions are satisfied */
vvec[a - 1][b - 1]++;
vvec[c - 1][d - 1]++;
vvec[e - 1][f - 1]--;
vvec[g - 1][h - 1]--;
j++;
}
}
}
/*write output file after iterations*/
std::stringstream filenamestr;
filenamestr<<"listdata."<<i<<".out";
writeListData(vvec, filenamestr.str());
}
return 0;
}
The programs runs and produces desirable output. However, when I change number of iteration in while loop to about 1000, and then run the program in the command line, it seems to be stuck in the loop ( doesn't produce any output and then terminal (on mac) becomes unresponsive). I am even scared to set it to 30,000 which is what my simulation required.
I am very new to C++ and I am not sure how to troubleshoot this.
Please help!
UPDATE: I changed the following lines:
srand((unsigned int) time(NULL));
...
double probMove=double(numerator)/denominator;
double prob = double(rand() )/ (RAND_MAX);
well, I cout prob, and it seems now that when prob is less than 10^(-5) the script becomes unresponsive. I have no idea how to approach this...
I'll tell you 2 things:
probMove is an integer, even though you are saving it in a double variable. When two integers are divided together, the result is always an integer. When at least one of the operands is a double then the result is a double. Fix this by making either num or den a double.
rand()%RAND_MAX is probably not doing what you intend (you want it to be a number between 0 and 1 it seems). rand() is a value between 0 and 32767, and RAND_MAX is 32767. So you're basically going to get the value of rand() back (number between 0 and 32766) unless rand() happened to return 32767, in which case you'll get a 0.
You are probably hitting a case where probMove is either zero, very close to zero, or even negative, in which case j++ will never execute to increment your loop.
Also,
double prob = rand() % RAND_MAX; //generate random numer [0,1]
doesn't do what the comment says. If that's what you want, you need
double prob = double(rand()) / RAND_MAX;