File:  [CENS] / python / pyGiNaC / wrappers3 / python_csrc.cpp
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Sun May 20 08:58:02 2001 UTC (16 years, 6 months ago) by pearu
Branches: MAIN
CVS tags: HEAD
Fixed get_precedence, cleaned up code, requires current CVS verion of GiNaC

/*
# This file is part of the PyGiNaC package.
# http://cens.ioc.ee/projects/pyginac/
#
# $Revision: 1.1 $
# $Id: python_csrc.cpp,v 1.1 2001-05-20 08:58:02 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.
#
*/

#include <boost/python/class_builder.hpp>

#include "pyfunc.hpp"


#define PYGINAC_WRAP(OBJ,CLASS) ((const wrap_##CLASS &)OBJ)

#if 0
#define DEBUG_STR(o) cout << o << endl;
#else
#define DEBUG_STR(o)
#endif

#define GINAC_python_csrc(e) e.print(print_context(os),level)

namespace GiNaC {
  
const ex & _ex1_2(void);
const ex & _ex1(void);
const numeric & _num_1(void);
const numeric & _num1(void);

class wrap_add: public add {
public:
  inline const epvector & get_seq(void) const { return this->seq; }
  inline const ex & get_overall_coeff(void) const { return this->overall_coeff; }
};
class wrap_mul: public mul {
public:
  inline const epvector & get_seq(void) const { return this->seq; }
  inline const ex & get_overall_coeff(void) const { return this->overall_coeff; }
};
class wrap_relational: public relational {
public:
  inline operators get_o(void) const { return this->o; }
};
class wrap_indexed: public indexed {
public:
  inline symmetry_type get_symmetry(void) const { return this->symmetry; }
};
class wrap_pseries: public pseries {
public:
  inline const epvector & get_seq(void) const { return this->seq; }
};
class wrap_matrix: public matrix {
public:
  inline const exvector & get_m(void) const { return this->m; }
};


void python_csrc(std::ostream &, const expair &, unsigned level=0);
void python_csrc(std::ostream &, const epvector &, unsigned level=0);
void python_csrc(std::ostream &, const exvector &, unsigned level=0);


static void python_csrc(std::ostream &, const matrix &, unsigned level=0);
static void python_csrc(std::ostream &, const lst &, unsigned level=0);
static void python_csrc(std::ostream &, const add &, unsigned level=0);
static void python_csrc(std::ostream &, const mul &, unsigned level=0);
static void python_csrc(std::ostream &, const relational &, unsigned level=0);
static void python_csrc(std::ostream &, const power &, unsigned level=0);
static void python_csrc(std::ostream &, const pseries &, unsigned level=0);
static void python_csrc(std::ostream &, const idx &, unsigned level=0);
static void python_csrc(std::ostream & os, const indexed & v, unsigned level=0);
static void python_csrc(std::ostream &, const ncmul &, unsigned level=0);
static void python_csrc(std::ostream &, const function &, unsigned level=0);

void python_csrc(std::ostream & os, const ex & e, unsigned level=0)
{
  DEBUG_STR("python_csrc("<<e.bp->class_name()<<",hash="<<e.bp->gethash()<<")");
  if (is_ex_of_type(e, matrix))
    python_csrc(os, ex_to_matrix(e), level);
  else if (is_ex_of_type(e, add))
    python_csrc(os, ex_to_add(e), level);
  else if (is_ex_of_type(e, mul))
    python_csrc(os, ex_to_mul(e), level);
  else if (is_ex_of_type(e, power))
    python_csrc(os, ex_to_power(e), level);
  else if (is_ex_of_type(e, function))
    python_csrc(os, ex_to_function(e), level);
  else if (is_ex_of_type(e, lst))
    python_csrc(os, ex_to_lst(e), level);
  else if (is_ex_of_type(e, relational))
    python_csrc(os, ex_to_relational(e), level);
  else if (is_ex_of_type(e, pseries))
    python_csrc(os, ex_to_pseries(e), level);
  else if (is_ex_of_type(e, ncmul))
    python_csrc(os, ex_to_ncmul(e), level);
  else if (is_ex_of_type(e, indexed))
    python_csrc(os, ex_to_indexed(e), level);
  else if (is_ex_of_type(e, idx)) {
    if (is_ex_of_type(e, varidx) && ex_to_varidx(e).is_contravariant())
      os << '~';
    else
      os << '.';
    python_csrc(os, ex_to_idx(e), level);
  }
  else if (is_ex_of_type(e, numeric))
    GINAC_python_csrc(e.evalf());
  else if (is_ex_of_type(e, symbol)
	   || is_ex_of_type(e, constant)
	   || is_ex_of_type(e, tensor)
	   )
    GINAC_python_csrc(e);
  else {
    cerr << "PyGiNaC warning: NotImplemented to_csrc("<<e.bp->class_name()<<")"<<std::endl;
    GINAC_python_csrc(e);
  }
}
  
void python_csrc(std::ostream & os, const expair & v, unsigned level=0)
{
  DEBUG_STR("python_csrc_expair()");
  os << '(';
  python_csrc(os, v.rest);
  os << ", ";
  python_csrc(os, v.coeff);
  os << ')';
}

void python_csrc(std::ostream & os, const epvector & v, unsigned level=0)
{
  DEBUG_STR("python_csrc_epvector()");
  unsigned n = v.size();
  os << "[";
  for (unsigned i=0; i<n; i++) {
    python_csrc(os, v[i]);
    if (i != n-1)
      os << ", ";
  }
  os << "]";
}

void python_csrc(std::ostream & os, const exvector & v, unsigned level=0)
{
  DEBUG_STR("python_csrc_exvector()");
  unsigned n = v.size();
  os << "[";
  for (unsigned i=0; i<n; i++) {
    python_csrc(os, v[i]);
    if (i != n-1)
      os << ", ";
  }
  os << "]";
}

static void python_csrc(std::ostream & os, const matrix & m, unsigned level=0)
{
  DEBUG_STR("python_csrc_matrix(hash="<<m.gethash()<<')');
  unsigned rows = m.rows();
  unsigned cols = m.cols();
  os << '[';
  for (unsigned j=0; j<rows; ++j) {
    if (j>0)
      os << ' ';
    os << '[';
    for (unsigned i=0; i<cols-1; ++i) {
      python_csrc(os, m(j,i));
      os << ", ";
    }
    python_csrc(os, m(j,cols-1));
    os << ']';
    if (j<rows-1)
      os << ',' << std::endl;
  }
  os << ']';
}

static void python_csrc(std::ostream & os, const lst & m, unsigned level=0)
{
  DEBUG_STR("python_csrc_lst(hash="<<m.gethash()<<')');
  unsigned n = m.nops();
  os << '[';
  if (n>0)
    python_csrc(os, m.op(0));
  for (unsigned i=1; i<n; ++i) {
    os << ", ";
    python_csrc(os, m.op(i));
  }
  os << ']';
}

static void python_csrc(std::ostream & os, const relational & r, unsigned level=0)
{
  DEBUG_STR("python_csrc_relational(hash="<<r.gethash()<<')');
  unsigned precedence = r.precedence();
  relational::operators o = PYGINAC_WRAP(r,relational).get_o(); 
  if (precedence <= level)
    os << '(';
  python_csrc(os, r.lhs(), precedence);
  switch (o) {
  case relational::equal: os << " == "; break;
  case relational::not_equal: os << " != "; break;
  case relational::less: os << " < "; break;
  case relational::less_or_equal: os << " <= "; break;
  case relational::greater: os << " > "; break;
  case relational::greater_or_equal: os << " >= "; break;
  default: os << "(INVALID RELATIONAL OPERATOR)";
  }
  python_csrc(os, r.rhs(), precedence);
  if (precedence <= level)
    os << ')';
}

static void python_sym_pow(std::ostream & os, const symbol &x, int exp) {
  // Optimal output of integer powers of symbols to aid compiler CSE.
  // C.f. ISO/IEC 14882:1998, section 1.9 [intro execution], paragraph 15
  // to learn why such a hack is really necessary.
  if (exp == 1) {
    python_csrc(os, x);
  } else if (exp == 2) {
    python_csrc(os, x);
    os << "*";
    python_csrc(os, x);
  } else if (exp & 1) {
    python_csrc(os, x);
    os << "*";
    python_sym_pow(os, x, exp-1);
  } else {
    os << "(";
    python_sym_pow(os, x, exp >> 1);
    os << ")*(";
    python_sym_pow(os, x, exp >> 1);
    os << ")";
  }
}
static void python_csrc(std::ostream & os, const power & p, unsigned level=0)
{
  DEBUG_STR("python_csrc_power(hash="<<p.gethash()<<')');
  ex basis = p.op(0);
  ex exponent = p.op(1);
  if (exponent.is_equal(_ex1_2())) {
    if (is_ex_exactly_of_type(basis, numeric)) {
      python_csrc(os, p.evalf());
    } else {
      os << "sqrt(";
      python_csrc(os, basis);
      os << ')';
    }
  }
  else if (exponent.info(info_flags::integer)
      && (is_ex_exactly_of_type(basis, symbol)
	  || is_ex_exactly_of_type(basis, constant))) {
    int exp = ex_to_numeric(exponent).to_int();
    if (exp > 0)
      os << "(";
    else {
      exp = -exp;
      os << "1.0/(";
    }
    python_sym_pow(os, ex_to_symbol(basis), exp);
    os << ")";
  }
  else if (exponent.compare(_num_1()) == 0) {
    os << "1.0/(";
    python_csrc(os, basis);
    os << ")";
  }
  else {
    os << "pow(";
    python_csrc(os, basis);
    os << ", ";
    python_csrc(os, exponent);
    os << ')';
  }
}

static void python_csrc(std::ostream & os, const add & s, unsigned level=0)
{
  DEBUG_STR("python_csrc_add(hash="<<s.gethash()<<")");
  unsigned precedence = s.precedence();
  const ex & overall_coeff = PYGINAC_WRAP(s,add).get_overall_coeff();
  const epvector & seq = PYGINAC_WRAP(s,add).get_seq();
  if (precedence <= level)
    os << '(';
  numeric coeff;
  bool first = true;
  if (!overall_coeff.is_zero()) {
    python_csrc(os, overall_coeff);
    first = false;
  }
  epvector::const_iterator it = seq.begin(), itend = seq.end();
  while (it != itend) {
    coeff = ex_to_numeric(it->coeff);
    if (!first) {
      if (coeff.csgn() == -1) os << " - "; else os << " + ";
    } else {
      if (coeff.csgn() == -1) os << '-';
      first = false;
    }
    if (!coeff.is_equal(_num1()) &&
	!coeff.is_equal(_num_1())) {
      if (coeff.is_rational() || coeff.is_real()) {
	if (coeff.is_negative())
	  python_csrc(os,-coeff);
	else
	  python_csrc(os,coeff);
      } else {
	if (coeff.csgn() == -1)
	  python_csrc(os,-coeff, precedence);
	else
	  python_csrc(os,coeff, precedence);
      }
      os << " * ";
    }
    python_csrc(os,it->rest, precedence);
    it++;
  }
  if (precedence <= level)
    os << ')';
}

static void python_csrc(std::ostream & os, const mul & s, unsigned level=0)
{
  DEBUG_STR("python_csrc_mul(hash="<<s.gethash()<<")");
  unsigned precedence = s.precedence();
  const ex & overall_coeff = PYGINAC_WRAP(s,mul).get_overall_coeff();
  const epvector & seq = PYGINAC_WRAP(s,mul).get_seq();
  if (precedence <= level)
    os << '(';
  bool first = true;
  numeric coeff = ex_to_numeric(overall_coeff);
  if (coeff.csgn() == -1)
    os << '-';
  if (!coeff.is_equal(_num1()) &&
      !coeff.is_equal(_num_1())) {
    if (coeff.is_rational() || coeff.is_real()) {
      if (coeff.is_negative())
	python_csrc(os, -coeff);
      else
	python_csrc(os, coeff);
    } else {
      if (coeff.csgn() == -1)
	python_csrc(os, -coeff, precedence);
      else
	python_csrc(os, coeff, precedence);
    }
    first = false;
  }
  epvector::const_iterator it = seq.begin(), itend = seq.end();
  while (it != itend) {
    if (ex_to_numeric(it->coeff).is_equal(_num1())) {
      if (!first) os << " * ";
      python_csrc(os, it->rest, precedence);
    }
    else if (ex_to_numeric(it->coeff).is_equal(_num_1())) {
      if (!first) os << " / "; else os << "1.0 / ";
      python_csrc(os, it->rest, precedence);
    }
    else if (ex_to_numeric(it->coeff).is_negative()) {
      if (!first) os << " / "; else os << "1.0 / ";
      python_csrc(os, power(it->rest, -it->coeff), precedence);
    }
    else {
      if (!first) os << " * ";
      python_csrc(os, power(it->rest, it->coeff), precedence);
    }
    it++;
    first = false;
  }
  if (precedence <= level)
    os << ')';
}

static void python_csrc(std::ostream & os, const pseries & s, unsigned level=0)
{
  DEBUG_STR("python_csrc_pseries(hash="<<s.gethash()<<")");
  unsigned precedence = s.precedence();
  const ex & var = s.get_var();
  const ex & point = s.get_point();
  const epvector & seq = PYGINAC_WRAP(s,pseries).get_seq();
  if (precedence <= level)
    os << '(';
  if (seq.size() == 0)
    os << '0';
  for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
    if (i != seq.begin())
      os << " + ";
    if (!is_order_function(i->rest)) {
      if (i->rest.info(info_flags::numeric) &&
	  i->rest.info(info_flags::positive)) {
	python_csrc(os, i->rest);
      } else {
	os << '(';
	python_csrc(os, i->rest);
	os << ')';
      }
      if (!i->coeff.is_zero()) {
	os << " * ";
	if (!point.is_zero()) {
	  os << '(';
	  python_csrc(os, var-point);
	  os << ')';
	} else
	  python_csrc(os, var);
	if (i->coeff.compare(_ex1())) {
	  os << " ** ";
	  if (i->coeff.info(info_flags::negative)) {
	    os << '(';
	    python_csrc(os, i->coeff);
	    os << ')';
	  } else
	    python_csrc(os, i->coeff);
	}
      }
    } else
      python_csrc(os, Order(power(var-point,i->coeff)));
  }
  if (precedence <= level)
    os << ')';
}

