001 /**
002 * Clifford.java
003 *
004 * This file is part of jclifford package and it's distributed under the terms of the MIT license.
005 *
006 * The MIT License :
007 * -----------------
008 * Copyright (c) 2002, 2003, 2004, 2005 Giorgio Vassallo, Pietro Brignola
009 *
010 * Permission is hereby granted, free of charge, to any person obtaining a
011 * copy of this software and associated documentation files (the "Software"),
012 * to deal in the Software without restriction, including without limitation
013 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
014 * and/or sell copies of the Software, and to permit persons to whom the
015 * Software is furnished to do so, subject to the following conditions:
016 * The above copyright notice and this permission notice shall be included in
017 * all copies or substantial portions of the Software.
018 *
019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
020 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
021 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
022 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
023 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
024 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
025 * DEALINGS IN THE SOFTWARE.
026 */
027
028 package jclifford;
029
030 import java.util.Map;
031 import java.util.TreeMap;
032 import java.util.Iterator;
033
034 /**
035 * <p>This class represents a Clifford element and all the operation in a signed space.</p>
036 * <p>Use this class for p + q <= 8. For p + q > 8 use CliffordBitSet or CliffordTreeSet instead.</p>
037 * @version <p>0.9</p>
038 * @author <p>Realized by <a href="mailto:vassallo@csai.unipa.it">Giorgio Vassallo</a>, <a href="mailto:pietro.brignola@libero.it">Pietro Brignola</a>, November 2002.</p>
039 * @see CliffordBitSet
040 * @see CliffordTreeSet
041 */
042 public class Clifford{
043
044 /**
045 * Element's blade-value mappings.
046 */
047 protected TreeMap map;
048
049 /**
050 * Algebra's Precision.
051 */
052 protected static double eps = 1e-12;
053
054 /**
055 * Number of dimensions with positive square versors.
056 */
057 protected static int p = 0;
058
059 /**
060 * Number of dimensions with negative square versors.
061 */
062 protected static int q = 0;
063
064 /**
065 * Algebra's dimension.
066 */
067 protected static int dim = 0;
068
069 /**
070 * Algebra's possible blades (2 ^ dim).
071 */
072 protected static int hdim = 1;
073
074 /**
075 * Mask with bits 1 corresponding to the presence of dimensions (starting from l.s.b.).
076 *
077 * Es.: dim = p + q = 5, spacemask = [0...011111].
078 */
079 protected static int spaceMask = 0;
080
081 /**
082 * Mask with p bits 0 and q bits 1 corresponding to negative square versors (starting from l.s.b.).
083 *
084 * Es.: p = 3, q = 2, signmask = [0...011000].
085 */
086 protected static int signMask = 0;
087
088 /**
089 * Stores the grade (number of bits 1 in the binary rappresentation) of a blade.
090 */
091 protected static int[] gradeTable = {0};
092
093 /**
094 * Stores the grade (number of bits 1 in the binary rappresentation) of a blade.
095 */
096 protected static boolean[][] signTable = {{false}};
097
098 /**
099 * Algebra's pseudoscalar.
100 */
101 protected static Clifford pseudoScalar;
102
103 /**
104 * Gets algebra's precision.
105 * @return algebra's precision.
106 */
107 public static double getEps()
108 {
109 return eps;
110 }
111
112 /**
113 * Sets algebra's precision.
114 * @throws IllegalArgumentException if the precision is negative.
115 * @param e positive precision.
116 */
117 public static void setEps(double e) throws IllegalArgumentException{
118 //Positive precision required
119 if(e <= 0)
120 throw new IllegalArgumentException("Invalid precision: positive precision required.");
121 eps = e;
122 }
123
124 /**
125 * Gets algebra's dimension.
126 * @return algebra's dimension.
127 */
128 public static int getDim(){
129 return dim;
130 }
131
132 /**
133 * Gets algebra's possible blades.
134 * @return algebra's possible blades.
135 */
136 public static int getPossibleBlades(){
137 return hdim;
138 }
139
140 /**
141 * Counts the number of bits 1 in the binary rappresentation of a blade.
142 * @param bld the blade whose number of bits 1 in its binary rappresentation are to be counted.
143 * @return the number of bits 1 in the binary rappresentation of the specified blade.
144 */
145 private static int bitCount(int bld){
146 int count = 0;
147 while(bld != 0){
148 count ++;
149 bld &= bld - 1;
150 }
151 return count;
152 }
153
154 /**
155 * Computes the sign of the product of two blades.
156 * @param bld1 the first blade of the product.
157 * @param bld2 the second blade of the product.
158 * @return true if the sign of the product of the specified blades is negative, false otherwise.
159 */
160 private static boolean getSign(int bld1,int bld2){
161 int k,l,sign = 0;
162 for(k = 1; k < hdim; k <<= 1){
163 if((bld1 & k) != 0){
164 l = bld2 & (k -1);
165 if((gradeTable[l] & 1) != 0)
166 sign ^= 1;
167 }
168 }
169 l = bld1 & bld2 & signMask;
170 if((gradeTable[l] & 1) != 0)
171 sign ^= 1;
172 return sign != 0;
173 }
174
175 /**
176 * Computes binomial coefficents.
177 * @param n the dimension.
178 * @param k the grade.
179 * @return binomial coefficent.
180 */
181 private static int bCoefficent(int n, int k){
182 if((k == 0) || (k == n))
183 return 1;
184 if(k > (n / 2))
185 k = n - k;
186 double c = ((double) n) / k;
187 n--;
188 k--;
189 while(k != 0){
190 c *= n;
191 c /= k;
192 n--;
193 k--;
194 }
195 return ((int) c);
196 }
197
198 /**
199 * Initializes algebra's signature.
200 * @throws IllegalArgumentException if p or q are negative or their sum is greater than 8.
201 * @param pdim the number of dimensions with versors that square in 1.
202 * @param ndim the number of dimensions with versors that square in -1.
203 */
204 public static void init(int pdim, int ndim) throws IllegalArgumentException{
205 //Checking for valid signature
206 if((pdim < 0) || (ndim < 0) || ((pdim + ndim) > 8))
207 throw new IllegalArgumentException("Invalid signature: use p >= 0, q >= 0, 0 <= p + q <= 8");
208 //Initializing signature
209 p = pdim;
210 q = ndim;
211 dim = p + q;
212 hdim = 1 << dim;
213 //Initializing spaceMask
214 spaceMask = hdim - 1;
215 //Initializing signMask
216 signMask = ~((1 << p) - 1) & spaceMask;
217 //Initializing gradeTable
218 gradeTable = new int[hdim];
219 for(int i = 0; i < hdim; i ++)
220 gradeTable[i] = bitCount(i);
221 //Initializing signTable
222 signTable = new boolean[hdim][hdim];
223 for(int i = 0; i < hdim; i++)
224 for(int j = 0; j < hdim; j++)
225 signTable[i][j] = getSign(i,j);
226 //Initialiting pseudoscalar
227 pseudoScalar = new Clifford();
228 pseudoScalar.map.put(new Blade(spaceMask),new Value(1.0));
229 }
230
231 /**
232 * Sets meet operation subspace.
233 * @throws IllegalArgumentException if subspace is negative or outside algebra's space mask.
234 * @param subspace the meet operation subspace.
235 */
236 public static void setMeetSubSpace(int subspace) throws IllegalArgumentException{
237 //Checking for valid subspace
238 if(subspace < 0)
239 throw new IllegalArgumentException("Blade cannot be negative.");
240 if(subspace > spaceMask)
241 throw new IllegalArgumentException("Invalid signature for this operation.");
242 //Setting pseudoscalar
243 pseudoScalar = new Clifford();
244 pseudoScalar.map.put(new Blade(subspace),new Value(1.0));
245 }
246
247 /**
248 * Creates and returns an element with no blade-value mappings.
249 * @throws RuntimeException if algebra's signature is not initialized.
250 */
251 public Clifford() throws RuntimeException{
252 map = new TreeMap();
253 }
254
255 /**
256 * Creates and returns an element with specified blade-value mappings.
257 * @throws RuntimeException if algebra's signature is not initialized.
258 * @throws IllegalArgumentException if the arrays have different lenght.
259 * @param blades the int array representing the specified blades.
260 * @param values the double array representing the corresponding values.
261 */
262 public Clifford(int blades[], double values[]) throws RuntimeException, IllegalArgumentException{
263 //Checking for same length arrays
264 if(blades.length != values.length)
265 throw new IllegalArgumentException("Different length arrays.");
266 //Creating element and adding mappings
267 map = new TreeMap();
268 for(int i = 0; i < blades.length; i ++)
269 map.put(new Blade(blades[i]),new Value(values[i]));
270 }
271
272 /**
273 * Gets the value of a blade.
274 * @throws IllegalArgumentException if blade is negative or outside algebra's space mask.
275 * @param blade the int representing the specified blade whose value is to be retrieved.
276 * @return the value of the specified blade, 0.0 if blade is not present.
277 */
278 public double get(int blade) throws IllegalArgumentException{
279 if(blade < 0)
280 throw new IllegalArgumentException("Blade cannot be negative.");
281 if(blade > spaceMask)
282 throw new IllegalArgumentException("Invalid signature for this operation.");
283 Value val = (Value) map.get(new Blade(blade));
284 return (val != null) ? val.value : 0.0;
285 }
286
287 /**
288 * Gets the value of a blade.
289 * @throws IllegalArgumentException if blademask is invalid, blade is negative or outside algebra's space mask.
290 * @param blademask the binary mask representing the specified blade whose value is to be retrieved.
291 * @return the value of the specified blade, 0.0 if blade is not present.
292 */
293 public double get(String blademask) throws IllegalArgumentException{
294 int blade;
295 try{
296 blade = Integer.parseInt(blademask,2);
297 }catch(Exception e){
298 throw new IllegalArgumentException("Invalid mask for this operation.");
299 }
300 if(blade < 0)
301 throw new IllegalArgumentException("Blade cannot be negative.");
302 if(blade > spaceMask)
303 throw new IllegalArgumentException("Invalid signature for this operation.");
304 Value val = (Value) map.get(new Blade(blade));
305 return (val != null) ? val.value : 0.0;
306 }
307
308 /**
309 * Puts a new blade-value mapping or updates existing.
310 * @throws IllegalArgumentException if blade is negative or outside algebra's space mask.
311 * @param blade the int representing the specified blade that is to be put.
312 * @param value the double representing the corresponding value of the specified blade.
313 */
314 public void put(int blade, double value) throws IllegalArgumentException{
315 if(blade < 0)
316 throw new IllegalArgumentException("Blade cannot be negative.");
317 if(blade > spaceMask)
318 throw new IllegalArgumentException("Invalid signature for this operation.");
319 //Adding tresholded value
320 map.put(new Blade(blade), new Value((Math.abs(value) >= eps) ? value : 0.0));
321 }
322
323 /**
324 * Puts a new blade-value mapping or updates existing.
325 * @throws IllegalArgumentException if blademask is invalid, blade is negative or outside algebra's space mask.
326 * @param blademask the binary mask representing the specified blade that is to be put.
327 * @param value the double representing the corresponding value of the specified blade.
328 */
329 public void put(String blademask, double value) throws IllegalArgumentException{
330 int blade;
331 try{
332 blade = Integer.parseInt(blademask,2);
333 }catch(Exception e){
334 throw new IllegalArgumentException("Invalid mask for this operation.");
335 }
336 if(blade < 0)
337 throw new IllegalArgumentException("Blade cannot be negative.");
338 if(blade > spaceMask)
339 throw new IllegalArgumentException("Invalid signature for this operation.");
340 //Adding tresholded value
341 map.put(new Blade(blade), new Value((Math.abs(value) >= eps) ? value : 0.0));
342 }
343
344 /**
345 * Removes blade-value mapping if existing.
346 * @throws IllegalArgumentException if blade is negative or outside algebra's space mask.
347 * @param blade the int representing the specified blade that is to be removed.
348 */
349 public void remove(int blade) throws IllegalArgumentException{
350 if(blade < 0)
351 throw new IllegalArgumentException("Blade cannot be negative.");
352 if(blade > spaceMask)
353 throw new IllegalArgumentException("Invalid signature for this operation.");
354 map.remove(new Blade(blade));
355 }
356
357 /**
358 * Returns a string representation of the element.
359 * @return the string representation of the element.
360 */
361 public String toString(){
362 //String representation of the element
363 String str = new String();
364 //Temporary reference variables
365 Map.Entry entry;
366 Blade bld;
367 Value val;
368 //For all blade-value mappings
369 Iterator it = map.entrySet().iterator();
370 while(it.hasNext()) {
371 //Getting blade and value
372 entry = (Map.Entry) it.next();
373 bld = (Blade) entry.getKey();
374 val = (Value) entry.getValue();
375 str = str + bld.toString() + "\t==>\t" + val.value + "\n";
376 }
377 str = str + "---------\n";
378 //Returning the string
379 return str;
380 }
381
382 /**
383 * Creates and returns an element deeply cloning this element.
384 */
385 public Object clone(){
386 //Creating a new empty element
387 Clifford newcl = new Clifford();
388 //Temporary reference variables
389 Map.Entry entry;
390 Blade bld;
391 Value val;
392 //For all blade-value mappings
393 Iterator it = map.entrySet().iterator();
394 while(it.hasNext()) {
395 //Getting blade and value
396 entry = (Map.Entry) it.next();
397 bld = (Blade) entry.getKey();
398 val = (Value) entry.getValue();
399 //Adding new blade-value mapping to newcl
400 newcl.map.put(new Blade(bld.blade), new Value(val.value));
401 }
402 return newcl;
403 }
404
405 /**
406 * Removes blades with values lower than eps.
407 */
408 public final void noZero(){
409 //Temporary reference variables
410 Map.Entry entry;
411 Blade bld;
412 Value val;
413 //For all blade-value mappings
414 Iterator it = map.entrySet().iterator();
415 while(it.hasNext()) {
416 entry = (Map.Entry) it.next();
417 bld = (Blade) entry.getKey();
418 val = (Value) entry.getValue();
419 //Tresholding
420 if(java.lang.Math.abs(val.value) < eps)
421 //Removing blade-value mappings
422 it.remove();
423 }
424 }
425
426 /**
427 * Computes the quad module of an element discarding signature.
428 * @return the quad module of the specified element discarding signature.
429 */
430 public final double uQuadMod(){
431 //Temporary unsigned quad module
432 double uqm = 0.0;
433 //Temporary reference variables
434 Map.Entry entry;
435 Value val;
436 //For all blade-value mappings
437 Iterator it = map.entrySet().iterator();
438 while(it.hasNext()) {
439 //Getting value
440 entry = (Map.Entry) it.next();
441 val = (Value) entry.getValue();
442 //Uptdating temporary module
443 uqm += val.value * val.value;
444 }
445 return uqm;
446 }
447
448 /**
449 * Computes the quad module of an element regarding signature.
450 * @return the quad module of the specified element regarding signature.
451 */
452 public final double sQuadMod(){
453 //Temporary module
454 double sqm = 0.0;
455 //Temporary reference variables
456 Map.Entry entry;
457 Blade bld;
458 Value val;
459 //For all blade-value mappings
460 Iterator it = map.entrySet().iterator();
461 while(it.hasNext()) {
462 //Getting blade and value
463 entry = (Map.Entry) it.next();
464 bld = (Blade) entry.getKey();
465 val = (Value) entry.getValue();
466 //Uptdating temporary module regarding versor square sign
467 sqm += val.value * (signTable[bld.blade][bld.blade] ? -val.value : val.value);
468 }
469 return sqm;
470 }
471
472 /**
473 * Normalizes this element respect the unsigned module.
474 */
475 public final void normalize(){
476 //Unsigned module
477 double um = Math.sqrt(uQuadMod());
478 //Checking for null module
479 if(um == 0.0)
480 return;
481 //Temporary reference variables
482 Map.Entry entry;
483 Blade bld;
484 Value val;
485 //For all blade-value mappings
486 Iterator it = map.entrySet().iterator();
487 while(it.hasNext()) {
488 entry = (Map.Entry) it.next();
489 bld = (Blade) entry.getKey();
490 val = (Value) entry.getValue();
491 //Updating value
492 val.value /= um;
493 //Tresholding
494 if(java.lang.Math.abs(val.value) < eps)
495 //Removing blade-value mappings
496 it.remove();
497 }
498 }
499
500 /**
501 * Gets highest grade of this element.
502 * @return highest grade of this element.
503 */
504 public final int getMaxGrade(){//Not using entrySet().iterator
505 //Temporary grade
506 int maxgrade = 0;
507 //Temporary reference variable
508 Blade bld;
509 //Defining an array of cl blades
510 Object[] arrbld = map.keySet().toArray();
511 //For all cl blades
512 for(int x = 0; x < arrbld.length; x ++){
513 //Getting blade
514 bld = (Blade) arrbld[x];
515 //Comparing blade grade with temporary grade
516 if(gradeTable[bld.blade] > maxgrade)
517 maxgrade = gradeTable[bld.blade];
518 }
519 return maxgrade;
520 }
521
522 /**
523 * Verifies if this element is a scalar.
524 * @return true if this element is a scalar, false otherwise.
525 */
526 public final boolean isScalar(){
527 return (getMaxGrade() == 0) ? true : false;
528 }
529
530 /**
531 * Verifies if this element is a vector.
532 * @return true if this element is a vector, false otherwise.
533 */
534 public final boolean isVector(){
535 return ((get(0) == 0.0) && (getMaxGrade() == 1)) ? true : false;
536 }
537
538 /**
539 * Compares two elements for equality.
540 * Two elements are considered equals if they have same blades and corresponding values differing less than 2*EPS.
541 * @param obj the second element that is to be compared.
542 * @return true if the two specified elements are equals, false otherwise.
543 */
544 public boolean equals(Object obj){
545 //Casting to Clifford object
546 Clifford cl = (Clifford) obj;
547 //Verifyng if blades maps have the same size (number of blade-value mappings)
548 if(map.size() != cl.map.size())
549 return false;
550 //Tollerance
551 double tol = 2*eps;
552 //Temporary reference variables
553 Blade bld1, bld2;
554 Value val1, val2;
555 //Defining ordered arrays of blades and values of cl1 and cl2
556 Object[] arrbld1 = map.keySet().toArray();
557 Object[] arrbld2 = cl.map.keySet().toArray();
558 Object[] arrval1 = map.values().toArray();
559 Object[] arrval2 = cl.map.values().toArray();
560 //For all blade-value mappings
561 for(int x = 0; x < arrbld1.length; x ++){
562 bld1 = (Blade) arrbld1[x];
563 bld2 = (Blade) arrbld2[x];
564 val1 = (Value) arrval1[x];
565 val2 = (Value) arrval2[x];
566 //Comparing blades
567 if(bld1.blade != bld2.blade)
568 return false;
569 //Comparing values
570 if(java.lang.Math.abs(val1.value - val2.value) > tol)
571 return false;
572 }
573 //Elements are equals
574 return true;
575 }
576
577 /**
578 * Adds two elements.
579 * @param cl the second element of the sum.
580 * @return a new element from the sum of the two specified elements.
581 */
582 public final Clifford add(final Clifford cl){
583 //Cloning this element
584 Clifford newcl = (Clifford) clone();
585 //Temporary reference variables
586 Map.Entry entry;
587 Blade bld;
588 Value val, newval;
589 //For all cl blade-value mappings
590 Iterator it = cl.map.entrySet().iterator();
591 while(it.hasNext()) {
592 //Getting blade and value
593 entry = (Map.Entry) it.next();
594 bld = (Blade) entry.getKey();
595 val = (Value) entry.getValue();
596 //Searching bld in newcl
597 newval = (Value) newcl.map.get(bld);
598 //If newcl already contains bld
599 if(newval != null)
600 //Updating corresponding value
601 newval.value += val.value;
602 else
603 //Adding new blade-value mappings to newcl
604 newcl.map.put(new Blade(bld.blade),new Value(val.value));
605 }
606 //Returning tresholded element
607 newcl.noZero();
608 return newcl;
609 }
610
611 /**
612 * Subtracts two elements.
613 * @param cl the second element of the difference.
614 * @return a new element from the difference of the two specified elements.
615 */
616 public final Clifford sub(final Clifford cl){
617 //Cloning this element
618 Clifford newcl = (Clifford) clone();
619 //Temporary reference variables
620 Map.Entry entry;
621 Blade bld;
622 Value val, newval;
623 //For all cl blade-value mappings
624 Iterator it = cl.map.entrySet().iterator();
625 while(it.hasNext()) {
626 //Getting blade and value
627 entry = (Map.Entry) it.next();
628 bld = (Blade) entry.getKey();
629 val = (Value) entry.getValue();
630 //Searching bld in newcl
631 newval = (Value) newcl.map.get(bld);
632 //If newcl already contains bld
633 if(newval != null)
634 //Updating corresponding value
635 newval.value -= val.value;
636 else
637 //Adding new blade-value mappings to newcl
638 newcl.map.put(new Blade(bld.blade),new Value(-val.value));
639 }
640 //Returning tresholded element
641 newcl.noZero();
642 return newcl;
643
644 }
645
646 /**
647 * Computes the grade involution of this element.
648 * @return a new element from the grade involution of the specified element.
649 */
650 public final Clifford gradeInv(){
651 //Creating a new empty element
652 Clifford newcl = new Clifford();
653 //Resulting value
654 double result;
655 //Temporary reference variables
656 Map.Entry entry;
657 Blade bld;
658 Value val;
659 //For all blade-value mappings
660 Iterator it = map.entrySet().iterator();
661 while(it.hasNext()) {
662 //Getting blade and value
663 entry = (Map.Entry) it.next();
664 bld = (Blade) entry.getKey();
665 val = (Value) entry.getValue();
666 //Computing resulting value regarding parity of the grade (number of inversions)
667 result = ((gradeTable[bld.blade] & 1) != 0) ? -val.value : val.value;
668 //Adding new blade-value mapping to newcl
669 newcl.map.put(new Blade(bld.blade), new Value(result));
670 }
671 return newcl;
672 }
673
674 /**
675 * Computes the reverse of this element.
676 * @return a new element from the reversion of this element.
677 */
678 public final Clifford rev(){
679 //Creating a new empty element
680 Clifford newcl = new Clifford();
681 //Resulting value
682 double result;
683 //Temporary reference variables
684 Map.Entry entry;
685 Blade bld;
686 Value val;
687 //For all blade-value mappings
688 Iterator it = map.entrySet().iterator();
689 while(it.hasNext()) {
690 //Getting blade and value
691 entry = (Map.Entry) it.next();
692 bld = (Blade) entry.getKey();
693 val = (Value) entry.getValue();
694 /*
695 Computing resulting value regarding the sign: (-1)^((r(r-1))/2)
696 Sign only depends upon the odd-ness or even-ness of the number of transpositions
697 required to get things back in order. This obeys a simple recurrance relationship.
698 Let T(n) be the number of transpositions required to revert an n-form.
699 Then, T(n+1) = T(n) + n - 1 because it will require T(n) transpositions to reorder
700 the first n subscripts and n-1 transpositions to get the n+1-th subscript from one
701 end of the list to the other.
702 So odd-ness or even-ness of T(n+4) is the same as that of T(n), because:
703 T(n+4) = T(n+3) + n + 2 = T(n+2) + 2n + 3 = T(n+1) + 3n + 3 = T(n) + 4n + 2
704 And, because T(0) and T(1) are even while T(2) and T(3) are odd an n-form requires:
705 an odd number of transpositions to revert if n = 2 or n = 3 modulo 4.
706 In code, this translates to whether the second bit of the grade is set.
707 */
708 result = ((gradeTable[bld.blade] & 2) != 0) ? -val.value : val.value;
709 //Adding new blade-value mapping to newcl
710 newcl.map.put(new Blade(bld.blade), new Value(result));
711 }
712 return newcl;
713 }
714
715 /**
716 * Computes the inverse of this element.
717 * @return a new element from the inversion of this element.
718 */
719 public final Clifford inv(){
720 //Creating a new empty element
721 Clifford newcl = new Clifford();
722 //Temporary sign
723 boolean sign;
724 //Resulting value
725 double result;
726 //Temporary module
727 double module = 0.0;
728 //Temporary reference variables
729 Map.Entry entry;
730 Blade bld;
731 Value val;
732 //For all blade-value mappings
733 Iterator it = map.entrySet().iterator();
734 while(it.hasNext()) {
735 //Getting blade and value
736 entry = (Map.Entry) it.next();
737 bld = (Blade) entry.getKey();
738 val = (Value) entry.getValue();
739 //Computing resulting sign
740 sign = ((gradeTable[bld.blade] & 2) != 0) ? true : false;
741 //Computing resulting value
742 result = sign ? -val.value : val.value;
743 //Adding new blade-value mapping to newcl
744 newcl.map.put(new Blade(bld.blade), new Value(result));
745 //Updating temporary module
746 module += val.value * ((signTable[bld.blade][bld.blade] ^ sign) ? -val.value : val.value);
747 }
748 return newcl.gP(1/module);
749 }
750
751 /**
752 * Computes the conjugation of this element.
753 * The conjugation of an element is a grade involution and a reversion.
754 * @return a new element from the conjugation of the specified element.
755 */
756 public final Clifford conj(){
757 //Creating a new empty element
758 Clifford newcl = new Clifford();
759 //Resulting value
760 double result = 0.0;
761 //Temporary reference variables
762 Map.Entry entry;
763 Blade bld;
764 Value val;
765 //For all blade-value mappings
766 Iterator it = map.entrySet().iterator();
767 while(it.hasNext()) {
768 //Getting blade and value
769 entry = (Map.Entry) it.next();
770 bld = (Blade) entry.getKey();
771 val = (Value) entry.getValue();
772 //Computing resulting value: it is a grade involution and a reversion.
773 switch(gradeTable[bld.blade] & 3){
774 case 0:
775 case 3:
776 result = val.value;
777 break;
778 case 1:
779 case 2:
780 result = -val.value;
781 break;
782 }
783 //Adding new blade-value mapping to newcl
784 newcl.map.put(new Blade(bld.blade), new Value(result));
785 }
786 return newcl;
787 }
788
789 /**
790 * Grades an element.
791 * @param grade the specified grade of the grading operation.
792 * @return a new element with only terms of the specified grade.
793 */
794 public final Clifford grade(int grade){
795 //Creating a new empty element
796 Clifford newcl = new Clifford();
797 //Temporary reference variables
798 Map.Entry entry;
799 Blade bld;
800 Value val;
801 //For all blade-value mappings
802 Iterator it = map.entrySet().iterator();
803 while(it.hasNext()) {
804 //Getting blade and value
805 entry = (Map.Entry) it.next();
806 bld = (Blade) entry.getKey();
807 val = (Value) entry.getValue();
808 //Selecting blades
809 if(gradeTable[bld.blade] == grade)
810 //Adding new blade-value mapping to newcl
811 newcl.map.put(new Blade(bld.blade), new Value(val.value));
812 }
813 return newcl;
814 }
815
816 /**
817 * Computes the geometric product of an element and a scalar.
818 * @param scalar the scalar of the geometric product.
819 * @return a new element from the geometric product of the specified element and the specified scalar.
820 */
821 public final Clifford gP(double scalar){
822 //Creating a new empty element
823 Clifford newcl = new Clifford();
824 double newvalue;
825 //Temporary reference variables
826 Map.Entry entry;
827 Blade bld;
828 Value val;
829 //For all blade-value mappings
830 Iterator it = map.entrySet().iterator();
831 while(it.hasNext()) {
832 //Getting blade and value
833 entry = (Map.Entry) it.next();
834 bld = (Blade) entry.getKey();
835 val = (Value) entry.getValue();
836 //Resulting value for newcl bld
837 newvalue = val.value * scalar;
838 //Tresholding
839 if(java.lang.Math.abs(newvalue) > eps)
840 //Adding new blade-value mapping to newcl blades map
841 newcl.map.put(new Blade(bld.blade), new Value(newvalue));
842 }
843 return newcl;
844 }
845
846 /**
847 * Computes the geometric product of two elements.
848 * @param cl the second element of the geometric product.
849 * @return a new element from the geometric product of the two specified elements.
850 */
851 public final Clifford gP(final Clifford cl){
852
853 //Creating a new empty element
854 Clifford newcl = new Clifford();
855 //Temporary reference variables
856 Blade bld1, bld2, newbld;
857 Value val1, val2, newval;
858 double result;
859 //Defining ordered arrays of blades and values of cl1 and cl2
860 Object[] arrbld1 = map.keySet().toArray();
861 Object[] arrbld2 = cl.map.keySet().toArray();
862 Object[] arrval1 = map.values().toArray();
863 Object[] arrval2 = cl.map.values().toArray();
864 //For all blade-value mappings
865 for(int x = 0; x < arrbld1.length; x ++){
866 bld1 = (Blade) arrbld1[x];
867 val1 = (Value) arrval1[x];
868 //For all cl blade-value mappings
869 for(int y = 0; y < arrbld2.length; y ++){
870 bld2 = (Blade) arrbld2[y];
871 val2 = (Value) arrval2[y];
872 //Computing resulting blade
873 newbld = new Blade(bld1.blade ^ bld2.blade);
874 //Computing resulting value (regarding the sign)
875 result = val1.value * (signTable[bld1.blade][bld2.blade] ? -val2.value : val2.value);
876 //Searching newbld in newcl
877 newval = (Value) newcl.map.get(newbld);
878 //Updating newval by adding result
879 if(newval != null)
880 newval.value += result;
881 //Adding new blade-value mapping to newcl
882 else
883 newcl.map.put(newbld, new Value(result));
884 }
885 }
886 //Returning tresholded element
887 newcl.noZero();
888 return newcl;
889 /*
890 //Using iterators
891
892 //Creating a new empty element
893 Clifford newcl = new Clifford();
894 //Temporary reference variables
895 Map.Entry entry1, entry2;
896 Blade bld1, bld2, newbld;
897 Value val1, val2, newval;
898 double result;
899 //Defining an iterator on cl1 blade-value mappings
900 Iterator it1 = cl1.map.entrySet().iterator(), it2;
901 //For all cl1 blade-value mappings
902 while(it1.hasNext()) {
903 //Getting blade and value
904 entry1 = (Map.Entry) it1.next();
905 bld1 = (Blade) entry1.getKey();
906 val1 = (Value) entry1.getValue();
907 //Defining an iterator on cl2 blade-value mappings
908 it2 = cl2.map.entrySet().iterator();
909 //For all cl1 blade-value mappings
910 while(it2.hasNext()) {
911 //Getting blade and value
912 entry2 = (Map.Entry) it2.next();
913 bld2 = (Blade) entry2.getKey();
914 val2 = (Value) entry2.getValue();
915 //Computing resulting blade
916 newbld = new Blade(bld1.blade ^ bld2.blade);
917 //Computing resulting value (regarding the sign)
918 result = val1.value * (signTable[bld1.blade][bld2.blade] ? -val2.value : val2.value);
919 //Searching newbld in newcl
920 newval = (Value) newcl.map.get(newbld);
921 //Updating newval by adding result
922 if(newval != null)
923 newval.value += result;
924 //Adding new blade-value mapping to newcl
925 else
926 newcl.map.put(newbld, new Value(result));
927 }
928 }
929 //Returning tresholded element
930 newcl.noZero();
931 return newcl;
932 */
933 }
934
935 /**
936 * Computes the wedge product of two elements.
937 * @param cl the second element of the wedge product.
938 * @return a new element from the wedge product of the two specified elements.
939 */
940 public final Clifford wP(final Clifford cl){
941 //Creating a new empty element
942 Clifford newcl = new Clifford();
943 //Temporary reference variables
944 Blade bld1, bld2, newbld;
945 Value val1, val2, newval;
946 double result;
947 //Defining ordered arrays of blades and values
948 Object[] arrbld1 = map.keySet().toArray();
949 Object[] arrbld2 = cl.map.keySet().toArray();
950 Object[] arrval1 = map.values().toArray();
951 Object[] arrval2 = cl.map.values().toArray();
952 //For all blade-value mappings
953 for(int x = 0; x < arrbld1.length; x ++){
954 bld1 = (Blade) arrbld1[x];
955 val1 = (Value) arrval1[x];
956 //For all cl blade-value mappings
957 for(int y = 0; y < arrbld2.length; y ++){
958 bld2 = (Blade) arrbld2[y];
959 val2 = (Value) arrval2[y];
960 //
961 if((bld1.blade & bld2.blade) != 0)
962 continue;
963 //Computing resulting blade
964 newbld = new Blade(bld1.blade ^ bld2.blade);
965 //Computing resulting value (regarding the sign)
966 result = val1.value * (signTable[bld1.blade][bld2.blade] ? -val2.value : val2.value);
967 //Searching newbld in newcl
968 newval = (Value) newcl.map.get(newbld);
969 //Updating newval by adding result
970 if(newval != null)
971 newval.value += result;
972 //Adding new blade-value mapping to newcl
973 else
974 newcl.map.put(newbld, new Value(result));
975 }
976 }
977 //Returning tresholded element
978 newcl.noZero();
979 return newcl;
980 }
981
982 /**
983 * Computes the left contraction with the specified element.
984 * @param cl the second element of the left contraction.
985 * @return a new element from the left contraction with the specified element.
986 */
987 public final Clifford lC(final Clifford cl){
988 //Creating a new empty element
989 Clifford newcl = new Clifford();
990 //Temporary reference variables
991 Blade bld1, bld2, newbld;
992 Value val1, val2, newval;
993 double result;
994 //Defining ordered arrays of blades and values
995 Object[] arrbld1 = map.keySet().toArray();
996 Object[] arrbld2 = cl.map.keySet().toArray();
997 Object[] arrval1 = map.values().toArray();
998 Object[] arrval2 = cl.map.values().toArray();
999 //For all blade-value mappings
1000 for(int x = 0; x < arrbld1.length; x ++){
1001 bld1 = (Blade) arrbld1[x];
1002 val1 = (Value) arrval1[x];
1003 //For all cl blade-value mappings
1004 for(int y = 0; y < arrbld2.length; y ++){
1005 bld2 = (Blade) arrbld2[y];
1006 val2 = (Value) arrval2[y];
1007 //Continue if bld1 has same versor not in bld2
1008 if((bld1.blade & ~(bld2.blade)) != 0)
1009 continue;
1010 //Computing resulting blade
1011 newbld = new Blade(bld1.blade ^ bld2.blade);
1012 //Computing resulting value (regarding the sign)
1013 result = val1.value * (signTable[bld1.blade][bld2.blade] ? -val2.value : val2.value);
1014 //Searching newbld in newcl
1015 newval = (Value) newcl.map.get(newbld);
1016 //Updating newval by adding result
1017 if(newval != null)
1018 newval.value += result;
1019 //Adding new blade-value mapping to newcl
1020 else
1021 newcl.map.put(newbld, new Value(result));
1022 }
1023 }
1024 //Returning tresholded element
1025 newcl.noZero();
1026 return newcl;
1027 }
1028
1029 /**
1030 * Computes the right contraction with the specified element.
1031 * @param cl the second element of the right contraction.
1032 * @return a new element from the right contraction with the specified element.
1033 */
1034 public final Clifford rC(final Clifford cl){
1035 //Creating a new empty element
1036 Clifford newcl = new Clifford();
1037 //Temporary reference variables
1038 Blade bld1, bld2, newbld;
1039 Value val1, val2, newval;
1040 double result;
1041 //Defining ordered arrays of map and values
1042 Object[] arrbld1 = map.keySet().toArray();
1043 Object[] arrbld2 = cl.map.keySet().toArray();
1044 Object[] arrval1 = map.values().toArray();
1045 Object[] arrval2 = cl.map.values().toArray();
1046 //For all blade-value mappings
1047 for(int x = 0; x < arrbld1.length; x ++){
1048 bld1 = (Blade) arrbld1[x];
1049 val1 = (Value) arrval1[x];
1050 //For all cl blade-value mappings
1051 for(int y = 0; y < arrbld2.length; y ++){
1052 bld2 = (Blade) arrbld2[y];
1053 val2 = (Value) arrval2[y];
1054 //Continue if bld2 has same versor not in bld1
1055 if((~ (bld1.blade) & bld2.blade) != 0)
1056 continue;
1057 //Computing resulting blade
1058 newbld = new Blade(bld1.blade ^ bld2.blade);
1059 //Computing resulting value (regarding the sign)
1060 result = val1.value * (signTable[bld1.blade][bld2.blade] ? -val2.value : val2.value);
1061 //Searching newbld in newcl
1062 newval = (Value) newcl.map.get(newbld);
1063 //Updating newval by adding result
1064 if(newval != null)
1065 newval.value += result;
1066 //Adding new blade-value mapping to newcl
1067 else
1068 newcl.map.put(newbld, new Value(result));
1069 }
1070 }
1071 //Returning tresholded element
1072 newcl.noZero();
1073 return newcl;
1074 }
1075
1076 /**
1077 * Computes the fast dot product of two vector.
1078 * @throws IllegalArgumentException if elements are not vectors.
1079 * @param cl the second vector of the fast dot product.
1080 * @return the dot product of the two specified vector.
1081 */
1082 public final double dot(final Clifford cl) throws IllegalArgumentException{
1083 //Temporary dot product
1084 double d = 0.0;
1085 //Temporary reference variables
1086 Map.Entry entry1;
1087 Blade bld1;
1088 Value val1,val2;
1089 //For all blade-value mappings
1090 Iterator it = map.entrySet().iterator();
1091 while(it.hasNext()) {
1092 //Getting blade and value
1093 entry1 = (Map.Entry) it.next();
1094 bld1 = (Blade) entry1.getKey();
1095 val1 = (Value) entry1.getValue();
1096 //Checking for grade 1 blade
1097 if(gradeTable[bld1.blade] != 1)
1098 throw new RuntimeException("Invalid argument: fast dot product is only for vectors.");
1099 //Searching bld1 in cl
1100 val2 = (Value) cl.map.get(bld1);
1101 //Updating temporary dot product
1102 if(val2 != null)
1103 d += (val1.value * (((bld1.blade & signMask) != 0) ? -val2.value : val2.value));
1104 }
1105 return d;
1106 }
1107
1108 /**
1109 * Computes the commutation with the specified element.
1110 * @param cl the second element of the commutation.
1111 * @return a new element from the commutation with the specified element.
1112 */
1113 public final Clifford comm(final Clifford cl){
1114 return ((gP(cl)).sub(cl.gP(this))).gP(0.5);
1115 }
1116
1117 /**
1118 * Computes the dual of this element.
1119 * @return a new element that is the dual of this element.
1120 */
1121 public final Clifford dual(){
1122 return gP(pseudoScalar.rev());
1123 }
1124
1125 /**
1126 * Computes the meet with the specified element.
1127 * @param cl the second element of the meet.
1128 * @return a new element from the meet with the specified element.
1129 */
1130 public final Clifford meet(final Clifford cl){
1131 return (gP(pseudoScalar)).lC(cl);
1132 }
1133
1134 /**
1135 * Computes the meet with the specified element in a common subspace.
1136 * @param cl the second element of the meet.
1137 * @param is the element representing a common subspace.
1138 * @return a new element from the meet with the specified element.
1139 */
1140 public final Clifford meet(final Clifford cl, final Clifford is){
1141 return (gP(is)).lC(cl);
1142 }
1143
1144 /**
1145 * Computes the reflection against the specified vector.
1146 * @param n the vector against wich reflect.
1147 * @return a new element from the reflection against the specified vector.
1148 */
1149 public final Clifford reflect(final Clifford n){
1150 return (gP(n.sQuadMod())).sub(n.gP(2.0 * dot(n)));
1151 }
1152
1153 }