File:  [CENS] / python / pyGiNaC / wrappers / basic.py
Revision 1.5: download - view: text, annotated - select for diffs - revision graph
Tue Apr 17 22:39:25 2001 UTC (16 years, 7 months ago) by pearu
Branches: MAIN
CVS tags: HEAD
Fixed bugs. Exposed/checked functions. Started testing framework.

# This file is part of the PyGiNaC package.
# http://cens.ioc.ee/projects/pyginac/
#
# $Revision: 1.5 $
# $Id: basic.py,v 1.5 2001-04-17 22:39:25 pearu Exp $
#
# Copyright 2001 Pearu Peterson all rights reserved,
# Pearu Peterson <pearu@cens.ioc.ee>
# Permission to use, modify, and distribute this software is given under the
# terms of the LGPL.  See http://www.fsf.org
#
# NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
#
# TODO:
# fix normal(lst,lst)
# expose numer,denom, and other ex methods


depends = ['ex']

uses = []


#STARTPROTO

class basic:
    """ABC (abstract base class) of GiNaC's class hierarchy.
    Note: In Python it is exposed as ginac._ginac._basic.
    """
    def info(self,inf):
        """True if an object has information flag `inf' set. See info_flags."""
    def nops(self):
        """Number of operands/members."""
    def op(self, i):
        """Operand/member at position `i'."""
    def has(self, expr):
        """True if there are any occurrences of `expr'."""
    def degree(self, sym):
        """Degree of highest power in symbol `sym'."""
    def ldegree(self, sym):
        """Degree of lowest power in symbol `sym'."""
    def coeff(self, sym, n = 1):
        """Coefficient of degree `n' in symbol `sym'."""
    def collect(self,sym):
        """Sort expression in terms of powers of symbol `sym'."""
    def eval(self,level=0):
        """Perform automatic non-interruptive symbolic evaluation
    on expression.
    """
    def evalf(self,level=0):
        """Evaluate object numerically."""
    def get_free_indices(self):
        """Return an exvector containing the free indices of
    an expression."""
    def simplify_ncmul(self,seq):
        """"""
    #def eval_indexed(self, i):
    #    """Perform automatic symbolic evaluations on indexed expression
    #that contains this object as the base expression."""
    #def add_indexed(self,self_,other):
    #    """Add two indexed expressions.
    #They are guaranteed to be of class indexed (or a subclass) and
    #their indices are compatible. This function is used internally by
    #simplify_indexed().
    #self_ - First indexed expression; it's base object is self.
    #other - Second indexed expression.
    #"""
    #def scalar_mul_indexed(self,self_,other):
    #    """Multiply an indexed expression with a scalar.
    #This function is used internally by simplify_indexed().
    #self_ - Indexed expression; it's base object is self.
    #other - Numeric value.
    #"""
    def is_equal(self,other):
        """Test for equality.
    This is only a quick test, meaning objects should be in the same
    domain. You might have to .expand(), .normal() objects first,
    depending on the domain of your computation, to get a more
    reliable answer.
    """
    def get_hash(self):
        """Return hash."""
    def tinfo(self):
        """Return GiNaC type info."""
    def series(self,rel,order,options = 0):
        """Compute the truncated series expansion of an expression.
    This function returns an expression containing an object of class
    pseries to represent the series. If the series does not terminate
    within the given truncation order, the last term of the series
    will be an order term.
    rel    - expansion relation, lhs holds variable and rhs holds point 
    order  - truncation order of series calculations  
    options - see series_options.
    """
    def integer_content(self):
        """Compute the integer content (= GCD of all numeric coefficients)
    of an expanded polynomial. See ex.integer_content.
    """
    def smod(self, xi):
        """Apply symmetric modular homomorphism to a multivariate polynomial.
    See ex.smod."""
    def max_coefficient(self):
        """Return maximum (absolute value) coefficient of a polynomial.
    See ex.integer_content."""
    def subs(self,e_ls, lr = None):
        """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 (lr==None) and
    2) a list of relationals lst(object1==ex1,object2==ex2,...), which
       is converted to subs(lst(object1,object2,...),lst(ex1,ex2,...)).
    """
    def normal(self, sym_lst, repl_lst, level = 0):
        """It replaces the object with a temporary symbol. See ex.normal."""
    def to_rational(self, repl_lst):
        """It replaces the object with a temporary symbol. See ex.to_rational."""
    def diff(self,s,nth=1):
        """Default interface of nth derivative ex::diff(s, n).
    It should be called instead of derivative(s) for first derivatives
    and for nth derivatives it just recurses down. See ex.diff.
    s   - symbol to differentiate in
    nth - order of differentiation.
    """
    def hold(self):
        """Stop further evaluation. Returns object."""

