using System; using System.Collections.Generic; using System.Linq; using System.Text; using AutoDiff; using System.Diagnostics.Contracts; namespace AutoDiff { /// /// A column vector made of terms. /// [Serializable] public class TVec { private readonly Term[] terms; /// /// Constructs a new instance of the class given vector components. /// /// The vector component terms public TVec(IEnumerable terms) { Contract.Requires(terms != null); Contract.Requires(Contract.ForAll(terms, term => term != null)); Contract.Requires(terms.Any()); this.terms = terms.ToArray(); } /// /// Constructs a new instance of the class given vector components. /// /// The vector component terms public TVec(params Term[] terms) : this(terms as IEnumerable) { Contract.Requires(terms != null); Contract.Requires(Contract.ForAll(terms, term => term != null)); Contract.Requires(terms.Length > 0); } /// /// Constructs a new instance of the class using another vector's components. /// /// A vector containing the first vector components to use. /// More vector components to add in addition to the components in public TVec(TVec first, params Term[] rest) : this(first.terms.Concat(rest ?? System.Linq.Enumerable.Empty())) { Contract.Requires(first != null); Contract.Requires(Contract.ForAll(rest, term => term != null)); } private TVec(Term[] left, Term[] right, Func elemOp) { Contract.Assume(left.Length == right.Length); terms = new Term[left.Length]; for (int i = 0; i < terms.Length; ++i) terms[i] = elemOp(left[i], right[i]); } private TVec(Term[] input, Func elemOp) { terms = new Term[input.Length]; for (int i = 0; i < input.Length; ++i) terms[i] = elemOp(input[i]); } /// /// Gets a vector component given its zero-based index. /// /// The vector's component index. /// The vector component. public Term this[int index] { get { Contract.Requires(index >= 0 && index < Dimension); Contract.Ensures(Contract.Result() != null); return terms[index]; } } /// /// Gets a term representing the squared norm of this vector. /// public Term NormSquared { get { Contract.Ensures(Contract.Result() != null); var powers = terms.Select(x => TermBuilder.Power(x, 2)); return TermBuilder.Sum(powers); } } /// /// Gets the dimensions of this vector /// public int Dimension { get { Contract.Ensures(Contract.Result() > 0); return terms.Length; } } /// /// Gets the first vector component /// public Term X { get { Contract.Ensures(Contract.Result() != null); return this[0]; } } /// /// Gets the second vector component. /// public Term Y { get { Contract.Requires(Dimension >= 2); Contract.Ensures(Contract.Result() != null); return this[1]; } } /// /// Gets the third vector component /// public Term Z { get { Contract.Requires(Dimension >= 3); Contract.Ensures(Contract.Result() != null); return this[2]; } } /// /// Gets an array of all vector components. /// /// An array of all vector components. Users are free to modify this array. It doesn't point to any /// internal structures. public Term[] GetTerms() { Contract.Ensures(Contract.Result() != null); Contract.Ensures(Contract.Result().Length > 0); Contract.Ensures(Contract.ForAll(Contract.Result(), term => term != null)); return (Term[])terms.Clone(); } /// /// Constructs a sum of two term vectors. /// /// The first vector in the sum /// The second vector in the sum /// A vector representing the sum of and public static TVec operator+(TVec left, TVec right) { Contract.Requires(left != null); Contract.Requires(right != null); Contract.Requires(left.Dimension == right.Dimension); Contract.Ensures(Contract.Result().Dimension == left.Dimension); return new TVec(left.terms, right.terms, (x, y) => x + y); } /// /// Constructs a difference of two term vectors, /// /// The first vector in the difference /// The second vector in the difference. /// A vector representing the difference of and public static TVec operator-(TVec left, TVec right) { Contract.Requires(left != null); Contract.Requires(right != null); Contract.Requires(left.Dimension == right.Dimension); Contract.Ensures(Contract.Result().Dimension == left.Dimension); return new TVec(left.terms, right.terms, (x, y) => x - y); } /// /// Inverts a vector /// /// The vector to invert /// A vector repsesenting the inverse of public static TVec operator-(TVec vector) { Contract.Requires(vector != null); Contract.Ensures(Contract.Result().Dimension == vector.Dimension); return vector * -1; } /// /// Multiplies a vector by a scalar /// /// The vector /// The scalar /// A product of the vector and the scalar . public static TVec operator*(TVec vector, Term scalar) { Contract.Requires(vector != null); Contract.Requires(scalar != null); Contract.Ensures(Contract.Result().Dimension == vector.Dimension); return new TVec(vector.terms, x => scalar * x); } /// /// Multiplies a vector by a scalar /// /// The vector /// The scalar /// A product of the vector and the scalar . public static TVec operator *(Term scalar, TVec vector) { Contract.Requires(vector != null); Contract.Requires(scalar != null); Contract.Ensures(Contract.Result().Dimension == vector.Dimension); return vector * scalar; } /// /// Constructs a term representing the inner product of two vectors. /// /// The first vector of the inner product /// The second vector of the inner product /// A term representing the inner product of and . public static Term operator*(TVec left, TVec right) { Contract.Requires(left != null); Contract.Requires(right != null); Contract.Requires(left.Dimension == right.Dimension); Contract.Ensures(Contract.Result() != null); return InnerProduct(left, right); } /// /// Constructs a term representing the inner product of two vectors. /// /// The first vector of the inner product /// The second vector of the inner product /// A term representing the inner product of and . public static Term InnerProduct(TVec left, TVec right) { Contract.Requires(left != null); Contract.Requires(right != null); Contract.Requires(left.Dimension == right.Dimension); Contract.Ensures(Contract.Result() != null); var products = from i in System.Linq.Enumerable.Range(0, left.Dimension) select left.terms[i] * right.terms[i]; return TermBuilder.Sum(products); } /// /// Constructs a 3D cross-product vector given two 3D vectors. /// /// The left cross-product term /// The right cross product term /// A vector representing the cross product of and public static TVec CrossProduct(TVec left, TVec right) { Contract.Requires(left != null); Contract.Requires(right != null); Contract.Requires(left.Dimension == 3); Contract.Requires(right.Dimension == 3); Contract.Ensures(Contract.Result().Dimension == 3); return new TVec( left.Y * right.Z - left.Z * right.Y, left.Z * right.X - left.X * right.Z, left.X * right.Y - left.Y * right.X ); } } }