The all task is: Implement the deterministic mass ranking algorithm.
The task should be prepared using the MPI standard in C programming language. Run times should be measured during runs on 1, 2, and 4 threads and plotted on a graph. The input N should always be 2 powers and this should be given on the horizontal x-axis, but only the exponents. For example, in the case of 1024, the scale is 10, because the 10th power of 2 is 1024. This is the so-called logarithmic scale. Thus, the scale of the x-axis remains linear, and the result can be easily plotted even with larger inputs. In all cases, the malloc function must be used, otherwise they will get a segmentation error! Whenever possible, input should be generated randomly.
My problem is, how can I measure the MPI threads, without the following error:
MPI_Init_thread(517): Cannot call MPI_INIT or MPI_INIT_THREAD more than once
My second problem is, how can I visualize the measured numbers?
My code is following:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <dos.h>
#include <conio.h>
#include <graphics.h>
#include <math.h>
#include <mpi.h>
#include <string.h>
#include <omp.h>
#include "mpi.h"
int egyszal(int szomsz[], int rang[], int p, int x);
int ketszal(int szomsz[], int rang[], int p, int x);
int negyszal (int szomsz[], int rang[], int p, int x);
int egyszal(int szomsz[], int rang[], int p, int x)
{
int i, j;
MPI_Init_thread( 0, 0, MPI_THREAD_MULTIPLE, &x );
for(i = 0; i < p; ++i)
{
if(szomsz[i] == 0)
{
rang[i] = 0;
}
else
{
rang[i] = 1;
}
}
for(j = 0; j < log10(p); ++j)
{
//printf("j valtozo erteke: %d\n", j);
for(i = 0; i < p; ++i)
{
//printf("i valtozo erteke: %d\n", i);
if( szomsz[i] != 0)
{
rang[i] = rang[i] + rang[szomsz[i]];
szomsz[i] = szomsz[szomsz[i]];
}
}
}
double ido_1 = MPI_Wtime();
MPI_Finalize();
MPI_Abort;
return ido_1;
}
int ketszal(int szomsz[], int rang[], int p, int x)
{
int i, j;
MPI_Init_thread( 0, 0, MPI_THREAD_MULTIPLE, &x );
for(i = 0; i < p; ++i)
{
if(szomsz[i] == 0)
{
rang[i] = 0;
}
else
{
rang[i] = 1;
}
}
for(j = 0; j < log10(p); ++j)
{
//printf("j valtozo erteke: %d\n", j);
for(i = 0; i < p; ++i)
{
//printf("i valtozo erteke: %d\n", i);
if( szomsz[i] != 0)
{
rang[i] = rang[i] + rang[szomsz[i]];
szomsz[i] = szomsz[szomsz[i]];
}
}
}
double ido_1 = MPI_Wtime();
MPI_Finalize();
MPI_Abort;
return ido_1;
}
int negyszal(int szomsz[], int rang[], int p, int x)
{
int i, j;
MPI_Init_thread( 0, 0, MPI_THREAD_MULTIPLE, &x );
for(i = 0; i < p; ++i)
{
if(szomsz[i] == 0)
{
rang[i] = 0;
}
else
{
rang[i] = 1;
}
}
for(j = 0; j < log10(p); ++j)
{
//printf("j valtozo erteke: %d\n", j);
for(i = 0; i < p; ++i)
{
//printf("i valtozo erteke: %d\n", i);
if( szomsz[i] != 0)
{
rang[i] = rang[i] + rang[szomsz[i]];
szomsz[i] = szomsz[szomsz[i]];
}
}
}
double ido_1 = MPI_Wtime();
MPI_Finalize();
MPI_Abort;
return ido_1;
}
int main(int argc, char** argv)
{
int i, j;
int x = 1;
int szomsz[] = {5, 4, 2, 0, 3, 1};
int rang[] = {1, 1, 1, 0, 1, 1};
int seged_1 = sizeof(szomsz);
int seged_2 = sizeof(int);
int p = seged_1/seged_2;
egyszal(szomsz, rang, p, x);
x = 2;
ketszal(szomsz, rang, p, x);
x = 4;
negyszal(szomsz, rang, p, x);
return 0;
}
You can visualize with Gnuplot, considering the stdout prints, you can grab the stdout in a bash script file, and based on the input data, and the stdout you can visualize nice figures.
here is the example of collecting the "execution time" and then plot it then with Gnuplot:
In the following, based on the experiment, I will write results in a "CSV" file, then plot them.
FILENAME=MEASUREMENT
wdir=`pwd`
toolname=`pwd | awk -F/ '{print $NF}'`
cpath="run_mpi.sh" #command path of your executable
irange="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25" # input range
mstring="EXECUTION TIME" # matching string
mcolumn="5" # matching column
nrep="10" #number of repetition of the test
#-----------------------------------
if [ ! -d "$wdir" ]; then
echo "ERROR: cannot find '$wdir'"; exit 1
fi
if [ ! -s "$wdir/$cpath" ]; then
echo "ERROR: cannot find '$cpath' in '$wdir'"; exit 1
fi
cd $wdir
FILENAME=$FILENAME
re='^[0-9]+$'
echo "pwd=`pwd`"
echo "create log and plot file name: $FILENAME.csv"
echo "logs and plots will store into $wdir/logs/"
echo ""
for i in $irange; do
a="0"; min=""; max="0"
for r in `seq $nrep`; do
output=`./$cpath $i 2>error.log`
val=`echo "$output"|awk "/$mstring/{print \\$5}" c=$mcolumn`
if ! [[ $val =~ $re ]] ; then echo "ERROR: The output is not a number! (input=$i,output='$val')" >&2; exit 1; fi
if [ 1 = `echo "$val > $max"|bc` ]; then max="$val"; fi
if [ "$min" = "" ]; then
min="$val"; a="$val"
else
if [ 1 = `echo "$val < $min"|bc` ]; then min="$val"; fi
fi
i1=`expr $i - 1`
a=`echo "define trunc(x) { auto s; s=scale; scale=0; x=x/1; scale=s; return x } trunc($a * $i1 / $i + $val / $i)"|bc -l`
# echo "$i -- $val -- $a -- $min -- $max"
done
echo "$i,$a,$min,$max"
printf %s'\n' "$i,$a,$min,$max" >> $FILENAME.csv
done
### plot the collected CSV file
for FILE in ${FILENAME}.csv; do
gnuplot <<- EOF
set xlabel "Fib Index"
set ylabel "Execution time (ns)"
set key left
set term png
set style histogram cluster gap 1
set style fill solid 0.5
set boxwidth 0.9
set style histogram errorbars linewidth 1
set errorbars linecolor black
red = "#FF0000"; green = "#00FF00"; blue = "#0000FF"; skyblue = "#87CEEB" ; violet = "#FF00FF"; purple = "#440154" ;
set grid ytics
set format y '10^{%L}'
set logscale y
set autoscale x
set yrange [1:]
set output "${FILENAME}.png"
set datafile separator ","
set style data histogram
plot "${FILENAME}.csv" using 2:3:4:xtic(1) title "Execution time (ns)" linecolor rgb purple linewidth 0
EOF
done
You can also search about how to embed this script in your code, is possible to have Gnuplot in your C code. Look at here for instance:
Making C code plot a graph automatically
Related
As I see it the numerical sequence consists of 2 separate sequences. This is the code that I have so far. I am not sure if you must use a while or a for loop. I am fairly new at coding so if someone please could help me.
if the entered value is 10 it must give the first 10 terms of the sequence, and if I enter 5 it must give me the first 5 terms of the sequence.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main() {
int a, n = 1, t, y = 1; // First Numerical Sequence
int b, m = 2, s, x = 2; // Second Numerical Sequence
int d, r, z; // Extra
printf("Enter A Tn : ");
scanf(" %d", &z);
printf("\n");
while (n <= z) {
a = 15;
r = pow(2, n - y);
d = (9 * (r - 1)) / (2 - 1);
t = a + d;
printf("%d\n", t);
n += 2;
y++;
}
while (m <= z) {
b = 12;
r = pow(2, m - x);
d = (9 * (r - 1)) / (2 - 1);
s = b + d;
printf("%d\n", s);
m += 2;
x++;
}
printf("\n");
return 0;
}
This will get the job done.
#include <stdio.h>
int main(){
int val,ic; //iteration count, will print ic*2 number
scanf("%d %d",&val,&ic);
for(int i = 0;i<ic;i++){
printf("%d ",val);
val-=3;
printf("%d ",val);
val*=2;
}
printf("\n");
}
How to compile & run:
C:\Users\stike\Desktop>rem assume you saved it in a.c
C:\Users\stike\Desktop>gcc -o a a.c
C:\Users\stike\Desktop>a
15
5
15 12 24 21 42 39 78 75 150 147
If you want to print the same sequence starting from 15 and o till a certain number which the user inputs, you can follow the following code.
Hope you understood the sequence pattern when a number is given it is printed and reduce the number by 3, then it is printed and then twice the number and printed, and again reduce by 3, likewise, it flows on.
#include <stdio.h>
int main() {
int endNum;
int beginNum = 15;
printf("Enter the end: ");//(lineA) here we initialize the variables with beginNum as 15
scanf("%d", &endNum); //(Line B) let the user to input endNum of the sequence,in the example it is 147
while ((beginNum-3) <= endNum) { // checks the condition
printf("%d ", beginNum);
if(beginNum==endNum) return 0; //check whether you print the end number.
beginNum -= 3; // reduce by 3
printf("%d ", beginNum);
beginNum *= 2; // multiply by 2
}
return 0;
}
if you don't need to user input a endNum just initialize the value 147 to variable endNum.
And delete the lines A and B.
Here's another approach using static variables
#include <stdio.h>
int next(void) {
static int last, n = 0;
if (n++ == 0) return last = 15; // 1st element of sequence
if (n % 2) return last = last * 2; // odd elements
return last = last - 3; // even elements
}
int main(void) {
for (int k = 0; k < 10; k++) {
printf("%d ", next());
}
puts("");
return 0;
}
I want to write a function that prints all possible patterns like in the examples below. In every case, we must start in the top left of a 3x3 array. It's similar to the patterns to unlock mobile phones, except the line can't go diagonally and must pass through every box.
1--->2--->3 1--->2--->3
| |
v v
8<---7 4 or 6<---5<---4
| ^ | |
v | v v
9 6<---5 7--->8--->9
I started by writing a code where [0][0] was assigned 1 then randomise the rest of the digits in the 2d array until 1[0] or 0 was equal to 2, and so forth. But I feel like this is making the problem even more difficult to solve.
Then tried to use recursion to call the makePattern function again and again until the array is changed; however, it changes all values in the array to 2 because of these lines of code:
int value = 2;
array[x][y] = value;
However, I don't how to loop this value so that it increases as the function is called again.
#include <stdio.h>
#include <stdlib.h>
#define ROW 3
#define COLUMN 3
int makePattern(int array[ROW][COLUMN], int x, int y);
int main(void) {
int x, y;
int count = 2;
int i, j;
int array[ROW][COLUMN] = {
{'1', '0', '0'},
{'0', '0', '0'},
{'0', '0', '0'},
};
makePattern(array, 0, 0);
for (i = 0; i < ROW; i++) {
for (j = 0; j < COLUMN; j++) {
printf("%d", array[i][j]);
}
printf("\n");
}
return 0;
}
int makePattern(int array[ROW][COLUMN], int x, int y) {
int value = 2;
array[x][y] = value;
for (value = 2; value < 9; value++) {
if (x + 1 < ROW && array[x+1][y] == '0') {
makePattern(array, x + 1, y);
}
if (x - 1 >= 0 && array[x - 1][y] == '0') {
makePattern(array, x - 1, y);
}
if (y + 1 < COLUMN && array[x][y + 1] == '0') {
makePattern(array, x, y + 1);
}
if (y - 1 >= 0 && array[x][y - 1] == '0') {
makePattern(array, x, y - 1);
}
value++;
}
}
You're on the right track here in that you're using a 3x3 matrix to keep track of state (visited nodes and to store the path taken), x/y coordinates to represent the current location and spawning four recurse calls to handle the possible move directions (with bounds checks).
However, I'm not sure the loop running to 9 is going to work--this will spawn 36 recursive calls per frame. This might be workable in some implementations, but I think the easiest approach is to treat each frame as exploring one possible direction given an x/y coordinate pair, then backtracking (undoing the move) after all directions have been explored recursively from that square. Whenever we hit the last step, we know we've explored all of the squares and it's time to print the current solution path.
Here's code which achieves this and basically hardcodes the dimensions. An exercise would be to generalize the code to matrices of any size and return the path to separate printing from the traversal logic. I also opted to move state out of the main function.
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
static void print_unlock_patterns_r(int pad[3][3], int x, int y, int step) {
static int const directions[][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
pad[y][x] = 1 + step;
for (int i = 0; i < 4; i++) {
int xp = x + directions[i][0];
int yp = y + directions[i][1];
if (xp >= 0 && xp < 3 && yp >= 0 && yp < 3 && !pad[yp][xp]) {
print_unlock_patterns_r(pad, xp, yp, step + 1);
}
}
if (step == 8) {
for (int i = 0; i < 3; i++, puts("")) {
for (int j = 0; j < 3; printf("%d", pad[i][j++]));
}
puts("");
}
pad[y][x] = 0;
}
void print_unlock_patterns() {
int pad[3][3];
memset(pad, 0, sizeof(pad));
print_unlock_patterns_r(pad, 0, 0, 0);
}
int main(void) {
print_unlock_patterns();
return 0;
}
Output:
123
894
765
123
874
965
123
654
789
129
438
567
145
236
987
189
276
345
187
296
345
167
258
349
recently i read this topic about generating mazes in c . see here https://www.algosome.com/articles/maze-generation-depth-first.html
and i want to write it in c . here is my code and it's not working right .
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int check[5][5];
int v[5][5];
int border(int x , int y ){
if(x> -1 && x< 6 && y > -1 && y<6)
return 1;
else
return 0 ;
}
int wall[6][6][6][6];
void dfs ( int x , int y){
srand(time(NULL));
int s = 1/*rand() % 4 ;*/ ;
if(s=1 ){
if(border(x ,y-1)&& check[x][y-1]==0){
check[x][y]=1;
wall[x][y][x+1][y]=1;
dfs(x , y-1);
}
else
return ;
}
else if(s=2){
if(border(x+1 ,y)&&check[x+1][y]==0){
check[x][y]=1;
wall[x+1][y][x+1][y+1]=1;
dfs(x+1 , y);
}
else return ;
}
else if(s=3){
if(border(x ,y+1)&&check[x][y+1]==0){
check[x][y]=1;
wall[x][y+1][x+1][y+1]=1;
dfs(x , y+1);
}
else return ;
}
else if(s=0){
if(border(x-1 ,y)&&check[x-1][y]==0){
check[x][y]=1;
wall[x][y][x][y+1]=1;
dfs(x-1 , y);
}
else return ;
}
return ;
}
int main(){
dfs( 4, 4);
for(int i =0 ; i < 6 ; i++)
for (int j =0 ; j < 6 ; j++)
for ( int h =0 ; h <6 ; h++)
for (int k =0 ; k < 6 ; k ++)
printf("%d \n" , wall[i][j][h][k]);
return 0 ;
}
i invert my table to graph , and i want to show me the coordinates of my walls .
what's the problem ?
You have several errors – programming errors and logic errors – in your code:
When you distiguish between the directions the s=1 and so on should be s == 1. You want a comparison, not an assignment. (Your code is legal C, so there is no error.)
You call srand at the beginning of dfs, which you call recursively. This will make your single (commented) rand call always create the same random number. You should seed the pseudo random number generator only once at the beginning of main.
You can store the paths the way you do, but it is wasteful. There are only four possible paths from each cell, so you don't need an array that allows to create a path between (0,0) and (3,4), for example.
Your code would benefit from using constants or enumerated values instead of the hard-coded 5's and 6's. This will allow you to change the dimensions later easily.
But your principal error is in how you implement the algorithm. You pick one of the for directions at random, then test whether that direction leads to a valid unvisited cell. If so, you recurse. If not, you stop. This will create a single unbranched path through the cells. Note that if you start in a corner cell, you have already a 50% chance of stopping the recursion short.
But you want something else: You want a maze with many branches that leads to every cell in the maze. Therefore, when the first recursion returns, you must try to branch to other cells. The algorithm goes like this:
Make a list of all possible exits.
If there are possible exits:
Pick one exit, create a path to that exit and recurse.
Update the list of possible exits.
Note that you cannot re-use the old list of exits, because the recursion may have rendered some possible exits invalid by visiting the destination cells.
Below is code that creates a maze with the described algorithm. I've used two distinct arrays to describe horizontal and vertical paths:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
enum {
W = 36, // width of maze
H = 25 // height of maze
};
enum {
North,
East,
South,
West,
NDir
};
char visited[H][W];
char horz[H][W - 1]; // horizontal E-W paths in the maze
char vert[H - 1][W]; // veritcal N-S paths in the maze
/*
* Fill dir with directions to unvisited cells, return count
*/
int adjacent(int dir[], int x, int y)
{
int ndir = 0;
if (y > 0 && visited[y - 1][x] == 0) dir[ndir++] = North;
if (x < W - 1 && visited[y][x + 1] == 0) dir[ndir++] = East;
if (y < H - 1 && visited[y + 1][x] == 0) dir[ndir++] = South;
if (x > 0 && visited[y][x - 1] == 0) dir[ndir++] = West;
return ndir;
}
/*
* Traverse cells depth first and create paths as you go
*/
void dfs(int x, int y)
{
int dir[NDir];
int ndir;
visited[y][x] = 1;
ndir = adjacent(dir, x, y);
while (ndir) {
int pick = rand() % ndir;
switch (dir[pick]) {
case North: vert[y - 1][x] = 1; dfs(x, y - 1); break;
case East: horz[y][x] = 1; dfs(x + 1, y); break;
case South: vert[y][x] = 1; dfs(x, y + 1); break;
case West: horz[y][x - 1] = 1; dfs(x - 1, y); break;
}
ndir = adjacent(dir, x, y);
}
}
/*
* Print a map of the maze
*/
void map(void)
{
int i, j;
for (i = 0; i < W; i++) {
putchar('_');
putchar('_');
}
putchar('\n');
for (j = 0; j < H; j++) {
putchar('|');
for (i = 0; i < W; i++) {
putchar(j < H - 1 && vert[j][i] ? ' ' : '_');
putchar(i < W - 1 && horz[j][i] ? '_' : '|');
}
putchar('\n');
}
}
int main()
{
srand(time(NULL));
dfs(0, 0);
map();
return 0;
}
You can test it here. If you replace the while in dsf with a simple if, you get more or less what you implemented. Note that this creates only a single, usually short path.
The problem is the following: Given "ABC+DEF=GHI" format string, where A,B,C etc. represent unique digits, find the expression that gives maximum GHI. Ex: Input string is AAB+AAB=AAB, then there's no solution. If it is instead AAA + BBB = AAA, a solution is 999 + 000 = 999. Another example string: ABC + CBA = GGG, a result is => 543 + 345 = 888.
I have ruled out impossible cases easily. The algorithm I have in mind is a bruteforce, that simply tries maximizing the rhs first. However my problem was doing this fast, and also watching out for the unique digits. What's an efficient way to solve this problem?
Notes: I wish to solve this in a singlethreaded approach, and my current problem is detecting if a unique digit is used in "assign_value" function. Perhaps a better method to assign values is there?
EDIT: As per smci's suggestion, here's what I want to achieve, in the very end: ABRA + CADABRA + ABRA + CADABRA == HOUDINI ; 7457 + 1797457 + 7457 + 1797457 == 3609828 -- A system that can handle not only strings of the form I provided in the beginning (3 digit number + 3 digit number = 3 digit number) but also those. However it doesn't hurt to start simple and go with the solution of format I gave :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_EXPRESSION_SIZE 11 + 1
#define MAX_VARIABLES 9
int variables_read[MAX_VARIABLES] = { 0 };
struct variable {
int coefficient;
int* ptr;
int side;
int canhavezero;
unsigned value_max;
};
typedef struct variable Variable;
struct equation {
Variable* variables[9]; // max
unsigned distinct_on_rhs;
unsigned var_count;
};
typedef struct equation Equation;
int int_pow(int n, int k) {
int res = 1;
for(int i = 0; i < k; ++i)
res *= n;
return res;
}
void AddVariable(Equation* E, Variable* V) {
E->variables[E->var_count++] = V;
}
int IsImpossible(char* expression) {
// if all letters are same or end letters are same, no solution
if(
(expression[0] == expression[4] && expression[0] == expression[8]) ||
(!strncmp(expression, expression + 4, 3) && !strncmp(expression, expression + 8, 3))
)
return 1;
return 0;
}
int assign_value(Equation* E, int pos, int* values) {
if(!E->variables[pos]->value_count) {
if(pos < 0)
return 2;
// if no possible values left, reset this, but take one value count from the closest variable
E->variables[pos - 1]->value_count--;
E->variables[pos]->value_count = E->variables[pos]->value_max;
return 0;
}
int i;
for(i = 9; i >= 0 && values[i] == -1; --i)
printf("Assigning %d to %c\n", E->variables[pos]->value_set[E->variables[pos]->value_count - 1], 'A' + (E->variables[pos]->ptr - E->variables[0]->ptr));
*(E->variables[pos]->ptr) = values[i];
values[i] = -1; // we have unique numbers
return 0;
}
int isSolved(Equation E) {
int sum = 0, coeff = 0;
printf("Trying...\n");
for(int i = 0; i < E.var_count; ++i) {
coeff = E.variables[i]->coefficient * (*E.variables[i]->ptr);
printf("%d ", *E.variables[i]->ptr);
if(E.variables[i]->side)
coeff *= -1;
sum += coeff;
}
printf("\nSum was %d\n", sum);
return !sum;
}
char* evaluate(char* expression) {
char* res;
// check for impossible cases first
if(IsImpossible(expression)) {
res = (char *) malloc(sizeof(char) * strlen("No Solution!"));
strcpy(res, "No Solution!");
return res;
}
res = (char *) malloc(sizeof(char) * MAX_EXPRESSION_SIZE);
// now try to find solutions, first describe the given characters as equations
Equation E;
E.var_count = 0;
E.distinct_on_rhs = 0;
int side_mode = 0, powcounter = 0;
int a = -1, b = -1, c = -1, d = -1, e = -1, f = -1, g = -1, h = -1, i = -1;
int* max_variables[MAX_VARIABLES] = { &a, &b, &c, &d, &e, &f, &g, &h, &i };
for(int j = 0; j < MAX_EXPRESSION_SIZE - 1; ++j) {
if(expression[j] == '+')
continue;
if(expression[j] == '=') {
side_mode = 1;
continue;
}
Variable* V = (Variable *) malloc(sizeof(Variable));
// we know we always get 3 digit numbers but we can easily change if we need to
V->coefficient = int_pow(10, 2 - (powcounter % 3));
V->ptr = max_variables[expression[j] - 'A'];
V->side = side_mode;
E.distinct_on_rhs += side_mode && !variables_read[expression[j] - 'A'];
if(!(powcounter % 3)) { // beginning of a number
V->value_count = 9;
V->value_max = 9;
V->canhavezero = 0;
}
else {
V->value_count = 10;
V->value_max = 10;
V->canhavezero = 1;
}
AddVariable(&E, V);
variables_read[expression[j] - 'A'] = 1;
++powcounter;
}
for(int j = 0; j < E.var_count; ++j)
printf("%d %c %d\n", E.variables[j]->coefficient, 'A' + (E.variables[j]->ptr - max_variables[0]), E.variables[j]->side);
// we got a representaion of the equation, now try to solve it
int solved = 0;
// O(9^N), where N is number of distinct variables.
// An optimization we can do is, we first assign possible max values to rhs number, then go down. We need max number.
printf("Distincts: %d\n", E.distinct_on_rhs);
do {
// try to assign values to all variables and try if it solves the equation
// but first try to assign rhs as max as possible
int values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int temp = E.var_count - E.distinct_on_rhs;
while(temp < E.var_count) {
solved = assign_value(&E, temp, values);
++temp;
}
for(int j = E.var_count - 1 - E.distinct_on_rhs; j >= 0; --j)
solved = assign_value(&E, j, values);
if(solved) // can return no solution
break;
printf("Solving...\n");
solved = isSolved(E);
system("PAUSE");
} while(!solved);
if(solved == 2) {
res = (char *) malloc(sizeof(char) * strlen("No Solution!"));
strcpy(res, "No Solution!");
}
else {
}
return res;
}
int main() {
char expression[MAX_EXPRESSION_SIZE] = { 0 };
do {
printf("Enter the formula: ");
scanf("%s", expression);
char* res = evaluate(expression);
printf("%s\n", res);
free(res);
} while(expression[0] != '-');
return 0;
}
I would start with the result. There are not that many different cases:
AAA
AAB, ABA, BAA
ABC
All other cases can be reduced to these by renaming the variables. ABC + CBA = GGG would become DBC + CBD = AAA.
Then you have
10 possible solutions for the one-variable case AAA
90 (10*9) for the two variable cases
720 (10*9*8) for the three variable case
assuming that zero is allowed anywhere. If not, you can filter out those that are not allowed.
This sets the variables for the right side of the equation. Each variable that appears only on the left, adds possible solutions. B adds a factor of 9, C a factor of 8, D 7 and so forth.
The most "efficient" solution would take all knowledge of the task and simple print the result. So the question is how much of the conditions can be coded and where and what flexibility is needed.
An alternative is to view the generation of test cases and evaluation of them separately.
A simple recursion function can generate the 10! (362880) test cases of unique digits.
unsigned long long count = 0;
unsigned long long sol = 0;
void evaluate(int object[]) {
count++;
int ABC = object[0] * 100 + object[1] * 10 + object[2];
int DEF = object[3] * 100 + object[4] * 10 + object[5];
int GHI = object[6] * 100 + object[7] * 10 + object[8];
if (ABC + DEF == GHI) {
printf("%4llu %03d + %03d = %03d\n", ++sol, ABC,DEF,GHI);
}
}
void form_combos(int pool[], size_t pool_count, int object[],
size_t object_count, size_t object_count_max) {
if (object_count >= object_count_max) {
evaluate(object);
return;
}
assert(pool_count > 0);
int *pool_end = pool + pool_count - 1;
for (size_t p = 0; p < pool_count; p++) {
int sample = pool[p]; // take one out
pool[p] = *pool_end; // replace it with the end
object[object_count] = sample;
form_combos(pool, pool_count - 1, object, object_count + 1,
object_count_max);
pool[p] = sample; // restore pool item
}
}
int main() {
int pool[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
size_t pool_size = sizeof pool / sizeof pool[0];
#define object_count 9
int object[object_count];
form_combos(pool, pool_size, object, 0, object_count);
printf("Evaluate() iterations %llu\n", count);
}
Output
1 091 + 762 = 853
2 091 + 763 = 854
3 091 + 735 = 826
...
1726 874 + 061 = 935
1727 875 + 046 = 921
1728 876 + 045 = 921
Evaluate() iterations 3628800
What is nice about this approach is that if the task was now find
ABC*ABC + DEF*DEF == GHI*GHI
Changing only 2 lines of code:
if (ABC*ABC + DEF*DEF == GHI*GHI) {
printf("%4llu sqr(%03d) + sqr(%03d) = sqr(%03d)\n", ++sol, ABC,DEF,GHI);
}
results in
1 sqr(534) + sqr(712) = sqr(890)
2 sqr(546) + sqr(728) = sqr(910)
3 sqr(712) + sqr(534) = sqr(890)
4 sqr(728) + sqr(546) = sqr(910)
Evaluate() iterations 3628800
Ok, so for a trivial solution (a base to build a generalization on, so far it only works on the format <3 digit number> + <3 digit number> = <3 digit number>) inspired from #chux and #alain's suggestions is the following code. It truly runs on O(10^N) where N is the distinct number of digits present, or variables if you'd like to call them that. I'll see if I can generalize this even further.
Note that this is for the initial problem of finding the largest rhs. Take that into account as well.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_DIGITS 10
#define MAX_VARIABLES 9
#define MAX_EXPRESSION_SIZE 11
int IsImpossible(char* expression) {
// if all letters are same or end letters are same, no solution
if(
(expression[0] == expression[4] && expression[0] == expression[8]) ||
(!strncmp(expression, expression + 4, 3) && !strncmp(expression, expression + 8, 3))
)
return 1;
return 0;
}
int ArePointersAssigned(int*** pointers) {
for(int i = 0; i < MAX_VARIABLES; ++i) {
if(**pointers[i] == -1)
return 0;
}
return 1;
}
int evaluate(int*** pointers) {
int ABC = *(*pointers[0]) * 100 + *(*pointers[1]) * 10 + *(*pointers[2]);
int DEF = *(*pointers[3]) * 100 + *(*pointers[4]) * 10 + *(*pointers[5]);
int GHI = *(*pointers[6]) * 100 + *(*pointers[7]) * 10 + *(*pointers[8]);
if (ABC + DEF == GHI) { // since we use dfs, if this is a solution simply return it
//printf("%d + %d = %d\n", ABC, DEF, GHI);
return 1;
}
return 0;
}
// use the solved pointer to escape recursion early
// check_end checks if we reached 6 for the 2nd time, if it's first time we ignore (because it's start state)
void form_combos(int pool[], int pool_count, int object_count, int*** pointers, int* solved) {
if(object_count == MAX_DIGITS - 1)
object_count = 0;
if(*solved) // if a branch solved this, escape recursion
return;
if (ArePointersAssigned(pointers)) { // that means we got a full equation set
*solved = evaluate(pointers);
if(*solved)
return;
}
int *pool_end = pool + pool_count - 1;
for (int p = pool_count - 1; p >= 0 && !*solved; p--) {
int sample = pool[p]; // take one out
pool[p] = *pool_end; // replace it with the end
int temp = **pointers[object_count];
if(**pointers[object_count] == -1)
**pointers[object_count] = sample;
form_combos(pool, pool_count - 1, object_count + 1, pointers, solved);
pool[p] = sample; // restore pool item
if(!*solved)
**pointers[object_count] = temp;
}
}
int main() {
char expression[MAX_EXPRESSION_SIZE] = { 0 };
printf("Enter the formula: ");
scanf("%s", expression);
while(expression[0] != '-') {
if(IsImpossible(expression))
printf("No solution!\n");
else {
int digits[MAX_DIGITS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int object[MAX_VARIABLES] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; // stack for dfs
int *A = &object[0], *B = &object[1], *C = &object[2],
*D = &object[3], *E = &object[4], *F = &object[5],
*G = &object[6], *H = &object[7], *I = &object[8];
// set same pointers
int** pointers[MAX_VARIABLES] = { &A, &B, &C, &D, &E, &F, &G, &H, &I };
// analyze the equation
int var = 0;
for(int p = 0; p < MAX_EXPRESSION_SIZE; ++p) {
if(expression[p] >= 'A' && expression[p] <= 'I') {
*pointers[var++] = &object[expression[p] - 'A']; // link same pointers
}
}
int solved = 0, check_end = 0;
form_combos(digits, MAX_DIGITS, MAX_DIGITS - 4, pointers, &solved);
if(!solved) // it can be unsolvable still
printf("No solution!\n");
else
printf("%d%d%d + %d%d%d = %d%d%d\n", *A, *B, *C, *D, *E, *F, *G, *H, *I);
}
printf("Enter the formula: ");
scanf("%s", expression);
}
return 0;
}
EDIT (09/24/15): Added GCC on Ubuntu timestamps
I have a 17-dimensional array (containing exactly 79,626,240 values) that I need reset (to -3) every loop.
I've written a chunk of code to test out using memset and for-loops to reset this array, and logged the average time it takes to reset the array. Comparing the same code block in Xcode and Visual Studio, some very weird results emerge...
Here are my timestamps (the code is appended to the bottom of this post):
| XCODE 7.0 | VS 14 | GCC |
---------------------------------------------------------
memset (seconds) | 0.00450 s | 0.00719 s | 0.01197 s |
for-loop (seconds) | 0.73300 s | 0.00728 s | 1.08112 s |
What is up with the time discrepancies?! Why is memset two orders of magnitude faster than using for-loops in Xcode, but in Visual Studio, they functionally take the exact same time?
The code is below. compiletable_main uses for-loops to reset the array, while compiletable_main_3 uses memset.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <memory.h>
#define num_runs 10
#define num_gens 4000
#define num_threads 3
//// BEGIN CATABLE STRUCTURE
#define box1 3
#define box2 3
#define box3 3
#define box4 3
#define box5 4
#define box6 4
#define box7 4
#define box8 4
#define memvara 2
#define memvarb 2
#define memvarc 2
#define memvard 2
#define tdirect 1
#define adirect 4
#define outputnum 15
#define fs 2
#define bs 2
typedef struct calookup
{
signed char n[box1][box2][box3][box4][box5][box6][box7][box8][memvara][memvarb][memvarc][memvard][adirect][tdirect][fs][bs][outputnum];
} calookup;
//// END CATABLE STRUCTURE
int ra_pos = 0;
long int dimensions = box1*box2*box3*box4*box5*box6*box7*box8*memvara*memvarb*memvarc*memvard*adirect*tdirect*fs*bs*outputnum;
// Compiletable_main
void compiletable_main(calookup *lookup) {
int i, j, k, l, m, nb, o, p, na, nx, ny, nx1, naa, nbb;
int x, y, z, zz, xa, xb, xc, xd, ncc, ndd;
for (j = 0;j < box1; j++)
{
for (k = 0; k < box2; k++)
{
for (l = 0; l < box3; l++)
{
for (m = 0; m < box4; m++)
{
for (x = 0;x < box5; x++)
{
for (y = 0; y < box6; y++)
{
for (xa = 0;xa < box7; xa++)
{
for (xb = 0; xb < box8; xb++)
{
for (nb = 0; nb < memvara; nb++)
{
for (na = 0; na < memvarb; na++)
{
for (nx = 0; nx < memvarc; nx++)
{
for (nx1 = 0; nx1 < memvard; nx1++)
{
for (naa = 0; naa < adirect; naa++)
{
for (nbb = 0; nbb < tdirect; nbb++)
{
for (ncc = 0; ncc < fs; ncc++)
{
for (ndd = 0; ndd < bs; ndd++)
{
for (o = 0; o < outputnum; o++)
{
lookup->n[j][k][l][m][x][y][xa][xb][nb][na][nx][nx1][naa][nbb][ncc][ndd][o] = -3; //set to default value
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
void compiletable_main_3(calookup *lookup) {
memset(lookup->n, -3, (dimensions*sizeof(signed char)));
}
void evaluatepopulation_tissueb(calookup *rs) {
// Swap between compiletable_main_3 and compiletable_main
// for the memset and for-loop approaches, respectively
compiletable_main_3(rs);
}
calookup ra;
int main() {
printf(" Begin program... \n");
static double time_consumed = 0;
static double avg_time = 0;
clock_t start, end;
int i;
int i_max = 100;
start = clock();
for (i = 0; i < i_max; i++) {
evaluatepopulation_tissueb(&ra);
}
end = clock();
time_consumed = (double)(end-start)/CLOCKS_PER_SEC;
avg_time = time_consumed / i_max;
printf("Completed run \n");
printf(" Total Time : %lf \n ", time_consumed);
printf(" Avg Time/Loop : %lf \n", avg_time);
//sleep(70000);
return 0;
}
C has a long list of compilers developed by different organisations & individuals check here
These compilers vary a lot it the techniques they would employ for optimization & many other stuffs . Visual Studio and XCode being from different Tech Giants you should not expect them to use the same compiler.
A basic google Search Revealed that Apple supports LLVM/Clang which offers complete replacement for GCC
Microsoft uses a different one.
Thus you might notice a total time taken difference.
Try running your code on GCC or TCC ! You should again get different answers.
Result on GCC for the code you uploaded :