class exprseq(basic): pass
class expairseq(basic): pass
class tensor(basic): pass
#ENDPROTO

wrapperclass = '''
class basic_w : public GiNaC::basic {
// basic_w provides an interface to GiNaC::basic.
// It implements methods for classes derived from the GiNaC::basic
// suitable for usage in Python. However, basic_w itself should not
// be used in Python.
  PyObject * self;
public:
  std::string python_str(void) const {
    std::ostrstream os;
    GiNaC::python_str(os, GiNaC::ex(*this));
    os << std::ends;
    return os.str();
  }
  std::string python_repr(void) const {
    std::ostrstream os;
    GiNaC::python_repr(os, GiNaC::ex(*this));
    os << std::ends;
    return os.str();
  }
  PyObject * getitem(python::ref);
  void setitem(python::ref index, python::ref obj);

  UNEX_RET op_w(std::size_t i) const {
    DEBUG_M("basic.op(int)");
    if ((i>=this->nops()) || (i<0)) {
      PyErr_SetString(PyExc_IndexError, "basic.op index out of range");
      throw python::error_already_set();
    }
    return UNEX(this->op(i));
  }
  bool has_w(python::ref other) const { return this->has(ex_w(other)); }
  UNEX_RET collect_w(python::ref s) const { return UNEX(this->collect(ex_w(s))); }
  int degree_w(python::ref s) const { return this->degree(ex_w(s)); }
  int ldegree_w(python::ref s) const { return this->ldegree(ex_w(s)); }
  UNEX_RET coeff1_w(python::ref s) const { return UNEX(this->coeff(ex_w(s))); }
  UNEX_RET coeff2_w(python::ref s, int n) const { return UNEX(this->coeff(ex_w(s), n)); }
  UNEX_RET eval0_w() const { return UNEX(this->eval()); }
  UNEX_RET eval1_w(int level) const { return UNEX(this->eval(level)); }
  UNEX_RET evalf0_w() const { return UNEX(this->evalf()); }
  UNEX_RET evalf1_w(int level) const { return UNEX(this->evalf(level)); }
#ifdef PYGINAC_relational
  UNEX_RET series2_w(python::ref rel,int order,unsigned opt) const { return UNEX(this->series(as_relational_w(rel),order)); }
  UNEX_RET series3_w(python::ref rel,int order,unsigned opt) const { return UNEX(this->series(as_relational_w(rel),order,opt)); }
#endif
#ifdef PYGINAC_numeric
  UNEX_RET smod_w(python::ref s) const { return UNEX(this->smod(as_numeric_w(s))); }
#endif
  UNEX_RET normal_w(void) const {
    return UNEX(GiNaC::ex(*this).normal());
  }
#ifdef PYGINAC_lst
  UNEX_RET subs1_w(python::ref s1) const { return UNEX(this->subs(as_lst_w(s1))); }
  UNEX_RET subs2_w(python::ref s1,python::ref s2) const { return UNEX(this->subs(as_lst_w(s1),as_lst_w(s2))); }
  UNEX_RET normal2_w(python::ref s1,python::ref s2) const {
    GiNaC::lst l1 = as_lst_w(s1);
    GiNaC::lst l2 = as_lst_w(s2);
    return UNEX(this->normal(l1,l2));
  }
  UNEX_RET normal3_w(python::ref s1,python::ref s2,int level) const {
    GiNaC::lst l1 = as_lst_w(s1);
    GiNaC::lst l2 = as_lst_w(s2);
    return UNEX(this->normal(l1,l2,level));
  }
  UNEX_RET to_rational_w(python::ref s1) const {
    GiNaC::lst l1 = as_lst_w(s1);
    return UNEX(this->to_rational(l1));
  }
#endif
#ifdef PYGINAC_symbol
  UNEX_RET diff1_w(python::ref s) const { return UNEX(this->diff(as_symbol_w(s))); }
  UNEX_RET diff2_w(python::ref s, unsigned nth) const { return UNEX(this->diff(as_symbol_w(s), nth)); }
#endif
  bool is_equal_w(python::ref other) const { return this->is_equal(*(ex_w(other).bp)); }
#ifdef PYGINAC_exvector
  UNEX_RET simplify_ncmul_w(python::ref v) const { return UNEX(this->simplify_ncmul(as_exvector_w(v))); }
#endif
  UNEX_RET eval_indexed_w(python::ref o) const { return UNEX(this->eval_indexed(*(ex_w(o).bp))); }
  UNEX_RET add_indexed_w(python::ref s, python::ref o) const { return UNEX(this->add_indexed(ex_w(s), ex_w(o))); }
#ifdef PYGINAC_numeric
  UNEX_RET scalar_mul_indexed_w(python::ref s,python::ref o) const { return UNEX(this->scalar_mul_indexed(ex_w(s), as_numeric_w(o))); }
#endif
//#ifdef PYGINAC_exvector
//  inline bool contract_with_w(python::ref s, python::ref o, python::ref v) const { return this->contract_with(as_exvector_w(s), ex_w(o), as_exvector_w(v)); }
//#endif

  static python::tuple coerce(const GiNaC::basic & left, python::ref right) {
    if (0) ;
#ifdef PYGINAC_numeric
    else if (is_exactly_of_type(left, numeric))
      return numeric_coerce((const GiNaC::numeric &)left, right);
#endif
#ifdef PYGINAC_matrix
    else if (is_exactly_of_type(left, matrix))
      return matrix_coerce((const GiNaC::matrix &)left, right);
#endif
    return python::tuple(GiNaC::ex(left), (const GiNaC::ex &)ex_w(right));
  }
  UNEX_RET op_pos(void) const {return UNEX(+(*this)); }
  UNEX_RET op_neg(void) const {return UNEX(-(*this)); }
   UNEX_RET op_add(python::ref other) const { return UNEX((*this)+ex_w(other)); }
   UNEX_RET op_sub(python::ref other) const { return UNEX((*this)-ex_w(other)); }
   UNEX_RET op_mul(python::ref other) const { return UNEX((*this)*ex_w(other)); }
   UNEX_RET op_div(python::ref other) const { return UNEX((*this)/ex_w(other)); }
   UNEX_RET op_pow(python::ref other, python::ref m) const { return UNEX(GiNaC::ex(GiNaC::power(*this,ex_w(other)))); }
};

'''

