001    /**
002     * CliffordBitSet.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 PARTICif(blade > spaceMask)
022                            throw ULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
023     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
024     * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
025     * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
026     * DEALINGS IN THE SOFTWARE.
027     */
028    
029    package jclifford;
030    
031    import java.util.Iterator;
032    import java.util.Map;
033    import java.util.TreeMap;
034    
035    /**
036     * <p>This class represents a BitSet - value map implementation of the Clifford element and all the operation in an arbitrary dimension space.</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 Clifford
040     * @see CliffordTreeSet
041     */
042    public class CliffordBitSet{
043    
044            /**
045             * Precision.
046             */
047            private static double eps = 1e-12;
048    
049            /**
050             * Blade-value mappings of the element.
051             */
052            private TreeMap map;
053    
054            /**
055             * Creates and returns an element with no blade-value mappings.
056             */
057            public CliffordBitSet()
058            {
059                    map = new TreeMap();
060            }
061    
062            /**
063             * Gets the value of a blade.
064             * @param blade the blade whose value is to be retrieved.
065             * @return the value of the specified blade, 0.0 if blade is not present.
066             */
067            public final double get(BladeBitSet blade)
068            {
069                    Value val = (Value) map.get(blade);
070                    return (val != null) ? val.value : 0.0;
071            }
072    
073            /**
074             * Gets the value of a blade.
075             * @param blade the binary mask representing the specified blade (format is "i, j, ...", where i, j are versor indexes) whose value is to be retrieved.
076             * @return the value of the specified blade, 0.0 if blade is not present.
077             */
078            public final double get(String blade)
079            {
080                    return get(new BladeBitSet(blade));
081            }
082    
083            /**
084             * Puts a new blade-value mapping or updates existing.
085             * @param blade the specified blade that is to be put.
086             * @param value the corresponding value of the specified blade.
087             */
088            public final void put(BladeBitSet blade, double value)
089            {
090                    map.put(blade.clone(), new Value(value));
091            }
092    
093            /**
094             * Puts a new blade-value mapping or updates existing.
095             * @param blade the binary mask representing the specified blade (format is "i, j, ...", where i, j are versor indexes) that is to be put.
096             * @param value the corresponding value of the specified blade.
097             */
098            public final void put(String blade, double value)
099            {
100                    map.put(new BladeBitSet(blade), new Value(value));
101            }
102    
103            /**
104             * Removes blade-value mapping if existing.
105             * @param blade the specified blade that is to be removed.
106             */
107            public final void remove(BladeBitSet blade)
108            {
109                    map.remove(blade);
110            }
111    
112            /**
113             * Removes blade-value mapping if existing.
114             * @param blade the binary mask representing the specified blade (format is "i, j, ...", where i, j are versor indexes) that is to be removed.
115             */
116            public final void remove(String blade)
117            {
118                    map.remove(new BladeBitSet(blade));
119            }
120    
121            /**
122             * Returns a string representation of this element.
123             * @return the string representation of this element.
124             */
125            public String toString()
126            {
127                    //String representation of the element
128                    String str = new String();
129                    //Temporary reference variables
130                    Map.Entry entry;
131                    BladeBitSet bld;
132                    Value val;
133                    //For all blade-value mappings
134                    Iterator it = map.entrySet().iterator();
135                    while(it.hasNext()) {
136                            //Getting blade and value
137                            entry = (Map.Entry) it.next();
138                            bld = (BladeBitSet) entry.getKey();
139                            val = (Value) entry.getValue();
140                            //Printing blade-value mapping
141                            str += bld.toString() + "\t\t==>\t\t" + val.toString() + "\n";
142                    }
143                    str += "----------------\n";
144                    //Returning the string
145                    return str;
146            }
147    
148            /**
149             * Creates and returns an element deeply cloning this element.
150             */
151            public Object clone()
152            {
153                    //Creating a new empty element
154                    CliffordBitSet newcl = new CliffordBitSet();
155                    //Temporary reference variables
156                    Map.Entry entry;
157                    BladeBitSet bld;
158                    Value val;
159                    //For all blade-value mappings
160                    Iterator it = map.entrySet().iterator();
161                    while(it.hasNext()) {
162                            //Getting blade and value
163                            entry = (Map.Entry) it.next();
164                            bld = (BladeBitSet) entry.getKey();
165                            val = (Value) entry.getValue();
166                            //Adding a copy of blade-value mapping to newcl
167                            newcl.map.put(bld.clone(), val.clone());
168                    }
169                    return newcl;
170            }
171    
172            /**
173             * Removes blades with values lower than eps.
174             */
175            public final void noZero()
176            {
177                    //Temporary reference variables
178                    Map.Entry entry;
179                    Value val;
180                    //For all blade-value mappings
181                    Iterator it = map.entrySet().iterator();
182                    while(it.hasNext()) {
183                            entry = (Map.Entry) it.next();
184                            val = (Value) entry.getValue();
185                            //Tresholding
186                            if(java.lang.Math.abs(val.value) < eps)
187                                    //Removing blade-value mappings
188                                    it.remove();
189                    }
190            }
191    
192            /**
193             * Computes the quad module of an element discarding signature.
194             * @return the quad module of the specified element discarding signature.
195             */
196            public final double uQuadMod()
197            {
198                    //Temporary unsigned quad module
199                    double uqm = 0.0;
200                    //Temporary reference variables
201                    Map.Entry entry;
202                    Value val;
203                    //For all blade-value mappings
204                    Iterator it = map.entrySet().iterator();
205                    while(it.hasNext()) {
206                            //Getting value
207                            entry = (Map.Entry) it.next();
208                            val = (Value) entry.getValue();
209                            //Uptdating temporary module
210                            uqm += val.value * val.value;
211                    }
212                    return uqm;
213            }
214    
215            /**
216             * Normalizes this element respect the unsigned module.
217             */
218            public final void normalize()
219            {
220                    //Unsigned module
221                    double um = Math.sqrt(uQuadMod());
222                    //Checking for null module
223                    if(um == 0.0)
224                            return;
225                    //Temporary reference variables
226                    Map.Entry entry;
227                    BladeBitSet bld;
228                    Value val;
229                    //For all blade-value mappings
230                    Iterator it = map.entrySet().iterator();
231                    while(it.hasNext()) {
232                            entry = (Map.Entry) it.next();
233                            bld = (BladeBitSet) entry.getKey();
234                            val = (Value) entry.getValue();
235                            //Updating value
236                            val.value /= um;
237                            //Tresholding
238                            if(java.lang.Math.abs(val.value) < eps)
239                                    //Removing blade-value mappings
240                                    it.remove();
241                    }
242            }
243    
244            /**
245             * Gets highest grade of this element.
246             * @return highest grade of this element.
247             */
248            public final int getMaxGrade()//Not using entrySet().iterator
249            {
250                    //Temporary grade
251                    int maxgrade = 0, bldgrade;
252                    //Temporary reference variable
253                    BladeBitSet bld;
254                    //Defining an array of blades
255                    Object[] arrbld = map.keySet().toArray();
256                    //For all cl blades
257                    for(int x = 0; x < arrbld.length; x ++){
258                            //Getting blade
259                            bld = (BladeBitSet) arrbld[x];
260                            //Comparing blade grade with temporary grade
261                            bldgrade = bld.getGrade();
262                            if(bldgrade > maxgrade)
263                                    maxgrade = bldgrade;
264                    }
265                    return maxgrade;
266            }
267    
268            /**
269             * Verifies if this element is a scalar.
270             * @return true if this element is a scalar, false otherwise.
271             */
272            public final boolean isScalar()
273            {
274                    return (getMaxGrade() == 0) ? true : false;
275            }
276    
277            /**
278             * Verifies if this element is a scalar.
279             * @return true if this element is a scalar, false otherwise.
280             */
281            public final boolean isZero()
282            {
283                    return ((get(new BladeBitSet()) == 0.0) && (getMaxGrade() == 0)) ? true : false;
284            }
285    
286            /**
287             * Verifies if this element is a vector.
288             * @return true if this element is a vector, false otherwise.
289             */
290            public final boolean isVector()
291            {
292                    return ((get(new BladeBitSet()) == 0.0) && (getMaxGrade() == 1)) ? true : false;
293            }
294    
295            /**
296             * Gets highest dimension present in this element.
297             * @return highest present in this element.
298             */
299            public final int getMaxDimension()//Not using entrySet().iterator
300            {
301                    //Temporary grade
302                    int maxdim = 0, bldmaxdim;
303                    //Temporary reference variable
304                    BladeBitSet bld;
305                    //Defining an array of blades
306                    Object[] arrbld = map.keySet().toArray();
307                    //For all cl blades
308                    for(int x = 0; x < arrbld.length; x ++){
309                            //Getting blade
310                            bld = (BladeBitSet) arrbld[x];
311                            //Comparing blade grade with temporary grade
312                            bldmaxdim = bld.getMaxDimension();
313                            if(bldmaxdim > maxdim)
314                                    maxdim = bldmaxdim;
315                    }
316                    return maxdim;
317            }
318    
319            /**
320             * Compares this element with the specified element for equality.
321             * Two elements are considered equals if they have same blades and corresponding values differing less than tollerance.
322             * @param obj the second element that is to be compared.
323             * @return true if this Element and the specified element are equals, false otherwise.
324             */
325             public boolean equals(Object obj)
326             {
327                    //Casting to Clifford object
328                    CliffordBitSet cl = (CliffordBitSet) obj;
329                    //Verifyng if elements have the same size (number of blade-value mappings)
330                    if(map.size() != cl.map.size())
331                            return false;
332                    //Tollerance
333                    double tol = 2 * eps;
334                    //Temporary reference variables
335                    Map.Entry entry1, entry2;
336                    BladeBitSet bld1, bld2;
337                    Value val1, val2;
338                    //For all blade-value mappings
339                    Iterator it1 = map.entrySet().iterator();
340                    Iterator it2 = cl.map.entrySet().iterator();
341                    while(it1.hasNext()) {
342                            entry1 = (Map.Entry) it1.next();
343                            entry2 = (Map.Entry) it2.next();
344                            //Getting blades
345                            bld1 = (BladeBitSet) entry1.getKey();
346                            bld2 = (BladeBitSet) entry2.getKey();
347                            //Comparing blades
348                            if(!bld1.equals(bld2))
349                                    return false;
350                            //Getting values
351                            val1 = (Value) entry1.getValue();
352                            val2 = (Value) entry2.getValue();
353                            //Comparing values
354                            if(java.lang.Math.abs(val1.value - val2.value) > tol)
355                                    return false;
356                    }
357                    //Elements are equals
358                    return true;
359            }
360    
361            /**
362             * Computes the sum with the specified element.
363             * @param cl the second element of the sum.
364             * @return a new element from the sum with the specified element.
365             */
366            public final CliffordBitSet add(final CliffordBitSet cl)
367            {
368                    //Creating a new empty element
369                    CliffordBitSet newcl = (CliffordBitSet) clone();
370                    //Temporary reference variables
371                    Map.Entry entry2;
372                    BladeBitSet bld2;
373                    Value val2, newval;
374                    //For all cl blade-value mappings
375                    Iterator it2 = cl.map.entrySet().iterator();
376                    while(it2.hasNext()) {
377                            //Getting blade and value
378                            entry2 = (Map.Entry) it2.next();
379                            bld2 = (BladeBitSet) entry2.getKey();
380                            val2 = (Value) entry2.getValue();
381                            //Searching bld2 in newcl
382                            newval = (Value) newcl.map.get(bld2);
383                            //If newcl already contains bld2
384                            if(newval != null)
385                                    //Updating corresponding value
386                                    newval.value += val2.value;
387                            else
388                                    //Adding new blade-value mappings to newcl
389                                    newcl.map.put(bld2.clone(),new Value(val2.value));
390                    }
391                    //Returning tresholded element
392                    return newcl;
393            }
394    
395            /**
396             * Computes the difference with the specified element.
397             * @param cl the second element of the difference.
398             * @return a new element subtracting the second specified element from this.
399             */
400            public final CliffordBitSet sub(final CliffordBitSet cl)
401            {
402                    //Creating a new empty element
403                    CliffordBitSet newcl = (CliffordBitSet) clone();
404                    //Temporary reference variables
405                    Map.Entry entry2;
406                    BladeBitSet bld2;
407                    Value val2, newval;
408                    //For all cl blade-value mappings
409                    Iterator it2 = cl.map.entrySet().iterator();
410                    while(it2.hasNext()) {
411                            //Getting blade and value
412                            entry2 = (Map.Entry) it2.next();
413                            bld2 = (BladeBitSet) entry2.getKey();
414                            val2 = (Value) entry2.getValue();
415                            //Searching bld2 in newcl
416                            newval = (Value) newcl.map.get(bld2);
417                            //If newcl already contains bld2
418                            if(newval != null)
419                                    //Updating corresponding value
420                                    newval.value -= val2.value;
421                            else
422                                    //Adding new blade-value mappings to newcl
423                                    newcl.map.put(bld2.clone(),new Value(-val2.value));
424                    }
425                    //Returning tresholded element
426                    return newcl;
427            }
428    
429            /**
430             * Computes the grade involution of this element.
431             * @return a new element from the grade involution of the specified element.
432             */
433            public final CliffordBitSet gradeInv()
434            {
435                    //Creating a new empty element
436                    CliffordBitSet newcl = new CliffordBitSet();
437                    //Resulting value
438                    double result;
439                    //Temporary reference variables
440                    Map.Entry entry;
441                    BladeBitSet bld;
442                    Value val;
443                    //For all blade-value mappings
444                    Iterator it = map.entrySet().iterator();
445                    while(it.hasNext()) {
446                            //Getting blade and value
447                            entry = (Map.Entry) it.next();
448                            bld = (BladeBitSet) entry.getKey();
449                            val = (Value) entry.getValue();
450                            //Computing resulting value regarding parity of the grade (number of inversions)
451                            result = ((bld.getGrade() & 1) != 0) ? -val.value : val.value;
452                            //Adding new blade-value mapping to newcl
453                            newcl.map.put(bld.clone(), new Value(result));
454                    }
455                    return newcl;
456            }
457    
458            /**
459             * Computes the reverse of this element.
460             * @return a new element from the reversion of this element.
461             */
462            public final CliffordBitSet rev()
463            {
464                    //Creating a new empty element
465                    CliffordBitSet newcl = new CliffordBitSet();
466                    //Resulting value
467                    double result;
468                    //Temporary reference variables
469                    Map.Entry entry;
470                    BladeBitSet bld;
471                    Value val;
472                    //For all blade-value mappings
473                    Iterator it = map.entrySet().iterator();
474                    while(it.hasNext()) {
475                            //Getting blade and value
476                            entry = (Map.Entry) it.next();
477                            bld = (BladeBitSet) entry.getKey();
478                            val = (Value) entry.getValue();
479                            /*
480                            Computing resulting value regarding the sign: (-1)^((r(r-1))/2)
481                            Sign only depends upon the odd-ness or even-ness of the number of transpositions
482                            required to get things back in order. This obeys a simple recurrance relationship.
483                            Let T(n) be the number of transpositions required to revert an n-form.
484                            Then, T(n+1) = T(n) + n - 1 because it will require T(n) transpositions to reorder
485                            the first n subscripts and n-1 transpositions to get the n+1-th subscript from one
486                            end of the list to the other.
487                            So odd-ness or even-ness of T(n+4) is the same as that of T(n), because:
488                            T(n+4) = T(n+3) + n + 2 = T(n+2) + 2n + 3 = T(n+1) + 3n + 3 = T(n) + 4n + 2
489                            And, because T(0) and T(1) are even while T(2) and T(3) are odd an n-form requires:
490                            an odd number of transpositions to revert if n = 2 or n = 3 modulo 4.
491                            In code, this translates to whether the second bit of the grade is set.
492                            */
493                            result = ((bld.getGrade() & 2) != 0) ? -val.value : val.value;
494                            //Adding new blade-value mapping to newcl
495                            newcl.map.put(bld.clone(), new Value(result));
496                    }
497                    return newcl;
498            }
499    
500            /**
501             * Computes the inverse of this element.
502             * @return a new element from the inversion of this element.
503             */
504            public final CliffordBitSet inv()
505            {
506                    //Creating a new empty element
507                    CliffordBitSet newcl = new CliffordBitSet();
508                    //Temporary sign
509                    boolean sign;
510                    //Resulting value
511                    double result;
512                    //Temporary module
513                    double module = 0.0;
514                    //Temporary reference variables
515                    Map.Entry entry;
516                    BladeBitSet bld;
517                    Value val;
518                    //For all blade-value mappings
519                    Iterator it = map.entrySet().iterator();
520                    while(it.hasNext()) {
521                            //Getting blade and value
522                            entry = (Map.Entry) it.next();
523                            bld = (BladeBitSet) entry.getKey();
524                            val = (Value) entry.getValue();
525                            //Computing resulting sign
526                            sign = ((bld.getGrade() & 2) != 0) ? true : false;
527                            //Computing resulting value
528                            result = sign ? -val.value : val.value;
529                            //Adding new blade-value mapping to newcl
530                            newcl.map.put(bld.clone(), new Value(result));
531                            //Updating temporary module
532                            module += val.value * ((bld.getSign(bld) ^ sign) ? -val.value : val.value);
533                    }
534                    return newcl.gP(1/module);
535            }
536    
537            /**
538             * Computes the conjugation of this element.
539             * The conjugation of an element is a grade involution and a reversion.
540             * @return a new element from the conjugation of the specified element.
541             */
542            public final CliffordBitSet conj()
543            {
544                    //Creating a new empty element
545                    CliffordBitSet newcl = new CliffordBitSet();
546                    //Resulting value
547                    double result = 0.0;
548                    //Temporary reference variables
549                    Map.Entry entry;
550                    BladeBitSet bld;
551                    Value val;
552                    //For all blade-value mappings
553                    Iterator it = map.entrySet().iterator();
554                    while(it.hasNext()) {
555                            //Getting blade and value
556                            entry = (Map.Entry) it.next();
557                            bld = (BladeBitSet) entry.getKey();
558                            val = (Value) entry.getValue();
559                            //Computing resulting value: it is a grade involution and a reversion.
560                            switch(bld.getGrade() & 3){
561                                    case 0:
562                                    case 3:
563                                            result = val.value;
564                                    break;
565                                    case 1:
566                                    case 2:
567                                            result = -val.value;
568                                    break;
569                            }
570                            //Adding new blade-value mapping to newcl
571                            newcl.map.put(bld.clone(), new Value(result));
572                    }
573                    return newcl;
574            }
575    
576            /**
577             * Computes the geometric product with the specified scalar.
578             * @param scalar the scalar of the geometric product.
579             * @return a new element from the geometric product with the specified scalar.
580             */
581            public final CliffordBitSet gP(double scalar)
582            {
583                    //Creating a new empty element
584                    CliffordBitSet newcl = new CliffordBitSet();
585                    double newvalue;
586                    //Temporary reference variables
587                    Map.Entry entry;
588                    BladeBitSet bld;
589                    Value val;
590                    //For all blade-value mappings
591                    Iterator it = map.entrySet().iterator();
592                    while(it.hasNext()) {
593                            //Getting blade and value
594                            entry = (Map.Entry) it.next();
595                            bld = (BladeBitSet) entry.getKey();
596                            val = (Value) entry.getValue();
597                            //Resulting value for newcl bld
598                            newvalue = val.value * scalar;
599                            //Tresholding
600                            if(java.lang.Math.abs(newvalue) > eps)
601                                    //Adding new blade-value mapping to newcl blades map
602                                    newcl.map.put(bld.clone(), new Value(newvalue));
603                    }
604                    return newcl;
605            }
606    
607    
608            /**
609             * Computes the geometric product with the specified element.
610             * @param cl the second element of the geometric product.
611             * @return a new element from the geometric product with the specified element.
612             */
613            public final CliffordBitSet gP(final CliffordBitSet cl)
614            {
615                    //Creating a new empty element
616                    CliffordBitSet newcl = new CliffordBitSet();
617                    //Temporary reference variables
618                    Map.Entry entry1, entry2;
619                    BladeBitSet bld1, bld2, newbld;
620                    Value val1, val2, newval;
621                    double result;
622                    //For all blade-value mappings
623                    Iterator it1 = map.entrySet().iterator(), it2;
624                    while(it1.hasNext()) {
625                            //Getting blade and value
626                            entry1 = (Map.Entry) it1.next();
627                            bld1 = (BladeBitSet) entry1.getKey();
628                            val1 = (Value) entry1.getValue();
629                            //For all cl blade-value mappings
630                            it2 = cl.map.entrySet().iterator();
631                            while(it2.hasNext()) {
632                                    //Getting blade and value
633                                    entry2 = (Map.Entry) it2.next();
634                                    bld2 = (BladeBitSet) entry2.getKey();
635                                    val2 = (Value) entry2.getValue();
636                                    //Computing resulting blade
637                                    newbld = bld1.geometricProduct(bld2);
638                                    //Computing resulting value (regarding the sign)
639                                    result = val1.value * (bld1.getSign(bld2) ? -val2.value : val2.value);
640                                    //Searching newbld in newcl
641                                    newval = (Value) newcl.map.get(newbld);
642                                    //Updating newval by adding result
643                                    if(newval != null)
644                                            newval.value += result;
645                                    //Adding new blade-value mapping to newcl
646                                    else
647                                            newcl.map.put(newbld, new Value(result));
648                            }
649                    }
650                    //Returning tresholded element
651                    newcl.noZero();
652                    return newcl;
653            }
654    
655            /**
656             * Computes the wedge product with the specified element.
657             * @param cl the second element of the wedge product.
658             * @return a new element from the wedge product with the specified element.
659             */
660            public final CliffordBitSet wP(final CliffordBitSet cl)
661            {
662                    //Creating a new empty element
663                    CliffordBitSet newcl = new CliffordBitSet();
664                    //Temporary reference variables
665                    Map.Entry entry1, entry2;
666                    BladeBitSet bld1, bld2, newbld;
667                    Value val1, val2, newval;
668                    double result;
669                    //For all blade-value mappings
670                    Iterator it1 = map.entrySet().iterator(), it2;
671                    while(it1.hasNext()) {
672                            //Getting blade and value
673                            entry1 = (Map.Entry) it1.next();
674                            bld1 = (BladeBitSet) entry1.getKey();
675                            val1 = (Value) entry1.getValue();
676                            //For all cl blade-value mappings
677                            it2 = cl.map.entrySet().iterator();
678                            while(it2.hasNext()) {
679                                    //Getting blade and value
680                                    entry2 = (Map.Entry) it2.next();
681                                    bld2 = (BladeBitSet) entry2.getKey();
682                                    val2 = (Value) entry2.getValue();
683                                    //Computing resulting blade
684                                    newbld = bld1.wedgeProduct(bld2);
685                                    //If bld1 and bld2 have common versor wedge product is null
686                                    if(newbld == null) continue;
687                                    //Computing resulting value (regarding the sign)
688                                    result = val1.value * (bld1.getSign(bld2) ? -val2.value : val2.value);
689                                    //Searching newbld in newcl
690                                    newval = (Value) newcl.map.get(newbld);
691                                    //Updating newval by adding result
692                                    if(newval != null)
693                                            newval.value += result;
694                                    //Adding new blade-value mapping to newcl
695                                    else
696                                            newcl.map.put(newbld, new Value(result));
697                            }
698                    }
699                    //Returning tresholded element
700                    newcl.noZero();
701                    return newcl;
702            }
703    
704            /**
705             * Computes the left contraction with the specified element.
706             * @param cl the second element of the left contraction.
707             * @return a new element from the left contraction with the specified element.
708             */
709            public final CliffordBitSet lC(final CliffordBitSet cl)
710            {
711                    //Creating a new empty element
712                    CliffordBitSet newcl = new CliffordBitSet();
713                    //Temporary reference variables
714                    Map.Entry entry1, entry2;
715                    BladeBitSet bld1, bld2, newbld;
716                    Value val1, val2, newval;
717                    double result;
718                    //For all blade-value mappings
719                    Iterator it1 = map.entrySet().iterator(), it2;
720                    while(it1.hasNext()) {
721                            //Getting blade and value
722                            entry1 = (Map.Entry) it1.next();
723                            bld1 = (BladeBitSet) entry1.getKey();
724                            val1 = (Value) entry1.getValue();
725                            //For all cl blade-value mappings
726                            it2 = cl.map.entrySet().iterator();
727                            while(it2.hasNext()) {
728                                    //Getting blade and value
729                                    entry2 = (Map.Entry) it2.next();
730                                    bld2 = (BladeBitSet) entry2.getKey();
731                                    val2 = (Value) entry2.getValue();
732                                    //Computing resulting blade
733                                    newbld = bld1.leftContraction(bld2);
734                                    //If bld1 versors are not a subset of bld2 versors left contraction is null
735                                    if(newbld == null) continue;
736                                    //Computing resulting value (regarding the sign)
737                                    result = val1.value * (bld1.getSign(bld2) ? -val2.value : val2.value);
738                                    //Searching newbld in newcl
739                                    newval = (Value) newcl.map.get(newbld);
740                                    //Updating newval by adding result
741                                    if(newval != null)
742                                            newval.value += result;
743                                    //Adding new blade-value mapping to newcl
744                                    else
745                                            newcl.map.put(newbld, new Value(result));
746                            }
747                    }
748                    //Returning tresholded element
749                    newcl.noZero();
750                    return newcl;
751            }
752    
753            /**
754             * Computes the right contraction with the specified element.
755             * @param cl the second element of the right contraction.
756             * @return a new element from the right contraction with the specified element.
757             */
758            public final CliffordBitSet rC(final CliffordBitSet cl)
759            {
760                    //Creating a new empty element
761                    CliffordBitSet newcl = new CliffordBitSet();
762                    //Temporary reference variables
763                    Map.Entry entry1, entry2;
764                    BladeBitSet bld1, bld2, newbld;
765                    Value val1, val2, newval;
766                    double result;
767                    //For all blade-value mappings
768                    Iterator it1 = map.entrySet().iterator(), it2;
769                    while(it1.hasNext()) {
770                            //Getting blade and value
771                            entry1 = (Map.Entry) it1.next();
772                            bld1 = (BladeBitSet) entry1.getKey();
773                            val1 = (Value) entry1.getValue();
774                            //Defining an iterator on cl2 blade-value mappings
775                            it2 = cl.map.entrySet().iterator();
776                            //For all cl blade-value mappings
777                            while(it2.hasNext()) {
778                                    //Getting blade and value
779                                    entry2 = (Map.Entry) it2.next();
780                                    bld2 = (BladeBitSet) entry2.getKey();
781                                    val2 = (Value) entry2.getValue();
782                                    //Computing resulting blade
783                                    newbld = bld1.rightContraction(bld2);
784                                    //If bld2 versors are not a subset of bld1 versors right contraction is null
785                                    if(newbld == null) continue;
786                                    //Computing resulting value (regarding the sign)
787                                    result = val1.value * (bld1.getSign(bld2) ? -val2.value : val2.value);
788                                    //Searching newbld in newcl
789                                    newval = (Value) newcl.map.get(newbld);
790                                    //Updating newval by adding result
791                                    if(newval != null)
792                                            newval.value += result;
793                                    //Adding new blade-value mapping to newcl
794                                    else
795                                            newcl.map.put(newbld, new Value(result));
796                            }
797                    }
798                    //Returning tresholded element
799                    newcl.noZero();
800                    return newcl;
801            }
802    
803            /**
804             * Computes the meet with the specified element in a common subspace.
805             * @param cl the second element of the meet.
806             * @param i the element representing a common subspace.
807             * @return a new element from the meet with the specified element.
808             */
809            public final CliffordBitSet meet(final CliffordBitSet cl, final CliffordBitSet i){
810                    return (gP(i)).lC(cl);
811            }
812    
813    }