Subversion Repositories programming

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
77 irasnyd 1
/* Ira Snyder
2
 * 04-20-2005
3
 *
4
 * CS331: Analysis of Algorithms
5
 * Project #1
6
 *
7
 * Due: 05-11-2005
8
 *
9
 * Changelog follows:
10
 *
11
 * 04-20-2005:
12
 *  Added code for Classical Method
13
 *  Added code for Divide-and-Conquer Method
14
 *  Switched to char (1 byte) from int (4 byte) to increase possible matrix size
15
 *
16
 * 04-21-2005:
17
 *  Changed creatematrix() to use malloc() instead of calloc() for speed
18
 *  Added createzeromatrix() which initializes the returned matrix to 0
19
 *  Changed the base case of multiply_dnq(). This gives a 4x speed up.
20
 *  Added Strassen's Method
21
 *
22
 *  CODE IS FEATURE COMPLETE AT THIS POINT
23
 *
24
 */
25
 
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <time.h>
29
 
30
/* function prototypes */
31
void printmatrix (char **matrix, int size);
32
char** creatematrix (int size);
33
char** createzeromatrix (int size);
34
char** freematrix (char **matrix, int size);
35
void fillmatrix (char **matrix, int size);
36
void multiply_classical (char **matrix1, char **matrix2, char **result, int size);
37
void copymatrix (char **source, char **dest, int startrow, int startcol, int size);
38
void multiply_dnq (char **matrix1, char **matrix2, char **result, int size);
39
void multiply_strassen (char **matrix1, char **matrix2, char **result, int size);
40
void copymatrix (char **source, char **dest, int startrow, int startcol, int size);
41
void copymatrixback (char **source, char **dest, int startrow, int startcol, int size);
42
void addmatrices (char **matrix1, char **matrix2, char **result, int size);
43
void submatrices (char **matrix1, char **matrix2, char **result, int size);
44
void startclock (void);
45
void stopclock (void);
46
void printtimetaken (char *funcname);
47
 
48
/* global timeval for timing the function calls */
49
struct timeval start_time, end_time, lapsed;
50
 
51
int main (void)
52
{
53
    int size;
54
    char **matrix1;
55
    char **matrix2;
56
    char **result;
57
 
58
    /* for loop runs in powers of 2 (2, 4, 8, 16, 32 ...) */
59
    for (size=2; size<=4096; size*=2)
60
    {
61
        /* create matrices */
62
        matrix1 = creatematrix (size);
63
        matrix2 = creatematrix (size);
64
        result = createzeromatrix (size);
65
 
66
        /* fill the matrices to be multiplied (with 1's) */
67
        fillmatrix (matrix1, size);
68
        fillmatrix (matrix2, size);
69
 
70
        /* print the current iteration's title */
71
        printf("Using %d x %d matrix\n", size, size);
72
 
73
        /* run the classical method */
74
        startclock();
75
        multiply_classical (matrix1, matrix2, result, size);
76
        stopclock();
77
        printtimetaken("classical");
78
 
79
        /* run the divide-and-conquer method */
80
        startclock();
81
        multiply_dnq (matrix1, matrix2, result, size);
82
        stopclock();
83
        printtimetaken("div-n-con");
84
 
85
        /* run the strassen method */
86
        startclock();
87
        multiply_strassen (matrix1, matrix2, result, size);
88
        stopclock();
89
        printtimetaken("strassens");
90
 
91
        printf("\n");
92
 
93
        /* free all the memory used for the matrices */
94
        freematrix (matrix1, size);
95
        freematrix (matrix2, size);
96
        freematrix (result, size);
97
    }
98
 
99
    return 0;
100
}
101
 
102
/* start the timer */
103
void startclock (void)
104
{
105
    /* gettimeofday(&start_time, (struct timeval*)0); */
106
    gettimeofday(&start_time, NULL);
107
}
108
 