protos = '''
'''

builder = '''
python::class_builder<basic_w> basic_w_class(this_module, "_basic_w");
python::class_builder<GiNaC::basic, basic_w> basic_class(this_module, "_basic");
basic_py_class = python::as_object(basic_class.get_extension_class());
basic_class.declare_base(basic_w_class);
'''

constructors = '''
'''

defs = '''
//basic_class.def(&basic_w::python_str, "__str__"); // must define in each derived class
//basic_class.def(&basic_w::python_repr, "__repr__"); // must define in each derived class

//basic_class.def(&basic_w::torepr, "__repr__"); // no use
//basic_class.def(&basic_w::nops, "__len__"); // must define in each derived class
//basic_class.def(&basic_w::getitem, "__getitem__"); // must define in each derived class
basic_class.def(&basic_w::coerce, "__coerce__"); // must define in each derived class
//basic_class.def(&basic_w::op_pos, "__pos__");
//basic_class.def(&basic_w::op_neg, "__neg__");

//basic_class.def(python::operators<(python::op_sub | python::op_add | python::op_mul | python::op_div | python::op_neg | python::op_pos)>()); // must define in each derived class

basic_class.def(&basic_w::info, "info");
basic_class.def(&basic_w::nops, "nops");
basic_class.def(&basic_w::op_w, "op");
//basic_class.def(&basic_w::let_op_w, "let_op"); // not different from op
basic_class.def(&basic_w::has_w, "has");
basic_class.def(&basic_w::collect_w, "collect");
basic_class.def(&basic_w::degree_w, "degree");
basic_class.def(&basic_w::ldegree_w, "ldegree");
basic_class.def(&basic_w::coeff1_w, "coeff");
basic_class.def(&basic_w::coeff2_w, "coeff");
basic_class.def(&basic_w::eval0_w, "eval");
basic_class.def(&basic_w::eval1_w, "eval");
basic_class.def(&basic_w::evalf0_w, "evalf");
basic_class.def(&basic_w::evalf1_w, "evalf");
#ifdef PYGINAC_exvector
basic_class.def(&basic_w::get_free_indices, "get_free_indices");
basic_class.def(&basic_w::simplify_ncmul_w, "simplify_ncmul");
#endif
/*
basic_class.def(&basic_w::eval_indexed_w, "eval_indexed");
basic_class.def(&basic_w::add_indexed_w, "add_indexed");
#ifdef PYGINAC_numeric
basic_class.def(&basic_w::scalar_mul_indexed_w, "scalar_mul_indexed");
#endif
//#ifdef PYGINAC_exvector
//basic_class.def(&basic_w::contract_with_w, "contract_with");
//#endif
*/
//basic_class.def(&basic_w::compare, "compare");  // for internal use

basic_class.def(&basic_w::is_equal_w, "is_equal");
//basic_class.def(&basic_w::hold_w, "hold");   // must define in each derived class
basic_class.def(&basic_w::gethash, "get_hash");
basic_class.def(&basic_w::tinfo, "tinfo");
//basic_class.def(&basic_w::setflag, "setflag"); // must define in each derived class
//basic_class.def(&basic_w::clearflag, "clearflag"); // must define in each derived class
#ifdef PYGINAC_relational
basic_class.def(&basic_w::series2_w, "series");
basic_class.def(&basic_w::series3_w, "series");
#endif
#ifdef PYGINAC_numeric
basic_class.def(&basic_w::integer_content, "integer_content");
basic_class.def(&basic_w::smod_w, "smod");
basic_class.def(&basic_w::max_coefficient, "max_coefficient");
#endif
#ifdef PYGINAC_lst
basic_class.def(&basic_w::subs1_w, "subs");
basic_class.def(&basic_w::subs2_w, "subs");
basic_class.def(&basic_w::normal_w, "normal");
basic_class.def(&basic_w::normal2_w, "normal");
basic_class.def(&basic_w::normal3_w, "normal");
basic_class.def(&basic_w::to_rational_w, "to_rational");
#endif
#ifdef PYGINAC_symbol
basic_class.def(&basic_w::diff1_w, "diff");
basic_class.def(&basic_w::diff2_w, "diff");
#endif
'''

