Class LinearOperator

All Implemented Interfaces:
CoordinateTransformationOperator, Operator

public final class LinearOperator extends ProjectiveOperator

Linear operator (affine transformation): O f(x) = f(Ax + b), where the numeric n x n matrix A and the n-dimensional vector b are parameters of the transformation. (It is a particular case of the projective transformation, when c vector is zero and d number is 1.0.)

This class is immutable and thread-safe: there are no ways to modify settings of the created instance.

Author:
Daniel Alievsky
  • Method Details

    • getInstance

      public static LinearOperator getInstance(double[] a, double[] b)
      Returns an instance of this class, describing the linear operator with the specified matrix A and vector b: O f(x) = f(Ax + b). The coordinates of the vector b must be listed in b array. The elements of the matrix A must be listed, row by row, in the a array: A={aij}, aij=a[i*n+j], i is the index of the row (0..n-1), j is the index of the column (0..n-1), n=b.length. The length a.length of the a array must be equal to the square n2 of the length n=b.length of the b array. Empty arrays (n=0) are not allowed.

      The passed a and b Java arrays are cloned by this method: no references to them are maintained by the created instance.

      Parameters:
      a - the elements of A matrix.
      b - the coordinates of b vector.
      Returns:
      the linear operator O f(x) = f(Ax + b).
      Throws:
      NullPointerException - if one of the arguments of the method is null.
      IllegalArgumentException - if b.length==0 or a.length!=b.length2.
    • getDiagonalInstance

      public static LinearOperator getDiagonalInstance(double[] diagonal, double[] b)
      Returns an instance of this class, describing the linear operator with the diagonal matrix A and vector b: O f(x) = f(Ax + b), where A={aij}, aij=0.0 if i!=j, aii=diagonal[i]. The coordinates of the vector b must be listed in b array. Empty arrays (diagonal.length=b.length=0) are not allowed.

      This linear operator performs resizing and shift along coordinate axes.

      The passed diagonal and b Java arrays are cloned by this method: no references to them are maintained by the created instance.

      Parameters:
      diagonal - the diagonal elements of A matrix (all other elements are supposed to be zero).
      b - the coordinates of b vector.
      Returns:
      the linear operator O f(x) = f(Ax + b).
      Throws:
      NullPointerException - if one of the arguments of the method is null.
      IllegalArgumentException - if diagonal.length==0 or diagonal.length!=b.length.
    • getDiagonalInstance

      public static LinearOperator getDiagonalInstance(double... diagonal)
      Equivalent to getDiagonalInstance(diagonal, new double[diagonal.length]) (the case of zero b vector). This linear operator performs resizing along coordinate axes.
      Parameters:
      diagonal - the diagonal elements of A matrix (all other elements are supposed to be zero).
      Returns:
      the linear operator O f(x) = f(Ax).
      Throws:
      NullPointerException - if the argument of the method is null.
      IllegalArgumentException - if diagonal.length==0.
    • getShiftInstance

      public static LinearOperator getShiftInstance(double... b)
      Equivalent to getDiagonalInstance(diagonal, b), where diagonal is an array consisting of b.length unit values (1.0). This linear operator performs shifting along coordinate axes.
      Parameters:
      b - the coordinates of b vector.
      Returns:
      the linear operator O f(x) = f(x + b).
      Throws:
      NullPointerException - if the argument of the method is null.
      IllegalArgumentException - if b.length==0.
    • getRotation2D

      public static LinearOperator getRotation2D(double centerX, double centerY, double angle)
      Returns an instance of this class, describing rotation in 2D plane by the specified angle (in radians) around the specified center. Almost equivalent to getInstance(a,b), where:
      • a = {cos,sin,-sin,cos} — matrix A (cos=StrictMath.cos(angle)), sin=StrictMath.sin(angle));
      • b = {centerX-a[0]*centerX-a[1]*centerY, centerY-a[2]*centerX-a[3]*centerY} — vector b=cAc (c={centerX, centerY}).

      The only difference from these formulas is special processing some cases, when the angle is kπ/2 with integer k (more precisely, k/2.0*StrictMath.PI): StrictMath.cos and StrictMath.sin methods can return inexact results here, but this method uses precise values ±1 in these cases.

      Parameters:
      centerX - the x-coordinate of the rotation center.
      centerY - the y-coordinate of the rotation center.
      angle - the rotation angle (in radians; positive values correspond to clockwise rotation, if the x axis is directed rightwards and the y axis is directed downwards, according traditions of computer image processing).
      Returns:
      2-dimensional linear operator, describing this rotation.
    • getInstanceByPoints

      public static LinearOperator getInstanceByPoints(Point[] q, Point[] p)
      Returns the n-dimensional linear operator, that transforms (maps) the given n+1 points p0, p1, ..., pn to the given another n+1 points q0, q1, ..., qn of the n-dimensional space. In other words, the matrix A and the vector b in the returned operator fulfil the following n+1 conditions:
      Ap0 + b = q0,
      Ap1 + b = q1,
      ...,
      Apn + b = qn

      It is possible that there is no such operator or there are many different solutions (degenerated cases). In this case, this method still returns some operator, but some coefficients of A matrix and b vector in the returned operator will probably be Double.NaN, Double.POSITIVE_INFINITY or Double.NEGATIVE_INFINITY.

      All passed points must be n-dimensional, where n+1=p.length=q.length.

      Parameters:
      q - the destination points.
      p - the source points.
      Returns:
      the n-dimensional linear operator, which maps pi to qi for all i=0,1,2,...,n.
      Throws:
      NullPointerException - if one of arguments of this method or one of elements of p and q arrays null.
      IllegalArgumentException - if the lengths of the passed p and q arrays are not equal, or if for some k p[k].coordCount()!=p.length-1 or q[k].coordCount()!=p.length-1.
      OutOfMemoryError - if there is not enough Java memory for storing two Java arrays double[n*n] and double[(n+1)*(n+1)], where n+1=p.length, or if (n+1)*(n+1)>Integer.MAX_VALUE.
    • superposition

      public LinearOperator superposition(LinearOperator operator)
      Returns superposition of this and the passed linear operators. More precisely, if this operator corresponds to the affine transformation Ax + b, and the passed one corresponds to the affine transformation A'x + b', then the returned operator corresponds to the affine transformation A''x + b'' = A'(Ax + b) + b', i.e. in the returned operator A'' = A'A, b'' = A'b + b'.
      Parameters:
      operator - the second operator, that should be applied after this one.
      Returns:
      superposition of this and the passed operator.
      Throws:
      NullPointerException - if the argument of the method is null.
      IllegalArgumentException - if operator.n()!=this.n().
    • changeB

      public LinearOperator changeB(double... b)
      Returns an instance of this class, identical to this one execpting that the new instance has the specified vector b.

      The passed b Java array is cloned by this method: no references to it are maintained by the created instance.

      Parameters:
      b - the new coordinates of b vector.
      Returns:
      the linear operator with changed b vector.
      Throws:
      NullPointerException - if the argument of the method is null.
      IllegalArgumentException - if b.length!=this.n().
    • map

      public void map(double[] destPoint, double[] srcPoint)
      This implementation calculates destPoint by multiplication the srcPoint by the matrix A and adding the vector b. to the coordinates destPoint of the destination point.
      Specified by:
      map in interface CoordinateTransformationOperator
      Overrides:
      map in class ProjectiveOperator
      Parameters:
      destPoint - the coordinates of the destination point y, filled by this method.
      srcPoint - the coordinates of the source point x.
      Throws:
      NullPointerException - if one of the arguments is null.
      IllegalArgumentException - if destPoint.length or srcPoint.length is not equal to the number of dimensions.
    • inverseMap

      public final void inverseMap(double[] srcPoint, double[] destPoint)
      Transforms the coordinates destPoint of the destination point in n-dimensional space back to the coordinates srcPoint of the original point.

      To find the srcPoint, this method solves the system of linear equations Ax=y−b, where the matrix A and the vector b are the parameters of this transformation, y is destPoint, x is srcPoint. This method uses Gauss elimination algorithm with partial (column) pivoting. This algorithm requires O(n3) operations.

      It is possible that there is no required srcPoint or there are many different solutions (degenerated cases). In this case, this method still returns some point, but some found srcPoint coordinates will probably be Double.NaN, Double.POSITIVE_INFINITY or Double.NEGATIVE_INFINITY.

      Note: this method allocates some additional memory if the matrix A is not diagonal. If you don't want to occupy additional memory, you can directly use solveLinearEquationsSet(double[], double[], double[]) method.

      Note: this method works correctly even if destPoint and srcPoint is the same Java array.

      Parameters:
      srcPoint - the coordinates of the source point x, filled by this method.
      destPoint - the coordinates of the destinated point y.
      Throws:
      NullPointerException - if one of the arguments is null.
      IllegalArgumentException - if destPoint.length or srcPoint.length is not equal to the number of dimensions.
    • solveLinearEquationsSet

      public static void solveLinearEquationsSet(double[] x, double[] a, double[] y)
      Solves the system of linear equations Ax=y by Gauss elimination algorithm with partial (column) pivoting.

      The coordinates of the vector y must be listed in y array. The elements of the matrix A must be listed, row by row, in the a array: A={aij}, aij=a[i*n+j], i is the index of the row (0..n-1), j is the index of the column (0..n-1), n=b.length. The length a.length of the a array must be equal to the square n2 of the length n=b.length of the b array. Empty arrays (n=0) are not allowed.

      It is possible that there is no required x vector or there are many different solutions (degenerated cases). In this case, this method still find some x vector, but some found coordinates in the x array will probably be Double.NaN, Double.POSITIVE_INFINITY or Double.NEGATIVE_INFINITY.

      This method is called in the inverseMap(double[], double[]) method, if the matrix A is not diagonal.

      Warning: this method destroys the content of the passed a and y arrays! But this method does not occupy any additional memory, unlike inverseMap(double[], double[]) method.

      Warning: this method will not work correctly if x and y is the same Java array.

      Parameters:
      x - the coordinates of x vector, filled by this method.
      a - the elements of A matrix (row by row).
      y - the coordinates of y vector.
      Throws:
      NullPointerException - if one of the arguments of the method is null.
      IllegalArgumentException - if the length of one of the passed arrays is 0, or if x.length!=y.length, or if a.length!=x.length2.
    • toString

      public String toString()
      Returns a brief string description of this object.
      Overrides:
      toString in class ProjectiveOperator
      Returns:
      a brief string description of this object.