Subversion Repositories programming

Rev

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