File:  [CENS] / python / pyGiNaC / wrappers3 / python_str.cpp
Revision 1.2: 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.2 $
# $Id: python_str.cpp,v 1.2 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 "python_repr.hpp"
#include "pyfunc.hpp"

#if GINACLIB_MAJOR_VERSION == 0 && (GINACLIB_MINOR_VERSION < 8 || (GINACLIB_MINOR_VERSION == 8 && GINACLIB_MICRO_VERSION == 0))
#define GINAC_VERSION_0_8_0_OR_EARLIER
#endif

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

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

#ifdef GINAC_VERSION_0_8_0_OR_EARLIER
#define GINAC_python_str(e) e.print(os,level)
#define PYGINAC_FUNCTION_GETNAME(f) PYGINAC_WRAP(f,function).get_name()
#else
#define GINAC_python_str(e) e.print(print_context(os),level)
#define PYGINAC_FUNCTION_GETNAME(f) f.get_name()
#endif

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_str(std::ostream &, const expair &, unsigned level=0);
void python_str(std::ostream &, const epvector &, unsigned level=0);
void python_str(std::ostream &, const exvector &, unsigned level=0);


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

void python_str(std::ostream & os, const ex & e, unsigned level=0)
{
  DEBUG_STR("python_str("<<e.bp->class_name()<<",hash="<<e.bp->gethash()<<")");
  if (is_ex_of_type(e, matrix))
    python_str(os, ex_to_matrix(e), level);
  else if (is_ex_of_type(e, add))
    python_str(os, ex_to_add(e), level);
  else if (is_ex_of_type(e, mul))
    python_str(os, ex_to_mul(e), level);
  else if (is_ex_of_type(e, power))
    python_str(os, ex_to_power(e), level);
  else if (is_ex_of_type(e, function))
    python_str(os, ex_to_function(e), level);
  else if (is_ex_of_type(e, lst))
    python_str(os, ex_to_lst(e), level);
  else if (is_ex_of_type(e, relational))
    python_str(os, ex_to_relational(e), level);
  else if (is_ex_of_type(e, pseries))
    python_str(os, ex_to_pseries(e), level);
  else if (is_ex_of_type(e, ncmul))
    python_str(os, ex_to_ncmul(e), level);
  else if (is_ex_of_type(e, indexed))
    python_str(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_str(os, ex_to_idx(e), level);
  }
  else if (is_ex_of_type(e, symbol)
	   || is_ex_of_type(e, constant)
	   || is_ex_of_type(e, numeric)
	   || is_ex_of_type(e, tensor)
	   )
    GINAC_python_str(e);
  else {
    cerr << "PyGiNaC warning: NotImplemented str("<<e.bp->class_name()<<")"<<std::endl;
    GINAC_python_str(e);
  }
}

void python_str(std::ostream & os, const expair & v, unsigned level=0)
{
  DEBUG_STR("python_str_expair()");
  os << '(';
  python_str(os, v.rest);
  os << ", ";
  python_str(os, v.coeff);
  os << ')';
}

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

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

static void python_str(std::ostream & os, const matrix & m, unsigned level=0)
{
  DEBUG_STR("python_str_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_str(os, m(j,i));
      os << ", ";
    }
    python_str(os, m(j,cols-1));
    os << ']';
    if (j<rows-1)
      os << ',' << std::endl;
  }
  os << ']';
}

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

