1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.Linq;
|
---|
4 | using System.Text;
|
---|
5 | using AutoDiff;
|
---|
6 | using System.Diagnostics.Contracts;
|
---|
7 |
|
---|
8 | namespace AutoDiff
|
---|
9 | {
|
---|
10 | /// <summary>
|
---|
11 | /// A column vector made of terms.
|
---|
12 | /// </summary>
|
---|
13 | [Serializable]
|
---|
14 | public class TVec
|
---|
15 | {
|
---|
16 | private readonly Term[] terms;
|
---|
17 |
|
---|
18 | /// <summary>
|
---|
19 | /// Constructs a new instance of the <see cref="TVec"/> class given vector components.
|
---|
20 | /// </summary>
|
---|
21 | /// <param name="terms">The vector component terms</param>
|
---|
22 | public TVec(IEnumerable<Term> terms)
|
---|
23 | {
|
---|
24 | Contract.Requires(terms != null);
|
---|
25 | Contract.Requires(Contract.ForAll(terms, term => term != null));
|
---|
26 | Contract.Requires(terms.Any());
|
---|
27 |
|
---|
28 | this.terms = terms.ToArray();
|
---|
29 | }
|
---|
30 |
|
---|
31 | /// <summary>
|
---|
32 | /// Constructs a new instance of the <see cref="TVec"/> class given vector components.
|
---|
33 | /// </summary>
|
---|
34 | /// <param name="terms">The vector component terms</param>
|
---|
35 | public TVec(params Term[] terms)
|
---|
36 | : this(terms as IEnumerable<Term>)
|
---|
37 | {
|
---|
38 | Contract.Requires(terms != null);
|
---|
39 | Contract.Requires(Contract.ForAll(terms, term => term != null));
|
---|
40 | Contract.Requires(terms.Length > 0);
|
---|
41 | }
|
---|
42 |
|
---|
43 | /// <summary>
|
---|
44 | /// Constructs a new instance of the <see cref="TVec"/> class using another vector's components.
|
---|
45 | /// </summary>
|
---|
46 | /// <param name="first">A vector containing the first vector components to use.</param>
|
---|
47 | /// <param name="rest">More vector components to add in addition to the components in <paramref name="first"/></param>
|
---|
48 | public TVec(TVec first, params Term[] rest)
|
---|
49 | : this(first.terms.Concat(rest ?? System.Linq.Enumerable.Empty<Term>()))
|
---|
50 | {
|
---|
51 | Contract.Requires(first != null);
|
---|
52 | Contract.Requires(Contract.ForAll(rest, term => term != null));
|
---|
53 | }
|
---|
54 |
|
---|
55 | private TVec(Term[] left, Term[] right, Func<Term, Term, Term> elemOp)
|
---|
56 | {
|
---|
57 | Contract.Assume(left.Length == right.Length);
|
---|
58 | terms = new Term[left.Length];
|
---|
59 | for (int i = 0; i < terms.Length; ++i)
|
---|
60 | terms[i] = elemOp(left[i], right[i]);
|
---|
61 | }
|
---|
62 |
|
---|
63 | private TVec(Term[] input, Func<Term, Term> elemOp)
|
---|
64 | {
|
---|
65 | terms = new Term[input.Length];
|
---|
66 | for (int i = 0; i < input.Length; ++i)
|
---|
67 | terms[i] = elemOp(input[i]);
|
---|
68 | }
|
---|
69 |
|
---|
70 | /// <summary>
|
---|
71 | /// Gets a vector component given its zero-based index.
|
---|
72 | /// </summary>
|
---|
73 | /// <param name="index">The vector's component index.</param>
|
---|
74 | /// <returns>The vector component.</returns>
|
---|
75 | public Term this[int index]
|
---|
76 | {
|
---|
77 | get
|
---|
78 | {
|
---|
79 | Contract.Requires(index >= 0 && index < Dimension);
|
---|
80 | Contract.Ensures(Contract.Result<Term>() != null);
|
---|
81 |
|
---|
82 | return terms[index];
|
---|
83 | }
|
---|
84 | }
|
---|
85 |
|
---|
86 | /// <summary>
|
---|
87 | /// Gets a term representing the squared norm of this vector.
|
---|
88 | /// </summary>
|
---|
89 | public Term NormSquared
|
---|
90 | {
|
---|
91 | get
|
---|
92 | {
|
---|
93 | Contract.Ensures(Contract.Result<Term>() != null);
|
---|
94 |
|
---|
95 | var powers = terms.Select(x => TermBuilder.Power(x, 2));
|
---|
96 | return TermBuilder.Sum(powers);
|
---|
97 | }
|
---|
98 | }
|
---|
99 |
|
---|
100 | /// <summary>
|
---|
101 | /// Gets the dimensions of this vector
|
---|
102 | /// </summary>
|
---|
103 | public int Dimension
|
---|
104 | {
|
---|
105 | get
|
---|
106 | {
|
---|
107 | Contract.Ensures(Contract.Result<int>() > 0);
|
---|
108 |
|
---|
109 | return terms.Length;
|
---|
110 | }
|
---|
111 | }
|
---|
112 |
|
---|
113 | /// <summary>
|
---|
114 | /// Gets the first vector component
|
---|
115 | /// </summary>
|
---|
116 | public Term X
|
---|
117 | {
|
---|
118 | get
|
---|
119 | {
|
---|
120 | Contract.Ensures(Contract.Result<Term>() != null);
|
---|
121 |
|
---|
122 | return this[0];
|
---|
123 | }
|
---|
124 | }
|
---|
125 |
|
---|
126 | /// <summary>
|
---|
127 | /// Gets the second vector component.
|
---|
128 | /// </summary>
|
---|
129 | public Term Y
|
---|
130 | {
|
---|
131 | get
|
---|
132 | {
|
---|
133 | Contract.Requires(Dimension >= 2);
|
---|
134 | Contract.Ensures(Contract.Result<Term>() != null);
|
---|
135 |
|
---|
136 | return this[1];
|
---|
137 | }
|
---|
138 | }
|
---|
139 |
|
---|
140 | /// <summary>
|
---|
141 | /// Gets the third vector component
|
---|
142 | /// </summary>
|
---|
143 | public Term Z
|
---|
144 | {
|
---|
145 | get
|
---|
146 | {
|
---|
147 | Contract.Requires(Dimension >= 3);
|
---|
148 | Contract.Ensures(Contract.Result<Term>() != null);
|
---|
149 |
|
---|
150 | return this[2];
|
---|
151 | }
|
---|
152 | }
|
---|
153 |
|
---|
154 | /// <summary>
|
---|
155 | /// Gets an array of all vector components.
|
---|
156 | /// </summary>
|
---|
157 | /// <returns>An array of all vector components. Users are free to modify this array. It doesn't point to any
|
---|
158 | /// internal structures.</returns>
|
---|
159 | public Term[] GetTerms()
|
---|
160 | {
|
---|
161 | Contract.Ensures(Contract.Result<Term[]>() != null);
|
---|
162 | Contract.Ensures(Contract.Result<Term[]>().Length > 0);
|
---|
163 | Contract.Ensures(Contract.ForAll(Contract.Result<Term[]>(), term => term != null));
|
---|
164 |
|
---|
165 | return (Term[])terms.Clone();
|
---|
166 | }
|
---|
167 |
|
---|
168 | /// <summary>
|
---|
169 | /// Constructs a sum of two term vectors.
|
---|
170 | /// </summary>
|
---|
171 | /// <param name="left">The first vector in the sum</param>
|
---|
172 | /// <param name="right">The second vector in the sum</param>
|
---|
173 | /// <returns>A vector representing the sum of <paramref name="left"/> and <paramref name="right"/></returns>
|
---|
174 | public static TVec operator+(TVec left, TVec right)
|
---|
175 | {
|
---|
176 | Contract.Requires(left != null);
|
---|
177 | Contract.Requires(right != null);
|
---|
178 | Contract.Requires(left.Dimension == right.Dimension);
|
---|
179 | Contract.Ensures(Contract.Result<TVec>().Dimension == left.Dimension);
|
---|
180 |
|
---|
181 | return new TVec(left.terms, right.terms, (x, y) => x + y);
|
---|
182 | }
|
---|
183 |
|
---|
184 | /// <summary>
|
---|
185 | /// Constructs a difference of two term vectors,
|
---|
186 | /// </summary>
|
---|
187 | /// <param name="left">The first vector in the difference</param>
|
---|
188 | /// <param name="right">The second vector in the difference.</param>
|
---|
189 | /// <returns>A vector representing the difference of <paramref name="left"/> and <paramref name="right"/></returns>
|
---|
190 | public static TVec operator-(TVec left, TVec right)
|
---|
191 | {
|
---|
192 | Contract.Requires(left != null);
|
---|
193 | Contract.Requires(right != null);
|
---|
194 | Contract.Requires(left.Dimension == right.Dimension);
|
---|
195 | Contract.Ensures(Contract.Result<TVec>().Dimension == left.Dimension);
|
---|
196 |
|
---|
197 | return new TVec(left.terms, right.terms, (x, y) => x - y);
|
---|
198 | }
|
---|
199 |
|
---|
200 | /// <summary>
|
---|
201 | /// Inverts a vector
|
---|
202 | /// </summary>
|
---|
203 | /// <param name="vector">The vector to invert</param>
|
---|
204 | /// <returns>A vector repsesenting the inverse of <paramref name="vector"/></returns>
|
---|
205 | public static TVec operator-(TVec vector)
|
---|
206 | {
|
---|
207 | Contract.Requires(vector != null);
|
---|
208 | Contract.Ensures(Contract.Result<TVec>().Dimension == vector.Dimension);
|
---|
209 |
|
---|
210 | return vector * -1;
|
---|
211 | }
|
---|
212 |
|
---|
213 | /// <summary>
|
---|
214 | /// Multiplies a vector by a scalar
|
---|
215 | /// </summary>
|
---|
216 | /// <param name="vector">The vector</param>
|
---|
217 | /// <param name="scalar">The scalar</param>
|
---|
218 | /// <returns>A product of the vector <paramref name="vector"/> and the scalar <paramref name="scalar"/>.</returns>
|
---|
219 | public static TVec operator*(TVec vector, Term scalar)
|
---|
220 | {
|
---|
221 | Contract.Requires(vector != null);
|
---|
222 | Contract.Requires(scalar != null);
|
---|
223 | Contract.Ensures(Contract.Result<TVec>().Dimension == vector.Dimension);
|
---|
224 |
|
---|
225 | return new TVec(vector.terms, x => scalar * x);
|
---|
226 | }
|
---|
227 |
|
---|
228 | /// <summary>
|
---|
229 | /// Multiplies a vector by a scalar
|
---|
230 | /// </summary>
|
---|
231 | /// <param name="vector">The vector</param>
|
---|
232 | /// <param name="scalar">The scalar</param>
|
---|
233 | /// <returns>A product of the vector <paramref name="vector"/> and the scalar <paramref name="scalar"/>.</returns>
|
---|
234 | public static TVec operator *(Term scalar, TVec vector)
|
---|
235 | {
|
---|
236 | Contract.Requires(vector != null);
|
---|
237 | Contract.Requires(scalar != null);
|
---|
238 | Contract.Ensures(Contract.Result<TVec>().Dimension == vector.Dimension);
|
---|
239 |
|
---|
240 | return vector * scalar;
|
---|
241 | }
|
---|
242 |
|
---|
243 | /// <summary>
|
---|
244 | /// Constructs a term representing the inner product of two vectors.
|
---|
245 | /// </summary>
|
---|
246 | /// <param name="left">The first vector of the inner product</param>
|
---|
247 | /// <param name="right">The second vector of the inner product</param>
|
---|
248 | /// <returns>A term representing the inner product of <paramref name="left"/> and <paramref name="right"/>.</returns>
|
---|
249 | public static Term operator*(TVec left, TVec right)
|
---|
250 | {
|
---|
251 | Contract.Requires(left != null);
|
---|
252 | Contract.Requires(right != null);
|
---|
253 | Contract.Requires(left.Dimension == right.Dimension);
|
---|
254 | Contract.Ensures(Contract.Result<Term>() != null);
|
---|
255 |
|
---|
256 | return InnerProduct(left, right);
|
---|
257 | }
|
---|
258 |
|
---|
259 | /// <summary>
|
---|
260 | /// Constructs a term representing the inner product of two vectors.
|
---|
261 | /// </summary>
|
---|
262 | /// <param name="left">The first vector of the inner product</param>
|
---|
263 | /// <param name="right">The second vector of the inner product</param>
|
---|
264 | /// <returns>A term representing the inner product of <paramref name="left"/> and <paramref name="right"/>.</returns>
|
---|
265 | public static Term InnerProduct(TVec left, TVec right)
|
---|
266 | {
|
---|
267 | Contract.Requires(left != null);
|
---|
268 | Contract.Requires(right != null);
|
---|
269 | Contract.Requires(left.Dimension == right.Dimension);
|
---|
270 | Contract.Ensures(Contract.Result<Term>() != null);
|
---|
271 |
|
---|
272 | var products = from i in System.Linq.Enumerable.Range(0, left.Dimension)
|
---|
273 | select left.terms[i] * right.terms[i];
|
---|
274 |
|
---|
275 | return TermBuilder.Sum(products);
|
---|
276 | }
|
---|
277 |
|
---|
278 | /// <summary>
|
---|
279 | /// Constructs a 3D cross-product vector given two 3D vectors.
|
---|
280 | /// </summary>
|
---|
281 | /// <param name="left">The left cross-product term</param>
|
---|
282 | /// <param name="right">The right cross product term</param>
|
---|
283 | /// <returns>A vector representing the cross product of <paramref name="left"/> and <paramref name="right"/></returns>
|
---|
284 | public static TVec CrossProduct(TVec left, TVec right)
|
---|
285 | {
|
---|
286 | Contract.Requires(left != null);
|
---|
287 | Contract.Requires(right != null);
|
---|
288 | Contract.Requires(left.Dimension == 3);
|
---|
289 | Contract.Requires(right.Dimension == 3);
|
---|
290 | Contract.Ensures(Contract.Result<TVec>().Dimension == 3);
|
---|
291 |
|
---|
292 | return new TVec(
|
---|
293 | left.Y * right.Z - left.Z * right.Y,
|
---|
294 | left.Z * right.X - left.X * right.Z,
|
---|
295 | left.X * right.Y - left.Y * right.X
|
---|
296 | );
|
---|
297 | }
|
---|
298 | }
|
---|
299 | }
|
---|