109
/* stop the timer */
110
void stopclock (void)
111
{
112
    /* gettimeofday(&end_time, (struct timeval*)0); */
113
    gettimeofday(&end_time, NULL);
114
}
115
 
116
/* print the time taken to run, in microseconds */
117
void printtimetaken (char *funcname)
118
{
119
    double total_usecs = (end_time.tv_sec-start_time.tv_sec) * 1000000.0
120
                       + (end_time.tv_usec-start_time.tv_usec);
121
 
122
    printf("%s : %.3lf milliseconds\n", funcname, total_usecs/1000.0);
123
}
124
 
125
/* print out the contents of a matrix */
126
void printmatrix (char **matrix, int size)
127
{
128
    int i,j;
129
 
130
    for (i=0; i<size; i++)
131
    {
132
        for (j=0; j<size; j++)
133
            printf ("%i ", matrix[i][j]);
134
 
135
        printf("\n");
136
    }
137
}
138
 
139
/* allocate a matrix with dimensions size x size
140
 *
141
 * NOTE: The values are NOT INITIALIZED
142
 * 
143
 * WARNING: These get big fast!
144
 * size = 4096 is 16MB
145
 * size = 8192 is 64MB
146
 * size = 16384 is 256MB
147
 * size = 32768 is 1024MB (1GB)
148
 */
149
char** creatematrix (int size)
150
{
151
    char **matrix;
152
    int i;
153
 
154
    /* try to allocate first part of memory */
155
    matrix = (char**) malloc (size * sizeof(char*));
156
 
157
    /* check to make sure it allocated okay, exit if it didn't */
158
    if (matrix == NULL)
159
    {
160
        fprintf (stderr,"out of memory allocating size=%i matrix\n", size);
161
        exit (1);
162
    }
163
 
164
    for (i=0; i<size; i++)
165
    {
166
        /* try to allocate the array cells */
167
        matrix[i] = (char*) malloc (size * sizeof(char));
168
 
169
        /* check to make sure it allocated okay, exit if it didn't */
170
        if (matrix[i] == NULL)
171
        {
172
            fprintf (stderr, "out of memory allocating size=%i matrix\n", size);
173
            exit (1);
174
        }
175
    }
176
 
177
    return matrix;
178
}
179
 
180
/* allocate a matrix with dimensions size x size
181
 *
182
 * NOTE: The values are initialized to 0
183
 * 
184
 * WARNING: These get big fast!
185
 * size = 4096 is 16MB
186
 * size = 8192 is 64MB
187
 * size = 16384 is 256MB
188
 * size = 32768 is 1024MB (1GB)
189
 */
190
char** createzeromatrix (int size)
191
{
192
    char **matrix;
193
    int i;
194
 
195
    /* try to allocate first part of memory */
196
    matrix = (char**) calloc (size, sizeof(char*));
197
 
198
    /* check to make sure it allocated okay, exit if it didn't */
199
    if (matrix == NULL)
200
    {
201
        fprintf (stderr,"out of memory allocating size=%i matrix\n", size);
202
        exit (1);
203
    }
204
 
205
    for (i=0; i<size; i++)
206
    {
207
        /* try to allocate the array cells */
208
        matrix[i] = (char*) calloc (size, sizeof(char));
209
 
210
        /* check to make sure it allocated okay, exit if it didn't */
211
        if (matrix[i] == NULL)
212
        {
213
            fprintf (stderr, "out of memory allocating size=%i matrix\n", size);
214
            exit (1);
215
        }
216
    }
217
 
218
    return matrix;
219
}
220
 
221
/* free all the memory associated with the matrix */
222
char** freematrix (char **matrix, int size)
223
{
224
    int i;
225
 
226
    for (i=0; i<size; i++)
227
        free (matrix[i]);
228
 
229
    free (matrix);
230
 
231
    return NULL;
232
}
233
 
