# Class MatrixSIS

Object
MatrixSIS

All Implemented Interfaces:
  `Serializable`, `Cloneable`, `LenientComparable`, `Matrix`

Direct Known Subclasses:
  `Matrix1`, `Matrix2`, `Matrix3`, `Matrix4`

public abstract class MatrixSIS extends Object implements Matrix, LenientComparable, Cloneable, Serializable
A `Matrix` able to perform some operations of interest to Spatial Information Systems (SIS). This class completes the GeoAPI `Matrix` interface with some operations used by `org​.apache​.sis​.referencing`. It is not a `MatrixSIS` goal to provide all possible Matrix operations, as there is too many of them. This class focuses on:

- Only the basic matrix operations needed for referencing by coordinates:
  - `isIdentity()`
  - `multiply(Matrix)`
  - `inverse()`
  - `transpose()`
- Other operations which are not general-purpose matrix operations, but are needed in the context of referencing by coordinates:
  - `isAffine()`
  - `normalizeColumns()`
  - `convertBefore(int, Number, Number)`
  - `convertAfter(int, Number, Number)`

Since:
  0.4
See Also:
  - `Matrices`
  - Serialized Form

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  `protected`
  `MatrixSIS()`
  For sub-class constructors.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static MatrixSIS`
  `castOrCopy(Matrix matrix)`
  Casts or copies the given matrix to a SIS implementation.
  `MatrixSIS`
  `clone()`
  Returns a clone of this matrix.
  `void`
  `convertAfter(int tgtDim, Number scale, Number offset)`
  Assuming that this matrix represents an affine transform, pre-concatenates a scale and a translation on the given dimension.
  `void`
  `convertBefore(int srcDim, Number scale, Number offset)`
  Assuming that this matrix represents an affine transform, concatenates a scale and a translation on the given dimension.
  `boolean`
  `equals(Object object)`
  Returns `true` if the specified object is of the same class as this matrix and all of the data members are equal to the corresponding data members in this matrix.
  `boolean`
  `equals(Object object, ComparisonMode mode)`
  Compares this matrix with the given object for equality.
  `boolean`
  `equals(Matrix matrix, double tolerance)`
  Compares the given matrices for equality, using the given absolute tolerance threshold.
  `double[]`
  `getElements()`
  Returns a copy of all matrix elements in a flat, row-major (column indices vary fastest) array.
  `Number`
  `getNumber(int row, int column)`
  Retrieves the value at the specified row and column of this matrix, wrapped in a `Number`.
  `int`
  `hashCode()`
  Returns a hash code value based on the data values in this matrix.
  `MatrixSIS`
  `inverse()`
  Returns the inverse of this matrix.
  `boolean`
  `isAffine()`
  Returns `true` if this matrix represents an affine transform.
  `abstract boolean`
  `isIdentity()`
  Returns `true` if this matrix is an identity matrix.
  `double[]`
  `multiply(double[] vector)`
  Returns a new vector which is the result of multiplying this matrix with the specified vector.
  `MatrixSIS`
  `multiply(Matrix other)`
  Returns a new matrix which is the result of multiplying this matrix with the specified one.
  `MatrixSIS`
  `normalizeColumns()`
  Normalizes all columns in-place and returns their magnitudes as a row vector.
  `MatrixSIS`
  `removeColumns(int lower, int upper)`
  Returns a new matrix with the same elements as this matrix except for the specified columns.
  `MatrixSIS`
  `removeRows(int lower, int upper)`
  Returns a new matrix with the same elements as this matrix except for the specified rows.
  `void`
  `setElements(double[] elements)`
  Sets all matrix elements from a flat, row-major (column indices vary fastest) array.
  `void`
  `setMatrix(Matrix source)`
  Sets this matrix to the values of another matrix.
  `void`
  `setNumber(int row, int column, Number value)`
  Modifies the value at the specified row and column of this matrix.
  `MatrixSIS`
  `solve(Matrix target)`
  Returns the value of U which solves `this` × U = `target`.
  `String`
  `toString()`
  Returns a unlocalized string representation of this matrix.
  `void`
  `translate(double[] vector)`
  Multiplies this matrix by a translation matrix.
  `abstract void`
  `transpose()`
  Sets the value of this matrix to its transpose.

  ### Methods inherited from class Object

  `finalize, getClass, notify, notifyAll, wait, wait, wait`

  ### Methods inherited from interface Matrix

  `getElement, getNumCol, getNumRow, setElement`

- ## Constructor Details

  - ### MatrixSIS

    protected MatrixSIS()
    For sub-class constructors.

- ## Method Details

  - ### castOrCopy

    public static MatrixSIS castOrCopy(Matrix matrix)
    Casts or copies the given matrix to a SIS implementation. If `matrix` is already an instance of `MatrixSIS`, then it is returned unchanged. Otherwise all elements are copied in a new `MatrixSIS` object.
    Parameters:
      `matrix` - the matrix to cast or copy, or `null`.
    Returns:
      the matrix argument if it can be safely cast (including `null` argument), or a copy of the given matrix otherwise.
    See Also:
      - `Matrices​.copy(Matrix)`

  - ### getNumber

    public Number getNumber(int row, int column)
    Retrieves the value at the specified row and column of this matrix, wrapped in a `Number`. The `Number` type depends on the matrix accuracy.

    #### Use case

    This method may be more accurate than `Matrix​.getElement(int, int)` in some implementations when the value is expected to be an integer, for example in conversions of pixel coordinates. `Number​.longValue()` can be more accurate than `Number​.doubleValue()` because a `long` may have more significant digits than what a `double` can contain. For safety against rounding errors and overflows, `Numbers​.round(Number)` should be used instead of `Number​.longValue()`.
    Parameters:
      `row` - the row index, from 0 inclusive to `Matrix​.getNumRow()` exclusive.
      `column` - the column index, from 0 inclusive to `Matrix​.getNumCol()` exclusive.
    Returns:
      the current value at the given row and column.
    Throws:
      `IndexOutOfBoundsException` - if the specified row or column is out of bounds.
    See Also:
      - `Matrix​.getElement(int, int)`
      - `Numbers​.round(Number)`

  - ### setNumber

    public void setNumber(int row, int column, Number value)
    Modifies the value at the specified row and column of this matrix. This method is the converses of `getNumber(int, int)`.
    Parameters:
      `row` - the row index, from 0 inclusive to `Matrix​.getNumRow()` exclusive.
      `column` - the column index, from 0 inclusive to `Matrix​.getNumCol()` exclusive.
      `value` - the new matrix element value. A `null` value is interpreted as zero.
    Throws:
      `IndexOutOfBoundsException` - if the specified row or column is out of bounds.
      `UnsupportedOperationException` - if this matrix is unmodifiable.
    Since:
      0.8
    See Also:
      - `Matrix​.setElement(int, int, double)`

  - ### getElements

    public double[] getElements()
    Returns a copy of all matrix elements in a flat, row-major (column indices vary fastest) array. The array length is `Matrix​.getNumRow() * Matrix​.getNumCol()`.
    Returns:
      a copy of all current matrix elements in a row-major array.

  - ### setElements

    public void setElements(double[] elements)
    Sets all matrix elements from a flat, row-major (column indices vary fastest) array. The array length shall be `Matrix​.getNumRow() * Matrix​.getNumCol()`.
    Parameters:
      `elements` - The new matrix elements in a row-major array.
    Throws:
      `IllegalArgumentException` - if the given array does not have the expected length.
      `UnsupportedOperationException` - if this matrix is unmodifiable.
    See Also:
      - `Matrices​.create(int, int, double[])`

  - ### setMatrix

    public void setMatrix(Matrix source) throws MismatchedMatrixSizeException
    Sets this matrix to the values of another matrix. The given matrix must have the same size.
    Parameters:
      `source` - the matrix to copy.
    Throws:
      `MismatchedMatrixSizeException` - if the given matrix has a different size than this matrix.
    Since:
      0.7

  - ### isAffine

    public boolean isAffine()
    Returns `true` if this matrix represents an affine transform. A transform is affine if the matrix is square and its last row contains only zeros, except in the last column which contains 1.
    Returns:
      `true` if this matrix represents an affine transform.
    See Also:
      - `Matrices​.isAffine(Matrix)`
      - `LinearTransform​.isAffine()`

  - ### isIdentity

    public abstract boolean isIdentity()
    Returns `true` if this matrix is an identity matrix. This method is equivalent to the following code, except that it is potentially more efficient:

        return Matrices.isIdentity(this, 0.0);

    Specified by:
      `isIdentity` in interface `Matrix`
    Returns:
      `true` if this matrix is an identity matrix.
    See Also:
      - `Matrices​.isIdentity(Matrix, double)`
      - `AffineTransform​.isIdentity()`

  - ### transpose

    public abstract void transpose()
    Sets the value of this matrix to its transpose.
    Throws:
      `UnsupportedOperationException` - if this matrix is unmodifiable.

  - ### normalizeColumns

    public MatrixSIS normalizeColumns()
    Normalizes all columns in-place and returns their magnitudes as a row vector. Each columns in this matrix is considered as a vector. For each column (vector), this method computes the magnitude (vector length) as the square root of the sum of all squared values. Then, all values in the column are divided by that magnitude.

    This method is useful when the matrix is a transform derivative. In such matrix, each column is a vector representing the displacement in target space when an coordinate in the source space is increased by one. Invoking this method turns those vectors into unitary vectors, which is useful for forming the basis of a new coordinate system.

    Returns:
      the magnitude for each column in a matrix having only one row.
    Throws:
      `UnsupportedOperationException` - if this matrix is unmodifiable.

  - ### convertBefore

    public void convertBefore(int srcDim, Number scale, Number offset)
    Assuming that this matrix represents an affine transform, concatenates a scale and a translation on the given dimension. Converting a point with the resulting matrix is equivalent to first convert the point with `coordinates[srcDim] = coordinates[srcDim] * scale + offset`, then apply the original matrix.

    #### Equivalence between this method and Java2D `AffineTransform` methods

    If this matrix was an instance of Java2D `AffineTransform`, then invoking this method would be equivalent to invoking the following `AffineTransform` methods in the order shown below:

    Equivalence between this method and AffineTransform methods
    `MatrixSIS` method | `AffineTransform` methods
    --- | ---
    `convertBefore(0, scale, offset)` | `at.translate(offset, 0); at.scale(scale, 1);`
    `convertBefore(1, scale, offset)` | `at.translate(0, offset); at.scale(1, scale);`

    Parameters:
      `srcDim` - the dimension of the coordinate to rescale in the source coordinates.
      `scale` - the amount by which to multiply the source coordinate value before to apply the transform, or `null` if none.
      `offset` - the amount by which to translate the source coordinate value before to apply the transform, or `null` if none.
    Throws:
      `UnsupportedOperationException` - if this matrix is unmodifiable.
    Since:
      0.6
    See Also:
      - `AffineTransform​.concatenate(AffineTransform)`

  - ### convertAfter

    public void convertAfter(int tgtDim, Number scale, Number offset)
    Assuming that this matrix represents an affine transform, pre-concatenates a scale and a translation on the given dimension. Converting a point with the resulting matrix is equivalent to first convert the point with the original matrix, then convert the result with `coordinates[tgtDim] = coordinates[tgtDim] * scale + offset`.
    Parameters:
      `tgtDim` - the dimension of the coordinate to rescale in the target coordinates.
      `scale` - the amount by which to multiply the target coordinate value after this transform, or `null` if none.
      `offset` - the amount by which to translate the target coordinate value after this transform, or `null` if none.
    Throws:
      `UnsupportedOperationException` - if this matrix is unmodifiable.
    Since:
      0.6
    See Also:
      - `AffineTransform​.preConcatenate(AffineTransform)`

  - ### multiply

    public MatrixSIS multiply(Matrix other) throws MismatchedMatrixSizeException
    Returns a new matrix which is the result of multiplying this matrix with the specified one. In other words, returns `this` × `other`.

    #### Relationship with coordinate operations

    In the context of coordinate operations, `other​.multiply(other)` is equivalent to `AffineTransform​.concatenate(other)`: first transforms by the `other` transform and then transform the result by `this` transform.
    Parameters:
      `other` - the matrix to multiply to this matrix.
    Returns:
      the result of `this` × `other`.
    Throws:
      `MismatchedMatrixSizeException` - if the number of rows in the given matrix is not equals to the number of columns in this matrix.

  - ### multiply

    public double[] multiply(double[] vector)
    Returns a new vector which is the result of multiplying this matrix with the specified vector. In other words, returns `this` × `vector`. The length of the given vector must be equal to the number of columns in this matrix, and the length of the returned vector will be equal to the number of rows in this matrix.

    #### Relationship with coordinate operations

    In the context of coordinate operations, `Matrix​.multiply(vector)` is related to `AffineTransform​.transform(…)` except that the last `vector` number is implicitly 1 in `AffineTransform` operations. While this `multiply(double[])` method could be used for coordinate transformation, it is not its purpose. This method is designed for occasional uses when accuracy is more important than performance.
    Parameters:
      `vector` - the vector to multiply to this matrix.
    Returns:
      the result of `this` × `vector`.
    Throws:
      `MismatchedMatrixSizeException` - if the length of the given vector is not equals to the number of columns in this matrix.
    Since:
      0.8

  - ### translate

    public void translate(double[] vector)
    Multiplies this matrix by a translation matrix. Invoking this method is equivalent to invoking `multiply(T)` where T is a matrix like below (size varies):

                ┌                    ┐
                │ 1  0  0  vector[0] │
            T = │ 0  1  0  vector[1] │
                │ 0  0  1  vector[2] │
                │ 0  0  0  vector[3] │
                └                    ┘

    The length of the given vector must be equal to the number of columns in this matrix. The last vector element is 1 for an affine transform, but other values are allowed. This matrix will be modified in-place.

    If this matrix is used for coordinate conversions, then converting a position with the resulting matrix is equivalent to first translating the point by the given vector, then applying the conversion represented by the original matrix.

    Parameters:
      `vector` - a vector representing a translation to be applied before this matrix.
    Since:
      1.0
    See Also:
      - `AffineTransform​.translate(double, double)`

  - ### solve

    public MatrixSIS solve(Matrix target) throws MismatchedMatrixSizeException, NoninvertibleMatrixException
    Returns the value of U which solves `this` × U = `target`. This is equivalent to first computing the inverse of `this`, then multiplying the result by the given matrix.
    Parameters:
      `target` - the matrix to solve.
    Returns:
      the U matrix that satisfies `this` × U = `target`.
    Throws:
      `MismatchedMatrixSizeException` - if the number of rows in the given matrix is not equals to the number of columns in this matrix.
      `NoninvertibleMatrixException` - if this matrix is not invertible.

  - ### inverse

    public MatrixSIS inverse() throws NoninvertibleMatrixException
    Returns the inverse of this matrix.
    Returns:
      the inverse of this matrix.
    Throws:
      `NoninvertibleMatrixException` - if this matrix is not invertible.
    See Also:
      - `AffineTransform​.createInverse()`

  - ### removeRows

    public MatrixSIS removeRows(int lower, int upper)
    Returns a new matrix with the same elements as this matrix except for the specified rows. This method is useful for removing a range of target dimensions in an affine transform.
    Parameters:
      `lower` - index of the first row to remove (inclusive).
      `upper` - index after the last row to remove (exclusive).
    Returns:
      a copy of this matrix with the specified rows removed.
    Since:
      0.7

  - ### removeColumns

    public MatrixSIS removeColumns(int lower, int upper)
    Returns a new matrix with the same elements as this matrix except for the specified columns. This method is useful for removing a range of source dimensions in an affine transform. Coordinates will be converted as if the values in the removed dimensions were zeros.
    Parameters:
      `lower` - index of the first column to remove (inclusive).
      `upper` - index after the last column to remove (exclusive).
    Returns:
      a copy of this matrix with the specified columns removed.
    Since:
      0.7

  - ### hashCode

    public int hashCode()
    Returns a hash code value based on the data values in this matrix.
    Overrides:
      `hashCode` in class `Object`
    Returns:
      a hash code value for this matrix.

  - ### equals

    public boolean equals(Object object)
    Returns `true` if the specified object is of the same class as this matrix and all of the data members are equal to the corresponding data members in this matrix.
    Specified by:
      `equals` in interface `LenientComparable`
    Overrides:
      `equals` in class `Object`
    Parameters:
      `object` - the object to compare with this matrix for equality.
    Returns:
      `true` if the given object is equal to this matrix.
    See Also:
      - `ComparisonMode​.STRICT`

  - ### equals

    public boolean equals(Matrix matrix, double tolerance)
    Compares the given matrices for equality, using the given absolute tolerance threshold. The given matrix does not need to be the same implementation class as this matrix.

    The matrix elements are compared as below:

    - `Double​.NaN` values are considered equals to all other NaN values.
    - Infinite values are considered equal to other infinite values of the same sign.
    - All other values are considered equal if the absolute value of their difference is smaller than or equals to the given threshold.
    Parameters:
      `matrix` - the matrix to compare.
      `tolerance` - the tolerance value.
    Returns:
      `true` if this matrix is close enough to the given matrix given the tolerance value.
    See Also:
      - `Matrices​.equals(Matrix, Matrix, double, boolean)`

  - ### equals

    public boolean equals(Object object, ComparisonMode mode)
    Compares this matrix with the given object for equality. To be considered equal, the two objects must met the following conditions, which depend on the `mode` argument:
    - `STRICT`: the two matrices must be of the same class, have the same size and the same element values.
    - `BY_CONTRACT`: the two matrices must have the same size and the same element values, but are not required to be the same implementation class (any `Matrix` is okay).
    - `IGNORE_METADATA`: same as `BY_CONTRACT`.
    - `APPROXIMATE`: the two matrices must have the same size, but the element values can differ up to some threshold. The threshold value is determined empirically and may change in any future SIS versions.
    Specified by:
      `equals` in interface `LenientComparable`
    Parameters:
      `object` - the object to compare to `this`.
      `mode` - the strictness level of the comparison.
    Returns:
      `true` if both objects are equal.
    See Also:
      - `Matrices​.equals(Matrix, Matrix, ComparisonMode)`

  - ### clone

    public MatrixSIS clone()
    Returns a clone of this matrix.
    Specified by:
      `clone` in interface `Matrix`
    Overrides:
      `clone` in class `Object`
    Returns:
      a new matrix of the same class and with the same values as this matrix.
    See Also:
      - `Matrices​.copy(Matrix)`

  - ### toString

    public String toString()
    Returns a unlocalized string representation of this matrix. For each column, the numbers are aligned on the decimal separator.
    Overrides:
      `toString` in class `Object`
    See Also:
      - `Matrices​.toString(Matrix)`