]> www.ginac.de Git - ginac.git/blobdiff - ginac/symbol.cpp
Make symbol::name be initialized lazily.
[ginac.git] / ginac / symbol.cpp
index f9d64929323020aae7cafa3292b100b943457e49..e7eb9c92317b5d53b55e333b9ec206e4ae4605a3 100644 (file)
@@ -1,8 +1,9 @@
 /** @file symbol.cpp
  *
- *  Implementation of GiNaC's symbolic objects.
- *
- *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
+ *  Implementation of GiNaC's symbolic objects. */
+
+/*
+ *  GiNaC Copyright (C) 1999-2010 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
  *
  *  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 <string>
+#include "symbol.h"
+#include "lst.h"
+#include "archive.h"
+#include "tostring.h"
+#include "utils.h"
+#include "hash_seed.h"
+#include "inifcns.h"
+
+#include <map>
 #include <stdexcept>
+#include <string>
 
-#include "ginac.h"
-#include "utils.h"
+namespace GiNaC {
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(symbol, basic,
+  print_func<print_context>(&symbol::do_print).
+  print_func<print_latex>(&symbol::do_print_latex).
+  print_func<print_tree>(&symbol::do_print_tree).
+  print_func<print_python_repr>(&symbol::do_print_python_repr))
 
 //////////
-// default constructor, destructor, copy constructor assignment operator and helpers
+// default constructor
 //////////
 
-symbol::symbol() : basic(TINFO_SYMBOL)
-{
-    debugmsg("symbol default constructor",LOGLEVEL_CONSTRUCT);
-    serial=next_serial++;
-    name=autoname_prefix()+ToString(serial);
-    asexinfop=new assigned_ex_info;
-    setflag(status_flags::evaluated);
-}
+// symbol
 
-symbol::~symbol()
+symbol::symbol() : serial(next_serial++), name(""), TeX_name("")
 {
-    debugmsg("symbol destructor",LOGLEVEL_DESTRUCT);
-    destroy(0);
+       setflag(status_flags::evaluated | status_flags::expanded);
 }
 
-symbol::symbol(symbol const & other)
-{
-    debugmsg("symbol copy constructor",LOGLEVEL_CONSTRUCT);
-    copy(other);
-}
+// realsymbol
+
+realsymbol::realsymbol() : symbol() { }
+
+// possymbol
+
+possymbol::possymbol() : realsymbol() { }
 
-void symbol::copy(symbol const & other)
+//////////
+// other constructors
+//////////
+
+// public
+
+// symbol
+
+symbol::symbol(const std::string & initname) : serial(next_serial++),
+       name(initname), TeX_name("")
 {
-    basic::copy(other);
-    name=other.name;
-    serial=other.serial;
-    asexinfop=other.asexinfop;
-    ++asexinfop->refcount;
+       setflag(status_flags::evaluated | status_flags::expanded);
 }
 
-void symbol::destroy(bool call_parent)
+symbol::symbol(const std::string & initname, const std::string & texname) :
+       serial(next_serial++), name(initname), TeX_name(texname)
 {
-    if (--asexinfop->refcount == 0) {
-        delete asexinfop;
-    }
-    if (call_parent) {
-        basic::destroy(call_parent);
-    }
+       setflag(status_flags::evaluated | status_flags::expanded);
 }
 
-// how should the following be interpreted?
-// symbol x;
-// symbol y;
-// x=y;
-// probably as: x=ex(y);
+// realsymbol
+       
+realsymbol::realsymbol(const std::string & initname) : symbol(initname) { }
+
+realsymbol::realsymbol(const std::string & initname, const std::string & texname)
+       : symbol(initname, texname) { }
+
+// possymbol
+       
+possymbol::possymbol(const std::string & initname) : realsymbol(initname) { }
+
+possymbol::possymbol(const std::string & initname, const std::string & texname) 
+       : realsymbol(initname, texname) { }
 
 //////////
-// other constructors
+// archiving
 //////////
 
-// public
+/** Read object from archive_node. */
+void symbol::read_archive(const archive_node &n, lst &sym_lst)
+{
+       inherited::read_archive(n, sym_lst);
+       serial = next_serial++;
+       std::string tmp_name;
+       n.find_string("name", tmp_name);
+
+       // If symbol is in sym_lst, return the existing symbol
+       for (lst::const_iterator it = sym_lst.begin(); it != sym_lst.end(); ++it) {
+               if (is_a<symbol>(*it) && (ex_to<symbol>(*it).name == tmp_name)) {
+                       *this = ex_to<symbol>(*it);
+                       // XXX: This method is responsible for reading realsymbol
+                       // and possymbol objects too. But
+                       // basic::operator=(const basic& other)
+                       // resets status_flags::evaluated if other and *this are
+                       // of different types. Usually this is a good idea, but
+                       // doing this for symbols is wrong (for one, nothing is
+                       // going to set status_flags::evaluated, evaluation will
+                       // loop forever). Therefore we need to restore flags.
+                       setflag(status_flags::evaluated | status_flags::expanded);
+                       return;
+               }
+       }
+       name = tmp_name;
+       if (!n.find_string("TeXname", TeX_name))
+               TeX_name = std::string("");
+       setflag(status_flags::evaluated | status_flags::expanded);
+
+       setflag(status_flags::dynallocated);
+       sym_lst.append(*this);
+}
 