234
/* fill a matrix with 1's */
235
void fillmatrix (char **matrix, int size)
236
{
237
    int i,j;
238
 
239
    for (i=0; i<size; i++)
240
        for (j=0; j<size; j++)
241
            matrix[i][j] = 1;
242
 
243
    /* if you want numbers 0-9 to fill the matrix, use:
244
     * matrix[i][j] = (i+j)%10;
245
     */
246
 
247
}
248
 
249
/* multiply with the classical method (row * column) */
250
void multiply_classical (char **matrix1, char **matrix2, char **result, int size)
251
{
252
    int i, j, k;
253
 
254
    for (i=0; i<size; i++)
255
        for (j=0; j<size; j++)
256
            for (k=0; k<size; k++)
257
            {
258
                #ifdef DEBUG
259
                printf("i=%d j=%d k=%d\n", i,j,k);
260
                #endif
261
                result[i][j] += matrix1[i][k] * matrix2[k][j];
262
            }
263
}
264
 
265
/* Divide-and-Conquer method of matrix multiplication
266
 *
267
 * The matrix is broken up as follows:
268
 * 
269
 *           |
270
 *     quad1 | quad2
271
 *   -----------------
272
 *     quad3 | quad4
273
 *           |
274
 *
275
 * NOTE: Only works on matrices of size = 2^n
276
 */
277
void multiply_dnq (char **matrix1, char **matrix2, char **result, int size)
278
{
279
    char **m1quad1, **m1quad2, **m1quad3, **m1quad4;
280
    char **m2quad1, **m2quad2, **m2quad3, **m2quad4;
281
    char **resquad1, **resquad2, **resquad3, **resquad4;
282
    char **temp1, **temp2, **temp3, **temp4;
283
    char **temp5, **temp6, **temp7, **temp8;
284
    int newsize = size/2;
285
 
286
    /* base case */
287
    if (size == 2)
288
    {
289
        result[0][0] = matrix1[0][0] * matrix2[0][0] + matrix1[0][1] * matrix2[1][0];
290
        result[0][1] = matrix1[0][0] * matrix2[0][1] + matrix1[0][1] * matrix2[1][1];
291
        result[1][0] = matrix1[1][0] * matrix2[0][0] + matrix1[1][1] * matrix2[1][0];
292
        result[1][1] = matrix1[1][0] * matrix2[0][1] + matrix1[1][1] * matrix2[1][1];
293
        return;
294
    }
295
 
296
    /* create the matrices to hold matrix1 */
297
    m1quad1 = creatematrix(newsize);
298
    m1quad2 = creatematrix(newsize);
299
    m1quad3 = creatematrix(newsize);
300
    m1quad4 = creatematrix(newsize);
301
 
302
    /* create the matrices to hold matrix2 */
303
    m2quad1 = creatematrix(newsize);
304
    m2quad2 = creatematrix(newsize);
305
    m2quad3 = creatematrix(newsize);
306
    m2quad4 = creatematrix(newsize);
307
 
308
    /* create the matrices to hold the result */
309
    resquad1 = creatematrix(newsize);
310
    resquad2 = creatematrix(newsize);
311
    resquad3 = creatematrix(newsize);
312
    resquad4 = creatematrix(newsize);
313
 
314
    /* create the temporary matrices for addition */
315
    temp1 = creatematrix(newsize);
316
    temp2 = creatematrix(newsize);
317
    temp3 = creatematrix(newsize);
318
    temp4 = creatematrix(newsize);
319
    temp5 = creatematrix(newsize);
320
    temp6 = creatematrix(newsize);
321
    temp7 = creatematrix(newsize);
322
    temp8 = creatematrix(newsize);
323
 
324
    /* split matrix1 into it's 4 quadrants */
325
    copymatrix (matrix1, m1quad1, 0, 0, newsize);
326
    copymatrix (matrix1, m1quad2, 0, newsize, newsize);
327
    copymatrix (matrix1, m1quad3, newsize, 0, newsize);
328
    copymatrix (matrix1, m1quad4, newsize, newsize, newsize);
329
 
330
    /* split matrix2 into it's 4 quadrants */
331
    copymatrix (matrix2, m2quad1, 0, 0, newsize);
332
    copymatrix (matrix2, m2quad2, 0, newsize, newsize);
333
    copymatrix (matrix2, m2quad3, newsize, 0, newsize);
334
    copymatrix (matrix2, m2quad4, newsize, newsize, newsize);
335
 
336
    /* calculate each of the 8 multiplications */
337
    multiply_dnq (m1quad1, m2quad1, temp1, newsize);
338
    multiply_dnq (m1quad2, m2quad3, temp2, newsize);
339
    multiply_dnq (m1quad1, m2quad2, temp3, newsize);
340
    multiply_dnq (m1quad1, m2quad4, temp4, newsize);
341
    multiply_dnq (m1quad3, m2quad1, temp5, newsize);
342
    multiply_dnq (m1quad4, m2quad3, temp6, newsize);
343
    multiply_dnq (m1quad3, m2quad2, temp7, newsize);
344
    multiply_dnq (m1quad4, m2quad4, temp8, newsize);
345
 
346
    /* add the 8 multiplications to get the 4 quadrants */
347
    addmatrices (temp1, temp2, resquad1, newsize);
348
    addmatrices (temp3, temp4, resquad2, newsize);
349
    addmatrices (temp5, temp6, resquad3, newsize);
350
    addmatrices (temp7, temp8, resquad4, newsize);
351
 
352
    /* copy the quadrants back into result */
353
    copymatrixback (resquad1, result, 0, 0, newsize);
354
    copymatrixback (resquad2, result, 0, newsize, newsize);
355
    copymatrixback (resquad3, result, newsize, 0, newsize);
356
    copymatrixback (resquad4, result, newsize, newsize, newsize);
357
 
358
    /* free all the temporary matrices */
359
    freematrix (m1quad1, newsize);
360
    freematrix (m1quad2, newsize);
361
    freematrix (m1quad3, newsize);
362
    freematrix (m1quad4, newsize);
363
 
364
    freematrix (m2quad1, newsize);
365
    freematrix (m2quad2, newsize);
366
    freematrix (m2quad3, newsize);
367
    freematrix (m2quad4, newsize);
368
 
369
    freematrix (resquad1, newsize);
370
    freematrix (resquad2, newsize);
371
    freematrix (resquad3, newsize);
372
    freematrix (resquad4, newsize);
373
 
374
    freematrix (temp1, newsize);
375
    freematrix (temp2, newsize);
376
    freematrix (temp3, newsize);
377
    freematrix (temp4, newsize);
378
    freematrix (temp5, newsize);
379
    freematrix (temp6, newsize);
380
    freematrix (temp7, newsize);
381
    freematrix (temp8, newsize);
382
}
383
 
