better transposition algorithm

This commit is contained in:
cozis
2022-01-14 03:36:59 +01:00
parent 01e3863880
commit 0701880326
5 changed files with 172 additions and 47 deletions
+1
View File
@@ -1,3 +1,4 @@
.swp .swp
test test
time
.vscode .vscode
+1
View File
@@ -1 +1,2 @@
gcc test.c lina.c -o test -Wall -Wextra -g gcc test.c lina.c -o test -Wall -Wextra -g
gcc time.c lina.c -o time -Wall -Wextra -O3
+47 -28
View File
@@ -12,24 +12,25 @@ void lina_dot(double *A, double *B, double *C, int m, int n, int l){
assert(A != NULL && B != NULL && C != NULL); assert(A != NULL && B != NULL && C != NULL);
assert(A != C && B != C); assert(A != C && B != C);
//Actual dot // Iteration over A's rows
//Iteration over A's rows for(int i = 0; i < m; i++)
for(int i=0; i < m;i++){ {
// Iteration over B's columns
//Iteration over B's columns for(int k = 0; k < l; k++)
for(int k=0; k < l; k++){ {
double pos = 0; double pos = 0;
//Iteration over the single B column for executing the product of sum // Iteration over the single B column
// for executing the product of sum
for(int j=0; j < n; j++) for(int j=0; j < n; j++)
pos += A[i * n + j] * B[j * l + k];
//The usage of a support variable 'pos' is for safety purpose (non-zero C matrix) pos += A[i*n + j] * B[j*l + k];
C[i*l+k] = pos;
// The usage of a support variable 'pos'
// is for safety purpose (non-zero C matrix)
C[i*l + k] = pos;
} }
} }
} }
@@ -40,10 +41,9 @@ void lina_add(double *A, double *B, double *C, int m, int n){
assert(A != NULL && B != NULL && C != NULL); assert(A != NULL && B != NULL && C != NULL);
for(int i = 0; i < m; i++) for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++) for(int j = 0; j < n; j++)
C[i * n + j] = A[i * n + j] + B[i * n + j]; C[i*n + j] = A[i*n + j] + B[i*n + j];
} }
void lina_scale(double *A, double *B, double k, int m, int n){ void lina_scale(double *A, double *B, double k, int m, int n){
@@ -55,27 +55,46 @@ void lina_scale(double *A, double *B, double k, int m, int n){
for(int j = 0; j < n; j++) for(int j = 0; j < n; j++)
B[i * n + j] = k * A[i * n + j]; B[i*n + j] = k * A[i*n + j];
} }
void lina_transpose(double *A, double *B, int m, int n){ void lina_transpose(double *A, double *B, int m, int n)
{
assert(m > 0 && n > 0); assert(m > 0 && n > 0);
assert(A != NULL && B != NULL); assert(A != NULL && B != NULL);
#warning "Try to think better algorithm" if(m == 1 || n == 1)
{
memcpy(B, A, sizeof(A[0]) * m * n);
return;
}
double *support = malloc(sizeof(*support) * m * n); if(m == n)
{
for(int i = 0; i < n; i += 1)
for(int j = 0; j < i+1; j += 1)
{
double temp = A[i*n + j];
B[i*n + j] = A[j*n + i];
B[j*n + i] = temp;
}
}
else
{
B[0] = A[0];
B[m*n-1] = A[m*n-1];
check(support != NULL); double item = A[1];
int next = m;
memcpy(support, A, sizeof(*support) * m * n); while(next != 1)
{
double temp = A[next];
B[next] = item;
item = temp;
next = (next % n) * m + (next / n);
}
for(int i = 0; i < n; i++) B[1] = item;
}
for(int j = 0; j < m; j++)
B[j*n + i] = support[i*m + j];
free(support);
} }
+57 -15
View File
@@ -1,8 +1,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include "lina.h" #include "lina.h"
#define check assert
//Print the matrix A with size m by n //Print the matrix A with size m by n
static void pmatrix(FILE *fp, double *A, int m, int n); static void pmatrix(FILE *fp, double *A, int m, int n);
@@ -51,57 +54,91 @@ struct {
}; };
struct { struct {
double A[9], B[9]; double *A, *B;
int m, n;
} transp_tests[] = { } transp_tests[] = {
{ {
.A = { .A = (double[]) {
1, 0, 0, 1, 0, 0,
0, 2, 0, 0, 2, 0,
0, 0, 3, 0, 0, 3,
}, },
.B = { .B = (double[]) {
1, 0, 0, 1, 0, 0,
0, 2, 0, 0, 2, 0,
0, 0, 3, 0, 0, 3,
}, },
.m = 3,
.n = 3,
}, },
{ {
.A = { .A = (double[]) {
1, 2, 3, 1, 2, 3,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
}, },
.B = { .B = (double[]) {
1, 0, 0, 1, 0, 0,
2, 0, 0, 2, 0, 0,
3, 0, 0, 3, 0, 0,
}, },
.m = 3,
.n = 3,
}, },
{ {
.A = { .A = (double[]) {
0, 1, 0, 0, 1, 0,
0, 2, 0, 0, 2, 0,
0, 3, 0, 0, 3, 0,
}, },
.B = { .B = (double[]) {
0, 0, 0, 0, 0, 0,
1, 2, 3, 1, 2, 3,
0, 0, 0, 0, 0, 0,
}, },
.m = 3,
.n = 3,
}, },
{ {
.A = { .A = (double[]) {
0, 0, 1, 0, 0, 1,
0, 0, 2, 0, 0, 2,
0, 0, 3, 0, 0, 3,
}, },
.B = { .B = (double[]) {
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
1, 2, 3, 1, 2, 3,
}, },
.m = 3,
.n = 3,
},
{
.A = (double[]) {
1, 2, 3,
4, 5, 6,
},
.B = (double[]) {
1, 4,
2, 5,
3, 6,
},
.m = 2,
.n = 3,
},
{
.A = (double[]) {
1, 4,
2, 5,
3, 6,
},
.B = (double[]) {
1, 2, 3,
4, 5, 6,
},
.m = 3,
.n = 2,
}, },
}; };
int main() int main()
@@ -168,11 +205,16 @@ int main()
for(int i = 0; i < transp_total; i += 1) for(int i = 0; i < transp_total; i += 1)
{ {
double R[9]; int m = transp_tests[i].m;
int n = transp_tests[i].n;
lina_transpose(transp_tests[i].A, R, 3, 3); double R[32];
if(!memcmp(R, transp_tests[i].B, sizeof(R))) assert(sizeof(R) >= m * n * sizeof(R[0]));
lina_transpose(transp_tests[i].A, R, m, n);
if(!memcmp(R, transp_tests[i].B, sizeof(R[0]) * m * n))
{ {
fprintf(stderr, "Transposition test %d passed.\n", i); fprintf(stderr, "Transposition test %d passed.\n", i);
transp_passed += 1; transp_passed += 1;
@@ -180,9 +222,9 @@ int main()
else else
{ {
fprintf(stderr, "Transposition test %d failed:\n got matrix:\n\n", i); fprintf(stderr, "Transposition test %d failed:\n got matrix:\n\n", i);
pmatrix(stderr, R, 3, 3); pmatrix(stderr, R, m, n);
fprintf(stderr, " instead of:\n\n"); fprintf(stderr, " instead of:\n\n");
pmatrix(stderr, transp_tests[i].B, 3, 3); pmatrix(stderr, transp_tests[i].B, m, n);
} }
} }
fprintf(stderr, "\n\t%d transpositions out of %d were succesful.\n\n", transp_passed, transp_total); fprintf(stderr, "\n\t%d transpositions out of %d were succesful.\n\n", transp_passed, transp_total);
+62
View File
@@ -0,0 +1,62 @@
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "lina.h"
/* This function compares the lina_transpose
** implementation against the naive implementation.
*/
#define check assert
static void naive_transpose(double *A, double *B, int m, int n)
{
assert(m > 0 && n > 0);
assert(A != NULL && B != NULL);
double *support = malloc(sizeof(*support) * m * n);
check(support != NULL);
memcpy(support, A, sizeof(*support) * m * n);
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
B[j*n + i] = support[i*m + j];
free(support);
}
int main()
{
int m = 1000;
int n = 100000;
double *big = malloc(sizeof(double) * m * n);
check(big != NULL);
memset(big, 0, sizeof(double) * m * n);
double t1, t2;
clock_t begin, end;
begin = clock();
lina_transpose(big, big, m, n);
end = clock();
t1 = (double) (end - begin) / CLOCKS_PER_SEC;
begin = clock();
naive_transpose(big, big, m, n);
end = clock();
t2 = (double) (end - begin) / CLOCKS_PER_SEC;
printf("lina_transpose took %gms\n", t1*1000);
printf("naive_transpose took %gms\n", t2*1000);
free(big);
return 0;
}