-symbol::symbol(string const & initname) : basic(TINFO_SYMBOL)
+/** Archive the object. */
+void symbol::archive(archive_node &n) const
 {
-    debugmsg("symbol constructor from string",LOGLEVEL_CONSTRUCT);
-    name=initname;
-    serial=next_serial++;
-    asexinfop=new assigned_ex_info;
-    setflag(status_flags::evaluated);
+       inherited::archive(n);
+       // XXX: we should not archive anonymous symbols.
+       if (!name.empty())
+               n.add_string("name", name);
+       if (!TeX_name.empty())
+               n.add_string("TeX_name", TeX_name);
 }
 
 //////////
-// functions overriding virtual functions from bases classes
+// functions overriding virtual functions from base classes
 //////////
 
+/** Return default TeX name for symbol. This recognizes some greek letters. */
+static const std::string& get_default_TeX_name(const std::string& name);
+
 // public
 
-basic * symbol::duplicate() const
+std::string symbol::get_name() const
 {
-    debugmsg("symbol duplicate",LOGLEVEL_DUPLICATE);
-    return new symbol(*this);
+       if (name.empty()) {
+               std::ostringstream s;
+               s << "symbol" << serial;
+               name = s.str();
+       }
+       return name;
 }
 
-bool symbol::info(unsigned inf) const
+// protected
+
+void symbol::do_print(const print_context & c, unsigned level) const
 {
-    if (inf==info_flags::symbol) return true;
-    if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
-        return true;
-    } else {
-        return basic::info(inf);
-    }
+       c.s << get_name();
 }
 
-ex symbol::expand(unsigned options) const
+void symbol::do_print_latex(const print_latex & c, unsigned level) const
 {
-    return this->hold();
+       if (!TeX_name.empty())
+               c.s << TeX_name;
+       else if (!name.empty())
+               c.s << get_default_TeX_name(name);
+       else
+               c.s << "symbol" << serial;
 }
 
-bool symbol::has(ex const & other) const
+void symbol::do_print_tree(const print_tree & c, unsigned level) const
 {
-    if (is_equal(*other.bp)) return true;
-    return false;
+       c.s << std::string(level, ' ') << name << " (" << class_name() << ")" << " @" << this
+           << ", serial=" << serial
+           << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
+           << ", domain=" << get_domain()
+           << std::endl;
 }
 
-int symbol::degree(symbol const & s) const
+void symbol::do_print_python_repr(const print_python_repr & c, unsigned level) const
 {
-    return compare_same_type(s)==0 ? 1 : 0;
+       c.s << class_name() << "('";
+       if (!name.empty())
+               c.s << name;
+       else
+               c.s << "symbol" << serial;
+       if (!TeX_name.empty())
+               c.s << "','" << TeX_name;
+       c.s << "')";
 }
 
-int symbol::ldegree(symbol const & s) const
+bool symbol::info(unsigned inf) const
 {
-    return compare_same_type(s)==0 ? 1 : 0;
+       switch (inf) {
+               case info_flags::symbol:
+               case info_flags::polynomial:
+               case info_flags::integer_polynomial: 
+               case info_flags::cinteger_polynomial: 
+               case info_flags::rational_polynomial: 
+               case info_flags::crational_polynomial: 
+               case info_flags::rational_function: 
+               case info_flags::expanded:
+                       return true;
+               case info_flags::real:
+                       return get_domain() == domain::real || get_domain() == domain::positive;
+               case info_flags::positive:
+               case info_flags::nonnegative:
+                       return get_domain() == domain::positive;
+               case info_flags::has_indices:
+                       return false;
+       }
+       return inherited::info(inf);
 }
 
