// -*- mode:C++ ; compile-command: "g++-3.4 -I. -I.. -I../include -g -c symbolic.cc -Wall -DIN_GIAC -DHAVE_CONFIG_H" -*-
#include "giacPCH.h"
/*
* Copyright (C) 2000, 2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
*
* 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
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
using namespace std;
#include "symbolic.h"
#include "identificateur.h"
#include "usual.h"
#include "prog.h"
#include "rpn.h"
#include "plot.h"
#include "giacintl.h"
#include "global.h"
// NB: the operator in the symbolic (sommet) can not be replace by a pointer
// to a unary_function_ptr in the current code. Indeed, symbolic are created
// in the parser from temporary gen objects of type _FUNC which contains
// copies of unary_function_ptr, these copies are deleted once the parser
// gen object is deleted -> segfault.
#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC
// unary_function_ptr quoted_op[]={at_of,at_for,at_bloc,at_local,at_program,at_rpn_prog,at_ifte,at_try_catch,at_print,at_signal,at_as_function_of,at_lieu,at_legende,at_debug,at_sst,at_sst_in,at_cont,at_kill,at_halt,at_watch,at_rmwatch,at_breakpoint,at_maple2mupad,at_mupad2maple,at_maple2xcas,at_mupad2xcas,at_purge,0};
#if defined(GIAC_GENERIC_CONSTANTS) || defined(VISUALC) || defined(x86_64)
const unary_function_ptr * archive_function_tab(){
static const unary_function_ptr archive_function_tab_ptr[]={*at_plus,*at_neg,*at_binary_minus,*at_prod,*at_division,*at_inv,*at_pow,*at_exp,*at_ln,*at_abs,*at_arg,*at_pnt,*at_point,*at_segment,*at_sto,*at_sin,
*at_cos,*at_tan,*at_asin,*at_acos,*at_atan,*at_sinh,*at_cosh,*at_tanh,*at_asinh,*at_acosh,*at_atanh,*at_interval,*at_union,*at_minus,*at_intersect,*at_not,
*at_and,*at_ou,*at_inferieur_strict,*at_inferieur_egal,*at_superieur_strict,*at_superieur_egal,*at_different,*at_equal,*at_rpn_prog,*at_local,*at_return,*at_Dialog,*at_double_deux_points,*at_pointprod,*at_pointdivision,*at_pointpow,*at_hash,*at_pourcent,*at_tilocal,*at_break,*at_continue,*at_ampersand_times,*at_maple_lib,*at_unit,*at_plot_style,*at_xor,*at_check_type,*at_quote_pow,*at_case,*at_dollar,*at_IFTE,*at_RPN_CASE,*at_RPN_LOCAL,*at_RPN_FOR,*at_RPN_WHILE,*at_NOP,*at_unit,*at_ifte,*at_for,*at_bloc,*at_program,*at_same,*at_increment,*at_decrement,*at_multcrement,*at_divcrement,*at_sq,*at_display,*at_of,*at_at,*at_normalmod,*at_equal2,*at_pointplus,*at_pointminus,0};
archive_function_tab_length=sizeof(archive_function_tab_ptr)/sizeof(const unary_function_ptr *);
return archive_function_tab_ptr;
}
int archive_function_tab_length=0;
#else
static const size_t archive_function_tab_alias[]={
// index = 2
alias_at_plus,alias_at_neg,alias_at_binary_minus,alias_at_prod,alias_at_division,
// 12
alias_at_inv,alias_at_pow,alias_at_exp,alias_at_ln,alias_at_abs,
// 22
alias_at_arg,alias_at_pnt,alias_at_point,alias_at_segment,alias_at_sto,
// 32
alias_at_sin,alias_at_cos,alias_at_tan,alias_at_asin,alias_at_acos,
// 42
alias_at_atan,alias_at_sinh,alias_at_cosh,alias_at_tanh,alias_at_asinh,
// 52
alias_at_acosh,alias_at_atanh,alias_at_interval,alias_at_union,alias_at_minus,
// 62
alias_at_intersect,alias_at_not,alias_at_and,alias_at_ou,alias_at_inferieur_strict,
// 72
alias_at_inferieur_egal,alias_at_superieur_strict,alias_at_superieur_egal,alias_at_different,alias_at_equal,
// 82
alias_at_rpn_prog,alias_at_local,alias_at_return,alias_at_Dialog,alias_at_double_deux_points,
// 92
alias_at_pointprod,alias_at_pointdivision,alias_at_pointpow,alias_at_hash,alias_at_pourcent,
// 102
alias_at_tilocal,alias_at_break,alias_at_continue,alias_at_ampersand_times,alias_at_maple_lib,
// 112
alias_at_unit,alias_at_plot_style,alias_at_xor,alias_at_check_type,alias_at_quote_pow,
// 122
alias_at_case,alias_at_dollar,alias_at_IFTE,alias_at_RPN_CASE,alias_at_RPN_LOCAL,
// 132
alias_at_RPN_FOR,alias_at_RPN_WHILE,alias_at_NOP,alias_at_unit,alias_at_ifte,
// 142
alias_at_for,alias_at_bloc,alias_at_program,alias_at_same,alias_at_increment,
// 152
alias_at_decrement,alias_at_multcrement,alias_at_divcrement,alias_at_sq,alias_at_display,
// 162
alias_at_of,alias_at_at,alias_at_normalmod,alias_at_equal2,alias_at_pointplus,
// 172
alias_at_pointminus,
0
};
const unary_function_ptr * _archive_function_tab = (const unary_function_ptr *) &archive_function_tab_alias;
const unary_function_ptr * archive_function_tab(){
return _archive_function_tab;
}
int archive_function_tab_length=sizeof(archive_function_tab_alias)/sizeof(size_t);
#endif
int archive_function_index(const unary_function_ptr & f){
return f.ptr()?(f.ptr()->index_quoted_function >> 1):0;
// return equalposcomp(archive_function_tab(),f);
}
int equalposcomp(const unary_function_ptr tab[],const unary_function_ptr & f){
for (int i=1;*((size_t *)tab)!=0;++tab,++i){
if (*tab==f)
return i;
}
return 0;
}
int equalposcomp(const vector & tab,const unary_function_ptr * f){
vector::const_iterator it=tab.begin(),itend=tab.end();
for (int i=1;it!=itend;++it,++i){
if (**it==*f)
return i;
}
return 0;
}
int equalposcomp(const const_unary_function_ptr_ptr tab[],const unary_function_ptr & f){
for (int i=1;*((size_t *)tab)!=0;++tab,++i){
if (**tab==f)
return i;
}
return 0;
}
symbolic::symbolic(const symbolic & mys,const gen & e): sommet(mys.sommet){
vecteur tmp;
if (mys.feuille.type==_VECT){
tmp = *mys.feuille._VECTptr;
tmp.push_back(e);
}
else {
tmp.push_back(mys.feuille);
tmp.push_back(e);
}
feuille = gen(tmp,_SEQ__VECT);
};
symbolic::symbolic(const gen & a,const unary_function_ptr & o,const gen & b):sommet(o) {
if (b.type==_VECT)
feuille=gen(mergevecteur(vecteur(1,a),*b._VECTptr),b.subtype);
else
feuille=gen(makevecteur(a,b),_SEQ__VECT);
};
symbolic::symbolic(const gen & a,const unary_function_ptr * o,const gen & b):sommet(*o) {
if (b.type==_VECT)
feuille=gen(mergevecteur(vecteur(1,a),*b._VECTptr),b.subtype);
else
feuille=gen(makevecteur(a,b),_SEQ__VECT);
};
int symbolic::size() const {
if (feuille.type==_SYMB)
return 1+feuille._SYMBptr->size();
if (feuille.type!=_VECT)
return 2;
int s=1;
iterateur it=feuille._VECTptr->begin(),itend=feuille._VECTptr->end();
for (;it!=itend;++it){
if (it->type==_SYMB)
s += it->_SYMBptr->size();
else
++s;
}
return s;
}
bool print_rewrite_prod_inv=false;
static string & add_print_plus(string & s,const symbolic & g,GIAC_CONTEXT){
if (is_inf(g.feuille)
// && calc_mode(contextptr)!=1
&& abs_calc_mode(contextptr)==38
){
s+="∞";
return s;
}
if (g.feuille.type!=_VECT){
s += '+';
return add_print(s,g.feuille,contextptr);
}
vecteur & v = *g.feuille._VECTptr;
if (v.empty())
return s;
int l=int(v.size());
if (l==1)
s += '+';
add_print(s, v.front(),contextptr);
for (int i=1;i - and +
if (l && s[l-1]=='+')
s[l-1]='-';
else {
if (l && s[l-1]=='-')
s[l-1]='+';
else
s += calc_mode(contextptr)==38?"−":"-";
}
if (feuille.type!=_CPLX){
if(feuille.type!=_SYMB || (feuille._SYMBptr->sommet==at_inv || feuille._SYMBptr->sommet==at_prod) || !need_parenthesis(feuille)){
return add_print(s,feuille,contextptr);
}
}
s += "(";
add_print(s,feuille,contextptr);
s += ")";
return s;
}
static string & add_print_inv(string & s,const gen & feuille,GIAC_CONTEXT){
gen f = feuille;
bool isneg=false;
bool calc38=calc_mode(contextptr)==38;
if (f.is_symb_of_sommet(at_neg) && f._SYMBptr->feuille.type!=_VECT){
f = f._SYMBptr->feuille;
isneg=true;
}
if (f.type<_CPLX && is_positive(-f,contextptr)){
f=-f;
isneg=!isneg;
}
int l=int(s.size());
if (isneg && l && s[l-1]=='-'){
if (l==1)
s.clear();
else
s[l-1]='+';
isneg=false;
}
if (isneg && l && s[l-1]=='+'){
s[l-1]='-';
isneg=false;
}
bool bt=f.type==_SYMB && (f._SYMBptr->sommet==at_plus || f._SYMBptr->sommet==at_inv || f._SYMBptr->sommet==at_prod || need_parenthesis(f._SYMBptr->sommet));
if ( !bt && (f.type!=_CPLX) && (f.type!=_MOD)){
s += (isneg?(calc38?"−1/":"-1/"):"1/");
return add_print(s,f,contextptr);
}
else {
s += (isneg?(calc38?"−1/(":"-1"):"1/(");
add_print(s,f,contextptr);
s += ")";
return s;
}
}
static string & add_print_prod(string & s,const symbolic & g,GIAC_CONTEXT){
gen n0,d0;
if (print_rewrite_prod_inv &&
rewrite_prod_inv(g.feuille,n0,d0)
){
if (n0.type<_CPLX || n0.type==_IDNT){
add_print(s,n0,contextptr);
s += "/";
}
else {
s +="(";
add_print(s,n0,contextptr);
s += ")/";
}
if (d0.type<_CPLX || d0.type==_IDNT)
add_print(s,d0,contextptr); // s += d0.print(contextptr);
else {
s += "(";
add_print(s,d0,contextptr); s += ")"; // s += "("+d0.print(contextptr)+")";
}
return s;
}
if (g.feuille.type!=_VECT)
return add_print(s,g.feuille,contextptr);
vecteur & v = *g.feuille._VECTptr;
int l=int(v.size());
for (int i=0;isommet==at_inv){
gen f(e._SYMBptr->feuille);
if (i){
if ( (f.type==_CPLX) || (f.type==_MOD) ||
((f.type==_SYMB) &&
( (f._SYMBptr->sommet==at_plus) || (f._SYMBptr->sommet==at_prod) || need_parenthesis(f._SYMBptr->sommet) || f._SYMBptr->sommet==at_inv || (f._SYMBptr->sommet==at_pow && f._SYMBptr->feuille[0].is_symb_of_sommet(at_inv))))
){
s += "/(";
add_print(s,f,contextptr);
s += ")"; // s += ("/("+f.print(contextptr) + ")");
}
else {
s += "/";
add_print(s,f,contextptr);
// s += ("/"+f.print(contextptr));
}
}
else
add_print(s,e,contextptr); // s += e.print(contextptr);
} // end if e._SYMBptr->sommet==at_inv
else {
if (i)
s += '*';
if ( e._SYMBptr->sommet==at_plus || e._SYMBptr->sommet==at_neg || is_inequation(e) ){
s += "(";
add_print(s,e,contextptr);
s += ")";
// s += ("("+e.print(contextptr)+")");
}
else
add_print(s,e,contextptr); // s += e.print(contextptr);
}
}
} // end_for
return s;
}
static string & add_print_pow(string & s,const symbolic & g,GIAC_CONTEXT){
if (g.feuille.type!=_VECT || g.feuille._VECTptr->size()!=2)
return add_print(s,g.feuille,contextptr);
gen pui=g.feuille._VECTptr->back();
gen arg=g.feuille._VECTptr->front();
#ifndef GIAC_HAS_STO_38
if (__pow.printsommet==&cprintaspow){
s+="pow(";
add_print(s,arg,contextptr);
s+=",";
add_print(s,pui,contextptr);
s+=')';
return s;
}
#endif
bool argpar = ( (arg.type>_CPLX && arg.type!=_FLOAT_) || !is_positive(arg,contextptr)) && arg.type!=_IDNT ;
#ifdef EMCC
bool need=need_parenthesis(arg) || arg.type==_SYMB;
if (pui==plus_one_half){
s += (need?"√(":"√");
add_print(s,arg,contextptr);
s += (need?")":"");
return s;
}
#endif
if (abs_calc_mode(contextptr)==38){
bool need=need_parenthesis(arg) || arg.type==_SYMB;
if (pui==plus_one_half){
s += (need?"√(":"√");
add_print(s,arg,contextptr);
s += (need?")":"");
return s;
}
if ( pui==minus_one_half || pui==fraction(minus_one,plus_two) ){
s += (need?"1/√(":"1/√");
add_print(s,arg,contextptr);
s += (need?")":"");
return s;
}
if (pui==minus_one){
s += (need?"(":"");
add_print(s,arg,contextptr);
s += (need?")":"");
return s;
// return s += (need?")\xe2\x81\xb2":"\xe2\x81\xb2");
}
#if 0
if (pui==plus_two){
s += (argpar?"(":"");
add_print(s,arg,contextptr);
s += (argpar?")²":"²");
return s;
}
#endif
}
if (pui.type>_REAL && pui==plus_one_half){
s += "sqrt(";
add_print(s,arg,contextptr);
s += ')';
return s;
}
if ( pui.type>_REAL && (pui==minus_one_half || pui==fraction(minus_one,plus_two) )){
s += "1/sqrt(";
add_print(s,arg,contextptr);
s += ')';
return s;
}
if (arg.type==_IDNT || (arg.type==_SYMB && arg._SYMBptr->sommet!=at_neg && (arg._SYMBptr->sommet!=at_exp || calc_mode(contextptr)!=1) && !arg._SYMBptr->sommet.ptr()->printsommet)){
argpar=arg.is_symb_of_sommet(at_inv) || (arg.is_symb_of_sommet(at_exp) && abs_calc_mode(contextptr)==38);
if (argpar) s +='(';
if (pui.type==_SYMB || pui.type==_FRAC || pui.type==_CPLX){
add_print(s,arg,contextptr);
if (argpar) s +=')';
#ifdef GIAC_HAS_STO_38
s += '^';
#else
s += __pow.s;
#endif
s += '(';
add_print(s,pui,contextptr);
s += ')';
return s;
}
else {
add_print(s,arg,contextptr);
if (argpar) s +=')';
#ifdef GIAC_HAS_STO_38
s += '^';
#else
s += __pow.s;
#endif
return add_print(s,pui,contextptr);
}
}
if (argpar)
s += '(';
add_print(s,arg,contextptr);
if (argpar)
s += ')';
#ifdef GIAC_HAS_STO_38
s += '^';
#else
s += __pow.s;
#endif
bool puipar = pui.type==_SYMB || pui.type==_FRAC || pui.type==_CPLX || (pui.type==_VECT && pui.subtype==_SEQ__VECT);
if (puipar)
s += '(';
add_print(s,pui,contextptr);
if (puipar)
s += ')';
return s ;
}
static string & add_print_int(string & s,int i,GIAC_CONTEXT){
char ch[32];
int l=int(s.size());
if (i<0){
if (l && s[l-1]=='+')
s[l-1]='-';
else {
if (l && s[l-1]=='-'){
if (l==1)
s.clear();
else
s[l-1]='+';
}
else
s += (calc_mode(contextptr)==38)?"−":"-"; // add a minus
}
i=-i;
}
switch (integer_format(contextptr)){
case 16:
my_sprintf(ch,"0x%X",i);
case 8:
my_sprintf(ch,"0o%o",i);
default:
my_sprintf(ch,"%d",i);
}
s += ch;
return s;
}
static string & add_print_symbolic(string & s,const symbolic & g,GIAC_CONTEXT){
if (!g.sommet.ptr()){
s+="NULL(";
s+=g.feuille.print();
s+=")";
return s;
}
if ( g.sommet.ptr()->printsommet && g.sommet!=at_plus && g.sommet!=at_prod && g.sommet!=at_pow){
s += g.sommet.ptr()->printsommet(g.feuille,g.sommet.ptr()->s,contextptr);
return s;
}
if ( g.feuille.type==_VECT && g.feuille._VECTptr->empty() ){
s += g.sommet.ptr()->print(contextptr);
s += "(NULL)";
return s;
}
if (g.sommet==at_prod)
return add_print_prod(s,g,contextptr);
if (g.sommet==at_plus)
return add_print_plus(s,g,contextptr);
if (g.sommet==at_pow)
return add_print_pow(s,g,contextptr);
if (g.sommet==at_neg)
return add_print_neg(s,g.feuille,contextptr);
if (g.sommet==at_inv)
return add_print_inv(s,g.feuille,contextptr);
if (g.sommet==at_exp
#ifndef EMCC
&& (calc_mode(contextptr)==1 || abs_calc_mode(contextptr)==38)
#endif
){
s += printasexp(g.feuille,0,contextptr);
return s;
}
if ( g.feuille.type!=_VECT || ( g.sommet!=at_prod && g.feuille._VECTptr->front().type==_VECT ) ){
s += g.sommet.ptr()->print(contextptr);
s += '(';
add_print(s,g.feuille,contextptr);
s += ')';
return s;
}
int l=int(g.feuille._VECTptr->size());
s += g.sommet.ptr()->print(contextptr);
s += '(';
if (g.feuille.subtype!=_SEQ__VECT)
s += begin_VECT_string(g.feuille.subtype,false,contextptr);
for (int i=0;;++i){
add_print(s,(*(g.feuille._VECTptr))[i],contextptr); // s += (*(feuille._VECTptr))[i].print(contextptr);
if (i==l-1){
break;
}
s += ',';
}
if (g.feuille.subtype!=_SEQ__VECT)
s += end_VECT_string(g.feuille.subtype,false,contextptr);
s += ')';
return s;
}
string & add_print(string & s,const gen & g,GIAC_CONTEXT){
if (g.type==_IDNT){
if (calc_mode(contextptr)==1 && (is_inf(g) || is_undef(g)))
s += "?";
else
(s += g._IDNTptr->print(contextptr));
return s;
}
int l=int(s.size());
if (g.type==_INT_ && g.subtype==0)
return add_print_int(s,g.val,contextptr);
if (g.type==_VECT && g.subtype==0){
s += calc_mode(contextptr)==1?'{':'[';
add_printinner_VECT(s,*g._VECTptr,0,contextptr);
s += calc_mode(contextptr)==1?'}':']';
return s;
}
if (g.type==_FRAC && g._FRACptr->num.type==_INT_ && g._FRACptr->den.type==_INT_){
add_print(s,g._FRACptr->num,contextptr);
s += "/";
add_print(s,g._FRACptr->den,contextptr);
return s;
}
if (g.type==_SYMB){
if (g.subtype==_SPREAD__SYMB)
s += "=";
return add_print_symbolic(s,*g._SYMBptr,contextptr);
}
#ifdef EMCC
const string tmp=g.print(contextptr);
#else
const string & tmp=g.print(contextptr);
#endif
// check +- -> - and -- -> +
if (l && s[l-1]=='+' ){
if (!tmp.empty() && tmp[0]=='-'){
s = s.substr(0,l-1);
s += tmp;
return s;
}
if (tmp.size()>3 && (unsigned char)tmp[0]==226 && (unsigned char)tmp[1]==136 && (unsigned char) tmp[2]==146 ) { // -30, -120, -110
s[l-1]='-';
s += tmp.substr(3,tmp.size()-3);
return s;
}
}
if (l && s[l-1]=='-' ){
if (!tmp.empty() && tmp[0]=='-'){
s[l-1]='+';
s += tmp.substr(1,tmp.size()-1);
return s;
}
if (tmp.size()>3 && (unsigned char)tmp[0]==226 && (unsigned char)tmp[1]==136 && (unsigned char) tmp[2]==146 ) { // -30, -120, -110
s[l-1]='+';
s += tmp.substr(3,tmp.size()-3);
return s;
}
}
s += tmp;
return s;
}
string symbolic::print(GIAC_CONTEXT) const{
string s;
add_print_symbolic(s,*this,contextptr);
return s;
}
/* EVAL without system stack */
static void eval_sto_pnt_symb(const gen & feuille,gen & e,GIAC_CONTEXT){
if (e.type==_SYMB && e.ref_count()==1 && e._SYMBptr->feuille.type==_VECT && e._SYMBptr->feuille.ref_count()==1){
vecteur & v=*e._SYMBptr->feuille._VECTptr;
// legende not converted to string to avoid malloc ->faster
v.push_back(feuille._VECTptr->back());
// v=makevecteur(v.front(),v.back(),string2gen(feuille._VECTptr->back().print(contextptr),false));
e._SYMBptr->feuille.subtype=_PNT__VECT;
}
else
e=new_ref_symbolic(symbolic(at_pnt,gen(makevecteur(e._SYMBptr->feuille._VECTptr->front(),e._SYMBptr->feuille._VECTptr->back(),string2gen(feuille._VECTptr->back().print(contextptr),false)),_PNT__VECT)));
e.subtype=gnuplot_show_pnt(*e._SYMBptr,contextptr);
}
static void eval_sto_pnt_vect(const gen & feuilleback,gen & e,GIAC_CONTEXT){
vecteur v=*e._VECTptr;
iterateur it=v.begin(),itend=v.end();
gen legende;
for (int pos=0;it!=itend;++pos,++it){
if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_pnt) && (it->_SYMBptr->feuille._VECTptr->size()==2)){
if (feuilleback.type==_VECT && possize()))
legende=(*feuilleback._VECTptr)[pos];
else
legende=feuilleback;
if (legende.type==_IDNT && abs_calc_mode(contextptr)==38){
// HP: if legende is an IDNT, keep it as legende
// this save alloc (2 alloc instead of 3 alloc + 1 print
*it=new_ref_symbolic(symbolic(at_pnt,gen(makevecteur(it->_SYMBptr->feuille._VECTptr->front(),it->_SYMBptr->feuille._VECTptr->back(),legende),_PNT__VECT)));
}
else {
*it=new_ref_symbolic(symbolic(at_pnt,gen(makevecteur(it->_SYMBptr->feuille._VECTptr->front(),it->_SYMBptr->feuille._VECTptr->back(),string2gen(legende.print(contextptr),false)),_PNT__VECT)));
}
it->subtype=gnuplot_show_pnt(*it->_SYMBptr,contextptr);
}
}
e=gen(v,e.subtype);
}
static gen eval_sto(const gen & feuille,std::vector & last,int level,GIAC_CONTEXT){ // autoname function
// detect vector/matrix addressing with () parsed as function definition
// e.g. M(j,k):=j+k+1 parsed as M:=(j,k)->j+k+1
// these affectations are marked by a subtype==1 by the parser
// if destination is a matrix
if (feuille.type==_VECT && feuille.subtype==_SORTED__VECT && feuille._VECTptr->size()==2 && feuille._VECTptr->front().is_symb_of_sommet(at_program)){
gen prog=feuille._VECTptr->front()._SYMBptr->feuille;
if (prog.type==_VECT && prog._VECTptr->size()==3 && (prog._VECTptr->front()!=_VECT || prog._VECTptr->front()._VECTptr->size()==2)){
gen val=prog._VECTptr->back();
if (feuille._VECTptr->back().type==_IDNT && feuille._VECTptr->back()._IDNTptr->eval(1,feuille._VECTptr->back(),contextptr).type==_VECT){
prog=symbolic(at_of,makesequence(feuille._VECTptr->back(),prog._VECTptr->front()));
return eval_sto(gen(makevecteur(val,prog),_SORTED__VECT),last,level,contextptr);
}
}
}
gen ans;
gen & feuilleback=feuille._VECTptr->back();
vecteur & lastarg=last_evaled_arg(contextptr);
if ( feuilleback.type==_SYMB && (feuilleback._SYMBptr->sommet==at_unquote || feuilleback._SYMBptr->sommet==at_hash ) ){
ans=_sto(feuille.eval(level,contextptr),contextptr);
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
bool b=show_point(contextptr),quotearg=false;
if (b)
show_point(false,contextptr);
gen e=feuille._VECTptr->front();
#ifdef GIAC_HAS_STO_38 // quote STO> E, STO> F, STO>R, STO> X, STO>Y
if (feuilleback.type==_IDNT){
const char * ch = feuilleback._IDNTptr->id_name;
if (strlen(ch)==2 && ch[1]>='0' && ch[1]<='9' && (ch[0]=='E' || ch[0]=='F' || ch[0]=='X' || ch[0]=='Y'))
quotearg=true;
}
#endif
if (!quotearg)
e=e.eval(level,contextptr);
if (b)
show_point(b,contextptr);
if (e.type==_SYMB && e._SYMBptr->sommet==at_pnt && e._SYMBptr->feuille.type==_VECT && e._SYMBptr->feuille._VECTptr->size()==2 && (contextptr?!contextptr->previous:!protection_level) )
eval_sto_pnt_symb(feuille,e,contextptr);
if ( e.type==_VECT && !e._VECTptr->empty() && e._VECTptr->back().type==_SYMB && e._VECTptr->back()._SYMBptr->sommet==at_pnt && (contextptr?!contextptr->previous:!protection_level))
eval_sto_pnt_vect(feuilleback,e,contextptr);
ans=sto(e,feuilleback,contextptr);
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
} // end sommet==at_sto
// http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-34.html#%_sec_5.4
enum {
nr_eval_dispatch=1,
nr_eval_vect=2,
nr_eval_of=18,
nr_eval_op=19, // below this increment destination
nr_eval_prog=21, // above this do not increment destination
nr_eval_sto=22,
nr_eval_local=23,
nr_eval_bloc=24,
nr_eval_if_cond=25,
nr_eval_if_true=26,
nr_eval_if_false=27,
nr_eval_for_init=28,
nr_eval_for_cond=29,
nr_eval_for_loop=30,
nr_eval_for_incr=31,
nr_eval_for_in=32,
nr_eval_catch=34,
};
#define NR_INIT_STACK_SIZE 200
struct nr_pointers_t{
gen * itbeg;
unsigned curpos,endpos;
unsigned arglpos;
gen old;
vecteur argl;
signed char state;
nr_pointers_t(unsigned _arglpos,gen * _itbeg,gen * _it,gen * _itend,gen _old,int argls,signed char _state):itbeg(_itbeg),curpos(unsigned(_it-_itbeg)),endpos(unsigned(_itend-_itbeg)),arglpos(_arglpos),old(_old),argl(argls),state(_state) {};
nr_pointers_t():itbeg(0),curpos(0),endpos(0),arglpos(0),old(0),argl(0),state(0){}
};
inline void fromto_restore(unsigned & arglpos,gen * & itbeg,gen * & it,gen * & itend,gen & old,vecteur & argl,signed char & state,vector & fromto_stack){
vector::iterator ptr=fromto_stack.end()-1;
arglpos=ptr->arglpos;
itbeg=ptr->itbeg;
it=ptr->itbeg+ptr->curpos;
itend=ptr->itbeg+ptr->endpos;
old=ptr->old;
argl.swap(ptr->argl);
state=ptr->state;
fromto_stack.pop_back();
}
struct nr_prog {
context * contextptr;
gen save_debug_info,vars;
bool save_sst_mode;
int protect;
nr_prog(context * _contextptr,const gen & _save_debug_info,const gen & _vars,bool _save_sst_mode,int _protect):contextptr(_contextptr),save_debug_info(_save_debug_info),vars(_vars),save_sst_mode(_save_sst_mode),protect(_protect) {};
nr_prog() : contextptr(0),save_debug_info(0),vars(0),save_sst_mode(false),protect(0) {}
};
// name changed: BESTA compiler see this as repeated code with same sig as passing the itor itself
// - compiler whinges like a wounded pig --
static void increment_instruction_ptr(const gen * it0,const gen * itend,GIAC_CONTEXT){
const gen * it=it0;
for (;it!=itend;++it)
increment_instruction(*it,contextptr);
}
// nr_eval is slower than usual eval because it saves what is usually saved
// on stack on the heap. It does not use stack for recursive calls
// Should be used if we are near the bottom of the stack
gen nr_eval(const gen & g,int level,const context * ct){
context * contextptr=(context *) ct;
gen *itbeg, * it, *itend; // source, begin, current and end of evaluation
gen * destination; // destination of evaluation result
gen res; // the final answer
gen tmp;
unsigned arglpos;
vector fromto_stack; // save/restore destination, source, source end pointers here
fromto_stack.reserve(NR_INIT_STACK_SIZE);
signed char state=nr_eval_dispatch;
gen old=0; // destination
gen progname=undef,label=undef,forlast,lasterr;
vecteur argl(1); // current evaled vecteur
vector nr_prog_stack;
vector nr_eval_for_stack;
nr_prog_stack.reserve(NR_INIT_STACK_SIZE);
gen prog;
itbeg=it=(gen *) &g; itend=it+1; destination=(gen *)&argl.front();
while (1){
#ifndef NO_STDEXCEPT
try {
#endif
if (lasterr.type==_STRNG || (destination->type==_STRNG && destination->subtype==-1)){
// error!
debug_ptr(contextptr)->current_instruction += int(itend-it);
it=itend;
if (lasterr.type!=_STRNG)
lasterr=*destination;
}
if (it!=itend){
if (state>=nr_eval_prog){
if (destination->type==_SYMB && (destination->_SYMBptr->sommet==at_return || destination->_SYMBptr->sommet==at_break || (state!=nr_eval_for_incr && destination->_SYMBptr->sommet==at_continue) ) ){
++it; // do not eval anymore until end of function or loop
++debug_ptr(contextptr)->current_instruction;
continue;
}
// goto
if (!is_undef(label)){
if (it->is_symb_of_sommet(at_label) && label==it->_SYMBptr->feuille){
*destination=*it;
label=undef;
}
++it;
if (it==itend){
debug_ptr(contextptr)->current_instruction -= int(itend-itbeg);
for (it=itbeg;it!=itend;++it){
if (it->is_symb_of_sommet(at_label) && label==it->_SYMBptr->feuille){
*destination=*it;
label=undef;
break;
}
++debug_ptr(contextptr)->current_instruction;
}
}
else
++debug_ptr(contextptr)->current_instruction;
continue;
}
if (state!=nr_eval_if_cond && state!=nr_eval_for_init && state!=nr_eval_for_cond && state!=nr_eval_for_incr && state!=nr_eval_sto){
if (state==nr_eval_for_loop && it==itbeg+3 && it->is_symb_of_sommet(at_bloc))
;
else {
++debug_ptr(contextptr)->current_instruction;
if (debug_ptr(contextptr)->debug_mode){
debug_loop(res,contextptr);
if (is_undef(res)) return res;
}
}
}
}
switch (it->type){
case _VECT:
if (it->subtype==_SPREAD__VECT){
makespreadsheetmatrice(*it->_VECTptr,contextptr);
spread_eval(*it->_VECTptr,contextptr);
*destination=*it;
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
}
if (it->subtype==_FOLDER__VECT || it->subtype==_RGBA__VECT){
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
}
fromto_stack.push_back(nr_pointers_t(unsigned(destination-(gen *) &argl.front()),itbeg,it,itend,old,1,state));
argl.swap(fromto_stack.back().argl);
// vecteur beginning by comment?
tmp=*it;
if (it->subtype==_SEQ__VECT && !it->_VECTptr->empty() && it->_VECTptr->front().type==_SYMB
&& (it->_VECTptr->front()._SYMBptr->sommet==at_comment)
&& (it->_VECTptr->back().is_symb_of_sommet(at_return))
){
itend=(gen *) &it->_VECTptr->back()+1;
it=(gen *) &it->_VECTptr->front();
for (;it!=itend;++it){
if ( (it->type!=_SYMB) || (it->_SYMBptr->sommet!=at_comment) )
break;
}
if (it+1==itend){
*destination=*it;
fromto_restore(arglpos,itbeg,it,itend,old,argl,state,fromto_stack);
destination=(gen *) &argl.front()+arglpos;
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
}
if (it==itend){
*destination=zero;
fromto_restore(arglpos,itbeg,it,itend,old,argl,state,fromto_stack);
destination=(gen *) &argl.front()+arglpos;
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
}
}
else {
itend=(gen *)&it->_VECTptr->back()+1;
it=(gen *)&it->_VECTptr->front();
}
itbeg=it;
old=tmp;
// normal vector evaluation
state=nr_eval_vect;
argl.resize(itend-it);
// vecteur_stack.push_back(argl);
// argl=vecteur(itend-it);
destination=(gen *)&argl.front();
continue;
case _SYMB: {
// special cases
unary_function_ptr & u =it->_SYMBptr->sommet;
gen f=it->_SYMBptr->feuille;
if (u==at_quote){
*destination=quote(f,contextptr);
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
}
if (u==at_program) {
*destination=quote_program(it->_SYMBptr->feuille,contextptr);
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
}
int specop=0;
if (u==at_goto)
label=f;
if (u==at_ifte || u==at_when)
specop=nr_eval_if_cond;
if (u==at_for){
if (state==nr_eval_for_cond){ // for in for_cond is for the syntax for x in l
*destination=*it;
++it;
continue;
}
nr_eval_for_stack.push_back(0); // index for for var in list/string
nr_eval_for_stack.push_back(debug_ptr(contextptr)->current_instruction);
specop=nr_eval_for_init;
}
if (u==at_bloc)
specop=nr_eval_bloc;
if (u==at_local)
specop=nr_eval_local;
if (u==at_sto)
specop=nr_eval_sto;
if (u==at_of)
specop=nr_eval_of;
if (u==at_try_catch)
specop=nr_eval_catch;
if (!specop && u.quoted() && !f.is_symb_of_sommet(at_unquote)){
// check for hash
if (f.is_symb_of_sommet(at_hash) && f._SYMBptr->feuille.type==_STRNG)
f=gen(*f._SYMBptr->feuille._STRNGptr,contextptr);
*destination=u(f,contextptr);
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
}
// save pointers and state, eval args
fromto_stack.push_back(nr_pointers_t(unsigned(destination-(gen *)&argl.front()),itbeg,it,itend,old,1,state));
argl.swap(fromto_stack.back().argl);
state=specop?specop:nr_eval_op;
old=*it;
destination=(gen *)&argl.front();
if ( f.type==_VECT &&
(
(specop==nr_eval_sto && f._VECTptr->size()==2) ||
(specop==nr_eval_if_cond && f._VECTptr->size()>=3) ||
(specop==nr_eval_for_init && f._VECTptr->size()>=3) ||
(specop==nr_eval_catch && f._VECTptr->size()>=3)
) ){
// sto: eval first arg, but not the second arg
// if: eval first arg, but not the second third arg
// for: eval first arg [init]
// try ... catch: eval first arg
itbeg=it=&f._VECTptr->front();
itend=it+1;
continue;
}
if (specop==nr_eval_local){
int protect=0;
gen vars,values;
context * save_contextptr=contextptr;
// Bind local var
prog=f;
vars=prog._VECTptr->front();
if (vars.type==_VECT && vars._VECTptr->size()==2 && vars._VECTptr->front().type!=_IDNT)
vars = vars._VECTptr->front();
if (vars.type!=_VECT)
vars=makevecteur(vars);
values=gen(vecteur(vars._VECTptr->size()));
for (unsigned i=0;isize();++i){
tmp=(*vars._VECTptr)[i];
if (tmp.is_symb_of_sommet(at_sto) || is_equal(tmp)){
(*values._VECTptr)[i]=tmp._SYMBptr->feuille._VECTptr->back();
(*vars._VECTptr)[i]=tmp._SYMBptr->feuille._VECTptr->front().eval(1,contextptr);
}
}
prog=prog._VECTptr->back();
protect=giac::bind(*values._VECTptr,*vars._VECTptr,contextptr);
if (protect==-RAND_MAX){
gensizeerr(res,contextptr);
return res;
}
// save previous state
nr_prog_stack.push_back(nr_prog(save_contextptr,0,vars,false,protect));
if (prog.type==_VECT && prog.subtype==0){
itbeg=it=(gen *)&prog._VECTptr->front();
itend=(gen *)&prog._VECTptr->back()+1;
}
else {
itbeg=it=&prog;
itend=it+1;
}
continue;
}
// if (specop==nr_eval_of || specof==nr_eval_bloc){
// state=specop; // program name is in old, eval args normally
// }
// normal symbolic
if (f.type==_VECT && (f.subtype==_SEQ__VECT || (specop==nr_eval_of || specop==nr_eval_bloc))){
itend=(gen *)&f._VECTptr->back()+1;
itbeg=it=(gen *)&f._VECTptr->front();
argl.resize(itend-it);
destination=(gen *)&argl.front();
}
else {
itbeg=it=&it->_SYMBptr->feuille; // do not use &f here!
itend=it+1;
}
continue;
}
case _IDNT:
tmp=eval(*it,level,contextptr);
if (tmp.type!=_VECT || tmp.subtype!=_SEQ__VECT || (state!=nr_eval_vect && !(state==nr_eval_op && old.type==_SYMB && old._SYMBptr->feuille.type==_VECT)))
*destination=tmp;
else {
// tmp is a sequence inside a vector,
// enlarge argl and copy tmp._VECTptr in argl
int pos=int(destination-(gen *)&argl.front());
for (unsigned i=1;isize();++i)
argl.push_back(0);
destination=(gen *)&argl.front()+pos;
for (unsigned i=0;;){
*destination=(*tmp._VECTptr)[i];
++i;
if (i==tmp._VECTptr->size())
break;
++destination;
}
}
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
default:
*destination=*it;
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
} // end switch on it->type
}
// it==itend
// end eval of current vector
signed char oldsubtype=old.type==_VECT?old.subtype:0;
if (fromto_stack.empty()){
return argl.front(); // end evaluation
}
// dispatch depending on current mode
switch (state){
case nr_eval_dispatch:
continue;
case nr_eval_vect:
// end eval of vecteur, store value in res
if (oldsubtype==_SET__VECT && !argl.empty()){
// remove multiple occurences
islesscomplexthanf_sort(argl.begin(),argl.end());
vecteur tmp;
tmp.reserve(argl.size());
tmp.push_back(argl.front());
for (iterateur jt=argl.begin()+1;jt!=argl.end();++jt){
if (*jt!=tmp.back())
tmp.push_back(*jt);
}
tmp.swap(argl);
res=gen(argl,oldsubtype);
}
else {
// FIXME: make a faster == check (may returns false for large == vecteurs)
if (old.type==_VECT && old._VECTptr->size()<17 && *old._VECTptr==argl)
res=old;
else
res=gen(argl,oldsubtype);
}
// restore previous state, old, pointers and argl
fromto_restore(arglpos,itbeg,it,itend,old,argl,state,fromto_stack);
destination=(gen *)&argl.front()+arglpos;
*destination=res;
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue; // end state==nr_eval_vect
case nr_eval_for_init:
forlast=undef;
++itend;
state=nr_eval_for_cond;
continue;
case nr_eval_for_cond:
res=*destination;
if ( nr_eval_for_stack.size()>=2 && (res.is_symb_of_sommet(at_for) || res.is_symb_of_sommet(at_pour)) && res._SYMBptr->feuille.type==_VECT && res._SYMBptr->feuille._VECTptr->size()==2){
// for var in list/string
res=eval(res._SYMBptr->feuille._VECTptr->back(),1,contextptr);
if (res.type==_VECT){
if (int(res._VECTptr->size())>nr_eval_for_stack[nr_eval_for_stack.size()-2]){
res=res[nr_eval_for_stack[nr_eval_for_stack.size()-2]];
sto(res,destination->_SYMBptr->feuille._VECTptr->front(),contextptr);
res=1;
}
else
res=0;
}
else {
if (res.type==_STRNG){
if (int(res._STRNGptr->size())>nr_eval_for_stack[nr_eval_for_stack.size()-2]){
res=string2gen(string(1,(*res._STRNGptr)[nr_eval_for_stack[nr_eval_for_stack.size()-2]]),false);
sto(res,destination->_SYMBptr->feuille._VECTptr->front(),contextptr);
res=1;
}
else
res=0;
}
else
res=0;
}
++nr_eval_for_stack[nr_eval_for_stack.size()-2];
}
res=equaltosame(res).eval(eval_level(contextptr),contextptr);
if (!is_integer(res)){
res=res.evalf_double(eval_level(contextptr),contextptr);
if ( res.type!=_DOUBLE_ && res.type!=_CPLX ){
if (old._SYMBptr->sommet==at_for){
if (!nr_eval_for_stack.empty()) // pop back instruction and for in index
nr_eval_for_stack.pop_back();
if (!nr_eval_for_stack.empty())
nr_eval_for_stack.pop_back();
fromto_restore(arglpos,itbeg,it,itend,old,argl,state,fromto_stack);
destination=(gen *)&argl.front()+arglpos;
gensizeerr(gettext("For: Unable to check test"),*destination);
res=*destination;
it=itend;
continue;
}
else
res=old;
}
}
if (!is_zero(res)){ // TRUE
it++; itend+=2;
state=nr_eval_for_loop;
}
else {
increment_instruction_ptr(it+1,it+3,contextptr);
if (!nr_eval_for_stack.empty()) // pop back instruction and for in index
nr_eval_for_stack.pop_back();
if (!nr_eval_for_stack.empty())
nr_eval_for_stack.pop_back();
// restore state and pointers
fromto_restore(arglpos,itbeg,it,itend,old,argl,state,fromto_stack);
destination=(gen *)&argl.front()+arglpos;
*destination=forlast;
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
}
continue;
case nr_eval_for_loop:
if (destination->type==_SYMB && (destination->_SYMBptr->sommet==at_break || destination->_SYMBptr->sommet==at_return)){
if (destination->_SYMBptr->sommet==at_break)
*destination=undef;
if (!nr_eval_for_stack.empty()) // pop back instruction and for in index
nr_eval_for_stack.pop_back();
if (!nr_eval_for_stack.empty())
nr_eval_for_stack.pop_back();
state=nr_eval_bloc;
}
else {
it -= 2; --itend;
state=nr_eval_for_incr;
forlast=*destination;
}
continue;
case nr_eval_for_incr:
if (!nr_eval_for_stack.empty())
debug_ptr(contextptr)->current_instruction=nr_eval_for_stack.back();
if (debug_ptr(contextptr)->debug_mode){
debug_loop(res,contextptr);
if (is_undef(res)) return res;
}
state=nr_eval_for_cond;
it -= 2;
itend -= 1;
continue;
case nr_eval_catch:
// catch lasterr, FIXME for debug
state=nr_eval_if_false;
if (lasterr.type==_STRNG){
lasterr.subtype=0;
sto(lasterr,*it,contextptr);
++it;
itend += 2;
lasterr=*destination=res=0;
continue;
}
increment_instruction(*(it+1),contextptr);
if (old._SYMBptr->feuille._VECTptr->size()==4){
it += 2;
itend += 3;
}
continue;
case nr_eval_if_cond:
res=*destination;
res=equaltosame(res).eval(eval_level(contextptr),contextptr);
if (!is_integer(res)){
res=res.evalf_double(eval_level(contextptr),contextptr);
if ( res.type!=_DOUBLE_ && res.type!=_CPLX ){
if (old._SYMBptr->sommet==at_ifte){
fromto_restore(arglpos,itbeg,it,itend,old,argl,state,fromto_stack);
destination=(gen *)&argl.front()+arglpos;
gensizeerr(gettext("Ifte: Unable to check test"),*destination);
res=*destination;
it=itend;
continue;
}
else
res=old;
}
}
if (!is_zero(res)){ // TRUE
state=nr_eval_if_true;
++itend;
}
else { //FALSE
if (old._SYMBptr->sommet==at_ifte){
increment_instruction(*it,contextptr);
}
state=nr_eval_if_false;
++it; itend+=2;
}
continue;
case nr_eval_of:
if (argl.size()==2 && argl.front().is_symb_of_sommet(at_program)){
debug_struct * dbgptr=debug_ptr(contextptr);
int protect=0;
bool save_sst_mode=dbgptr->sst_mode;
gen vars,values;
context * save_contextptr=contextptr;
dbgptr->sst_at_stack.push_back(dbgptr->sst_at);
dbgptr->sst_at.clear();
progname=old._SYMBptr->feuille._VECTptr->front();
if (progname.is_symb_of_sommet(at_program))
progname=undef;
if (progname.type==_IDNT)
adjust_sst_at(progname,contextptr);
dbgptr->current_instruction_stack.push_back(dbgptr->current_instruction);
dbgptr->current_instruction=0;
if (dbgptr->sst_in_mode){
dbgptr->sst_in_mode=false;
dbgptr->sst_mode=true;
}
else
dbgptr->sst_mode=false;
// Bind local var
prog=argl.front()._SYMBptr->feuille;
vars=prog._VECTptr->front();
values=argl[1];
prog=prog._VECTptr->back();
if (vars.type!=_VECT)
vars=gen(makevecteur(vars));
if (values.type!=_VECT || values.subtype!=_SEQ__VECT || (vars._VECTptr->size()==1 && values._VECTptr->size()!=1))
values=gen(makevecteur(values));
// *logptr(contextptr) << vars << " " << values << endl;
// removed sst test so that when a breakpoint is evaled
// the correct info is displayed
(*dbgptr->fast_debug_info_ptr)=prog;
(*dbgptr->debug_info_ptr)=prog;
if (!vars._VECTptr->empty())
protect=giac::bind(*values._VECTptr,*vars._VECTptr,contextptr);
if (protect==-RAND_MAX){
program_leave(*dbgptr->debug_info_ptr,save_sst_mode,dbgptr);
gensizeerr(res,contextptr);
return res;
}
// save previous state
nr_prog_stack.push_back(nr_prog(save_contextptr,*dbgptr->debug_info_ptr,vars,save_sst_mode,protect));
dbgptr->args_stack.push_back(gen(mergevecteur(vecteur(1,progname),*values._VECTptr)));
if (prog.type==_VECT && prog.subtype==0){
itbeg=it=(gen *)&prog._VECTptr->front();
itend=(gen *)&prog._VECTptr->back()+1;
}
else {
itbeg=it=&prog;
itend=it+1;
}
state=nr_eval_prog;
}
else
state=nr_eval_op; // like a goto nr_eval_op: below
continue;
case nr_eval_if_true:
if (old._SYMBptr->sommet==at_ifte)
increment_instruction(*it,contextptr); // no break here
case nr_eval_if_false:
res=*destination; // no break here
case nr_eval_op: case nr_eval_sto:
// eval operator
if (state==nr_eval_sto)
res=sto(*destination,old._SYMBptr->feuille._VECTptr->back(),contextptr);
else {
if (state==nr_eval_op){
if (old._SYMBptr->feuille.type==_VECT && old._SYMBptr->feuille.subtype==_SEQ__VECT)
res=gen(argl,_SEQ__VECT);
else
res=*destination;
res=(*old._SYMBptr->sommet.ptr())(res,contextptr);
}
}
// no break here -> restore
case nr_eval_bloc:
// restore state and pointers
if (state==nr_eval_bloc)
res=*destination;
fromto_restore(arglpos,itbeg,it,itend,old,argl,state,fromto_stack);
destination=(gen *)&argl.front()+arglpos;
*destination=res;
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
case nr_eval_prog: case nr_eval_local:
// end of program reached, restore context
res=*destination;
if (state==nr_eval_prog && res.is_symb_of_sommet(at_return))
res=res._SYMBptr->feuille;
if (!nr_prog_stack.back().vars._VECTptr->empty())
leave(nr_prog_stack.back().protect,*nr_prog_stack.back().vars._VECTptr,contextptr);
if (state==nr_eval_prog)
program_leave(nr_prog_stack.back().save_debug_info,nr_prog_stack.back().save_sst_mode,debug_ptr(contextptr));
contextptr=nr_prog_stack.back().contextptr;
nr_prog_stack.pop_back();
// restore state and pointers
fromto_restore(arglpos,itbeg,it,itend,old,argl,state,fromto_stack);
destination=(gen *)&argl.front()+arglpos;
*destination=res;
++it;
if (it!=itend && state<=nr_eval_op)
++destination;
continue;
default:
gensizeerr(gettext("Bad state"),res);
return res;
} // end switch
#ifndef NO_STDEXCEPT
}
catch (std::runtime_error & e) {
res=string2gen(e.what(),false);
res.subtype=-1;
*destination=res;
}
#endif
} // end while(1)
return argl.front();
}
gen symbolic::eval(int level,const context * contextptr) const {
if (level==0 || !sommet.ptr())
return *this;
gen ans;
// FIXME test should be removed later, it's here for tests. See global.cc DEFAULT_EVAL_LEVEL
int & elevel=eval_level(contextptr);
if (elevel==26)
return nr_eval(*this,level,contextptr);
std::vector & last =last_evaled_function_name(contextptr);
last.push_back(sommet.ptr()->s);
vecteur & lastarg=last_evaled_arg(contextptr);
lastarg.push_back(feuille);
if (sommet==at_sto && feuille.type==_VECT)
return eval_sto(feuille,last,level,contextptr);
if (sommet.quoted()){
#ifndef RTOS_THREADX
if (feuille.type==_SYMB){
unary_function_ptr & u=feuille._SYMBptr->sommet;
if (u==at_unquote){
ans=sommet(feuille.eval(level,contextptr),contextptr);
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
if (u==at_hash){
ans=sommet(gen(*feuille._SYMBptr->feuille._STRNGptr,contextptr),contextptr);
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
}
#endif
int save_level=elevel;
elevel=level;
#ifdef NO_STDEXCEPT
ans=sommet(feuille,contextptr);
#else
try {
ans=sommet(feuille,contextptr);
}
catch (std::runtime_error & err){
elevel=save_level;
throw(err);
}
#endif
elevel=save_level;
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
} // if (sommet.quoted())
else {
// pnt check required because pnt name might be the identifier->recursion
if (sommet==at_pnt && feuille.type==_VECT && feuille._VECTptr->size()==3){
ans=(*sommet.ptr())(gen(vecteur(feuille._VECTptr->begin(),feuille._VECTptr->begin()+2),feuille.subtype).in_eval(level,ans,contextptr)?ans:feuille,contextptr);
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
if ((sommet==at_neg) && (feuille.type==_IDNT) && !strcmp(feuille._IDNTptr->id_name,string_infinity)){
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return minus_inf;
}
if (sommet==at_quote){
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return quote(feuille,contextptr);
}
ans=(*sommet.ptr())(feuille.in_eval(level,ans,contextptr)?ans:feuille,contextptr);
/*
if (feuille.in_eval(level,ans,contextptr))
ans=(*sommet.ptr())(ans,contextptr);
else
ans=(*sommet.ptr())(feuille,contextptr);
*/
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
}
bool rewrite_prod_inv(const gen & arg,gen & n,gen & d){
n=1; d=1;
if (arg.type==_VECT && !arg._VECTptr->empty() && arg._VECTptr->back().is_symb_of_sommet(at_inv)) {
vecteur & uv=*arg._VECTptr;
int tmps=int(uv.size()),invbegin;
vecteur den(1,uv.back()._SYMBptr->feuille);
// group all inv from the end to the beginning for the denominator
for (invbegin=tmps-2;invbegin>=0;--invbegin){
if (!uv[invbegin].is_symb_of_sommet(at_inv))
break;
den.push_back(uv[invbegin]._SYMBptr->feuille);
}
vecteur num;
for (int i=0;i<=invbegin;++i){
if (uv[i].is_symb_of_sommet(at_inv) && uv[i]._SYMBptr->feuille.type<_POLY)
d=d*uv[i]._SYMBptr->feuille;
else
num.push_back(uv[i]);
}
if (!is_one(d))
den.insert(den.begin(),d);
if (den.size()>1)
d=new_ref_symbolic(symbolic(at_prod,den));
else
d=den.front();
if (!num.empty()){
if (num.size()==1)
n=num.front();
else
n=new_ref_symbolic(symbolic(at_prod,num));
}
return true;
}
// Group scalar denominators (warning, do not use for matrices!)
vecteur num,den;
prod2frac(new_ref_symbolic(symbolic(at_prod,arg)),num,den);
if (!den.empty()){
if (num.empty())
n=plus_one;
else {
if (num.size()==1)
n=num.front();
else
n=new_ref_symbolic(symbolic(at_prod,num));
}
/* code that does not work with matrices
if (den.size()==1)
d=den.front();
else
d=ref_symbolic(symbolic(at_prod,den);)
*/
if (den.size()==1 && den.front().type<_IDNT){
d=den.front();
return true;
}
}
return false;
}
gen symbolic::evalf(int level,const context * contextptr) const {
if (level==0)
return *this;
std::vector & last =last_evaled_function_name(contextptr);
last.push_back(sommet.ptr()->s);
vecteur & lastarg=last_evaled_arg(contextptr);
lastarg.push_back(feuille);
if (sommet==at_sto){ // autoname function
gen e=feuille._VECTptr->front().evalf(level,contextptr);
if ((e.type==_SYMB) && (e._SYMBptr->sommet==at_pnt) && (e._SYMBptr->feuille.type==_VECT) && (e._SYMBptr->feuille._VECTptr->size()==2))
e=new_ref_symbolic(symbolic(at_pnt,gen(makevecteur(e._SYMBptr->feuille._VECTptr->front(),e._SYMBptr->feuille._VECTptr->back(),string2gen(feuille._VECTptr->back().print(contextptr),false)),_PNT__VECT)));
if ( (e.type==_VECT) && (e._VECTptr->size()) && (e._VECTptr->back().type==_SYMB) && (e._VECTptr->back()._SYMBptr->sommet==at_pnt)){
vecteur v=*e._VECTptr;
iterateur it=v.begin(),itend=v.end();
for (;it!=itend;++it){
if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_pnt) && (it->_SYMBptr->feuille._VECTptr->size()==2))
*it=new_ref_symbolic(symbolic(at_pnt,gen(makevecteur(it->_SYMBptr->feuille._VECTptr->front(),it->_SYMBptr->feuille._VECTptr->back(),string2gen(feuille._VECTptr->back().print(contextptr),false)),_PNT__VECT)));
}
e=v;
}
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return sto(e,feuille._VECTptr->back(),contextptr);
}
gen ans;
if (sommet==at_plus){
if (feuille.type!=_VECT){
if (feuille.type==_IDNT && !strcmp(feuille._IDNTptr->id_name,string_infinity))
ans=plus_inf;
else
ans=feuille.evalf(level,contextptr);
}
else {
const_iterateur it=feuille._VECTptr->begin(),itend=feuille._VECTptr->end();
for (;it!=itend;++it){
ans=ans+it->evalf(level,contextptr);
}
}
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
if (sommet==at_prod){
if (feuille.type!=_VECT)
ans=feuille.evalf(level,contextptr);
else {
ans=1;
const_iterateur it=feuille._VECTptr->begin(),itend=feuille._VECTptr->end();
for (;it!=itend;++it){
ans=operator_times(ans,it->evalf(level,contextptr),contextptr);
}
}
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
if (sommet.quoted() && sommet!=at_and && !equalposcomp(plot_sommets,sommet) ){
ans=sommet(feuille,contextptr);
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
else {
if ((sommet==at_neg) && (feuille.type==_IDNT) && !strcmp(feuille._IDNTptr->id_name,string_infinity)){
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return minus_inf;
}
if (sommet==at_quote){
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return quote(feuille,contextptr);
}
if (sommet==at_and || (sommet!=at_cercle && equalposcomp(plot_sommets,sommet))){
// bool save_is_inevalf=is_inevalf;
// is_inevalf=true;
ans=new_ref_symbolic(symbolic(sommet,feuille.evalf(1,contextptr)));
// is_inevalf=save_is_inevalf;
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
ans=(*sommet.ptr())(feuille.evalf(level,contextptr),contextptr);
if (!last.empty())
last.pop_back();
if (!lastarg.empty())
lastarg.pop_back();
return ans;
}
}
unsigned taille(const gen & g,unsigned max){
if (g.type<=_IDNT)
return 1;
if (g.type==_FRAC)
return 1+taille(g._FRACptr->num,max)+taille(g._FRACptr->den,max);
if (g.type==_SYMB){
if (g.is_symb_of_sommet(at_curve))
return 10;
return 1+taille(g._SYMBptr->feuille,max);
}
if (g.type==_VECT){
unsigned res=0;
const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
for (;it!=itend;++it){
res += taille(*it,max);
if (max && res>max)
return res;
}
return res;
}
return 2;
}
int print_max_depth=100;
unsigned depth(const gen & g,unsigned add,unsigned max){
gen g_(g);
for (;g_.type==_SYMB;++add){
g_=g_._SYMBptr->feuille;
}
if (add>=max)
return add;
if (g_.type==_VECT){
unsigned res=add;
const_iterateur it=g_._VECTptr->begin(),itend=g_._VECTptr->end();
for (;it!=itend;++it){
unsigned cur=depth(*it,add,max);
if (max && cur>max)
return res;
if (cur>res)
res=cur;
}
return res;
}
return add;
}
#ifdef NSPIRE
template nio::ios_base & operator << (nio::ios_base & os,const symbolic & s) { return os << s.print(context0); }
#else
ostream & operator << (ostream & os,const symbolic & s) { return os << s.print(context0); }
#endif
#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC