Subversion Repositories programming

Rev

Rev 100 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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