-ex symbol::coeff(symbol const & s, int const n) const
+ex symbol::conjugate() const
 {
-    if (compare_same_type(s)==0) {
-        return n==1 ? exONE() : exZERO();
-    } else {
-        return n==0 ? *this : exZERO();
-    }
+       return conjugate_function(*this).hold();
 }
 
-ex symbol::eval(int level) const
+ex symbol::real_part() const
 {
-    if (level == -max_recursion_level) {
-        throw(std::runtime_error("max recursion level reached"));
-    }
-    
-    if (asexinfop->is_assigned) {
-        setflag(status_flags::evaluated);
-        if (level==1) {
-            return (asexinfop->assigned_expression);
-        } else {
-            return (asexinfop->assigned_expression).eval(level);
-        }
-    } else {
-        return this->hold();
-    }
+       return real_part_function(*this).hold();
 }
 
-ex symbol::subs(lst const & ls, lst const & lr) const
+ex symbol::imag_part() const
 {
-    ASSERT(ls.nops()==lr.nops());
-#ifdef DOASSERT
-    for (int i=0; i<ls.nops(); i++) {
-        ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
-               is_ex_of_type(ls.op(i),idx));
-    }
-#endif // def DOASSERT
-
-    for (int i=0; i<ls.nops(); i++) {
-        if (is_ex_exactly_of_type(ls.op(i),symbol)) {
-            if (compare_same_type(ex_to_symbol(ls.op(i)))==0) return lr.op(i);
-        }
-    }
-    return *this;
+       return imag_part_function(*this).hold();
 }
 
-// protected
-
-int symbol::compare_same_type(basic const & other) const
+bool symbol::is_polynomial(const ex & var) const
 {
-    ASSERT(is_of_type(other,symbol));
-    const symbol *o = static_cast<const symbol *>(&other);
-    if (serial==o->serial) return 0;
-    return serial < o->serial ? -1 : 1;
+       return true;
 }
 
-bool symbol::is_equal_same_type(basic const & other) const
+// protected
+
+/** Implementation of ex::diff() for single differentiation of a symbol.
+ *  It returns 1 or 0.
+ *
+ *  @see ex::diff */
+ex symbol::derivative(const symbol & s) const
 {
-    ASSERT(is_of_type(other,symbol));
-    const symbol *o = static_cast<const symbol *>(&other);
-    return serial==o->serial;
+       if (compare_same_type(s))
+               return _ex0;
+       else
+               return _ex1;
 }
 
-unsigned symbol::return_type(void) const
+int symbol::compare_same_type(const basic & other) const
 {
-    return return_types::commutative;
+       GINAC_ASSERT(is_a<symbol>(other));
+       const symbol *o = static_cast<const symbol *>(&other);
+       if (serial==o->serial) return 0;
+       return serial < o->serial ? -1 : 1;
 }
-   
-unsigned symbol::return_type_tinfo(void) const
+
+bool symbol::is_equal_same_type(const basic & other) const
 {
-    return tinfo_key;
+       GINAC_ASSERT(is_a<symbol>(other));
+       const symbol *o = static_cast<const symbol *>(&other);
+       return serial==o->serial;
 }
 
-unsigned symbol::calchash(void) const
+unsigned symbol::calchash() const
 {
-    // return golden_ratio_hash(tinfo()) ^ serial;
-    hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555555U ^ serial));
-    setflag(status_flags::hash_calculated);
-    return hashvalue;
+       unsigned seed = make_hash_seed(typeid(*this));
+       hashvalue = golden_ratio_hash(seed ^ serial);
+       setflag(status_flags::hash_calculated);
+       return hashvalue;
 }
 
 //////////
@@ -223,31 +288,65 @@ unsigned symbol::calchash(void) const
 // non-virtual functions in this class
 //////////
 