static void python_csrc(std::ostream & os, const idx & v, unsigned level=0)
{
  DEBUG_STR("python_csrc_idx()");
  ex value = v.get_value();
  bool need_parens = !(is_ex_exactly_of_type(value, numeric) || is_ex_of_type(value, symbol));
  if (need_parens) os << '(';
  python_csrc(os, value);
  if (need_parens) os << ')';
}

static void python_csrc(std::ostream & os, const indexed & v, unsigned level=0)
{
  DEBUG_STR("python_csrc_indexed()");
  unsigned n = v.nops();
  const ex & base = v.op(0);
  bool need_parens = is_ex_exactly_of_type(base, add) || is_ex_exactly_of_type(base, mul) || is_ex_exactly_of_type(base, ncmul) || is_ex_exactly_of_type(base, power);
  if (need_parens) os << '(';
  python_csrc(os, base);
  if (need_parens) os << ')';
  for (unsigned i=1; i<n; ++i)
    python_csrc(os, v.op(i),level);
}

static void python_csrc(std::ostream & os, const function & f, unsigned level=0)
{
  DEBUG_STR("python_csrc_function()");
  unsigned n = f.nops();
  unsigned precedence = f.exprseq::precedence();
  os << f.get_name() << '(';
  if (n>0
#ifdef PYGINAC_pyfunc
      && !is_ex_exactly_of_type(f.op(0), pyfunc)
#endif
      )
    python_csrc(os, f.op(0), precedence);
  for (unsigned i=1; i<n-1; ++i) {
    os << ", ";
    python_csrc(os, f.op(i), precedence);
  }
  if (n>1
#ifdef PYGINAC_pyfunc
      && !is_ex_exactly_of_type(f.op(n-1), pyfunc)
#endif
      ) {
    os << ", ";
    python_csrc(os, f.op(n-1), precedence);
  }
  os << ')';
}

static void python_csrc(std::ostream & os, const ncmul & s, unsigned level=0)
{
  DEBUG_STR("python_csrc_ncmul(hash="<<s.gethash()<<")");
  unsigned precedence = s.precedence();
  const exvector & seq = s.get_factors();
  if (precedence <= level)
    os << '(';
  if (seq.size() != 0) {
    exvector::const_iterator it = seq.begin(), itend = seq.end();
    --itend;
    while (it != itend) {
      python_csrc(os, *it, precedence);
      os << " * ";
      it++;
    }
    python_csrc(os, *it, precedence);
  }
  if (precedence <= level)
    os << ')';
}

}

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