static void python_str(std::ostream & os, const relational & r, unsigned level=0)
{
  DEBUG_STR("python_str_relational(hash="<<r.gethash()<<')');
  unsigned precedence = r.precedence();
  relational::operators o = PYGINAC_WRAP(r,relational).get_o(); 
  if (precedence <= level)
    os << '(';
  python_str(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_str(os, r.rhs(), precedence);
  if (precedence <= level)
    os << ')';
}

static void python_str(std::ostream & os, const power & p, unsigned level=0)
{
  DEBUG_STR("python_str_power(hash="<<p.gethash()<<')');
  unsigned precedence = p.precedence();
  ex basis = p.op(0);
  ex exponent = p.op(1);
  if (exponent.is_equal(_ex1_2())) {
    os << "sqrt(";
    python_str(os, basis);
    os << ')';
  } else {
    if (precedence <= level)
      os << '(';
    if (0 && is_ex_exactly_of_type(exponent, numeric)
	&& ex_to_numeric(exponent).is_negative()) {
      os << " 1 / ";
      python_str(os, power(basis, -exponent), level);
    } else {
      python_str(os, basis, precedence);
      os << " ** ";
      python_str(os, exponent, precedence);
    }
    if (precedence <= level)
      os << ')';
  }
}

static void python_str(std::ostream & os, const add & s, unsigned level=0)
{
  DEBUG_STR("python_str_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_str(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_str(os,-coeff);
	else
	  python_str(os,coeff);
      } else {
	if (coeff.csgn() == -1)
	  python_str(os,-coeff, precedence);
	else
	  python_str(os,coeff, precedence);
      }
      os << " * ";
    }
    python_str(os,it->rest, precedence);
    it++;
  }
  if (precedence <= level)
    os << ')';
}

static void python_str(std::ostream & os, const mul & s, unsigned level=0)
{
  DEBUG_STR("python_str_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_str(os, -coeff);
      else
	python_str(os, coeff);
    } else {
      if (coeff.csgn() == -1)
	python_str(os, -coeff, precedence);
      else
	python_str(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_str(os, it->rest, precedence);
    }
    else if (ex_to_numeric(it->coeff).is_equal(_num_1())) {
      if (!first) os << " / "; else os << "1 / ";
      python_str(os, it->rest, precedence);
    }
    else if (ex_to_numeric(it->coeff).is_negative()) {
      if (!first) os << " / "; else os << "1 / ";
      python_str(os, power(it->rest, -it->coeff), precedence);
    }
    else {
      if (!first) os << " * ";
      python_str(os, power(it->rest, it->coeff), precedence);
    }
    it++;
    first = false;
  }
  if (precedence <= level)
    os << ')';
}

static void python_str(std::ostream & os, const pseries & s, unsigned level=0)
{
  DEBUG_STR("python_str_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_str(os, i->rest);
      } else {
	os << '(';
	python_str(os, i->rest);
	os << ')';
      }
      if (!i->coeff.is_zero()) {
	os << " * ";
	if (!point.is_zero()) {
	  os << '(';
	  python_str(os, var-point);
	  os << ')';
	} else
	  python_str(os, var);
	if (i->coeff.compare(_ex1())) {
	  os << " ** ";
	  if (i->coeff.info(info_flags::negative)) {
	    os << '(';
	    python_str(os, i->coeff);
	    os << ')';
	  } else
	    python_str(os, i->coeff);
	}
      }
    } else
      python_str(os, Order(power(var-point,i->coeff)));
  }
  if (precedence <= level)
    os << ')';
}

static void python_str(std::ostream & os, const idx & v, unsigned level=0)
{
  DEBUG_STR("python_str_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_str(os, value);
  if (need_parens) os << ')';
}

static void python_str(std::ostream & os, const indexed & v, unsigned level=0)
{
  DEBUG_STR("python_str_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_str(os, base);
  if (need_parens) os << ')';
  for (unsigned i=1; i<n; ++i)
    python_str(os, v.op(i),level);
}

static void python_str(std::ostream & os, const function & f, unsigned level=0)
{
  DEBUG_STR("python_str_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_str(os, f.op(0), precedence);
  for (unsigned i=1; i<n-1; ++i) {
    os << ", ";
    python_str(os, f.op(i), precedence);
  }
  if (n>1
#ifdef PYGINAC_pyfunc
      && !is_ex_exactly_of_type(f.op(n-1), pyfunc)
#endif
      ) {
    os << ", ";
    python_str(os, f.op(n-1), precedence);
  }
  os << ')';
}

static void python_str(std::ostream & os, const ncmul & s, unsigned level=0)
{
  DEBUG_STR("python_str_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_str(os, *it, precedence);
      os << " * ";
      it++;
    }
    python_str(os, *it, precedence);
  }
  if (precedence <= level)
    os << ')';
}

}

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