1 /*
2  * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @key stress
27  *
28  * @summary converted from VM testbase nsk/stress/numeric/numeric010.
29  * VM testbase keywords: [stress, slow, nonconcurrent, quick]
30  * VM testbase readme:
31  * DESCRIPTION
32  *     This test calculates the product A*A for a square matrix A, and checks
33  *     if such product is calculated correctly. Elements of the matrix A are
34  *     initiated with integer numbers, so that A*A must be the same if calculated
35  *     with double, float, long, or int precision. The test just checks, if
36  *     double, float, long, and int variants of the product calculation result
37  *     in the same A*A matrix.
38  *     The product A*A is calculated twice: in a single thread, and in N separate
39  *     threads, where NxN is the size of square matrix A. When executing in N
40  *     threads, each thread calculate distinct row of the resulting matrix.
41  *     HotSpot releases 1.0 and 1.3 seem to do not adjust JVM for better
42  *     performance in single-thread calculation, while milti-threads calculation
43  *     usually runs much faster. I guess, that the 1-thread calculation is probably
44  *     executed by HotSpot interpreter, and HotSpot compiler is probably involved
45  *     to execute N-threads calculation. So, the test apparently checks accuracy
46  *     of A*A calculation in both compilation and interpretation modes.
47  *     By the way, the test checks JVM performance. The test is treated failed
48  *     due to poor performance, if single-thread calculation is essentially
49  *     slower than N-threads calculation (surely, the number of CPUs installed
50  *     on the platform executing the test is taken into account for performance
51  *     testing). The calculation algorithm is encoded with 3-levels cycle like:
52  *         for (int line=0; line<N; line++)
53  *             for (int column=0; column<N; column++) {
54  *                 float sum = 0;
55  *                 for (int k=0; k<N; k++)
56  *                     sum += A[line][k]    A[k][column];
57  *                 AA[line][column] = sum;
58  *             }
59  *     In this test, N=200, so that A is 200x200 matrix; and multiplication
60  *     A[line][k]*A[k][column] is executed 200**3=8 millions times in this
61  *     cycle. I believe, that this is HotSpot bug to do not adjust JVM for
62  *     best performance during such a huge series of executions of the rather
63  *     compact portion of program code.
64  * COMMENTS
65  *     The bug was filed referencing to the same numeric algorithm,
66  *     which is used by this test:
67  *         4242172 (P3/S5) 2.0: poor performance in matrix calculations
68  *     Note, that despite HotSpot works faster in milti-thread calculations,
69  *     it still remains essentially slower than classic VM with JIT on.
70  *
71  * @run main/othervm nsk.stress.numeric.numeric010.numeric010 200 200
72  */
73 
74 package nsk.stress.numeric.numeric010;
75 
76 import java.io.PrintStream;
77 
78 /**
79  * This test calculates the product <code>A<sup>.</sup>A</code> for a square
80  * matrix <code>A</code>, and checks if such product is calculated correctly.
81  * Elements of the matrix <code>A</code> are initiated with integer numbers,
82  * so that <code>A<sup>.</sup>A</code> must be the same if calculated with
83  * <code>double</code>, <code>float</code>, <code>long</code>, or
84  * <code>int</code> precision. The test just checks, if <code>double</code>,
85  * <code>float</code>, <code>long</code>, and <code>int</code> variants of
86  * the product calculation result in the same <code>A<sup>.</sup>A</code>
87  * matrix.
88  * <p>
89  * <p>The product <code>A<sup>.</sup>A</code> is calculated twice: in a single
90  * thread, and in <code>N</code> separate threads, where <code>NxN</code> is
91  * the size of square matrix <code>A</code>. When executing in <code>N</code>
92  * threads, each thread calculate distinct row of the resulting matrix. HotSpot
93  * releases 1.0 and 1.3 seem to do not adjust JVM for better performance in
94  * single-thread calculation, while milti-threads calculation usually runs much
95  * faster. I guess, that the 1-thread calculation is probably executed by HotSpot
96  * interpreter, and HotSpot compiler is probably involved to execute
97  * <code>N</code>-threads calculation. So, the test apparently checks accuracy
98  * of <code>A<sup>.</sup>A</code> calculation in both compilation and
99  * interpretation modes.
100  * <p>
101  * <p>By the way, the test checks JVM performance. The test is treated failed
102  * due to poor performance, if single-thread calculation is essentially
103  * slower than <code>N</code>-threads calculation (surely, the number of CPUs
104  * installed on the platform executing the test is taken into account for
105  * performance testing). The calculation algorithm is encoded with 3-levels
106  * cycle like:
107  * <pre>
108  *     for (int line=0; line&lt;N; line++)
109  *         for (int column=0; column&lt;N; column++) {
110  *             float sum = 0;
111  *             for (int k=0; k&lt;N; k++)
112  *                 sum += A[line][k] * A[k][column];
113  *             AA[line][column] = sum;
114  *         }
115  * </pre>
116  * <p>
117  * In this test, <code>N</code>=200, so that <code>A</code> is 200x200 matrix;
118  * and multiplication <code>A[line][k]*A[k][column]</code> is executed
119  * 200<sup>3</sup>=8 millions times in this cycle. I believe, that this is HotSpot
120  * bug to do not adjust JVM for best performance during such a huge series of
121  * executions of the rather compact portion of program code.
122  * <p>
123  * <p>See the bug-report:
124  * <br>&nbsp;&nbsp;
125  * 4242172 (P3/S5) 2.0: poor performance in matrix calculations
126  */
127 public class numeric010 {
128     /**
129      * When testing performance, 1-thread calculation is allowed to be 10%
130      * slower than multi-thread calculation (<code>tolerance</code> is
131      * assigned to 10 now).
132      */
133     public static double tolerance = 100; // 10;
134 
135     /**
136      * Re-assign this value to <code>true</code> for better diagnostics.
137      *
138      * @see #print(Object)
139      * @see #println(Object)
140      */
141     private static boolean verbose = false;
142 
143     /**
144      * Stream to print execution trace and/or error messages.
145      * This stream usually equals to <code>System.out</code>
146      */
147     private static PrintStream out = null;
148 
149     /**
150      * Print error-message.
151      *
152      * @see #out
153      */
complain(Object x)154     private static void complain(Object x) {
155         out.println("# " + x);
156     }
157 
158     /**
159      * Print to execution trace, if mode is <code>verbose</code>.
160      *
161      * @see #verbose
162      * @see #out
163      */
print(Object x)164     private static void print(Object x) {
165         if (verbose)
166             out.print(x);
167     }
168 
169     /**
170      * Print line to execution trace, if mode is <code>verbose</code>.
171      *
172      * @see #verbose
173      * @see #out
174      */
println(Object x)175     private static void println(Object x) {
176         print(x + "\n");
177     }
178 
179     /**
180      * Re-invoke <code>run(args,out)</code> in order to simulate
181      * JCK-like test interface.
182      */
main(String args[])183     public static void main(String args[]) {
184         int exitCode = run(args, System.out);
185         System.exit(exitCode + 95);
186         // JCK-like exit status
187     }
188 
189     /**
190      * Parse command-line parameters stored in <code>args[]</code> and run
191      * the test.
192      * <p>
193      * <p>Command-line parameters are:
194      * <br>&nbsp;&nbsp;
195      * <code>java numeric010 [-verbose] [-performance]
196      * [-tolerance:<i>percents</i>] [-CPU:<i>number</i>]
197      * <i>matrixSize</i> [<i>threads</i>]</code>
198      * <p>
199      * <p>Here:
200      * <br>&nbsp;&nbsp;<code>-verbose</code> -
201      * keyword, which alows to print execution trace
202      * <br>&nbsp;&nbsp;<code>-performance</code> -
203      * keyword, which alows performance testing
204      * <br>&nbsp;&nbsp;<code>-tolerance</code> -
205      * setup tolerance of performance checking
206      * <br>&nbsp;&nbsp;<code><i>percents</i></code> -
207      * 1-thread calculation is allowed to be
208      * <code><i>percents</i></code>% slower
209      * <br>&nbsp;&nbsp;<code><i>number</i></code> -
210      * number of CPU installed on the computer just executing the test
211      * <br>&nbsp;&nbsp;<code><i>matrixSize</i></code> -
212      * number of rows (and columns) in square matrix to be tested
213      * <br>&nbsp;&nbsp;<code><i>threads</i></code> -
214      * for multi-thread calculation
215      * (default: <code><i>matrixSize</i></code>)
216      *
217      * @param args strings array containing command-line parameters
218      * @param out  the test log, usually <code>System.out</code>
219      */
run(String args[], PrintStream out)220     public static int run(String args[], PrintStream out) {
221         numeric010.out = out;
222 
223         boolean testPerformance = false;
224         int numberOfCPU = 1;
225 
226         int argsShift = 0;
227         for (; argsShift < args.length; argsShift++) {
228             String argument = args[argsShift];
229 
230             if (!argument.startsWith("-"))
231                 break;
232 
233             if (argument.equals("-performance")) {
234                 testPerformance = true;
235                 continue;
236             }
237 
238             if (argument.equals("-verbose")) {
239                 verbose = true;
240                 continue;
241             }
242 
243             if (argument.startsWith("-tolerance:")) {
244                 String percents =
245                         argument.substring("-tolerance:".length(), argument.length());
246                 tolerance = Integer.parseInt(percents);
247 
248                 if ((tolerance < 0) || (tolerance > 100)) {
249                     complain("Tolerance should be 0 to 100%: " + argument);
250                     return 2; // failure
251                 }
252                 continue;
253             }
254 
255             if (argument.startsWith("-CPU:")) {
256                 String value =
257                         argument.substring("-CPU:".length(), argument.length());
258                 numberOfCPU = Integer.parseInt(value);
259 
260                 if (numberOfCPU < 1) {
261                     complain("Illegal number of CPU: " + argument);
262                     return 2; // failure
263                 }
264                 continue;
265             }
266 
267             complain("Cannot recognize argument: args[" + argsShift + "]: " + argument);
268             return 2; // failure
269         }
270 
271         if ((args.length < argsShift + 1) || (args.length > argsShift + 2)) {
272             complain("Illegal argument(s). Execute:");
273             complain(
274                     "    java numeric010 [-verbose] [-performance] " +
275                             "[-tolerance:percents] [-CPU:number] matrixSize [threads]");
276             return 2; // failure
277         }
278 
279         int size = Integer.parseInt(args[argsShift]);
280         if ((size < 100) || (size > 10000)) {
281             complain("Matrix size should be 100 to 1000 lines & columns.");
282             return 2; // failure
283         }
284 
285         int threads = size;
286         if (args.length >= argsShift + 2)
287             threads = Integer.parseInt(args[argsShift + 1]);
288         if ((threads < 1) || (threads > size)) {
289             complain("Threads number should be 1 to matrix size.");
290             return 2; // failure
291         }
292         if ((size % threads) != 0) {
293             complain("Threads number should evenly divide matrix size.");
294             return 2; // failure
295         }
296 
297         print("Preparing A[" + size + "," + size + "]:");
298         IntegerMatrix intA = new IntegerMatrix(size);
299         IntegerMatrix intAA = new IntegerMatrix(size);
300         LongMatrix longA = new LongMatrix(intA);
301         LongMatrix longAA = new LongMatrix(intA);
302         FloatMatrix floatA = new FloatMatrix(intA);
303         FloatMatrix floatAA = new FloatMatrix(intA);
304         DoubleMatrix doubleA = new DoubleMatrix(intA);
305         DoubleMatrix doubleAA = new DoubleMatrix(intA);
306         println(" done.");
307 
308         double elapsed[] = {0, 0};
309 
310         for (int i = 0; i < 2; i++) {
311             double seconds =
312                     elapsedTime((i == 0 ? 1 : threads),
313                             intA, intAA,
314                             longA, longAA,
315                             floatA, floatAA,
316                             doubleA, doubleAA);
317             elapsed[i] = seconds;
318 
319             print("Checking accuracy:");
320             for (int line = 0; line < size; line++)
321                 for (int column = 0; column < size; column++) {
322                     if (intAA.value[line][column] != longAA.value[line][column]) {
323                         println("");
324                         complain("Test failed:");
325                         complain("Integer and Long results differ at:");
326                         complain("  line=" + line + ", column=" + column);
327                         complain(" intAA.value[line][column]=" + intAA.value[line][column]);
328                         complain("longAA.value[line][column]=" + longAA.value[line][column]);
329                         return 2; // FAILED
330                     }
331                     if (intAA.value[line][column] != floatAA.value[line][column]) {
332                         println("");
333                         complain("Test failed:");
334                         complain("Integer and Float results differ at:");
335                         complain("  line=" + line + ", column=" + column);
336                         complain("  intAA.value[line][column]=" + intAA.value[line][column]);
337                         complain("floatAA.value[line][column]=" + floatAA.value[line][column]);
338                         return 2; // FAILED
339                     }
340                     if (intAA.value[line][column] != doubleAA.value[line][column]) {
341                         println("");
342                         complain("Test failed:");
343                         complain("Integer and Double results differ at:");
344                         complain("  line=" + line + ", column=" + column);
345                         complain("   intAA.value[line][column]=" + intAA.value[line][column]);
346                         complain("doubleAA.value[line][column]=" + doubleAA.value[line][column]);
347                         return 2; // FAILED
348                     }
349                 }
350             println(" done.");
351         }
352 
353         double overallTime = elapsed[0] + elapsed[1];
354         double averageTime = overallTime / 2;   // 2 excutions
355         double averagePerformance = 4 * size * size * (size + size) / averageTime / 1e6;
356         println("");
357         println("Overall elapsed time: " + overallTime + " seconds.");
358         println("Average elapsed time: " + averageTime + " seconds.");
359         println("Average performance: " + averagePerformance + " MOPS");
360 
361         if (testPerformance) {
362             println("");
363             print("Checking performance: ");
364             double elapsed1 = elapsed[0];
365             double elapsedM = elapsed[1] * numberOfCPU;
366             if (elapsed1 > elapsedM * (1 + tolerance / 100)) {
367                 println("");
368                 complain("Test failed:");
369                 complain("Single-thread calculation is essentially slower:");
370                 complain("Calculation time elapsed (seconds):");
371                 complain("  single thread: " + elapsed[0]);
372                 complain("  multi-threads: " + elapsed[1]);
373                 complain("  number of CPU: " + numberOfCPU);
374                 complain("  tolerance: " + tolerance + "%");
375                 return 2; // FAILED
376             }
377             println("done.");
378         }
379 
380         println("Test passed.");
381         return 0; // PASSED
382     }
383 
384     /**
385      * Return time (in seconds) elapsed for calculation of matrix
386      * product <code>A*A</code> with <code>int</code>, <code>long</code>,
387      * <code>float</code>, and <code>double</code> representations.
388      */
elapsedTime(int threads, IntegerMatrix intA, IntegerMatrix intAA, LongMatrix longA, LongMatrix longAA, FloatMatrix floatA, FloatMatrix floatAA, DoubleMatrix doubleA, DoubleMatrix doubleAA)389     private static double elapsedTime(int threads,
390                                       IntegerMatrix intA, IntegerMatrix intAA,
391                                       LongMatrix longA, LongMatrix longAA,
392                                       FloatMatrix floatA, FloatMatrix floatAA,
393                                       DoubleMatrix doubleA, DoubleMatrix doubleAA) {
394 
395         println("");
396         print("Computing A*A with " + threads + " thread(s):");
397         long mark1 = System.currentTimeMillis();
398         intAA.setSquareOf(intA, threads);
399         longAA.setSquareOf(longA, threads);
400         floatAA.setSquareOf(floatA, threads);
401         doubleAA.setSquareOf(doubleA, threads);
402         long mark2 = System.currentTimeMillis();
403         println(" done.");
404 
405         int size = intA.size();
406         double sec = (mark2 - mark1) / 1000.0;
407         double perf = 4 * size * size * (size + size) / sec;
408         println("Elapsed time: " + sec + " seconds");
409         println("Performance: " + perf / 1e6 + " MOPS");
410 
411         return sec;
412     }
413 
414     /**
415      * Compute <code>A*A</code> for <code>int</code> matrix <code>A</code>.
416      */
417     private static class IntegerMatrix {
418         volatile int value[][];
419 
420         /**
421          * Number of lines and columns in <code>this</code> square matrix.
422          */
size()423         public int size() {
424             return value.length;
425         }
426 
427         /**
428          * New square matrix with random elements.
429          */
IntegerMatrix(int size)430         public IntegerMatrix(int size) {
431             value = new int[size][size];
432             for (int line = 0; line < size; line++)
433                 for (int column = 0; column < size; column++)
434                     value[line][column] =
435                             Math.round((float) ((1 - 2 * Math.random()) * size));
436         }
437 
438         /**
439          * Assign <code>this</code> matrix with <code>A*A</code>.
440          *
441          * @param threads Split computation into the given number of threads.
442          */
setSquareOf(IntegerMatrix A, int threads)443         public void setSquareOf(IntegerMatrix A, int threads) {
444             if (this.size() != A.size())
445                 throw new IllegalArgumentException(
446                         "this.size() != A.size()");
447 
448             if ((size() % threads) != 0)
449                 throw new IllegalArgumentException("size()%threads != 0");
450             int bunch = size() / threads;
451 
452             Thread task[] = new Thread[threads];
453             for (int t = 0; t < threads; t++) {
454                 int line0 = bunch * t;
455                 MatrixComputer computer =
456                         new MatrixComputer(value, A.value, line0, bunch);
457                 task[t] = new Thread(computer);
458             }
459 
460             for (int t = 0; t < threads; t++)
461                 task[t].start();
462 
463             for (int t = 0; t < threads; t++)
464                 if (task[t].isAlive())
465                     try {
466                         task[t].join();
467                     } catch (InterruptedException exception) {
468                         throw new RuntimeException(exception.toString());
469                     }
470         }
471 
472         /**
473          * Thread to compute a bunch of lines of matrix square.
474          */
475         private static class MatrixComputer implements Runnable {
476             private int result[][];
477             private int source[][];
478             private int line0;
479             private int bunch;
480 
481             /**
482              * Register a task for matrix multiplication.
483              */
MatrixComputer( int result[][], int source[][], int line0, int bunch)484             public MatrixComputer(
485                     int result[][], int source[][], int line0, int bunch) {
486 
487                 this.result = result;   // reference to resulting matrix value
488                 this.source = source;   // reference to matrix to be squared
489                 this.line0 = line0;     // compute lines from line0 to ...
490                 this.bunch = bunch;     // number of resulting lines to compute
491             }
492 
493             /**
494              * Do execute the task just registered for <code>this</code> thread.
495              */
run()496             public void run() {
497                 int line1 = line0 + bunch;
498                 int size = result.length;
499                 for (int line = line0; line < line1; line++)
500                     for (int column = 0; column < size; column++) {
501                         int sum = 0;
502                         for (int i = 0; i < size; i++)
503                             sum += source[line][i] * source[i][column];
504                         result[line][column] = sum;
505                     }
506             }
507 
508         }
509 
510     }
511 
512     /**
513      * Compute <code>A*A</code> for <code>long</code> matrix <code>A</code>.
514      */
515     private static class LongMatrix {
516         volatile long value[][];
517 
518         /**
519          * Number of lines and columns in <code>this</code> square matrix.
520          */
size()521         public int size() {
522             return value.length;
523         }
524 
525 
526         /**
527          * New square matrix with the given integer elements.
528          */
LongMatrix(IntegerMatrix A)529         public LongMatrix(IntegerMatrix A) {
530             int size = A.size();
531             value = new long[size][size];
532             for (int line = 0; line < size; line++)
533                 for (int column = 0; column < size; column++)
534                     value[line][column] = A.value[line][column];
535         }
536 
537         /**
538          * Assign <code>this</code> matrix with <code>A*A</code>.
539          *
540          * @param threads Split computation into the given number of threads.
541          */
setSquareOf(LongMatrix A, int threads)542         public void setSquareOf(LongMatrix A, int threads) {
543             if (this.size() != A.size())
544                 throw new IllegalArgumentException(
545                         "this.size() != A.size()");
546 
547             if ((size() % threads) != 0)
548                 throw new IllegalArgumentException("size()%threads != 0");
549             int bunch = size() / threads;
550 
551             Thread task[] = new Thread[threads];
552             for (int t = 0; t < threads; t++) {
553                 int line0 = bunch * t;
554                 MatrixComputer computer =
555                         new MatrixComputer(value, A.value, line0, bunch);
556                 task[t] = new Thread(computer);
557             }
558 
559             for (int t = 0; t < threads; t++)
560                 task[t].start();
561 
562             for (int t = 0; t < threads; t++)
563                 if (task[t].isAlive())
564                     try {
565                         task[t].join();
566                     } catch (InterruptedException exception) {
567                         throw new RuntimeException(exception.toString());
568                     }
569         }
570 
571         /**
572          * Thread to compute a bunch of lines of matrix square.
573          */
574         private static class MatrixComputer implements Runnable {
575             private long result[][];
576             private long source[][];
577             private int line0;
578             private int bunch;
579 
580             /**
581              * Register a task for matrix multiplication.
582              */
MatrixComputer( long result[][], long source[][], int line0, int bunch)583             public MatrixComputer(
584                     long result[][], long source[][], int line0, int bunch) {
585 
586                 this.result = result;   // reference to resulting matrix value
587                 this.source = source;   // reference to matrix to be squared
588                 this.line0 = line0;     // compute lines from line0 to ...
589                 this.bunch = bunch;     // number of resulting lines to compute
590             }
591 
592             /**
593              * Do execute the task just registered for <code>this</code> thread.
594              */
run()595             public void run() {
596                 int line1 = line0 + bunch;
597                 int size = result.length;
598                 for (int line = line0; line < line1; line++)
599                     for (int column = 0; column < size; column++) {
600                         long sum = 0;
601                         for (int i = 0; i < size; i++)
602                             sum += source[line][i] * source[i][column];
603                         result[line][column] = sum;
604                     }
605             }
606 
607         }
608 
609     }
610 
611     /**
612      * Compute <code>A*A</code> for <code>float</code> matrix <code>A</code>.
613      */
614     private static class FloatMatrix {
615         volatile float value[][];
616 
617         /**
618          * Number of lines and columns in <code>this</code> square matrix.
619          */
size()620         public int size() {
621             return value.length;
622         }
623 
624 
625         /**
626          * New square matrix with the given integer elements.
627          */
FloatMatrix(IntegerMatrix A)628         public FloatMatrix(IntegerMatrix A) {
629             int size = A.size();
630             value = new float[size][size];
631             for (int line = 0; line < size; line++)
632                 for (int column = 0; column < size; column++)
633                     value[line][column] = A.value[line][column];
634         }
635 
636         /**
637          * Assign <code>this</code> matrix with <code>A*A</code>.
638          *
639          * @param threads Split computation into the given number of threads.
640          */
setSquareOf(FloatMatrix A, int threads)641         public void setSquareOf(FloatMatrix A, int threads) {
642             if (this.size() != A.size())
643                 throw new IllegalArgumentException(
644                         "this.size() != A.size()");
645 
646             if ((size() % threads) != 0)
647                 throw new IllegalArgumentException("size()%threads != 0");
648             int bunch = size() / threads;
649 
650             Thread task[] = new Thread[threads];
651             for (int t = 0; t < threads; t++) {
652                 int line0 = bunch * t;
653                 MatrixComputer computer =
654                         new MatrixComputer(value, A.value, line0, bunch);
655                 task[t] = new Thread(computer);
656             }
657 
658             for (int t = 0; t < threads; t++)
659                 task[t].start();
660 
661             for (int t = 0; t < threads; t++)
662                 if (task[t].isAlive())
663                     try {
664                         task[t].join();
665                     } catch (InterruptedException exception) {
666                         throw new RuntimeException(exception.toString());
667                     }
668         }
669 
670         /**
671          * Thread to compute a bunch of lines of matrix square.
672          */
673         private static class MatrixComputer implements Runnable {
674             private float result[][];
675             private float source[][];
676             private int line0;
677             private int bunch;
678 
679             /**
680              * Register a task for matrix multiplication.
681              */
MatrixComputer( float result[][], float source[][], int line0, int bunch)682             public MatrixComputer(
683                     float result[][], float source[][], int line0, int bunch) {
684 
685                 this.result = result;   // reference to resulting matrix value
686                 this.source = source;   // reference to matrix to be squared
687                 this.line0 = line0;     // compute lines from line0 to ...
688                 this.bunch = bunch;     // number of resulting lines to compute
689             }
690 
691             /**
692              * Do execute the task just registered for <code>this</code> thread.
693              */
run()694             public void run() {
695                 int line1 = line0 + bunch;
696                 int size = result.length;
697                 for (int line = line0; line < line1; line++)
698                     for (int column = 0; column < size; column++) {
699                         float sum = 0;
700                         for (int i = 0; i < size; i++)
701                             sum += source[line][i] * source[i][column];
702                         result[line][column] = sum;
703                     }
704             }
705 
706         }
707 
708     }
709 
710     /**
711      * Compute <code>A*A</code> for <code>float</code> matrix <code>A</code>.
712      */
713     private static class DoubleMatrix {
714         volatile double value[][];
715 
716         /**
717          * Number of lines and columns in <code>this</code> square matrix.
718          */
size()719         public int size() {
720             return value.length;
721         }
722 
723 
724         /**
725          * New square matrix with the given integer elements.
726          */
DoubleMatrix(IntegerMatrix A)727         public DoubleMatrix(IntegerMatrix A) {
728             int size = A.size();
729             value = new double[size][size];
730             for (int line = 0; line < size; line++)
731                 for (int column = 0; column < size; column++)
732                     value[line][column] = A.value[line][column];
733         }
734 
735         /**
736          * Assign <code>this</code> matrix with <code>A*A</code>.
737          *
738          * @param threads Split computation into the given number of threads.
739          */
setSquareOf(DoubleMatrix A, int threads)740         public void setSquareOf(DoubleMatrix A, int threads) {
741             if (this.size() != A.size())
742                 throw new IllegalArgumentException(
743                         "this.size() != A.size()");
744 
745             if ((size() % threads) != 0)
746                 throw new IllegalArgumentException("size()%threads != 0");
747             int bunch = size() / threads;
748 
749             Thread task[] = new Thread[threads];
750             for (int t = 0; t < threads; t++) {
751                 int line0 = bunch * t;
752                 MatrixComputer computer =
753                         new MatrixComputer(value, A.value, line0, bunch);
754                 task[t] = new Thread(computer);
755             }
756 
757             for (int t = 0; t < threads; t++)
758                 task[t].start();
759 
760             for (int t = 0; t < threads; t++)
761                 if (task[t].isAlive())
762                     try {
763                         task[t].join();
764                     } catch (InterruptedException exception) {
765                         throw new RuntimeException(exception.toString());
766                     }
767         }
768 
769         /**
770          * Thread to compute a bunch of lines of matrix square.
771          */
772         private static class MatrixComputer implements Runnable {
773             private double result[][];
774             private double source[][];
775             private int line0;
776             private int bunch;
777 
778             /**
779              * Register a task for matrix multiplication.
780              */
MatrixComputer( double result[][], double source[][], int line0, int bunch)781             public MatrixComputer(
782                     double result[][], double source[][], int line0, int bunch) {
783 
784                 this.result = result;   // reference to resulting matrix value
785                 this.source = source;   // reference to matrix to be squared
786                 this.line0 = line0;     // compute lines from line0 to ...
787                 this.bunch = bunch;     // number of resulting lines to compute
788             }
789 
790             /**
791              * Do execute the task just registered for <code>this</code> thread.
792              */
run()793             public void run() {
794                 int line1 = line0 + bunch;
795                 int size = result.length;
796                 for (int line = line0; line < line1; line++)
797                     for (int column = 0; column < size; column++) {
798                         double sum = 0;
799                         for (int i = 0; i < size; i++)
800                             sum += source[line][i] * source[i][column];
801                         result[line][column] = sum;
802                     }
803             }
804 
805         }
806 
807     }
808 
809 }
810