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 }