384
/* copies a portion of the source to the destination */
385
void copymatrix (char **source, char **dest, int startrow, int startcol, int size)
386
{
387
    int i, j;
388
 
389
    for (i=0; i<size; i++)
390
        for (j=0; j<size; j++)
391
            dest[i][j] = source[i+startrow][j+startcol];
392
 
393
}
394
 
395
/* copies from the source to a portion of the destination */
396
void copymatrixback (char **source, char **dest, int startrow, int startcol, int size)
397
{
398
    int i, j;
399
 
400
    for (i=0; i<size; i++)
401
        for (j=0; j<size; j++)
402
            dest[i+startrow][j+startcol] = source[i][j];
403
 
404
}
405
 
406
/* adds two matrices together */
407
void addmatrices (char **matrix1, char **matrix2, char **result, int size)
408
{
409
    int i, j;
410
 
411
    for (i=0; i<size; i++)
412
        for (j=0; j<size; j++)
413
            result[i][j] = matrix1[i][j] + matrix2[i][j];
414
 
415
}
416
void multiply_strassen (char **matrix1, char **matrix2, char **result, int size)
417
{
418
    char **m1quad1, **m1quad2, **m1quad3, **m1quad4;
419
    char **m2quad1, **m2quad2, **m2quad3, **m2quad4;
420
    char **resquad1, **resquad2, **resquad3, **resquad4;
421
    char **p, **q, **r, **s, **t, **u, **v;
422
    char **temp1, **temp2, **temp3, **temp4, **temp5, **temp6, **temp7;
423
    char **temp8, **temp9, **temp10, **temp11, **temp12, **temp13, **temp14;
424
    int newsize = size/2;
425
 
426
    /* base case */
427
    if (size == 2)
428
    {
429
        result[0][0] = matrix1[0][0] * matrix2[0][0] + matrix1[0][1] * matrix2[1][0];
430
        result[0][1] = matrix1[0][0] * matrix2[0][1] + matrix1[0][1] * matrix2[1][1];
431
        result[1][0] = matrix1[1][0] * matrix2[0][0] + matrix1[1][1] * matrix2[1][0];
432
        result[1][1] = matrix1[1][0] * matrix2[0][1] + matrix1[1][1] * matrix2[1][1];
433
        return;
434
    }
435
 
436
    /* create the matrices to hold matrix1 */
437
    m1quad1 = creatematrix(newsize);
438
    m1quad2 = creatematrix(newsize);
439
    m1quad3 = creatematrix(newsize);
440
    m1quad4 = creatematrix(newsize);
441
 
442
    /* create the matrices to hold matrix2 */
443
    m2quad1 = creatematrix(newsize);
444
    m2quad2 = creatematrix(newsize);
445
    m2quad3 = creatematrix(newsize);
446
    m2quad4 = creatematrix(newsize);
447
 
448
    /* create the matrices to hold the result */
449
    resquad1 = creatematrix(newsize);
450
    resquad2 = creatematrix(newsize);
451
    resquad3 = creatematrix(newsize);
452
    resquad4 = creatematrix(newsize);
453
 
454
    /* create the temporary matrices for addition */
455
    temp1 = creatematrix(newsize);
456
    temp2 = creatematrix(newsize);
457
    temp3 = creatematrix(newsize);
458
    temp4 = creatematrix(newsize);
459
    temp5 = creatematrix(newsize);
460
    temp6 = creatematrix(newsize);
461
    temp7 = creatematrix(newsize);
462
    temp8 = creatematrix(newsize);
463
    temp9 = creatematrix(newsize);
464
    temp10 = creatematrix(newsize);
465
    temp11 = creatematrix(newsize);
466
    temp12 = creatematrix(newsize);
467
    temp13 = creatematrix(newsize);
468
    temp14 = creatematrix(newsize);
469
    p = creatematrix(newsize);
470
    q = creatematrix(newsize);
471
    r = creatematrix(newsize);
472
    s = creatematrix(newsize);
473
    t = creatematrix(newsize);
474
    u = creatematrix(newsize);
475
    v = creatematrix(newsize);
476
 
477
    /* split matrix1 into it's 4 quadrants */
478
    copymatrix (matrix1, m1quad1, 0, 0, newsize);
479
    copymatrix (matrix1, m1quad2, 0, newsize, newsize);
480
    copymatrix (matrix1, m1quad3, newsize, 0, newsize);
481
    copymatrix (matrix1, m1quad4, newsize, newsize, newsize);
482
 
483
    /* split matrix2 into it's 4 quadrants */
484
    copymatrix (matrix2, m2quad1, 0, 0, newsize);
485
    copymatrix (matrix2, m2quad2, 0, newsize, newsize);
486
    copymatrix (matrix2, m2quad3, newsize, 0, newsize);
487
    copymatrix (matrix2, m2quad4, newsize, newsize, newsize);
488
 
489
    /* calculate all the additions necessary for pqrstuv */
490
    addmatrices (m1quad1, m1quad4, temp1, newsize);
491
    addmatrices (m2quad1, m2quad4, temp2, newsize);
492
    addmatrices (m1quad3, m1quad4, temp3, newsize);
493
    submatrices (m2quad2, m2quad4, temp4, newsize);
494
    submatrices (m2quad3, m2quad1, temp5, newsize);
495
    addmatrices (m1quad1, m1quad2, temp6, newsize);
496
    submatrices (m1quad3, m1quad1, temp7, newsize);
497
    addmatrices (m2quad1, m2quad2, temp8, newsize);
498
    submatrices (m1quad2, m1quad4, temp9, newsize);
499
    addmatrices (m2quad3, m2quad4, temp10, newsize);
500
 
501
    /* call multiply_strassen() */
502
    multiply_strassen (temp1, temp2, p, newsize);
503
    multiply_strassen (temp3, m2quad1, q, newsize);
504
    multiply_strassen (m1quad1, temp4, r, newsize);
505
    multiply_strassen (m1quad4, temp5, s, newsize);
506
    multiply_strassen (temp6, m2quad4, t, newsize);
507
    multiply_strassen (temp7, temp8, u, newsize);
508
    multiply_strassen (temp9, temp10, v, newsize);
509
 
510
    /* find first result quadrant */
511
    addmatrices (p, s, temp11, newsize);
512
    addmatrices (t, v, temp12, newsize);
513
    submatrices (temp11, temp12, resquad1, newsize);
514
 
515
    /* find second result quadrant */
516
    addmatrices (r, t, resquad2, newsize);
517
 
518
    /* find third result quadrant */
519
    addmatrices (q, s, resquad3, newsize);
520
 
521
    /* find fourth result quadrant */
522
    addmatrices (p, r, temp13, newsize);
523
    addmatrices (q, u, temp14, newsize);
524
    submatrices (temp13, temp14, resquad4, newsize);
525
 
526
    /* copy the quadrants back into result */
527
    copymatrixback (resquad1, result, 0, 0, newsize);
528
    copymatrixback (resquad2, result, 0, newsize, newsize);
529
    copymatrixback (resquad3, result, newsize, 0, newsize);
530
    copymatrixback (resquad4, result, newsize, newsize, newsize);
531
 
532
    /* free all the temporary matrices */
533
    freematrix (m1quad1, newsize);
534
    freematrix (m1quad2, newsize);
535
    freematrix (m1quad3, newsize);
536
    freematrix (m1quad4, newsize);
537
 
538
    freematrix (m2quad1, newsize);
539
    freematrix (m2quad2, newsize);
540
    freematrix (m2quad3, newsize);
541
    freematrix (m2quad4, newsize);
542
 
543
    freematrix (resquad1, newsize);
544
    freematrix (resquad2, newsize);
545
    freematrix (resquad3, newsize);
546
    freematrix (resquad4, newsize);
547
 
548
    freematrix (p, newsize);
549
    freematrix (q, newsize);
550
    freematrix (r, newsize);
551
    freematrix (s, newsize);
552
    freematrix (t, newsize);
553
    freematrix (u, newsize);
554
    freematrix (v, newsize);
555
 
556
    freematrix (temp1, newsize);
557
    freematrix (temp2, newsize);
558
    freematrix (temp3, newsize);
559
    freematrix (temp4, newsize);
560
    freematrix (temp5, newsize);
561
    freematrix (temp6, newsize);
562
    freematrix (temp7, newsize);
563
    freematrix (temp8, newsize);
564
    freematrix (temp9, newsize);
565
    freematrix (temp10, newsize);
566
    freematrix (temp11, newsize);
567
    freematrix (temp12, newsize);
568
    freematrix (temp13, newsize);
569
    freematrix (temp14, newsize);
570
}
571
 
572
/* subtracts two matrices (matrix1 - matrix2) */
573
void submatrices (char **matrix1, char **matrix2, char **result, int size)
574
{
575
    int i, j;
576
 
577
    for (i=0; i<size; i++)
578
        for (j=0; j<size; j++)
579
            result[i][j] = matrix1[i][j] - matrix2[i][j];
580
 
581
}
582