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
);
}
}
}