]> www.ginac.de Git - ginac.git/blobdiff - ginac/ex.cpp
* Avoid getrusage(2) on systems that don't have it (by ASheplyakov Alexei
[ginac.git] / ginac / ex.cpp
index 43b93766b9f0d2307c07f97583f4114d10de2412..a5ede054b13eeb35ebb3b50fc90d4b3166a04a94 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's light-weight expression handles. */
 
 /*
- *  GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2005 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <iostream>
@@ -73,7 +73,7 @@ void ex::dbgprinttree() const
 ex ex::expand(unsigned options) const
 {
        if (options == 0 && (bp->flags & status_flags::expanded)) // The "expanded" flag only covers the standard options; someone might want to re-expand with different options
-               return *bp;
+               return *this;
        else
                return bp->expand(options);
 }
@@ -117,6 +117,74 @@ bool ex::find(const ex & pattern, lst & found) const
        return any_found;
 }
 
+/** Substitute objects in an expression (syntactic substitution) and return
+ *  the result as a new expression. */
+ex ex::subs(const lst & ls, const lst & lr, unsigned options) const
+{
+       GINAC_ASSERT(ls.nops() == lr.nops());
+
+       // Convert the lists to a map
+       exmap m;
+       for (lst::const_iterator its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
+               m.insert(std::make_pair(*its, *itr));
+
+               // Search for products and powers in the expressions to be substituted
+               // (for an optimization in expairseq::subs())
+               if (is_exactly_a<mul>(*its) || is_exactly_a<power>(*its))
+                       options |= subs_options::pattern_is_product;
+       }
+       if (!(options & subs_options::pattern_is_product))
+               options |= subs_options::pattern_is_not_product;
+
+       return bp->subs(m, options);
+}
+
+/** Substitute objects in an expression (syntactic substitution) and return
+ *  the result as a new expression.  There are two valid types of
+ *  replacement arguments: 1) a relational like object==ex and 2) a list of
+ *  relationals lst(object1==ex1,object2==ex2,...). */
+ex ex::subs(const ex & e, unsigned options) const
+{
+       if (e.info(info_flags::relation_equal)) {
+
+               // Argument is a relation: convert it to a map
+               exmap m;
+               const ex & s = e.op(0);
+               m.insert(std::make_pair(s, e.op(1)));
+
+               if (is_exactly_a<mul>(s) || is_exactly_a<power>(s))
+                       options |= subs_options::pattern_is_product;
+               else
+                       options |= subs_options::pattern_is_not_product;
+
+               return bp->subs(m, options);
+
+       } else if (e.info(info_flags::list)) {
+
+               // Argument is a list: convert it to a map
+               exmap m;
+               GINAC_ASSERT(is_a<lst>(e));
+               for (lst::const_iterator it = ex_to<lst>(e).begin(); it != ex_to<lst>(e).end(); ++it) {
+                       ex r = *it;
+                       if (!r.info(info_flags::relation_equal))
+                               throw(std::invalid_argument("basic::subs(ex): argument must be a list of equations"));
+                       const ex & s = r.op(0);
+                       m.insert(std::make_pair(s, r.op(1)));
+
+                       // Search for products and powers in the expressions to be substituted
+                       // (for an optimization in expairseq::subs())
+                       if (is_exactly_a<mul>(s) || is_exactly_a<power>(s))
+                               options |= subs_options::pattern_is_product;
+               }
+               if (!(options & subs_options::pattern_is_product))
+                       options |= subs_options::pattern_is_not_product;
+
+               return bp->subs(m, options);
+
+       } else
+               throw(std::invalid_argument("ex::subs(ex): argument must be a relation_equal or a list"));
+}
+
 /** Traverse expression tree with given visitor, preorder traversal. */
 void ex::traverse_preorder(visitor & v) const
 {
@@ -180,7 +248,20 @@ void ex::makewriteable()
 {
        GINAC_ASSERT(bp->flags & status_flags::dynallocated);
        bp.makewritable();
-       GINAC_ASSERT(bp->refcount == 1);
+       GINAC_ASSERT(bp->get_refcount() == 1);
+}
+
+/** Share equal objects between expressions.
+ *  @see ex::compare(const ex &) */
+void ex::share(const ex & other) const
+{
+       if ((bp->flags | other.bp->flags) & status_flags::not_shareable)
+               return;
+
+       if (bp->get_refcount() <= other.bp->get_refcount())
+               bp = other.bp;
+       else
+               other.bp = bp;
 }
 
 /** Helper function for the ex-from-basic constructor. This is where GiNaC's
@@ -215,7 +296,7 @@ ptr<basic> ex::construct_from_basic(const basic & other)
                // it means that eval() hit case b) above. The original object is
                // no longer needed (it evaluated into something different), so we
                // delete it (because nobody else will).
-               if ((other.refcount==0) && (other.flags & status_flags::dynallocated))
+               if ((other.get_refcount() == 0) && (other.flags & status_flags::dynallocated))
                        delete &other; // yes, you can apply delete to a const pointer
 
                // We can't return a basic& here because the tmpex is destroyed as
@@ -238,7 +319,7 @@ ptr<basic> ex::construct_from_basic(const basic & other)
                        // on the heap.
                        basic *bp = other.duplicate();
                        bp->setflag(status_flags::dynallocated);
-                       GINAC_ASSERT(bp->refcount == 0);
+                       GINAC_ASSERT(bp->get_refcount() == 0);
                        return bp;
                }
        }
@@ -248,59 +329,59 @@ basic & ex::construct_from_int(int i)
 {
        switch (i) {  // prefer flyweights over new objects
        case -12:
-               return const_cast<numeric &>(_num_12);
+               return *const_cast<numeric *>(_num_12_p);
        case -11:
-               return const_cast<numeric &>(_num_11);
+               return *const_cast<numeric *>(_num_11_p);
        case -10:
-               return const_cast<numeric &>(_num_10);
+               return *const_cast<numeric *>(_num_10_p);
        case -9:
-               return const_cast<numeric &>(_num_9);
+               return *const_cast<numeric *>(_num_9_p);
        case -8:
-               return const_cast<numeric &>(_num_8);
+               return *const_cast<numeric *>(_num_8_p);
        case -7:
-               return const_cast<numeric &>(_num_7);
+               return *const_cast<numeric *>(_num_7_p);
        case -6:
-               return const_cast<numeric &>(_num_6);
+               return *const_cast<numeric *>(_num_6_p);
        case -5:
-               return const_cast<numeric &>(_num_5);
+               return *const_cast<numeric *>(_num_5_p);
        case -4:
-               return const_cast<numeric &>(_num_4);
+               return *const_cast<numeric *>(_num_4_p);
        case -3:
-               return const_cast<numeric &>(_num_3);
+               return *const_cast<numeric *>(_num_3_p);
        case -2:
-               return const_cast<numeric &>(_num_2);
+               return *const_cast<numeric *>(_num_2_p);
        case -1:
-               return const_cast<numeric &>(_num_1);
+               return *const_cast<numeric *>(_num_1_p);
        case 0:
-               return const_cast<numeric &>(_num0);
+               return *const_cast<numeric *>(_num0_p);
        case 1:
-               return const_cast<numeric &>(_num1);
+               return *const_cast<numeric *>(_num1_p);
        case 2:
-               return const_cast<numeric &>(_num2);
+               return *const_cast<numeric *>(_num2_p);
        case 3:
-               return const_cast<numeric &>(_num3);
+               return *const_cast<numeric *>(_num3_p);
        case 4:
-               return const_cast<numeric &>(_num4);
+               return *const_cast<numeric *>(_num4_p);
        case 5:
-               return const_cast<numeric &>(_num5);
+               return *const_cast<numeric *>(_num5_p);
        case 6:
-               return const_cast<numeric &>(_num6);
+               return *const_cast<numeric *>(_num6_p);
        case 7:
-               return const_cast<numeric &>(_num7);
+               return *const_cast<numeric *>(_num7_p);
        case 8:
-               return const_cast<numeric &>(_num8);
+               return *const_cast<numeric *>(_num8_p);
        case 9:
-               return const_cast<numeric &>(_num9);
+               return *const_cast<numeric *>(_num9_p);
        case 10:
-               return const_cast<numeric &>(_num10);
+               return *const_cast<numeric *>(_num10_p);
        case 11:
-               return const_cast<numeric &>(_num11);
+               return *const_cast<numeric *>(_num11_p);
        case 12:
-               return const_cast<numeric &>(_num12);
+               return *const_cast<numeric *>(_num12_p);
        default:
                basic *bp = new numeric(i);
                bp->setflag(status_flags::dynallocated);
-               GINAC_ASSERT(bp->refcount == 0);
+               GINAC_ASSERT(bp->get_refcount() == 0);
                return *bp;
        }
 }
@@ -309,35 +390,35 @@ basic & ex::construct_from_uint(unsigned int i)
 {
        switch (i) {  // prefer flyweights over new objects
        case 0:
-               return const_cast<numeric &>(_num0);
+               return *const_cast<numeric *>(_num0_p);
        case 1:
-               return const_cast<numeric &>(_num1);
+               return *const_cast<numeric *>(_num1_p);
        case 2:
-               return const_cast<numeric &>(_num2);
+               return *const_cast<numeric *>(_num2_p);
        case 3:
-               return const_cast<numeric &>(_num3);
+               return *const_cast<numeric *>(_num3_p);
        case 4:
-               return const_cast<numeric &>(_num4);
+               return *const_cast<numeric *>(_num4_p);
        case 5:
-               return const_cast<numeric &>(_num5);
+               return *const_cast<numeric *>(_num5_p);
        case 6:
-               return const_cast<numeric &>(_num6);
+               return *const_cast<numeric *>(_num6_p);
        case 7:
-               return const_cast<numeric &>(_num7);
+               return *const_cast<numeric *>(_num7_p);
        case 8:
-               return const_cast<numeric &>(_num8);
+               return *const_cast<numeric *>(_num8_p);
        case 9:
-               return const_cast<numeric &>(_num9);
+               return *const_cast<numeric *>(_num9_p);
        case 10:
-               return const_cast<numeric &>(_num10);
+               return *const_cast<numeric *>(_num10_p);
        case 11:
-               return const_cast<numeric &>(_num11);
+               return *const_cast<numeric *>(_num11_p);
        case 12:
-               return const_cast<numeric &>(_num12);
+               return *const_cast<numeric *>(_num12_p);
        default:
                basic *bp = new numeric(i);
                bp->setflag(status_flags::dynallocated);
-               GINAC_ASSERT(bp->refcount == 0);
+               GINAC_ASSERT(bp->get_refcount() == 0);
                return *bp;
        }
 }
@@ -346,59 +427,59 @@ basic & ex::construct_from_long(long i)
 {
        switch (i) {  // prefer flyweights over new objects
        case -12:
-               return const_cast<numeric &>(_num_12);
+               return *const_cast<numeric *>(_num_12_p);
        case -11:
-               return const_cast<numeric &>(_num_11);
+               return *const_cast<numeric *>(_num_11_p);
        case -10:
-               return const_cast<numeric &>(_num_10);
+               return *const_cast<numeric *>(_num_10_p);
        case -9:
-               return const_cast<numeric &>(_num_9);
+               return *const_cast<numeric *>(_num_9_p);
        case -8:
-               return const_cast<numeric &>(_num_8);
+               return *const_cast<numeric *>(_num_8_p);
        case -7:
-               return const_cast<numeric &>(_num_7);
+               return *const_cast<numeric *>(_num_7_p);
        case -6:
-               return const_cast<numeric &>(_num_6);
+               return *const_cast<numeric *>(_num_6_p);
        case -5:
-               return const_cast<numeric &>(_num_5);
+               return *const_cast<numeric *>(_num_5_p);
        case -4:
-               return const_cast<numeric &>(_num_4);
+               return *const_cast<numeric *>(_num_4_p);
        case -3:
-               return const_cast<numeric &>(_num_3);
+               return *const_cast<numeric *>(_num_3_p);
        case -2:
-               return const_cast<numeric &>(_num_2);
+               return *const_cast<numeric *>(_num_2_p);
        case -1:
-               return const_cast<numeric &>(_num_1);
+               return *const_cast<numeric *>(_num_1_p);
        case 0:
-               return const_cast<numeric &>(_num0);
+               return *const_cast<numeric *>(_num0_p);
        case 1:
-               return const_cast<numeric &>(_num1);
+               return *const_cast<numeric *>(_num1_p);
        case 2:
-               return const_cast<numeric &>(_num2);
+               return *const_cast<numeric *>(_num2_p);
        case 3:
-               return const_cast<numeric &>(_num3);
+               return *const_cast<numeric *>(_num3_p);
        case 4:
-               return const_cast<numeric &>(_num4);
+               return *const_cast<numeric *>(_num4_p);
        case 5:
-               return const_cast<numeric &>(_num5);
+               return *const_cast<numeric *>(_num5_p);
        case 6:
-               return const_cast<numeric &>(_num6);
+               return *const_cast<numeric *>(_num6_p);
        case 7:
-               return const_cast<numeric &>(_num7);
+               return *const_cast<numeric *>(_num7_p);
        case 8:
-               return const_cast<numeric &>(_num8);
+               return *const_cast<numeric *>(_num8_p);
        case 9:
-               return const_cast<numeric &>(_num9);
+               return *const_cast<numeric *>(_num9_p);
        case 10:
-               return const_cast<numeric &>(_num10);
+               return *const_cast<numeric *>(_num10_p);
        case 11:
-               return const_cast<numeric &>(_num11);
+               return *const_cast<numeric *>(_num11_p);
        case 12:
-               return const_cast<numeric &>(_num12);
+               return *const_cast<numeric *>(_num12_p);
        default:
                basic *bp = new numeric(i);
                bp->setflag(status_flags::dynallocated);
-               GINAC_ASSERT(bp->refcount == 0);
+               GINAC_ASSERT(bp->get_refcount() == 0);
                return *bp;
        }
 }
@@ -407,35 +488,35 @@ basic & ex::construct_from_ulong(unsigned long i)
 {
        switch (i) {  // prefer flyweights over new objects
        case 0:
-               return const_cast<numeric &>(_num0);
+               return *const_cast<numeric *>(_num0_p);
        case 1:
-               return const_cast<numeric &>(_num1);
+               return *const_cast<numeric *>(_num1_p);
        case 2:
-               return const_cast<numeric &>(_num2);
+               return *const_cast<numeric *>(_num2_p);
        case 3:
-               return const_cast<numeric &>(_num3);
+               return *const_cast<numeric *>(_num3_p);
        case 4:
-               return const_cast<numeric &>(_num4);
+               return *const_cast<numeric *>(_num4_p);
        case 5:
-               return const_cast<numeric &>(_num5);
+               return *const_cast<numeric *>(_num5_p);
        case 6:
-               return const_cast<numeric &>(_num6);
+               return *const_cast<numeric *>(_num6_p);
        case 7:
-               return const_cast<numeric &>(_num7);
+               return *const_cast<numeric *>(_num7_p);
        case 8:
-               return const_cast<numeric &>(_num8);
+               return *const_cast<numeric *>(_num8_p);
        case 9:
-               return const_cast<numeric &>(_num9);
+               return *const_cast<numeric *>(_num9_p);
        case 10:
-               return const_cast<numeric &>(_num10);
+               return *const_cast<numeric *>(_num10_p);
        case 11:
-               return const_cast<numeric &>(_num11);
+               return *const_cast<numeric *>(_num11_p);
        case 12:
-               return const_cast<numeric &>(_num12);
+               return *const_cast<numeric *>(_num12_p);
        default:
                basic *bp = new numeric(i);
                bp->setflag(status_flags::dynallocated);
-               GINAC_ASSERT(bp->refcount == 0);
+               GINAC_ASSERT(bp->get_refcount() == 0);
                return *bp;
        }
 }
@@ -444,7 +525,7 @@ basic & ex::construct_from_double(double d)
 {
        basic *bp = new numeric(d);
        bp->setflag(status_flags::dynallocated);
-       GINAC_ASSERT(bp->refcount == 0);
+       GINAC_ASSERT(bp->get_refcount() == 0);
        return *bp;
 }