bool Multivector::Multiply( const Multivector& multivectorA, const Multivector& multivectorB, Term::ProductType productType ) { Term::ProductType otherProductType = Term::OtherProductType( productType ); if( multivectorA.CountProductTypes( otherProductType ) > 0 ) if( !const_cast< Multivector* >( &multivectorA )->CollectTerms( productType ) ) return false; if( multivectorB.CountProductTypes( otherProductType ) > 0 ) if( !const_cast< Multivector* >( &multivectorB )->CollectTerms( productType ) ) return false; Multivector* multivectorResult = this; Multivector multivectorStorage; if( this == &multivectorA || this == &multivectorB ) multivectorResult = &multivectorStorage; multivectorResult->sumOfTerms.RemoveAll(); for( const SumOfTerms::Node* nodeA = multivectorA.sumOfTerms.Head(); nodeA; nodeA = nodeA->Next() ) { const Term* termA = nodeA->data; for( const SumOfTerms::Node* nodeB = multivectorB.sumOfTerms.Head(); nodeB; nodeB = nodeB->Next() ) { const Term* termB = nodeB->data; Term* termResult = new Term( productType ); multivectorResult->sumOfTerms.InsertAfter()->data = termResult; if( !termResult->coeficient->AssignProduct( *termA->coeficient, *termB->coeficient ) ) return false; for( const Term::ProductOfVectors::Node* node = termA->productOfVectors.Head(); node; node = node->Next() ) termResult->productOfVectors.InsertAfter()->data = node->data->Clone(); for( const Term::ProductOfVectors::Node* node = termB->productOfVectors.Head(); node; node = node->Next() ) termResult->productOfVectors.InsertAfter()->data = node->data->Clone(); } } if( !multivectorResult->CollectTerms( productType ) ) return false; if( multivectorResult == &multivectorStorage ) return Assign( multivectorStorage ); return true; }
std::string DebugString(Multivector<Scalar, Frame, rank> const& multivector) { // This |using| is required for the |Trivector|, since we need an ambiguity // between |geometry::DebugString(R3Element<Scalar> const&)| and // |quantities::DebugString(Scalar const&)| in order for the template magic // to work out. using quantities::DebugString; return DebugString(multivector.coordinates()); }
bool Multivector::AssignInnerProduct( const Multivector& multivectorA, const Multivector& multivectorB ) { if( multivectorA.CountProductTypes( Term::GEOMETRIC_PRODUCT ) > 0 ) if( !const_cast< Multivector* >( &multivectorA )->CollectTerms( Term::OUTER_PRODUCT ) ) return false; if( multivectorB.CountProductTypes( Term::GEOMETRIC_PRODUCT ) > 0 ) if( !const_cast< Multivector* >( &multivectorB )->CollectTerms( Term::OUTER_PRODUCT ) ) return false; Multivector* multivectorResult = this; Multivector multivectorStorage; if( this == &multivectorA || this == &multivectorB ) multivectorResult = &multivectorStorage; for( const SumOfTerms::Node* nodeA = multivectorA.sumOfTerms.Head(); nodeA; nodeA = nodeA->Next() ) { const Term* termA = nodeA->data; for( const SumOfTerms::Node* nodeB = multivectorB.sumOfTerms.Head(); nodeB; nodeB = nodeB->Next() ) { const Term* termB = nodeB->data; Multivector innerProductMultivector; if( !termA->InnerProductMultiply( termB, innerProductMultivector ) ) return false; Scalar scalar; if( !scalar.AssignProduct( *termA->coeficient, *termB->coeficient ) ) return false; if( !innerProductMultivector.AssignScalarProduct( scalar, innerProductMultivector ) ) return false; multivectorResult->sumOfTerms.Absorb( &innerProductMultivector.sumOfTerms ); } } if( multivectorResult == &multivectorStorage ) return Assign( multivectorStorage ); return true; }
Multivector<quantities::Quotient<LScalar, quantities::Quantity<RDimension>>, Frame, rank> operator/(Multivector<LScalar, Frame, rank> const& left, quantities::Quantity<RDimension> const& right) { return Multivector< quantities::Quotient<LScalar, quantities::Quantity<RDimension>>, Frame, rank>(left.coordinates() / right); }
Multivector<quantities::Product<quantities::Quantity<LDimension>, RScalar>, Frame, rank> operator*(quantities::Quantity<LDimension> const& left, Multivector<RScalar, Frame, rank> const& right) { return Multivector< quantities::Product<quantities::Quantity<LDimension>, RScalar>, Frame, rank>(left * right.coordinates()); }
inline Multivector< quantities::Product<LScalar, quantities::Quantity<RDimension>>, Frame, rank> operator*(Multivector<LScalar, Frame, rank> const& left, quantities::Quantity<RDimension> const& right) { return Multivector< quantities::Product<LScalar, quantities::Quantity<RDimension>>, Frame, rank>(left.coordinates() * right); }
bool operator!=(Multivector<Scalar, Frame, rank> const& left, Multivector<Scalar, Frame, rank> const& right) { return left.coordinates() != right.coordinates(); }
Multivector<Scalar, Frame, rank> operator/( Multivector<Scalar, Frame, rank> const& left, double const right) { return Multivector<Scalar, Frame, rank>(left.coordinates() / right); }
Multivector<Scalar, Frame, rank> operator*( double const left, Multivector<Scalar, Frame, rank> const& right) { return Multivector<Scalar, Frame, rank>(left * right.coordinates()); }
Multivector<Scalar, Frame, rank> operator-( Multivector<Scalar, Frame, rank> const& left, Multivector<Scalar, Frame, rank> const& right) { return Multivector<Scalar, Frame, rank>( left.coordinates() - right.coordinates()); }
Multivector<Scalar, Frame, rank> operator+( Multivector<Scalar, Frame, rank> const& right) { return Multivector<Scalar, Frame, rank>(+right.coordinates()); }
Multivector<double, Frame, 3> Normalize( Multivector<Scalar, Frame, 3> const& multivector) { Scalar const norm = multivector.Norm(); CHECK_NE(Scalar(), norm); return multivector / norm; }
Multivector<double, Frame, 2> Normalize( Multivector<Scalar, Frame, 2> const& multivector) { return Multivector<double, Frame, 2>(Normalize(multivector.coordinates())); }
// Note that in the interest of efficiency, we do not preserve this term in this process. // Also note that we accumulate into the given multivector. bool Multivector::Term::PerformProductMorphism( Multivector& multivector ) { ProductType targetProductType = OtherProductType( productType ); if( productOfVectors.Count() == 1 ) { ProductOfVectors::Node* node = productOfVectors.Head(); productOfVectors.Remove( node, false ); Term* term = new Term( targetProductType, coeficient ); term->productOfVectors.InsertAfter( 0, node ); multivector.sumOfTerms.InsertAfter()->data = term; return true; } else if( productOfVectors.Count() == 0 ) { Term* term = new Term( targetProductType, coeficient ); multivector.sumOfTerms.InsertAfter()->data = term; return true; } ProductOfVectors::Node* node = productOfVectors.Head(); Vector* vector = node->data; productOfVectors.Remove( node, false ); bool success = false; do { if( targetProductType == GEOMETRIC_PRODUCT ) { Multivector termMultivector; termMultivector.sumOfTerms.InsertAfter()->data = Clone(); Multivector innerProductMultivector; if( !innerProductMultivector.InnerProductMultiply( *vector, termMultivector ) ) break; innerProductMultivector.Negate(); while( innerProductMultivector.sumOfTerms.Count() > 0 ) { SumOfTerms::Node* node = innerProductMultivector.sumOfTerms.Head(); Term* term = node->data; if( !term->PerformProductMorphism( multivector ) ) break; innerProductMultivector.sumOfTerms.Remove( node, true ); } if( innerProductMultivector.sumOfTerms.Count() > 0 ) break; } Multivector subMultivector; if( !PerformProductMorphism( subMultivector ) ) break; if( targetProductType == OUTER_PRODUCT ) { if( !multivector.InnerProductMultiply( *vector, subMultivector ) ) break; if( !multivector.OuterProductMultiply( *vector, subMultivector ) ) break; } else if( targetProductType == GEOMETRIC_PRODUCT ) { if( !multivector.GeometricProductMultiply( *vector, subMultivector ) ) break; } success = true; } while( false ); delete node; return success; }
inline Multivector<double, Frame, rank> Normalize( Multivector<Scalar, Frame, rank> const& multivector) { return multivector / multivector.Norm(); }