]> www.ginac.de Git - ginac.git/blobdiff - ginac/symbol.cpp
Use C++11 range-based foor loops and auto, where possible.
[ginac.git] / ginac / symbol.cpp
index bf73ccfb0f8f1efcecbeb7936ed142a4401151b3..4dd0691c648ac435b4ef60cbaf1074f6fed28ff5 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's symbolic objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2015 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 <stdexcept>
-
 #include "symbol.h"
 #include "lst.h"
-#include "idx.h"
 #include "archive.h"
-#include "debugmsg.h"
+#include "tostring.h"
 #include "utils.h"
+#include "hash_seed.h"
+#include "inifcns.h"
+
+#include <map>
+#include <stdexcept>
+#include <string>
 
-#ifndef NO_GINAC_NAMESPACE
 namespace GiNaC {
-#endif // ndef NO_GINAC_NAMESPACE
 
-GINAC_IMPLEMENT_REGISTERED_CLASS(symbol, basic)
+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() : inherited(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
 
-void symbol::copy(symbol const & other)
-{
-    inherited::copy(other);
-    name=other.name;
-    serial=other.serial;
-    asexinfop=other.asexinfop;
-    ++asexinfop->refcount;
-}
+realsymbol::realsymbol() : symbol() { }
 
-void symbol::destroy(bool call_parent)
-{
-    if (--asexinfop->refcount == 0) {
-        delete asexinfop;
-    }
-    if (call_parent) {
-        inherited::destroy(call_parent);
-    }
-}
+// possymbol
 
-// how should the following be interpreted?
-// symbol x;
-// symbol y;
-// x=y;
-// probably as: x=ex(y);
+possymbol::possymbol() : realsymbol() { }
 
 //////////
 // other constructors
@@ -92,204 +65,217 @@ void symbol::destroy(bool call_parent)
 
 // public
 
-symbol::symbol(string const & initname) : inherited(TINFO_symbol)
+// symbol
+
+symbol::symbol(const std::string & initname) : serial(next_serial++),
+       name(initname), TeX_name("")
 {
-    debugmsg("symbol constructor from string", LOGLEVEL_CONSTRUCT);
-    name=initname;
-    serial=next_serial++;
-    asexinfop=new assigned_ex_info;
-    setflag(status_flags::evaluated);
+       setflag(status_flags::evaluated | status_flags::expanded);
 }
 
+symbol::symbol(const std::string & initname, const std::string & texname) :
+       serial(next_serial++), name(initname), TeX_name(texname)
+{
+       setflag(status_flags::evaluated | status_flags::expanded);
+}
+
+// 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) { }
+
 //////////
 // archiving
 //////////
 
-/** Construct object from archive_node. */
-symbol::symbol(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+/** Read object from archive_node. */
+void symbol::read_archive(const archive_node &n, lst &sym_lst)
 {
-    debugmsg("symbol constructor from archive_node", LOGLEVEL_CONSTRUCT);
-    serial = next_serial++;
-    if (!(n.find_string("name", name)))
-        name = autoname_prefix() + ToString(serial);
-    asexinfop = new assigned_ex_info;
-    setflag(status_flags::evaluated);
-}
-
-/** Unarchive the object. */
-ex symbol::unarchive(const archive_node &n, const lst &sym_lst)
-{
-    ex s = (new symbol(n, sym_lst))->setflag(status_flags::dynallocated);
-
-    // If symbol is in sym_lst, return the existing symbol
-    for (int i=0; i<sym_lst.nops(); i++) {
-        if (is_ex_of_type(sym_lst.op(i), symbol) && (ex_to_symbol(sym_lst.op(i)).name == ex_to_symbol(s).name))
-            return sym_lst.op(i);
-    }
-    return s;
+       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 (auto & s : sym_lst) {
+               if (is_a<symbol>(s) && (ex_to<symbol>(s).name == tmp_name)) {
+                       *this = ex_to<symbol>(s);
+                       // 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);
 }
 
 /** Archive the object. */
 void symbol::archive(archive_node &n) const
 {
-    inherited::archive(n);
-    n.add_string("name", name);
+       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
 //////////
 
-// public
+/** Return default TeX name for symbol. This recognizes some greek letters. */
+static const std::string& get_default_TeX_name(const std::string& name);
 
-basic *symbol::duplicate() const
-{
-    debugmsg("symbol duplicate", LOGLEVEL_DUPLICATE);
-    return new symbol(*this);
-}
-
-void symbol::print(ostream & os, unsigned upper_precedence) const
-{
-    debugmsg("symbol print",LOGLEVEL_PRINT);
-    os << name;
-}
+// public
 
-void symbol::printraw(ostream & os) const
+std::string symbol::get_name() const
 {
-    debugmsg("symbol printraw",LOGLEVEL_PRINT);
-    os << "symbol(" << "name=" << name << ",serial=" << serial
-       << ",hash=" << hashvalue << ",flags=" << flags << ")";
+       if (name.empty()) {
+               std::ostringstream s;
+               s << "symbol" << serial;
+               name = s.str();
+       }
+       return name;
 }
 
-void symbol::printtree(ostream & os, unsigned indent) const
-{
-    debugmsg("symbol printtree",LOGLEVEL_PRINT);
-    os << string(indent,' ') << name << " (symbol): "
-       << "serial=" << serial
-       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
-       << ", flags=" << flags << endl;
-}
+// protected
 
-void symbol::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+void symbol::do_print(const print_context & c, unsigned level) const
 {
-    debugmsg("symbol print csrc", LOGLEVEL_PRINT);
-    os << name;
+       c.s << get_name();
 }
 
-bool symbol::info(unsigned inf) const
+void symbol::do_print_latex(const print_latex & c, unsigned level) const
 {
-    if (inf==info_flags::symbol) return true;
-    if (inf==info_flags::polynomial ||
-        inf==info_flags::integer_polynomial ||
-        inf==info_flags::cinteger_polynomial ||
-        inf==info_flags::rational_polynomial ||
-        inf==info_flags::crational_polynomial ||
-        inf==info_flags::rational_function) {
-        return true;
-    } else {
-        return inherited::info(inf);
-    }
+       if (!TeX_name.empty())
+               c.s << TeX_name;
+       else if (!name.empty())
+               c.s << get_default_TeX_name(name);
+       else
+               c.s << "symbol" << serial;
 }
 
-ex symbol::expand(unsigned options) const
+void symbol::do_print_tree(const print_tree & c, unsigned level) const
 {
-    return this->hold();
+       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;
 }
 
-bool symbol::has(ex const & other) const
+void symbol::do_print_python_repr(const print_python_repr & c, unsigned level) const
 {
-    if (is_equal(*other.bp)) return true;
-    return false;
+       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::degree(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);
 }
 
-int symbol::ldegree(symbol const & s) const
+ex symbol::conjugate() const
 {
-    return compare_same_type(s)==0 ? 1 : 0;
+       return conjugate_function(*this).hold();
 }
 
-ex symbol::coeff(symbol const & s, int const n) const
+ex symbol::real_part() const
 {
-    if (compare_same_type(s)==0) {
-        return n==1 ? _ex1() : _ex0();
-    } else {
-        return n==0 ? *this : _ex0();
-    }
+       return real_part_function(*this).hold();
 }
 
-ex symbol::eval(int level) const
+ex symbol::imag_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 imag_part_function(*this).hold();
 }
 
-ex symbol::subs(lst const & ls, lst const & lr) const
+bool symbol::is_polynomial(const ex & var) const
 {
-    GINAC_ASSERT(ls.nops()==lr.nops());
-#ifdef DO_GINAC_ASSERT
-    for (unsigned i=0; i<ls.nops(); i++) {
-        GINAC_ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
-               is_ex_of_type(ls.op(i),idx));
-    }
-#endif // def DO_GINAC_ASSERT
-
-    for (unsigned 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 true;
 }
 
 // protected
 
-int symbol::compare_same_type(basic const & other) const
+/** 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
 {
-    GINAC_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;
+       if (compare_same_type(s))
+               return _ex0;
+       else
+               return _ex1;
 }
 
-bool symbol::is_equal_same_type(basic const & other) const
+int symbol::compare_same_type(const basic & other) const
 {
-    GINAC_ASSERT(is_of_type(other,symbol));
-    const symbol *o = static_cast<const symbol *>(&other);
-    return serial==o->serial;
+       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(void) const
+bool symbol::is_equal_same_type(const basic & other) const
 {
-    return return_types::commutative;
-}
-   
-unsigned symbol::return_type_tinfo(void) 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;
 }
 
 //////////
@@ -302,31 +288,65 @@ unsigned symbol::calchash(void) const
 // non-virtual functions in this class
 //////////
 
-// public
-
-void symbol::assign(ex const & value)
-{
-    asexinfop->is_assigned=1;
-    asexinfop->assigned_expression=value;
-    clearflag(status_flags::evaluated);
-}
-
-void symbol::unassign(void)
+/** Return default TeX name for symbol. This recognizes some greek letters. */
+static const std::string& get_default_TeX_name(const std::string& name)
 {
-    if (asexinfop->is_assigned) {
-        asexinfop->is_assigned=0;
-        asexinfop->assigned_expression=_ex0();
-    }
-    setflag(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;
 }
 
-// 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
@@ -334,26 +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);
-
-//////////
-// subclass assigned_ex_info
-//////////
-
-/** Default ctor.  Defaults to unassigned. */
-symbol::assigned_ex_info::assigned_ex_info(void) : is_assigned(0), refcount(1)
-{
-}
+unsigned symbol::next_serial = 0;
 
-#ifndef NO_GINAC_NAMESPACE
 } // namespace GiNaC
-#endif // ndef NO_GINAC_NAMESPACE