I have been struggling to try to parallel this function which calculates interactions between particles. I had an idea to use Allgatherv which should distribute my original buffer to all other processes. Then using "rank" make a loop in which each process will calculate its part.In this program, MPI is overwritten to show stats that's why I am calling it mpi->function. Unfortunately, when I run it I receive following error. Can somebody advice what is wrong?
void calcInteraction() {
totalInteraction = 0.0;
int procs_number;
int rank;
int particle_amount = particles;
mpi->MPI_Comm_size(MPI_COMM_WORLD,&procs_number);
mpi->MPI_Comm_rank(MPI_COMM_WORLD,&rank);
//long sendBuffer[particle_amount];
//int *displs[procs_number];
//long send_counts[procs_number+mod];
int mod = (particle_amount%procs_number);
int elements_per_process = particle_amount/procs_number;
int *send_buffer = new int[particle_amount]; //data to send
int *displs = new int[procs_number]; //displacement
int *send_counts = new int[procs_number];
if(rank == 0)
{
for(int i = 0; i < particle_amount; i++)
{
send_buffer[i] = i; // filling buffer with particles
}
}
for (int i = 0; i < procs_number;i++)
{
send_counts[i] = elements_per_process; // filling buffer since it can't be empty
}
// calculating displacement
displs[ 0 ] = 0;
for ( int i = 1; i < procs_number; i++ )
displs[ i ] = displs[ i - 1 ] + send_counts[ i - 1 ];
int allData = displs[ procs_number - 1 ] + send_counts[ procs_number - 1 ];
int * endBuffer = new int[allData];
int start,end; // initializing indices
cout<<"entering allgather"<<endl;
mpi->MPI_Allgatherv(send_buffer,particle_amount,MPI_INT,endBuffer,send_counts,displs,MPI_INT,MPI_COMM_WORLD);
// ^from ^how many ^send ^receive ^how many ^displ ^send ^communicator
// to send type buffer receive type
start = rank*elements_per_process;
cout<<"start = "<< start <<endl;
if(rank == procs_number) //in case that particle_amount is not even
{
end = (rank+1)*elements_per_process + mod;
}
else
{
end = (rank+1)*elements_per_process;
}
cout<<"end = "<< end <<endl;
cout << "calcInteraction" << endl;
for (long idx = start; idx < end; idx++) {
for (long idxB = start; idxB < end; idxB++) {
if (idx != idxB) {
totalInteraction += physics->interaction(x[idx], y[idx], z[idx], age[idx], x[idxB], y[idxB],
z[idxB], age[idxB]);
}
}
}
cout << "calcInteraction - done" << endl;
}
You are not using MPI_Allgatherv() correctly.
I had an idea to use Allgatherv which should distribute my original
buffer to all other processes.
The description suggests you need MPI_Scatter[v]() in order to slice your array from a given rank, and distributes the chunks to all the MPI tasks.
If all tasks should receive the full array, then MPI_Bcast() is what you need.
Anyway, let's assume you need an all gather.
First, you must ensure all tasks have the same particles value.
Second, since you gather the same amout of data from every MPI tasks, and store them in a contiguous location, you can simplify your code with MPI_Allgather(). If only the last task might have a bit less data, then you can use MPI_Allgatherv() (but this is not what your code is currently doing) or transmit some ghost data so you can use the simple (and probably more optimized) MPI_Allgather().
Last but not least, you should send elements_per_process elements (and not particle_amount). That should be enough to get rid of the crash (e.g. MPI_ERR_TRUNCATE). But that being said, i am not sure that will achieve the result you need or expect.
Related
int mpi_vertex_dist(graph_t *graph, int start_vertex, int *result)
{
int num_vertices = graph->num_vertices;
fill_n(result, num_vertices, MAX_DIST);
auto start_time = Time::now();
int depth = 0;
result[start_vertex] = depth;
int keep_going = true;
int start,stop;
int elements_per_proc = num_vertices / num_proc;
int remainder = num_vertices % num_proc;
if(my_rank < remainder)
{
start = my_rank * (elements_per_proc + 1);
stop = start + elements_per_proc;
}
else
{
start = my_rank * elements_per_proc + remainder;
stop = start + (elements_per_proc-1);
}
int *resultTmp = new int[num_vertices];
int count = 0;
while (keep_going)
{
keep_going = false;
for (int vertex = start; vertex <= stop; vertex++)
{
if (result[vertex] == depth) {
for (int n = graph->v_adj_begin[vertex];
n < graph->v_adj_begin[vertex] + graph->v_adj_length[vertex];
n++)
{
int neighbor = graph->v_adj_list[n];
if (result[neighbor] > depth+1)
{
result[neighbor] = depth+1;
keep_going = true;
resultTmp[count] = neighbor;
count++;
}
}
}
}
if(count != 0)
{
MPI_Allreduce(resultTmp,result,count, MPI_INT, MPI_MIN, MPI_COMM_WORLD);
}
// Old Code
/*
if(count != 0)
{
MPI_Reduce(resultTmp,result,count, MPI_INT, MPI_MIN,my_rank,MPI_COMM_WORLD);
}
*/
depth++;
}
//print_result(graph, result, depth);
return std::chrono::duration_cast<us>(Time::now()-start_time).count();
}
I managed to split the graph vertices between processors each getting 5 5 4 4 - I have total of 18 in the graph I am using for testing. I keep count of the updates using count. And at the end of the iteration I use that buffer to send to result array using MPI_Allreduce, however when I run the code it doesn't end. What am I doing wrong?
Your main problem is that you approach MPI as if it's shared memory. In your code, each process has a copy of the whole graph, which is wasteful if you ever run this at large scale, but it's not a serious problem for now.
The real problem is the result array: each process does reads and writes into it, but each process has a copy of that array, so it does not see the changes that other processes make.
The fix to this problem is that in each iteration of the while loop you need to reconcile these copies: do an Allreduce with the maximum operator. (I think. I'm not entirely sure what your algorithm is supposed to be.)
Finally, you are using each vertex to update its neigbors. That works fine sequentially, but is not a good design in parallel. Use symmetry, and update each vertex from its neigbors. That is a much better design in shared memory and distributed memory both.
I am trying to create an application to calculate multiplicative persistence, like in this video: https://youtu.be/Wim9WJeDTHQ?t=197.
However my problem is that it does not appear that my vector is being cleared during iterations of the while loop. Which means the output produced is growing exponentially instead of working down to 0.
I am very new to coding c++ so any feedback would be appreciated.
std::vector<int> per;
int input;
int result;
int new_total = 1;
int loop_total;
std::cin >> input;
//Moving the user input into a vector
while (input > 0)
{
result = input % 10;
input = input / 10;
per.push_back(result);
}
//loops to multiply new sets of numbers together until "new_total" is 0
while (new_total > 0) {
for (int i = per.size() - 1; i >= 0; i--)
{
new_total = new_total * per[i];
}
per.clear();
std::cout << "\n" << new_total << "\n";
loop_total = new_total;
while (loop_total > 0)
{
result = loop_total % 10;
loop_total = loop_total / 10;
per.push_back(result);
}
}
I expected for the vector to be cleared each time so that the new sets of numbers were moved into the vector to be multiplied.
However the previous set of numbers appeared to remain present in the vector.
Thanks for all the help everyone. The solution to my problem was fixed by setting new_total=1; at the beginning of the while loop which makes sense as before new_value was being continually multiplied into.
Thanks for all the help :)
I am using an arduino to read a sensor which stores 256 values into an array. I am trying to find local max's but some values being stored have repeating values to the left and right of itself causing the value to print multiple times. Is there a way to take all true values meaning they are a max value and store them in another array to process and reduce the repeated values to just 1 value...
OR is there a way to send the max values to another array where the repeated values get reduced to just 1? OR
IE:
Array1[] = {1,2,3,4,4,4,3,2,7,8,9,10}
max = 4 at index 3
max = 4 at index 4
max = 4 at index 5
since 4 is a peak point but repeats how can I reduce it so that the array looks like
Array2[] = {1,2,3,4,3,2,7,8,9,10}
max = 4 at index 3
I need the most basic breakdown if possible nothing on an expert level, thanks.
Code from Arduino:
int inp[20] = {24,100,13,155,154,157,156,140,14,175,158,102,169,160,190,100,200,164,143,20};
void setup()
{
Serial.begin(9600); // for debugging
}
void loop()
{
int i;
int count = 0;
for (i = 0; i < 20; i++)
{
Serial.println((String)inp[i]+" index at - "+i);
delay(100);
};
int N = 5; // loc max neighborhood size
for (int i = N-1; i < 19-N; i++)
{
bool loc = false;
for (int j = 1; j < N; j++) // look N-1 back and N-1 ahead
{
if (inp[i] > inp[i-j] && inp[i] > inp[i+j]) loc = true;
}
if (loc == true)
{
Serial.println((String)"max = "inp[i]+" at index "+i);
}
}
Serial.println("----------------------------------");
}
You can detect "local maxima" or peaks in a single loop without the need of copying something into another array. You just have to ignore repeating values, and you just have to keep track if the values considered are currently increasing or decreasing. Each value after which this status switches from increasing to decreasing is then a peak:
int main() {
int Array1[] = {1,2,3,4,4,4,3,2,7,8,9,10};
int prevVal = INT_MIN;
enum {
Ascending,
Descending
} direction = Ascending;
for (int i=0; i<sizeof(Array1)/sizeof(*Array1); i++) {
int curVal = Array1[i];
if (prevVal < curVal) { // (still) ascending?
direction = Ascending;
}
else if (prevVal > curVal) { // (still) descending?
if (direction != Descending) { // starts descending?
cout << "peak at index " << i-1 << ": " << prevVal << endl;
direction = Descending;
}
}
// prevVal == curVal is simply ignored...
prevVal = curVal;
}
}
EDIT Took a different approach and found the solution, updated the function to correctly find the mode or modes
I've been at this algorithm all day and night, I've looked at about 12 code examples 10x over but none of them seem to go above and beyond to address my problem.
Problem: Find the mode(s) in an array, if the array has more than one mode, display them all. (This is a homework assignment so I must use arrays/pointers)
Sample array:
-1, -1, 5, 6, 1, 1
Sample output:
This array has the following mode(s): -1, 1
The problem I'm having is trying to figure how to store and display just the highest mode OR the multiple modes if they exist.
I have used a lot of approaches and so I will post my most recent approach:
void getMode(int *arr, int size)
{
int *count = new int[size]; // to hold the number of times a value appears in the array
// fill the count array with zeros
for (int i = 0; i < size; i++)
count[i] = 0;
// find the possible modes
for (int x = 0; x < size; x++)
{
for (int y = 0; y < size; y++)
{
// don't count the values that will always occur at the same element
if (x == y)
continue;
if (arr[x] == arr[y])
count[x]++;
}
}
// find the the greatest count occurrences
int maxCount = getMaximum(count, size);
// store only unique values in the mode array
int *mode = new int[size]; // to store the mode(s) in the list
int modeCount = 0; // to count the number of modes
if (maxCount > 0)
{
for (int i = 0; i < size; i++)
{
if (count[i] == maxCount)
{
// call to function searchList
if (!searchList(mode, modeCount, arr[i]))
{
mode[modeCount] = arr[i];
modeCount++;
}
}
}
}
// display the modes
if (modeCount == 0)
cout << "The list has no mode\n";
else if (modeCount == 1)
{
cout << "The list has the following mode: " << mode[0] << endl;
}
else if (modeCount > 1)
{
cout << "The list has the following modes: ";
for (int i = 0; i < modeCount - 1; i++)
{
cout << mode[i] << ", ";
}
cout << mode[modeCount - 1] << endl;
}
// delete the dynamically allocated arrays
delete[]count;
delete[]mode;
count = NULL;
mode = NULL;
}
/*
definition of function searchList.
searchList accepts a pointer to an int array, its size, and a value to be searched for as its arguments.
if searchList finds the value to be searched for, searchList returns true.
*/
bool searchList(int *arr, int size, int value)
{
for (int x = 0; x < size; x++)
{
if (arr[x] == value)
{
return true;
}
}
return false;
}
It's best to build algorithms from smaller building blocks. The standard <algorithm> library is a great source of such components. Even if you're not using that, the program should be similarly structured with subroutines.
For homework at least, the reasoning behind the program should be fairly "obvious," especially given some comments.
Here's a version using <algorithm>, and std::unique_ptr instead of new, which you should never use. If it helps to satisfy the homework requirements, you might implement your own versions of the standard library facilities.
// Input: array "in" of size "count"
// Output: array "in" contains "count" modes of the input sequence
void filter_modes( int * in, int & count ) {
auto end = in + count;
std::sort( in, end ); // Sorting groups duplicate values.
// Use an ordered pair data type, <frequency, value>
typedef std::pair< int, int > value_frequency;
// Reserve memory for the analysis.
auto * frequencies = std::make_unique< value_frequency[] >( count );
int frequency_count = 0;
// Loop once per group of equal values in the input.
for ( auto group = in; group != end; ++ group ) {
auto group_start = group;
// Skip to the last equal value in this subsequence.
group = std::adjacent_find( group, end, std::not_equal_to<>{} );
frequencies[ frequency_count ++ ] = { // Record this group in the list.
group - group_start + 1, // One unique value plus # skipped values.
* group // The value.
};
}
// Sort <frequency, value> pairs in decreasing order (by frequency).
std::sort( frequencies.get(), frequencies.get() + frequency_count,
std::greater<>{} );
// Copy modes back to input array and set count appropriately.
for ( count = 0; frequencies[ count ].first == frequencies[ 0 ].first; ++ count ) {
in[ count ] = frequencies[ count ].second;
}
}
There's no real answer because of the way the mode is defined. Occasionally you see in British high school leaving exams the demand to identify the mode from a small distribution which is clearly amodal, but has one bin with excess count.
You need to bin the data, choosing bins so that the data has definite peaks and troughs. The modes are then the tips of the peaks. However little subsidiary peaks on the way up to the top are not modes, they're a sign that your binning has been too narrow. It's easy enough to eyeball the modes, a bit more difficult to work it out in a computer algorithm which has to be formal. One test is to move the bins by half a bin. If a mode disappears, it's noise rather than a real mode.
The question:
Input data will give the number of test-cases in the first line.
Then test-cases themselves will follow, one case per line.
Each test-case describes an array of positive integers with value of 0 marking end. (this zero should not be included into calculations!!!).
Answer should contain average values for each array, rounded to nearest integer (see task on rounding), separated by spaces.
Problem:
Works fine but at third indice sum is assigned value of arrayInput and it messes everything up. Why does this happen and how can I fix it?
//araytest
#include<cmath>
#include<iostream>
using namespace std;
int main()
{
//var
int i = 0;
int array[13] = {};
//take in # arrays
cin >> i;
for(int x = 0; x<i; x++ )
{
//reset variables (for every array)
float arraySize = 0,
sum = 0, avg = 0;
int indice = 0,
arrayInput = 0;
while(cin >> arrayInput){
if(arrayInput == 0)
{
if(indice == 0)
{
arraySize = 1; /*if only 0 put in first indice
to prevent divide by 0 */
break;
}
else
{
arraySize = indice; // 0 doesn't count
break;
}
}
sum += arrayInput;
array[indice] = arrayInput;
arrayInput = 0;
indice++;
}
avg = round(sum/arraySize);
cout << avg << " ";
}
return 0;
}
First, like other people said, the array you used in this code is totally useless. It did nothing but save arrayinput.
Second, you let arraysize sum avg to be type float. However, arrayinput is assigned to be integer!! That means you never get result like this 2.xxx. So the type you declare for variables is meaningless. They should have same type declaration. I don't understand why you code does not work well. Because if you enter integer number, you wont get anything wrong. But it will crash if you give number like 2.xxx or x.xxx.