001/* 002 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences. 003 * Copyright (C) 2006 - JScience (http://jscience.org/) 004 * All rights reserved. 005 * 006 * Permission to use, copy, modify, and distribute this software is 007 * freely granted, provided that this notice is preserved. 008 */ 009package org.jscience.mathematics.vector; 010 011import java.util.Comparator; 012import javolution.lang.Realtime; 013import javolution.lang.ValueType; 014import javolution.text.Text; 015import javolution.text.TextBuilder; 016import javolution.util.FastTable; 017 018import org.jscience.mathematics.structure.Field; 019import org.jscience.mathematics.structure.VectorSpace; 020 021/** 022 * <p> This class represents an immutable element of a vector space.</p> 023 * 024 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 025 * @version 3.3, January 2, 2007 026 * @see <a href="http://en.wikipedia.org/wiki/Vector_space"> 027 * Wikipedia: Vector Space</a> 028 */ 029public abstract class Vector<F extends Field<F>> 030 implements VectorSpace<Vector<F>, F>, ValueType, Realtime { 031 032 /** 033 * Default constructor (for sub-classes). 034 */ 035 protected Vector() { 036 } 037 038 /** 039 * Returns the number of elements held by this vector. 040 * 041 * @return this vector dimension. 042 */ 043 public abstract int getDimension(); 044 045 /** 046 * Returns a single element from this vector. 047 * 048 * @param i the element index (range [0..n[). 049 * @return the element at <code>i</code>. 050 * @throws IndexOutOfBoundsException <code>(i < 0) || (i >= size())</code> 051 */ 052 public abstract F get(int i); 053 054 /** 055 * Returns the negation of this vector. 056 * 057 * @return <code>-this</code>. 058 */ 059 public abstract Vector<F> opposite(); 060 061 /** 062 * Returns the sum of this vector with the one specified. 063 * 064 * @param that the vector to be added. 065 * @return <code>this + that</code>. 066 * @throws DimensionException is vectors dimensions are different. 067 */ 068 public abstract Vector<F> plus(Vector<F> that); 069 070 /** 071 * Returns the difference between this vector and the one specified. 072 * 073 * @param that the vector to be subtracted. 074 * @return <code>this - that</code>. 075 */ 076 public Vector<F> minus(Vector<F> that) { 077 return this.plus(that.opposite()); 078 } 079 080 /** 081 * Returns the product of this vector with the specified coefficient. 082 * 083 * @param k the coefficient multiplier. 084 * @return <code>this · k</code> 085 */ 086 public abstract Vector<F> times(F k); 087 088 /** 089 * Returns the dot product of this vector with the one specified. 090 * 091 * @param that the vector multiplier. 092 * @return <code>this · that</code> 093 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 094 * @see <a href="http://en.wikipedia.org/wiki/Dot_product"> 095 * Wikipedia: Dot Product</a> 096 */ 097 public abstract F times(Vector<F> that); 098 099 /** 100 * Returns the cross product of two 3-dimensional vectors. 101 * 102 * @param that the vector multiplier. 103 * @return <code>this x that</code> 104 * @throws DimensionException if 105 * <code>(this.getDimension() != 3) && (that.getDimension() != 3)</code> 106 */ 107 public Vector<F> cross(Vector<F> that) { 108 if ((this.getDimension() != 3) || (that.getDimension() != 3)) 109 throw new DimensionException( 110 "The cross product of two vectors requires " 111 + "3-dimensional vectors"); 112 FastTable<F> elements = FastTable.newInstance(); 113 elements.add((this.get(1).times(that.get(2))).plus((this.get(2).times(that 114 .get(1))).opposite())); 115 elements.add((this.get(2).times(that.get(0))).plus((this.get(0).times(that 116 .get(2))).opposite())); 117 elements.add((this.get(0).times(that.get(1))).plus((this.get(1).times(that 118 .get(0))).opposite())); 119 DenseVector<F> V = DenseVector.valueOf(elements); 120 FastTable.recycle(elements); 121 return V; 122 } 123 124 /** 125 * Returns the text representation of this vector. 126 * 127 * @return the text representation of this vector. 128 */ 129 public Text toText() { 130 final int dimension = this.getDimension(); 131 TextBuilder tmp = TextBuilder.newInstance(); 132 tmp.append('{'); 133 for (int i = 0; i < dimension; i++) { 134 tmp.append(get(i)); 135 if (i != dimension - 1) { 136 tmp.append(", "); 137 } 138 } 139 tmp.append('}'); 140 Text txt = tmp.toText(); 141 TextBuilder.recycle(tmp); 142 return txt; 143 } 144 145 /** 146 * Returns the text representation of this vector as a 147 * <code>java.lang.String</code>. 148 * 149 * @return <code>toText().toString()</code> 150 */ 151 public final String toString() { 152 return toText().toString(); 153 } 154 155 /** 156 * Indicates if this vector can be considered equals to the one 157 * specified using the specified comparator when testing for 158 * element equality. The specified comparator may allow for some 159 * tolerance in the difference between the vector elements. 160 * 161 * @param that the vector to compare for equality. 162 * @param cmp the comparator to use when testing for element equality. 163 * @return <code>true</code> if this vector and the specified matrix are 164 * both vector with equal elements according to the specified 165 * comparator; <code>false</code> otherwise. 166 */ 167 public boolean equals(Vector<F> that, Comparator<F> cmp) { 168 if (this == that) 169 return true; 170 final int dimension = this.getDimension(); 171 if (that.getDimension() != dimension) 172 return false; 173 for (int i = dimension; --i >= 0;) { 174 if (cmp.compare(this.get(i), that.get(i)) != 0) 175 return false; 176 } 177 return true; 178 } 179 180 /** 181 * Indicates if this vector is equal to the object specified. 182 * 183 * @param that the object to compare for equality. 184 * @return <code>true</code> if this vector and the specified object are 185 * both vectors with equal elements; <code>false</code> otherwise. 186 */ 187 public boolean equals(Object that) { 188 if (this == that) 189 return true; 190 if (!(that instanceof Vector)) 191 return false; 192 final int dimension = this.getDimension(); 193 Vector v = (Vector) that; 194 if (v.getDimension() != dimension) 195 return false; 196 for (int i = dimension; --i >= 0;) { 197 if (!this.get(i).equals(v.get(i))) 198 return false; 199 } 200 return true; 201 } 202 203 /** 204 * Returns a hash code value for this vector. 205 * Equals objects have equal hash codes. 206 * 207 * @return this vector hash code value. 208 * @see #equals 209 */ 210 public int hashCode() { 211 final int dimension = this.getDimension(); 212 int code = 0; 213 for (int i = dimension; --i >= 0;) { 214 code += get(i).hashCode(); 215 } 216 return code; 217 } 218 219 /** 220 * Returns a copy of this vector 221 * {@link javolution.context.AllocatorContext allocated} 222 * by the calling thread (possibly on the stack). 223 * 224 * @return an identical and independant copy of this matrix. 225 */ 226 public abstract Vector<F> copy(); 227 228}