docs: public static Matrix copy(Matrix m) {
  		if (m==null) throw new NullPointerException();
  		Matrix copy=createMatrix(m.getRowCount(), m.getColumnCount());
  		for (int row=0; row<m.getRowCount(); row++) for (int col=0; col<m.getColumnCount(); col++)
  			copy.set(row, col, m.getQuick(row, col));
  		return copy;
  	}
  
  	/**
  	 * Creates a copy of a matrix.
  	 * @param m the matrix to copy
  	 * @return a new matrix with the same dimensions and contents as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Matrix2 copy(Matrix2 m) {
  		return (Matrix2) copy((Matrix)m);
  	}
  
  	/**
  	 * Creates a copy of a matrix.
  	 * @param m the matrix to copy
  	 * @return a new matrix with the same dimensions and contents as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Matrix3 copy(Matrix3 m) {
  		return (Matrix3) copy((Matrix)m);
  	}
  
  	/**
  	 * Creates a copy of a matrix.
  	 * @param m the matrix to copy
  	 * @return a new matrix with the same dimensions and contents as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Vector copy(Vector m) {
  		return (Vector) copy((Matrix)m);
  	}
  
  	/**
  	 * Creates a copy of a matrix.
  	 * @param m the matrix to copy
  	 * @return a new matrix with the same dimensions and contents as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Vector2 copy(Vector2 m) {
  		return (Vector2) copy((Matrix)m);
  	}
  
  	/**
  	 * Creates a copy of a matrix.
  	 * @param m the matrix to copy
  	 * @return a new matrix with the same dimensions and contents as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Vector3 copy(Vector3 m) {
  		return (Vector3) copy((Matrix)m);
  	}
  
  	/**
  	 * Creates a copy of a matrix.
  	 * @param m the matrix to copy
  	 * @return a new matrix with the same dimensions and contents as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Vector4 copy(Vector4 m) {
  		return (Vector4) copy((Matrix)m);
  	}
  	
  	/**
  	 * Creates a matrix with the same dimensions as the argument.
  	 * @param matrix the template matrix
  	 * @return a new zero matrix with the same dimensions as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Matrix createLike(Matrix matrix) {
  		return createMatrix(matrix.getRowCount(), matrix.getColumnCount());
  	}
  	
  	/**
  	 * Creates a matrix with the same dimensions as the argument.
  	 * @param matrix the template matrix
  	 * @return a new zero matrix with the same dimensions as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Matrix2 createLike(Matrix2 matrix) {
  		return (Matrix2) createMatrix(matrix.getRowCount(), matrix.getColumnCount());
  	}
  	
  	/**
  	 * Creates a matrix with the same dimensions as the argument.
  	 * @param matrix the template matrix
  	 * @return a new zero matrix with the same dimensions as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Matrix3 createLike(Matrix3 matrix) {
  		return (Matrix3) createMatrix(matrix.getRowCount(), matrix.getColumnCount());
  	}
  	
  	/**
  	 * Creates a matrix with the same dimensions as the argument.
  	 * @param matrix the template matrix
  	 * @return a new zero matrix with the same dimensions as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Vector createLike(Vector matrix) {
  		return (Vector) createMatrix(matrix.getRowCount(), matrix.getColumnCount());
  	}
  	
  	/**
  	 * Creates a matrix with the same dimensions as the argument.
  	 * @param matrix the template matrix
  	 * @return a new zero matrix with the same dimensions as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Vector2 createLike(Vector2 matrix) {
  		return (Vector2) createMatrix(matrix.getRowCount(), matrix.getColumnCount());
  	}
  	
  	/**
  	 * Creates a matrix with the same dimensions as the argument.
  	 * @param matrix the template matrix
  	 * @return a new zero matrix with the same dimensions as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Vector3 createLike(Vector3 matrix) {
  		return (Vector3) createMatrix(matrix.getRowCount(), matrix.getColumnCount());
  	}
  	
  	/**
  	 * Creates a matrix with the same dimensions as the argument.
  	 * @param matrix the template matrix
  	 * @return a new zero matrix with the same dimensions as the argument
  	 * @throws NullPointerException if {@code matrix} is {@code null}
  	 */
  	public static Vector4 createLike(Vector4 matrix) {
  		return (Vector4) createMatrix(matrix.getRowCount(), matrix.getColumnCount());
  	}
  	
  	/**
  	 * Creates an identity matrix of the specified dimension.
  	 * @param size the dimension of the matrix
  	 * @return a <code>size</code>×<code>size</code> identity matrix
  	 * @throws IllegalArgumentException if the size is not positive
  	 */
  	public static Matrix identity(int size) {
  		Matrix m = MatrixFactory.createMatrix(size, size);
  		for (int i = 0; i < size; i++)
  			m.set(i, i, 1);
  		return m;
  	}
  
  	/**
  	 * Creates a matrix of the specified size whose elements are all 1.
  	 * @param rows the number of rows
  	 * @param columns the number of columns
  	 * @return a <code>rows</code>×<code>columns</code> matrix whose elements are all 1
  	 * @throws IllegalArgumentException if either argument is non-positive
  	 */
  	public static Matrix ones(int rows, int columns) {
  		Matrix m = MatrixFactory.createMatrix(rows, columns);
  		for (int i = 0; i < m.getRowCount(); i++)
  			for (int j = 0; j < m.getColumnCount(); j++)
  				m.set(i, j, 1);
  		return m;
  	}
  
  	/**
  	 * Creates a matrix of the specified size whose elements are pseudorandom, uniformly distributed
  	 * values between 0 (inclusive) and 1 (exclusive).
  	 * @param rows the number of rows
  	 * @param columns the number of columns
  	 * @return a <code>rows</code>×<code>columns</code> matrix of random elements
  	 * @throws IllegalArgumentException if either argument is non-positive
  	 */
  	public static Matrix random(int rows, int columns) {
  		Matrix m = MatrixFactory.createMatrix(rows, columns);
  		for (int i = 0; i < m.getRowCount(); i++)
  			for (int j = 0; j < m.getColumnCount(); j++)
  				m.set(i, j, Math.random());
  		return m;
  	}
  	
  	//
  	// Matrix creation from arrays
  	//
  	
  	/**
  	 * Creates a matrix and initializes its elements from an array. The parameter should be a {@code double[r][c]}
  	 * array with {@code r>0} and {@code c>0}. The matrix element at row {@code row} and column {@code col} will be
  	 * {@code elements[row][col]}.
  	 * @param elements the array containing the elements of the matrix
  	 * @return the new matrix initialized from the array
  	 * @throws NullPointerException if the array is {@code null}
  	 * @throws IllegalArgumentException if the dimensions of the array are not valid
  	 */
  	public static Matrix createMatrix(double[][] elements) {
  		Matrix m=createMatrix(elements.length, elements[0].length);
  		for (int row=0; row<m.getRowCount(); row++) {
  			double[] rowData=elements[row];
  			if (rowData.length!=m.getColumnCount()) throw new IllegalArgumentException("Invalid array");
  			for (int col=0; col<m.getColumnCount(); col++) {
  				m.set(row, col, rowData[col]);
  			}
  		}
  		return m;
  	}
  	
  	/**
  	 * Creates a matrix and initializes its elements from an array. The parameter should be a {@code double[2][2]}
  	 * array. The matrix element at row {@code row} and column {@code col} will be
  	 * {@code elements[row][col]}.
  	 * @param elements the array containing the elements of the matrix
  	 * @return the new matrix initialized from the array
  	 * @throws NullPointerException if the array is {@code null}
  	 * @throws IllegalArgumentException if the dimensions of the array are not correct
  	 */
  	public static Matrix2 createMatrix2(double[][] elements) {
  		Matrix m=createMatrix(elements);
  		if (m.getRowCount()!=2 || m.getColumnCount()!=2)
  			throw new IllegalArgumentException("Array describes a matrix of size "+m.getRowCount()+"x"+m.getColumnCount()+" instead of 2x2");
  		return (Matrix2)m;
  	}
  	
  	/**
  	 * Creates a matrix and initializes its elements from an array. The parameter should be a {@code double[3][3]}
  	 * array. The matrix element at row {@code row} and column {@code col} will be
  	 * {@code elements[row][col]}.
  	 * @param elements the array containing the elements of the matrix
  	 * @return the new matrix initialized from the array
  	 * @throws NullPointerException if the array is {@code null}
  	 * @throws IllegalArgumentException if the dimensions of the array are not correct
  	 */
  	public static Matrix3 createMatrix3(double[][] elements) {
  		Matrix m=createMatrix(elements);
  		if (m.getRowCount()!=3 || m.getColumnCount()!=3)
  			throw new IllegalArgumentException("Array describes a matrix of size "+m.getRowCount()+"x"+m.getColumnCount()+" instead of 3x3");
  		return (Matrix3)m;
  	}
  	
  	/**
  	 * Creates a vector and initializes its elements from an array.
  	 * @param elements the array containing the elements of the vector
  	 * @return the new vector initialized from the array
  	 * @throws NullPointerException if the array is {@code null}
  	 * @throws IllegalArgumentException if the length of the array is zero
  	 */
  	public static Vector createVector(double[] elements) {
  		Vector v=createVector(elements.length);
  		for (int i=0; i<elements.length; i++)
  			v.setCoordQuick(i, elements[i]);
  		return v;
  	}
  	
  	/**
  	 * Creates a matrix backed by the specified data structure.
  	 * @param core the data structure for the new matrix
  	 * @return a matrix of proper type using the specified matrix core for its implementation
  	 * @throws NullPointerException if {@code core} is {@code null}
  	 */
  	public static Matrix create(MatrixCore core) {
  		if (core.getColumnCount()==1) {
  			switch (core.getRowCount()) {
  				case 2: return new CoredVector2Impl(core);
  				case 3: return new CoredVector3Impl(core);
  				case 4: return new CoredVector4Impl(core);
  				default: return new CoredVectorImpl(core);
  			}
  		} else {
  			if (core.getRowCount()==2 && core.getColumnCount()==2)
  				return new CoredMatrix2Impl(core);
  			if (core.getRowCount()==3 && core.getColumnCount()==3)
  				return new CoredMatrix3Impl(core);
  			return new CoredMatrixImpl(core);
  		}
  	}
  }