Files
wscience/src/math/matrix/Vector.java

900 lines
19 KiB
Java

package math.matrix;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import math.Maths;
import math.geometry.Point;
import thisandthat.WObject;
import exception.IllegalDimensionException;
/**
* Vector of real numbers, v∈ℝ.
* @author Daniel Weschke
*/
public class Vector extends WObject implements Cloneable, Serializable{
/**
* UID
*/
private static final long serialVersionUID = 7909642082289701909L;
protected List<Double> vector;
// protected double[] vector;
public Vector(){
}
/**
* Create zero vector
* @param n
*/
public Vector(int n){
int i;
// vector = new double[n];
vector = new ArrayList<Double>();
for(i=0; i<n; i++)
add(0);
}
/**
* Create vector with given x value
* @param x
*/
public Vector(double x){
// vector = new double[]{x};
this(1);
set(0, x);
}
/**
* Create vector with given x and y value
* @param x
* @param y
*/
public Vector(double x, double y){
// vector = new double[]{x, y};
this(2);
set(0, x);
set(1, y);
}
/**
* Create vector with given x, y and z value
* @param x
* @param y
* @param z
*/
public Vector(double x, double y, double z){
// vector = new double[]{x, y, z};
this(3);
set(0, x);
set(1, y);
set(2, z);
}
private void add(double s){
vector.add(s);
}
/**
* Create vector with given array
* @param data array
*/
public Vector(double... data){
this(data.length);
int i;
int n = data.length;
// vector = new double[n];
for(i=0; i<n; i++)
set(i, data[i]);
}
/**
* Create vector with given array (integers)
* @param v array
*/
public Vector(int[] v){
this(v.length);
int i;
int n = v.length;
// vector = new double[n];
for(i=0; i<n; i++)
set(i, (v[i]));
}
/**
* Create vector with given array
* @param data array
*/
public Vector(List<Double> data){
this(data.size());
int i;
int n = data.size();
for(i=0; i<n; i++)
set(i, data.get(i));
}
public Vector(Point p){
this(p.get());
}
/**
* Copy vector
* @param v vector
*/
public Vector(Vector v){
this(v.vector);
}
private Vector create(int n){
if(this instanceof Vector2D) return new Vector2D();
if(this instanceof Vector3D) return new Vector3D();
else return new Vector(n);
}
private Vector create(double[] v){
if(this instanceof Vector2D) return new Vector2D(v);
if(this instanceof Vector3D) return new Vector3D(v);
else return new Vector(v);
}
private Matrix create(int m, int n){
if(this instanceof Vector2D) return new Matrix2D(n);
if(this instanceof Vector3D) return new Matrix3D(n);
else return new Matrix(m,n);
}
/**
* @return vector array
*/
public double[] getArray(){
int i, n = n();
double[] v = new double[n];
for(i=0; i<n; i++)
v[i] = get(i);
return v;
}
/**
* @return vector array
*/
public List<Double> get(){
return vector;
}
/**
* @param i index
* @return corresponding coordinate
*/
public double get(int i){
return vector.get(i);
}
/**
* @return vector array (integers)
*/
public int[] getInts(){
int i;
int[] result = new int[n()];
for(i=0; i<n(); i++)
result[i] = (int) get(i);
return result;
}
/**
* set value at index
* @param i index
* @param a value
*/
public Vector set(int i, double a){
vector.set(i, a);
return this;
}
/**
* get x (first element)
* @return x value
*/
public double x(){
return n()>0?get(0):Double.NaN;
}
/**
* get y (second element)
* @return y value
*/
public double y(){
return n()>1?get(1):Double.NaN;
}
/**
* get z (third element)
* @return z value
*/
public double z(){
return n()>2?get(2):Double.NaN;
}
/**
* length of vector
* @return dimension
*/
public int n(){
return length();
}
/**
* length of vector
* @return dimension
*/
public int length(){
// return vector.length;
return vector.size();
}
/**
* Create vector with zeros
* @param n size
* @return zero vector
*/
public static Vector zeros(int n){
return new Vector(n);
}
/**
* Create vector with ones
* @param n size
* @return one vector
*/
public static Vector ones(int n){
return fill(n, 1);
}
/**
* Create vector with given scalar
* @param n size
* @param s scalar
* @return filled vector
*/
public static Vector fill(int n, double s){
Vector a = new Vector(n);
int i;
for(i=0; i<n; i++)
a.set(i, s);
return a;
}
/**
* Create vector and fill it from a start value to an end value
* @param start
* @param end
* @return filled vector [start,start+1,...,end]
*/
public static Vector fill(double start, double end){
double delta = end-start;
int increment = delta>0 ? 1 : -1;
return fill(start, increment, end);
}
/**
* Create vector and fill it from a start value to an end value with n equidistant steps
* @param start
* @param end
* @param n steps
* @return filled vector [start,(end-start)*1/n,(end-start)*2/n,...,end]
*/
public static Vector fillN(double start, double end, int n){
double increment = (end-start)/n;
return fill(start, increment, end);
}
/**
* Create vector and fill it from a start value and increments it to an end value
* @param start
* @param increment
* @param end
* @return filled vector [start,start+increment,start+2*increment,...,end]
*/
public static Vector fill(double start, double increment, double end){
double delta = end-start;
int n = (int)(delta/increment)+1;
if((delta>=0&&increment<0)||(delta<0&&increment>=0)||increment==0) return new Vector();
Vector a = new Vector(n);
int i;
for(i=0; i<n; i++)
a.set(i, start + i*increment);
return a;
}
/**
* Create zero vector and fill it with given values at given positions (first position is 1)
* @param n
* @param position
* @param a value array
* @return filled vector
*/
public static Vector fill(int n, int[] position, double[] a){
Vector c = new Vector(n);
for(int i=0; i<position.length; i++)
c.set(position[i]-1, a[i]);
return c;
}
/**
* Create zero vector and fill it with given values at given positions (first position is 1)
* @param n
* @param position
* @param a value vector
* @return filled vector
*/
public static Vector fill(int n, int[] position, Vector a){
Vector c = new Vector(n);
for(int i=0; i<position.length; i++)
c.set(position[i]-1, a.get(i));
return c;
}
/**
* Create zero vector and fill it with given values at given positions (first position is 1)
* @param n
* @param position
* @param a value vector
* @return filled vector
*/
public static Vector fill(int n, Vector position, Vector a){
Vector c = new Vector(n);
for(int i=0; i<position.n(); i++)
c.set((int) position.get(i)-1, a.get(i));
return c;
}
/**
* Fill vector with given values at given indices (first index is 0)
* @param indices
* @param a value vector
*/
public void fill(int[] indices, Vector a){
for(int i=0; i<indices.length; i++)
set(indices[i], a.get(i));
}
/**
* Fill vector with given values at given positions (indices +1)
* @param positions
* @param a vector
*/
public void fillPos(int[] positions, Vector a){
fill(new Vector(positions).minus(1).getInts(),a);
}
/**
* Create vector and fill it with random values [0,1)
* @param n rows
* @return random number filled vector
*/
public static Vector rand(int n){
Vector a = new Vector(n);
int i;
for(i=0; i<n; i++)
a.set(i, Math.random());
return a;
}
/**
* Create vector and fill it with random values [0,s]
* @param n rows
* @param s scalar
* @return random number filled vector
*/
public static Vector rand(int n, double s){
Vector a = new Vector(n);
int i;
for(i=0; i<n; i++)
a.set(i, Math.random()*s);
return a;
}
/**
* add a Vector.
* @param a vector to add
* @return added Vector
*/
public Vector plus(Vector a){
int i;
Vector c = create(n());
for(i=0; i<n(); i++)
c.set(i, get(i) + a.get(i));
return c;
}
/**
* add a Vector.
* @param s as vector to add
* @return added Vector
*/
public Vector plus(double s){
return plus(Vector.fill(n(), s));
}
public void plus(int i, double s){
set(i, get(i)+s);
}
/**
* subtract a Vector.
* @param a vector to subtract
* @return subtracted Vector
*/
public Vector minus(Vector a){
return plus(a.times(-1));
}
/**
* subtract a Vector.
* @param s as vector to subtract
* @return subtracted Vector
*/
public Vector minus(double s){
return plus(Vector.fill(n(), -s));
}
/**
* lengthen the vector due scalar multiplication
* @param s scalar
* @return C = s A
*/
public Vector times(double s){
int i;
Vector c = create(n());
for(i=0; i<n(); i++)
c.set(i, get(i) * s);
return c;
}
/**
* Multiply a matrix right. Linear algebraic matrix multiplication.
* @param B matrix
* @return <b>C</b> = <b>A</b> • <b>B</b> = <b>A</b><sup>T</sup><b>B</b>
* @throws IllegalDimensionException Inner matrix dimensions must agree.
*/
public Vector times(Matrix B) throws IllegalDimensionException{
int i,j;
if(n() != B.getM()) throw new IllegalDimensionException("Inner matrix dimensions must agree.");
double[] c = new double[n()];
for(i=0; i<n(); i++)
for(j=0; j<B.getM(); j++)
c[i] += (get(j) * B.get(j,i));
return create(c);
}
/**
* Dot / inner / scalar product x<sup>T</sup>x.
* A • B = a<sub>1</sub>b<sub>1</sub> + a<sub>2</sub>b<sub>2</sub> +
* &hellip; + a<sub>n</sub>b<sub>n</sub>;
* a scalar quantity
* @return scalar
* @throws IllegalDimensionException
*/
public double dot() throws IllegalDimensionException{
return dot(this);
}
/**
* Dot / inner / scalar product x<sup>T</sup>y.
* A • B = a<sub>1</sub>b<sub>1</sub> + a<sub>2</sub>b<sub>2</sub> +
* &hellip; + a<sub>n</sub>b<sub>n</sub>;
* a scalar quantity
* @param a vector
* @return scalar
* @throws IllegalDimensionException
*/
public double dot(Vector a) throws IllegalDimensionException{
if(n() != a.n()) throw new IllegalDimensionException("Illegal vector dimension.");
int i;
double c = 0;
for(i=0; i<n(); i++)
c += get(i) * a.get(i);
return c;
}
/**
* Outer / tensor product vv'
* @param b vector
* @return matrix
*/
public Matrix tensorProduct(Vector b){
int i, j;
Matrix c = create(n(),b.n());
for(i=0; i<n(); i++)
for(j=0; j<b.n(); j++)
c.set(i, j, get(i) * b.get(j));
return c;
}
/**
* Multiplicate the vector a element wise with vector b.
* c<sub>i</sub> = a<sub>i</sub>b<sub>i</sub>
* @param b vector
* @return vector
*/
public Vector timesE(Vector b){
int i;
Vector c = create(n());
for(i=0; i<n(); i++)
c.set(i, get(i) * b.get(i));
return c;
}
/**
* shorten the vector due scalar division
* @param s scalar
* @return C = A/s
*/
public Vector over(double s){
int i;
Vector c = create(n());
for(i=0; i<n(); i++)
c.set(i, get(i) / s);
return c;
}
/**
* Divide the vector a element wise with vector b.
* c<sub>i</sub> = a<sub>i</sub>/b<sub>i</sub>
* @param b vector
* @return vector
*/
public Vector overE(Vector b){
int i;
Vector c = create(n());
for(i=0; i<n(); i++)
c.set(i, get(i) / b.get(i));
return c;
}
/**
* @return length or magnitude or Euclidean norm
*/
public double norm(){
try {
return Math.sqrt(dot(this));
} catch (IllegalDimensionException e) {
e.printStackTrace();
return Double.NaN;
}
}
/**
* @param b
* @return Euclidean distance between both vectors
* @throws IllegalDimensionException
*/
public double distanceTo(Vector b) throws IllegalDimensionException {
if(n() != b.n()) throw new IllegalDimensionException("Illegal vector dimension.");
return b.minus(this).norm();
}
/**
* normalizing a vector.
* A vector of arbitrary length divided by its length.
* <b>a</b>/||<b>a</b>||
* @return unit vector
*/
public Vector normalize(){
Vector c = times(1.0/norm());
this.vector = c.vector;
return this;
}
/**
* @return the corresponding unit vector
*/
public Vector direction() {
if(norm() == 0.0) throw new RuntimeException("Zero-vector has no direction");
return times(1.0 / norm());
}
/**
* Element-wise cosine of argument in radians.
* @return the cosine for each element of the matrix
*/
public Vector cos() {
int i;
int n = n();
Vector c = new Vector(n);
for(i=0; i<n; i++)
c.set(i, Math.cos(get(i)));
return c;
}
/**
* Element-wise cosine of argument in radians.
* @return the cosine for each element of the matrix
*/
public Vector sin() {
int i;
int n = n();
Vector c = new Vector(n);
for(i=0; i<n; i++)
c.set(i, Math.sin(get(i)));
return c;
}
/**
* cosine between this and given vector
* @param v vector
* @return cos&theta;
* @throws IllegalDimensionException
*/
public double cos(Vector v) throws IllegalDimensionException{
return dot(v)/(norm()*v.norm());
}
// sine see in Vector3D
public double angleD(Vector v) throws IllegalDimensionException{
return Maths.acosd(cos(v));
}
/**
* swap index i and j
* @param i index
* @param j index
*/
public Vector swap(int i, int j) {
double temp = get(i);
set(i, get(j));
set(j, temp);
return this;
}
/**
* swap min value and max value
*/
public Vector swapMinMax() {
int imin = indexOfMin();
int imax = indexOfMax();
double temp = get(imin);
set(imin, get(imax));
set(imax, temp);
return this;
}
/**
* Creates a sub vector only with chosen rows
* @param indices rows
* @return the sub vector
*/
public Vector sub(int[] indices){
return sub(indices,false);
}
/**
* Creates a sub vector only with chosen rows
* @param indices rows
* @return the sub vector
*/
public Vector sub(int[] indices, boolean positions){
int n = indices.length;
int d = positions?1:0;
double[] red = new double[n];
for(int i=0; i<n; i++)
red[i] = get(indices[i]-d);
return new Vector(red);
}
/**
* element wise absolute value.
* v = { |v<sub>1</sub>|, |v<sub>2</sub>|, &hellip;, |v<sub>n</sub>| }
* @return vector with absolute values
*/
public Vector abs(){
int i;
Vector c = create(n());
for(i=0; i<n(); i++)
c.set(i, get(i)>=0 ? get(i) : -get(i));
return c;
}
/**
* Reflection against a plane due to a vector
* @return reflected vector
* @throws IllegalDimensionException
*/
public Vector flip(Vector v) throws IllegalDimensionException{
// P = I - alpha v v'; alpha = 2 / (v'v)
return Matrix.mirror(v).times(this);
}
/**
* Maximum value of the vector
* @return maximum value in vector, -∞ if no such value.
*/
public double max(){
return Maths.max(getArray());
}
/**
* Minimum value of the vector
* @return minimum value in vector, +∞ if no such value.
*/
public double min(){
return Maths.min(getArray());
}
/**
* Find value in vector.
* @param a value
* @return index
*/
public int indexOf(double a){
int i;
for(i=0; i<n(); i++)
if(a == get(i)) return i;
return -1;
}
/**
* Find max value in vector.
* @return index
*/
public int indexOfMax(){
return indexOf(max());
}
/**
* Find min value in vector.
* @return index
*/
public int indexOfMin(){
return indexOf(min());
}
/**
* Sort vector in ascending order.
* @return sorted vector
*/
public Vector sort(){
// Arrays.sort(vector);
Collections.sort(vector);
return this;
}
/**
* Sort vector in descending order.
* @return sorted vector
*/
public Vector sortR(){
sort();
int i,j;
Vector tmp = create(n());
for(i = length()-1, j=0; i >= 0; i--, j++)
tmp.set(j, get(i));
vector = tmp.vector;
return this;
}
/**
* Zero vector?
* @return boolean
*/
public boolean isZero(){
int i;
boolean result = true;
for(i=0; i<n(); i++){
if(get(i) > 0){
result = false;
break;
}
}
return result;
}
public boolean isNormalized(){
return Math.abs(norm()-1)<Maths.ε;
}
/**
* Vector in euclidean plane &#x211D;<sup>2</sup>.
* n=2
* @return true or false
*/
public boolean isR2(){
return (n()==2);
}
/**
* Vector in euclidean plane &#x211D;<sup>3</sup>.
* n=3
* @return true or false
*/
public boolean isR3(){
return (n()==3);
}
/**
*
* @param a int array
* @param b int array
* @return true if two integer arrays have same length and
* all corresponding pairs of integers are equal
*/
public static boolean equals(int[] a, int[] b){
if(a.length != b.length) return false; // same length?
int i;
for(i=0; i<a.length; i++) // check each corresponding pair
if(a[i] != b[i]) return false;
return true; // all elements must be equal
}
/**
* A string representation of the vector.
*/
@Override
public String toString(){
return new Matrix(this).setName(getName()).toString();
}
/**
* Transpose (horizontal)
* @return string of vector in transposed form
*/
public String toStringT(){
return new Matrix(this).transpose().toString();
}
public void println(){
System.out.println(toString());
}
/**
* Transpose (horizontal)
*/
public void toConsoleT(){
System.out.println(toStringT());
}
/**
* test client
* @param args
*/
public static void main(String[] args) {
Vector a = new Vector(5, 1, 1);
a.println();
Vector b = a.normalize();
a.println();
b.println();
Vector.fill(2., 2.5).println();
Vector.fill(2., 8).println();
Vector.fill(8., 2).toConsoleT();
Vector.fill(2., 2, 8).println();
Vector.fill(8., -2, 2).toConsoleT();
System.out.println("a isNull? : " + a.isZero());
System.out.println("a-a isNull? : " + a.minus(a).isZero());
a = new Vector(1, 1);
a.println();
try {
System.out.println(a.dot(a));
} catch (IllegalDimensionException e1) {
e1.printStackTrace();
}
a.tensorProduct(a).println();
b = new Vector(1, 2, 3);
a.tensorProduct(b).println();
Vector v = new Vector(1, 1);
Vector w = new Vector(0, 1);
try {
w.flip(v).println();
} catch (IllegalDimensionException e) {
e.printStackTrace();
}
Vector c = new Vector(4, -21.0, 3);
c.setName("c").println();
c.sort().println();
c.sortR().println();
}
}