-// public
-
-void symbol::assign(ex const & value)
+/** Return default TeX name for symbol. This recognizes some greek letters. */
+static const std::string& get_default_TeX_name(const std::string& name)
 {
-    asexinfop->is_assigned=1;
-    asexinfop->assigned_expression=value;
-    clearflag(status_flags::evaluated);
+       static std::map<std::string, std::string> standard_names;
+       static bool names_initialized = false;
+       if (!names_initialized) {
+               standard_names["alpha"] = std::string("\\alpha");
+               standard_names["beta"] = std::string("\\beta");;
+               standard_names["gamma"] = std::string("\\gamma");;
+               standard_names["delta"] = std::string("\\delta");;
+               standard_names["epsilon"] = std::string("\\epsilon");
+               standard_names["varepsilon"] = std::string("\\varepsilon");
+               standard_names["zeta"] = std::string("\\zeta");
+               standard_names["eta" ] = std::string("\\eta" );
+               standard_names["theta"] = std::string("\\theta");
+               standard_names["vartheta"] = std::string("\\vartheta");
+               standard_names["iota"] = std::string("\\iota");
+               standard_names["kappa"] = std::string("\\kappa");
+               standard_names["lambda"] = std::string("\\lambda");
+               standard_names["mu"] = std::string("\\mu");
+               standard_names["nu"] = std::string("\\nu");
+               standard_names["xi"] = std::string("\\xi");
+               standard_names["omicron"] = std::string("\\omicron");
+               standard_names["pi"] = std::string("\\pi");
+               standard_names["varpi"] = std::string("\\varpi");
+               standard_names["rho"] = std::string("\\rho");
+               standard_names["varrho"] = std::string("\\varrho");
+               standard_names["sigma"] = std::string("\\sigma");
+               standard_names["varsigma"] = std::string("\\varsigma");
+               standard_names["tau"] = std::string("\\tau");
+               standard_names["upsilon"] = std::string("\\upsilon");
+               standard_names["phi"] = std::string("\\phi");
+               standard_names["varphi"] = std::string("\\varphi");
+               standard_names["chi"] = std::string("\\chi");
+               standard_names["psi"] = std::string("\\psi");
+               standard_names["omega"] = std::string("\\omega");
+               standard_names["Gamma"] = std::string("\\Gamma");
+               standard_names["Delta"] = std::string("\\Delta");
+               standard_names["Theta"] = std::string("\\Theta");
+               standard_names["Lambda"] = std::string("\\Lambda");
+               standard_names["Xi"] = std::string("\\Xi");
+               standard_names["Pi"] = std::string("\\Pi");
+               standard_names["Sigma"] = std::string("\\Sigma");
+               standard_names["Upsilon"] = std::string("\\Upsilon");
+               standard_names["Phi"] = std::string("\\Phi");
+               standard_names["Psi"] = std::string("\\Psi");
+               standard_names["Omega"] = std::string("\\Omega");
+               names_initialized = true;
+       }
+       std::map<std::string, std::string>::const_iterator it = standard_names.find(name);
+       if (it != standard_names.end())
+               return it->second;
+       else
+               return name;
 }
 
-void symbol::unassign(void)
-{
-    if (asexinfop->is_assigned) {
-        asexinfop->is_assigned=0;
-        asexinfop->assigned_expression=exZERO();
-    }
-    setflag(status_flags::evaluated);
-}
-
-// private
-
-string & symbol::autoname_prefix(void)
-{
-    static string * s=new string("symbol");
-    return *s;
-}
+GINAC_BIND_UNARCHIVER(symbol);
+GINAC_BIND_UNARCHIVER(realsymbol);
+GINAC_BIND_UNARCHIVER(possymbol);
 
 //////////
 // static member variables
@@ -255,22 +354,6 @@ string & symbol::autoname_prefix(void)
 
 // private
 
-unsigned symbol::next_serial=0;
-
-// string const symbol::autoname_prefix="symbol";
-
-//////////
-// global constants
-//////////
-
-const symbol some_symbol;
-type_info const & typeid_symbol=typeid(some_symbol);
+unsigned symbol::next_serial = 0;
 
-//////////
-// subclass assigned_ex_info
-//////////
-
-/** Default ctor.  Defaults to unassigned. */
-symbol::assigned_ex_info::assigned_ex_info(void) : is_assigned(0), refcount(1)
-{
-}
+} // namespace GiNaC