docs: public void print (PrintWriter output, NumberFormat format, int width) {
        output.println();  // start on new line.
        for (int i = 0; i < m; i++) {
           for (int j = 0; j < n; j++) {
              String s = format.format(A[i][j]); // format the number
              int padding = Math.max(1,width-s.length()); // At _least_ 1 space
              for (int k = 0; k < padding; k++)
                 output.print(' ');
              output.print(s);
           }
           output.println();
        }
        output.println();   // end with blank line.
     }
  
     /** Read a matrix from a stream.  The format is the same the print method,
       * so printed matrices can be read back in (provided they were printed using
       * US Locale).  Elements are separated by
       * whitespace, all the elements for each row appear on a single line,
       * the last row is followed by a blank line.
     @param input the input stream.
     */
  
     public static Matrix read (BufferedReader input) throws java.io.IOException {
        StreamTokenizer tokenizer= new StreamTokenizer(input);
  
        // Although StreamTokenizer will parse numbers, it doesn't recognize
        // scientific notation (E or D); however, Double.valueOf does.
        // The strategy here is to disable StreamTokenizer's number parsing.
        // We'll only get whitespace delimited words, EOL's and EOF's.
        // These words should all be numbers, for Double.valueOf to parse.
  
        tokenizer.resetSyntax();
        tokenizer.wordChars(0,255);
        tokenizer.whitespaceChars(0, ' ');
        tokenizer.eolIsSignificant(true);
        java.util.Vector v = new java.util.Vector();
  
        // Ignore initial empty lines
        while (tokenizer.nextToken() == StreamTokenizer.TT_EOL);
        if (tokenizer.ttype == StreamTokenizer.TT_EOF)
  	throw new java.io.IOException("Unexpected EOF on matrix read.");
        do {
           v.addElement(Double.valueOf(tokenizer.sval)); // Read & store 1st row.
        } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
  
        int n = v.size();  // Now we've got the number of columns!
        double row[] = new double[n];
        for (int j=0; j<n; j++)  // extract the elements of the 1st row.
           row[j]=((Double)v.elementAt(j)).doubleValue();
        v.removeAllElements();
        v.addElement(row);  // Start storing rows instead of columns.
        while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
           // While non-empty lines
           v.addElement(row = new double[n]);
           int j = 0;
           do {
              if (j >= n) throw new java.io.IOException
                 ("Row " + v.size() + " is too long.");
              row[j++] = Double.valueOf(tokenizer.sval).doubleValue();
           } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
           if (j < n) throw new java.io.IOException
              ("Row " + v.size() + " is too short.");
        }
        int m = v.size();  // Now we've got the number of rows.
        double[][] A = new double[m][];
        v.copyInto(A);  // copy the rows out of the vector
        return new Matrix(A);
     }
  
  
  /* ------------------------
     Private Methods
   * ------------------------ */
  
     /** Check if size(A) == size(B) **/
  
     private void checkMatrixDimensions (Matrix B) {
        if (B.m != m || B.n != n) {
           throw new IllegalArgumentException("Matrix dimensions must agree.");
        }
     }
  
  }