implementation = '''
PyObject * basic_w::getitem (python::ref index) {
  PyObject * o = index.get();
  int l = this->nops();
  int start, step_size, n_steps;
  DEBUG_M("basic::getitem(ref)");
  start = parse_subindex(o, &step_size, &n_steps, l);
  DEBUG_M("start="<<start<<",step_size="<<step_size<<",n_steps="<<n_steps)
  if (start < 0)
    throw python::error_already_set();
  if (n_steps==PseudoIndex || n_steps==RubberIndex) {
    PyErr_SetString(PyExc_NotImplementedError, "basic() getitem PseudoIndex|RubberIndex");
    throw python::error_already_set();
  }
  if (n_steps==SingleIndex)
    return BOOST_PYTHON_CONVERSION::to_python(UNEX(this->op_w(start)));
#ifdef PYGINAC_lst
  if (this->info(GiNaC::info_flags::list)) {
    GiNaC::lst v;
    int k = start;
    for (int i=0;i<n_steps;++i,k += step_size)
      v.append(this->op((k==l)?0:k));
    return BOOST_PYTHON_CONVERSION::to_python(v);
  }
#endif
  PyErr_SetString(PyExc_NotImplementedError, "basic() getitem slice");
  throw python::error_already_set();
/*
  GiNaC::exvector v(0);
  int k = start;
  for (int i=0;i<n_steps;++i,k += step_size)
    v.push_back((*this)[(k==l)?0:k]);
  return BOOST_PYTHON_CONVERSION::to_python(v);
*/
}

void basic_w::setitem (python::ref index, python::ref obj) {
  PyObject * o = index.get();
  int l = this->nops();
  int start, step_size, n_steps;
  DEBUG_M("basic::setitem(ref,ref)");
  start = parse_subindex(o, &step_size, &n_steps, l);
  DEBUG_M("start="<<start<<",step_size="<<step_size<<",n_steps="<<n_steps)
  if (start == -1)
    throw python::error_already_set();
  if (n_steps==PseudoIndex || n_steps==RubberIndex) {
    PyErr_SetString(PyExc_NotImplementedError, "basic() setitem PseudoIndex|RubberIndex");
    throw python::error_already_set();
  }
  if (n_steps==SingleIndex) {
    this->let_op(start) = ex_w(obj);
  } else {
    if (0) {
#ifdef PYGINAC_lst
    } else if (this->info(GiNaC::info_flags::list)) {
      lst_w v(obj);
      if (n_steps != int(v.nops())) {
         PyErr_SetString(PyExc_IndexError, "basic() not matching index vectors");
         throw python::error_already_set();
      }
      int k = start;
      for (int i=0;i<n_steps;++i,k += step_size)
        this->let_op((k==l)?0:k) = v[i];
#endif
    } else {
      PyErr_SetString(PyExc_NotImplementedError, "basic() setitem slice");
      throw python::error_already_set();
    }
  }
}

/*
void exlist_w::delitem(const std::size_t key) {
    GiNaC::exlist::iterator viter = (*this).begin();
    exlist_w::throw_index_error_if(*this, key);
    for(unsigned int i = 0; i < key; ++i,++viter);
    (*this).erase(viter);
}
*/
'''

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>