This file is not yet operational. Eventually it should record all changes.
-Till then, you are advised to resort to our CVS server where all changes are
+Till then, you are advised to resort to our git server where all changes are
logged. This is how to get anonymous read-only access:
-$ cvs -d :pserver:anoncvs@cvs.ginac.de:/home/cvs/GiNaC login
-enter the password `anoncvs'
-$ cvs -d :pserver:anoncvs@cvs.ginac.de:/home/cvs/GiNaC -z 9 co GiNaC
+$ git clone git://www.ginac.de/ginac.git ginac
+$ cd ginac; git whatchanged
+Alternatively you can browse the repository on-line at
+http://www.ginac.de/ginac.git
- GCC 2.96 or earlier because proper exception and standard library support
is missing there.
-If you install from CVS, you also need GNU autoconf (>=2.59), automake (>=1.7),
+If you install from git, you also need GNU autoconf (>=2.59), automake (>=1.7),
libtool (>= 1.5), bison (>= 2.3), flex (>= 2.5.33), autogen (>= 5.6.0) to be
installed.
make check | ~8m | ~12m | largely due to compilation
-To install from CVS
+To install from git
===================
First, download the code:
-
- $ cvs -d :pserver:anoncvs@cvs.ginac.de:/home/cvs/GiNaC login
- [enter "anoncvs" as the password]
- $ cvs -d :pserver:anoncvs@cvs.ginac.de:/home/cvs/GiNaC co GiNaC
- $ cd GiNaC
+ $ git clone git://www.ginac.de/ginac.git ginac
+ $ cd ginac
Secondly, make sure all required software is installed. This is *really*
important step. If some package is missing, the `configure' script might
dnl future trouble.
dnl ===========================================================================
-dnl Usage: GINAC_RLVERSION
-dnl The maintainers of libreadline are complete morons: they don't care a shit
-dnl about compatiblilty (which is not so bad by itself) and at the same time
-dnl they don't export the version to the preprocessor so we could kluge around
-dnl incomatiblities. The only reliable way to figure out the version is by
-dnl checking the extern variable rl_library_version at runtime. &#@$%*!
-AC_DEFUN([GINAC_LIB_READLINE_VERSION],
-[AC_CACHE_CHECK([for version of libreadline], ginac_cv_rlversion, [
-AC_TRY_RUN([
-#include <stdio.h>
-#include <sys/types.h>
-#include <readline/readline.h>
-
-int main()
-{
- FILE *fd;
- fd = fopen("conftest.out", "w");
- fprintf(fd, "%s\n", rl_library_version);
- fclose(fd);
- return 0;
-}], [
-dnl Some non-GNU readline implementations have non-numeric rl_library_version
-ginac_cv_rlversion=`sed -e 's/[[^0-9.]]//g' 'conftest.out'`], [ ginac_cv_rlversion='unknown'], [ ginac_cv_rlversion='4.2'])])
-if test -z "$ginac_cv_rlversion"; then
- GINAC_WARNING([Unsupported version of libreadline.])
- ginac_cv_rlversion='unknown'
-fi
-if test "x${ginac_cv_rlversion}" != "xunknown"; then
- AC_DEFINE(REALLY_HAVE_LIBREADLINE, ,[Define if GNU libreadline is installed])
- RL_VERSION_MAJOR=`echo ${ginac_cv_rlversion} | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
- AC_DEFINE_UNQUOTED(GINAC_RL_VERSION_MAJOR, $RL_VERSION_MAJOR, [Major version of installed readline library.])
- RL_VERSION_MINOR=`echo ${ginac_cv_rlversion} | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
- AC_DEFINE_UNQUOTED(GINAC_RL_VERSION_MINOR, $RL_VERSION_MINOR, [Minor version of installed readline library.])
-else
- GINAC_WARNING([I could not run a test of libreadline (needed for building ginsh).])
+dnl Usage: GINAC_STD_CXX_HEADERS
+dnl Check for standard C++ headers, bail out if something is missing.
+AC_DEFUN([GINAC_STD_CXX_HEADERS], [
+AC_CACHE_CHECK([for standard C++ header files], [ginac_cv_std_cxx_headers], [
+ ginac_cv_std_cxx_headers="no"
+ AC_LANG_PUSH([C++])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <iosfwd>
+ #include <iostream>
+ #include <vector>
+ #include <list>
+ #include <map>
+ #include <set>
+ #include <string>
+ #include <sstream>
+ #include <typeinfo>
+ #include <stdexcept>
+ #include <algorithm>
+ #include <limits>
+ #include <ctime>
+ ]])], [ginac_cv_std_cxx_headers="yes"])
+ AC_LANG_POP([C++])])
+if test "${ginac_cv_std_cxx_headers}" != "yes"; then
+ AC_MSG_ERROR([Standard ISO C++ 98 headers are missing])
fi
])
+dnl Usage: GINAC_LIBREADLINE
+dnl
+dnl Check if GNU readline library and headers are avialable.
+dnl Defines GINSH_LIBS variable, and HAVE_LIBREADLINE,
+dnl HAVE_READLINE_READLINE_H, HAVE_READLINE_HISTORY_H preprocessor macros.
+dnl
+dnl Note: this macro rejects readline versions <= 4.2 and non-GNU
+dnl implementations.
+dnl
+AC_DEFUN([GINAC_READLINE],[
+AC_REQUIRE([GINAC_TERMCAP])
+GINSH_LIBS=""
+AC_CHECK_HEADERS(readline/readline.h readline/history.h)
+if test "x${ac_cv_header_readline_readline_h}" != "xyes" -o "x${ac_cv_header_readline_history_h}" != "xyes"; then
+ GINAC_WARNING([readline headers could not be found.])
+else
+ AC_CACHE_CHECK([for version of libreadline], [ginac_cv_rl_supported], [
+ ginac_cv_rl_supported="no"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdio.h>
+ #include <readline/readline.h>
+ #if !defined(RL_VERSION_MAJOR) || !defined(RL_VERSION_MINOR)
+ #error "Ancient/unsupported version of readline"
+ #endif]])],
+ [ginac_cv_rl_supported="yes"])])
+ if test "x${ginac_cv_rl_supported}" != "xyes"; then
+ GINAC_WARNING([Unsupported version of readline (<= 4.2 or non-GNU).])
+ else
+ save_LIBS="$LIBS"
+ LIBS="$LIBTERMCAP $LIBS"
+ AC_CHECK_LIB(readline, readline)
+ if test "x${ac_cv_lib_readline_readline}" != "xyes"; then
+ GINAC_WARNING([libreadline could not be found.])
+ fi
+ GINSH_LIBS="$LIBS"
+ LIBS="$save_LIBS"
+ fi
+fi
+AC_SUBST(GINSH_LIBS)])
+
dnl Usage: GINAC_TERMCAP
dnl libreadline is based on the termcap functions.
dnl Some systems have tgetent(), tgetnum(), tgetstr(), tgetflag(), tputs(),
fi
AC_SUBST(CONFIG_RUSAGE)
])
+
+dnl Usage: GINAC_EXCOMPILER
+dnl - Checks if dlopen is available
+dnl - Allows user to disable GiNaC::compile_ex (e.g. for security reasons)
+dnl Defines HAVE_LIBDL preprocessor macro, sets DL_LIBS and CONFIG_EXCOMPILER
+dnl variables.
+AC_DEFUN([GINAC_EXCOMPILER], [
+CONFIG_EXCOMPILER=yes
+DL_LIBS=""
+
+AC_ARG_ENABLE([excompiler],
+ [AS_HELP_STRING([--enable-excompiler], [Enable GiNaC::compile_ex (default: yes)])],
+ [if test "$enableval" = "no"; then
+ CONFIG_EXCOMPILER="no"
+ fi],
+ [CONFIG_EXCOMPILER="yes"])
+
+case $host_os in
+ *mingw32*)
+ CONFIG_EXCOMPILER="notsupported"
+ ;;
+ *)
+ ;;
+esac
+
+if test "$CONFIG_EXCOMPILER" = "yes"; then
+ AC_CHECK_LIB(dl, dlopen, [
+ DL_LIBS="-ldl"
+ AC_DEFINE(HAVE_LIBDL, 1, [set to 1 if you have a working libdl installed.])],
+
+ [AC_MSG_WARN([libdl not found. GiNaC::compile_ex will be disabled.])
+ CONFIG_EXCOMPILER="no"])
+elif test "$CONFIG_EXCOMPILER" = "no"; then
+ AC_MSG_RESULT([INFO: GiNaC::compile_ex disabled at user request.])
+else
+ AC_MSG_RESULT([INFO: GiNaC::compile_ex is not supported on $host_os.])
+fi
+AC_SUBST(DL_LIBS)
+AC_SUBST(CONFIG_EXCOMPILER)])
+
AC_INIT([GiNaC], ginac_version, [<ginac-list@ginac.de>])
AC_PREREQ(2.59)
AC_CONFIG_SRCDIR(ginac/basic.cpp)
-AC_CONFIG_HEADERS(config.h)
+AC_CONFIG_AUX_DIR([config])
+AC_CONFIG_HEADERS([config/config.h])
dnl This defines PACKAGE and VERSION.
AM_INIT_AUTOMAKE([gnu 1.7 dist-bzip2])
AM_PROG_LEX
AC_PROG_YACC
-dnl Check for data types which are needed by the hash function
-dnl (golden_ratio_hash).
-AC_CHECK_SIZEOF(int)
-AC_CHECK_SIZEOF(long)
-AC_CHECK_SIZEOF(long long)
-AC_CHECK_SIZEOF(long double)
-AC_CHECK_SIZEOF(void *)
dnl Switch to C++ language mode for the following libraries and headers.
AC_LANG([C++])
-dnl Check for stuff needed for building the GiNaC interactive shell (ginsh).
-AC_CHECK_HEADERS(unistd.h)
-GINAC_HAVE_RUSAGE
-AC_CHECK_HEADERS(readline/readline.h readline/history.h)
-if test "x${ac_cv_header_readline_readline_h}" != "xyes" -o "x${ac_cv_header_readline_history_h}" != "xyes"; then
- GINAC_WARNING([I could not find the headers for libreadline (needed for building ginsh).])
-fi
-GINAC_TERMCAP
-save_LIBS=$LIBS
-LIBS="$LIBTERMCAP $LIBS"
-AC_CHECK_LIB(readline, readline)
-if test "x${ac_cv_lib_readline_readline}" = "xyes"; then
- GINAC_LIB_READLINE_VERSION
-else
- GINAC_WARNING([I could not find libreadline (needed by ginsh).])
-fi
-GINSH_LIBS=$LIBS
-LIBS=$save_LIBS
-AC_SUBST(GINSH_LIBS)
-
dnl Make sure all the necessary standard headers are installed on the system.
-AC_CHECK_HEADER(iosfwd, , GINAC_ERROR([The standard <iosfwd> header file could not be found.]))
-AC_CHECK_HEADER(iostream, , GINAC_ERROR([The standard <iostream> header file could not be found.]))
-AC_CHECK_HEADER(vector, , GINAC_ERROR([The standard <vector> header file could not be found.]))
-AC_CHECK_HEADER(list, , GINAC_ERROR([The standard <list> header file could not be found.]))
-AC_CHECK_HEADER(map, , GINAC_ERROR([The standard <map> header file could not be found.]))
-AC_CHECK_HEADER(string, , GINAC_ERROR([The standard <string> header file could not be found.]))
-AC_CHECK_HEADER(sstream, , GINAC_ERROR([The standard <sstream> header file could not be found.]))
-AC_CHECK_HEADER(typeinfo, , GINAC_ERROR([The standard <typeinfo> header file could not be found.]))
-AC_CHECK_HEADER(stdexcept, , GINAC_ERROR([The standard <stdexcept> header file could not be found.]))
-AC_CHECK_HEADER(algorithm, , GINAC_ERROR([The standard <algorithm> header file could not be found.]))
-AC_CHECK_HEADER(limits, , GINAC_ERROR([The standard <limits> header file could not be found.]))
-if test "x$CONFIG_RUSAGE" = "xno"; then
- AC_CHECK_HEADER(ctime, , GINAC_ERROR([The standard <ctime> header file could not be found.]))
-fi
-
-DL_LIBS=""
-dnl Check for dl library (needed for GiNaC::compile).
-AC_CHECK_LIB(dl, dlopen,
- [
- DL_LIBS="-ldl"
- AC_DEFINE(HAVE_LIBDL, 1, [set to 1 if you have a working libdl installed.])
- ],
- GINAC_WARNING([libdl not found. GiNaC::compile will be disabled.]))
-AC_SUBST(DL_LIBS)
+GINAC_STD_CXX_HEADERS
dnl We need to have Bruno Haible's CLN installed.
dnl (pkg-config must have installed pkg.m4 at a visible place, which provides
LIBS="$LIBS $CLN_LIBS"
CPPFLAGS="$CPPFLAGS $CLN_CFLAGS"
+dnl Check for data types which are needed by the hash function
+dnl (golden_ratio_hash).
+AC_CHECK_TYPE(long long)
+
+dnl Check for stuff needed for building the GiNaC interactive shell (ginsh).
+AC_CHECK_HEADERS(unistd.h)
+GINAC_HAVE_RUSAGE
+GINAC_READLINE
+
+dnl Check for dl library (needed for GiNaC::compile).
+GINAC_EXCOMPILER
+
dnl Check for utilities needed by the different kinds of documentation.
dnl Documentation needs only be built when extending it, so never mind if it
dnl cannot find those helpers:
info_TEXINFOS = $(TEXI)
-TXT = $(addsuffix .txt, $(basename $(TEXI)))
-HTML = $(addsuffix .html, $(basename $(TEXI)))
+TXT = ginac-examples.txt
+HTML = ginac-examples.html
all: $(EXFILES)
${MAKEINFO} --no-split --no-headers $(srcdir)/$(TEXI) > $(TXT)
if CONFIG_FIG2DEV
# Graphics file conversion
-PNG = $(addsuffix .png, $(basename $(FIG)))
-EPS = $(addsuffix .eps, $(basename $(FIG)))
-PDF = $(addsuffix .pdf, $(basename $(FIG)))
+PNG = classhierarchy.png repnaive.png reppair.png repreal.png
+EPS = classhierarchy.eps repnaive.eps reppair.eps repreal.eps
+PDF = classhierarchy.pdf repnaive.pdf reppair.pdf repreal.pdf
SUFFIXES = .fig .png .eps
warning levels. If omitted, it defaults to @option{-g
-O2}.@footnote{The @command{configure} script is itself generated from
the file @file{configure.ac}. It is only distributed in packaged
-releases of GiNaC. If you got the naked sources, e.g. from CVS, you
+releases of GiNaC. If you got the naked sources, e.g. from git, you
must generate @command{configure} along with the various
@file{Makefile.in} by using the @command{autoreconf} utility. This will
require a fair amount of support from your local toolchain, though.}
and @code{false} if it doesn't. If used in the second form, the actual
subexpressions matched by the wildcards get returned in the @code{repls}
object as a list of relations of the form @samp{wildcard == expression}.
-If @code{match()} returns false, the state of @code{repls} is undefined.
-For reproducible results, the list should be empty when passed to
-@code{match()}, but it is also possible to find similarities in multiple
-expressions by passing in the result of a previous match.
+If @code{match()} returns false, @code{repls} remains unmodified.
The matching algorithm works as follows:
if (!match_same_type(ex_to<basic>(pattern)))
return false;
+ // Even if the expression does not match the pattern, some of
+ // its subexpressions could match it. For example, x^5*y^(-1)
+ // does not match the pattern $0^5, but its subexpression x^5
+ // does. So, save repl_lst in order to not add bogus entries.
+ lst tmp_repl = repl_lst;
// Otherwise the subexpressions must match one-to-one
for (size_t i=0; i<nops(); i++)
- if (!op(i).match(pattern.op(i), repl_lst))
+ if (!op(i).match(pattern.op(i), tmp_repl))
return false;
// Looks similar enough, match found
+ repl_lst = tmp_repl;
return true;
}
}
std::vector<function_options> & function::registered_functions()
{
- static std::vector<function_options> * rf = new std::vector<function_options>;
- return *rf;
+ static std::vector<function_options> rf = std::vector<function_options>();
+ return rf;
}
bool function::lookup_remember_table(ex & result) const
// parameters and data for [Cra] algorithm
const cln::cl_N lambda = cln::cl_N("319/320");
-int L1;
-int L2;
-std::vector<std::vector<cln::cl_N> > f_kj;
-std::vector<cln::cl_N> crB;
-std::vector<std::vector<cln::cl_N> > crG;
-std::vector<cln::cl_N> crX;
-
void halfcyclic_convolute(const std::vector<cln::cl_N>& a, const std::vector<cln::cl_N>& b, std::vector<cln::cl_N>& c)
{
// [Cra] section 4
-void initcX(const std::vector<int>& s)
+static void initcX(std::vector<cln::cl_N>& crX,
+ const std::vector<int>& s,
+ const int L2)
{
- const int k = s.size();
-
- crX.clear();
- crG.clear();
- crB.clear();
-
- for (int i=0; i<=L2; i++) {
- crB.push_back(bernoulli(i).to_cl_N() / cln::factorial(i));
- }
+ std::vector<cln::cl_N> crB(L2 + 1);
+ for (int i=0; i<=L2; i++)
+ crB[i] = bernoulli(i).to_cl_N() / cln::factorial(i);
int Sm = 0;
int Smp1 = 0;
- for (int m=0; m<k-1; m++) {
- std::vector<cln::cl_N> crGbuf;
- Sm = Sm + s[m];
+ std::vector<std::vector<cln::cl_N> > crG(s.size() - 1, std::vector<cln::cl_N>(L2 + 1));
+ for (int m=0; m < s.size() - 1; m++) {
+ Sm += s[m];
Smp1 = Sm + s[m+1];
- for (int i=0; i<=L2; i++) {
- crGbuf.push_back(cln::factorial(i + Sm - m - 2) / cln::factorial(i + Smp1 - m - 2));
- }
- crG.push_back(crGbuf);
+ for (int i = 0; i <= L2; i++)
+ crG[m][i] = cln::factorial(i + Sm - m - 2) / cln::factorial(i + Smp1 - m - 2);
}
crX = crB;
- for (int m=0; m<k-1; m++) {
- std::vector<cln::cl_N> Xbuf;
- for (int i=0; i<=L2; i++) {
- Xbuf.push_back(crX[i] * crG[m][i]);
- }
+ for (std::size_t m = 0; m < s.size() - 1; m++) {
+ std::vector<cln::cl_N> Xbuf(L2 + 1);
+ for (int i = 0; i <= L2; i++)
+ Xbuf[i] = crX[i] * crG[m][i];
+
halfcyclic_convolute(Xbuf, crB, crX);
}
}
// [Cra] section 4
-cln::cl_N crandall_Y_loop(const cln::cl_N& Sqk)
+static cln::cl_N crandall_Y_loop(const cln::cl_N& Sqk,
+ const std::vector<cln::cl_N>& crX)
{
cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
cln::cl_N factor = cln::expt(lambda, Sqk);
// [Cra] section 4
-void calc_f(int maxr)
+static void calc_f(std::vector<std::vector<cln::cl_N> >& f_kj,
+ const int maxr, const int L1)
{
- f_kj.clear();
- f_kj.resize(L1);
-
cln::cl_N t0, t1, t2, t3, t4;
int i, j, k;
std::vector<std::vector<cln::cl_N> >::iterator it = f_kj.begin();
// [Cra] (3.1)
-cln::cl_N crandall_Z(const std::vector<int>& s)
+static cln::cl_N crandall_Z(const std::vector<int>& s,
+ const std::vector<std::vector<cln::cl_N> >& f_kj)
{
const int j = s.size();
std::vector<int> r = s;
const int j = r.size();
+ std::size_t L1;
+
// decide on maximal size of f_kj for crandall_Z
if (Digits < 50) {
L1 = 150;
L1 = Digits * 3 + j*2;
}
+ std::size_t L2;
// decide on maximal size of crX for crandall_Y
if (Digits < 38) {
L2 = 63;
}
}
- calc_f(maxr);
+ std::vector<std::vector<cln::cl_N> > f_kj(L1);
+ calc_f(f_kj, maxr, L1);
const cln::cl_N r0factorial = cln::factorial(r[0]-1);
Srun -= skp1buf;
r.pop_back();
- initcX(r);
+ std::vector<cln::cl_N> crX;
+ initcX(crX, r, L2);
for (int q=0; q<skp1buf; q++) {
- cln::cl_N pp1 = crandall_Y_loop(Srun+q-k);
- cln::cl_N pp2 = crandall_Z(rz);
+ cln::cl_N pp1 = crandall_Y_loop(Srun+q-k, crX);
+ cln::cl_N pp2 = crandall_Z(rz, f_kj);
rz.front()--;
}
rz.insert(rz.begin(), r.back());
- initcX(rz);
+ std::vector<cln::cl_N> crX;
+ initcX(crX, rz, L2);
- res = (res + crandall_Y_loop(S-j)) / r0factorial + crandall_Z(rz);
+ res = (res + crandall_Y_loop(S-j, crX)) / r0factorial
+ + crandall_Z(rz, f_kj);
return res;
}
throw exception(err.str()); \
} while (0)
+#define Parse_error_(message) \
+do { \
+ std::ostringstream err; \
+ err << "GiNaC: parse error at line " << scanner->line_num << \
+ ", column " << scanner->column << ": "; \
+ err << message << std::endl; \
+ err << '[' << __PRETTY_FUNCTION__ << "(" << __FILE__ << ':' << __LINE__ << ")]" << std::endl; \
+ throw parse_error(err.str(), scanner->line_num, scanner->column); \
+} while (0)
+
+#define Parse_error(message) \
+ Parse_error_(message << ", got: " << scanner->tok2str(token))
+
#define bug(message) bail_out(std::logic_error, message)
#define dout(condition, message) \
input = in;
line_num = 0;
column = 0;
+ c = ' ';
+}
+
+/// Symbolic name of current token (for error reporting)
+std::string lexer::tok2str(const int tok) const
+{
+ switch (tok) {
+ case lexer::token_type::identifier:
+ case lexer::token_type::number:
+ return std::string("\"") + str + "\"";
+ case lexer::token_type::eof:
+ return std::string("EOF");
+ default:
+ return std::string("\"") + char(tok) + "\"";
+ }
}
} // namespace GiNaC
};
};
+
+ /// Symbolic name of the token (for error reporting)
+ std::string tok2str(const int tok) const;
};
} // namespace GiNaC
break;
if (token != ',')
- throw std::invalid_argument("Expected ')' or ',' in argument list");
+ Parse_error("expected ')' or ',' in argument list");
get_next_tok();
}
prototype the_prototype = make_pair(name, args.size());
prototype_table::const_iterator reader = funcs.find(the_prototype);
if (reader == funcs.end()) {
- bail_out(std::invalid_argument,
- "no function \"" << name << "\" with " << args.size()
- << " arguments");
+ Parse_error_("no function \"" << name << "\" with " <<
+ args.size() << " arguments");
}
ex ret = reader->second(args);
return ret;
ex e = parse_expression();
if (token != ')')
- throw std::invalid_argument("parser::parse_paren_expr: expected ')'");
+ Parse_error("expected ')'");
get_next_tok(); // eat ).
return e;
}
case '+':
return v;
default:
- throw std::invalid_argument(
- std::string(__func__)
- + ": invalid unary operator \""
- + char(s) + "\"");
+ Parse_error_("invalid unary operator \"" << char(s) << "\"");
}
}
case lexer::token_type::literal:
return parse_literal_expr();
case lexer::token_type::eof:
- bail_out(std::invalid_argument, "got EOF while parsing the expression");
default:
- bail_out(std::invalid_argument, "unknown token " <<
- token << " (\"" <<
- (token ? std::string("") + char(token) : "NULL")
- << "\")");
+ Parse_error("unexpected token");
}
}
class lexer;
+class parse_error : public std::invalid_argument
+{
+public:
+ const std::size_t line;
+ const std::size_t column;
+ parse_error(const std::string& what_,
+ const std::size_t line_ = 0,
+ const std::size_t column_ = 0) throw () :
+ std::invalid_argument(what_), line(line_), column(column_)
+ { }
+};
+
/**
* Recursive descent parser for GiNaC expressions.
*/
std::vector<remember_table> & remember_table::remember_tables()
{
- static std::vector<remember_table> * rt = new std::vector<remember_table>;
- return *rt;
+ static std::vector<remember_table> rt = std::vector<remember_table>();
+ return rt;
}
} // namespace GiNaC
// symbol
symbol::symbol()
- : inherited(&symbol::tinfo_static), asexinfop(new assigned_ex_info), serial(next_serial++), name(autoname_prefix() + ToString(serial)), TeX_name(name), domain(domain::complex), ret_type(return_types::commutative), ret_type_tinfo(&symbol::tinfo_static)
+ : inherited(&symbol::tinfo_static), serial(next_serial++), name(autoname_prefix() + ToString(serial)), TeX_name(name), domain(domain::complex), ret_type(return_types::commutative), ret_type_tinfo(&symbol::tinfo_static)
{
setflag(status_flags::evaluated | status_flags::expanded);
}
// symbol
symbol::symbol(const std::string & initname, unsigned domain)
- : inherited(&symbol::tinfo_static), asexinfop(new assigned_ex_info), serial(next_serial++), name(initname), TeX_name(default_TeX_name()), domain(domain), ret_type(return_types::commutative), ret_type_tinfo(&symbol::tinfo_static)
+ : inherited(&symbol::tinfo_static), serial(next_serial++), name(initname), TeX_name(default_TeX_name()), domain(domain), ret_type(return_types::commutative), ret_type_tinfo(&symbol::tinfo_static)
{
setflag(status_flags::evaluated | status_flags::expanded);
}
symbol::symbol(const std::string & initname, unsigned rt, tinfo_t rtt, unsigned domain)
- : inherited(&symbol::tinfo_static), asexinfop(new assigned_ex_info), serial(next_serial++), name(initname), TeX_name(default_TeX_name()), domain(domain), ret_type(rt), ret_type_tinfo(rtt)
+ : inherited(&symbol::tinfo_static), serial(next_serial++), name(initname), TeX_name(default_TeX_name()), domain(domain), ret_type(rt), ret_type_tinfo(rtt)
{
setflag(status_flags::evaluated | status_flags::expanded);
}
symbol::symbol(const std::string & initname, const std::string & texname, unsigned domain)
- : inherited(&symbol::tinfo_static), asexinfop(new assigned_ex_info), serial(next_serial++), name(initname), TeX_name(texname), domain(domain), ret_type(return_types::commutative), ret_type_tinfo(&symbol::tinfo_static)
+ : inherited(&symbol::tinfo_static), serial(next_serial++), name(initname), TeX_name(texname), domain(domain), ret_type(return_types::commutative), ret_type_tinfo(&symbol::tinfo_static)
{
setflag(status_flags::evaluated | status_flags::expanded);
}
symbol::symbol(const std::string & initname, const std::string & texname, unsigned rt, tinfo_t rtt, unsigned domain)
- : inherited(&symbol::tinfo_static), asexinfop(new assigned_ex_info), serial(next_serial++), name(initname), TeX_name(texname), domain(domain), ret_type(rt), ret_type_tinfo(rtt)
+ : inherited(&symbol::tinfo_static), serial(next_serial++), name(initname), TeX_name(texname), domain(domain), ret_type(rt), ret_type_tinfo(rtt)
{
setflag(status_flags::evaluated | status_flags::expanded);
}
/** Construct object from archive_node. */
symbol::symbol(const archive_node &n, lst &sym_lst)
- : inherited(n, sym_lst), asexinfop(new assigned_ex_info), serial(next_serial++)
+ : inherited(n, sym_lst), serial(next_serial++)
{
if (!n.find_string("name", name))
name = autoname_prefix() + ToString(serial);
return inherited::info(inf);
}
-ex symbol::eval(int level) const
-{
- if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
-
- if (asexinfop->is_assigned) {
- setflag(status_flags::evaluated);
- if (level==1)
- return (asexinfop->assigned_expression);
- else
- return (asexinfop->assigned_expression).eval(level);
- } else {
- return this->hold();
- }
-}
-
ex symbol::conjugate() const
{
if (this->domain == domain::complex) {
// non-virtual functions in this class
//////////
-// public
-
-void symbol::assign(const ex & value)
-{
- asexinfop->is_assigned = true;
- asexinfop->assigned_expression = value;
- clearflag(status_flags::evaluated | status_flags::expanded);
-}
-
-void symbol::unassign()
-{
- if (asexinfop->is_assigned) {
- asexinfop->is_assigned = false;
- asexinfop->assigned_expression = _ex0;
- }
- setflag(status_flags::evaluated | status_flags::expanded);
-}
-
// private
/** Symbols not constructed with a string get one assigned using this
* prefix and a number. */
-std::string & symbol::autoname_prefix()
+std::string& symbol::autoname_prefix()
{
- static std::string *s = new std::string("symbol");
- return *s;
+ static std::string s("symbol");
+ return s;
}
/** Return default TeX name for symbol. This recognizes some greek letters. */
unsigned symbol::next_serial = 0;
-//////////
-// subclass assigned_ex_info
-//////////
-
-/** Default ctor. Defaults to unassigned. */
-symbol::assigned_ex_info::assigned_ex_info() throw() : is_assigned(false)
-{
-}
-
} // namespace GiNaC
namespace GiNaC {
/** Basic CAS symbol. It has a name because it must know how to output itself.
- * It may be assigned an expression, but this feature is only intended for
- * programs like 'ginsh' that want to associate symbols with expressions.
- * If you want to replace symbols by expressions in your code, you should
- * use ex::subs() or use objects of class ex instead of class symbol in the
- * first place. */
+ */
class symbol : public basic
{
GINAC_DECLARE_REGISTERED_CLASS(symbol, basic)
friend class realsymbol;
friend class possymbol;
-// types
-
- /** Symbols as keys to expressions - only for ginsh. */
- class assigned_ex_info : public refcounted {
- public:
- assigned_ex_info() throw(); ///< Default ctor
- bool is_assigned; ///< True if there is an expression assigned
- ex assigned_expression; ///< The actual expression
- };
-
// member functions
// other constructors
// functions overriding virtual functions from base classes
public:
bool info(unsigned inf) const;
- ex eval(int level = 0) const;
+ ex eval(int level = 0) const { return *this; } // for performance reasons
ex evalf(int level = 0) const { return *this; } // overwrites basic::evalf() for performance reasons
ex series(const relational & s, int order, unsigned options = 0) const;
ex subs(const exmap & m, unsigned options = 0) const { return subs_one_level(m, options); } // overwrites basic::subs() for performance reasons
// non-virtual functions in this class
public:
- void assign(const ex & value);
- void unassign();
void set_name(const std::string & n) { name = n; }
std::string get_name() const { return name; }
unsigned get_domain() const { return domain; }
// member variables
protected:
- ptr<assigned_ex_info> asexinfop; ///< assigned expression, only for private use by ginsh
unsigned serial; ///< unique serial number for comparison
std::string name; ///< printname of this symbol
std::string TeX_name; ///< LaTeX name of this symbol
return domain == domain::positive;
}
-// wrapper functions around member functions
-inline void unassign(symbol & symarg)
-{ symarg.unassign(); }
-
} // namespace GiNaC
#endif // ndef __GINAC_SYMBOL_H__
library_init::~library_init()
{
if (--count==0) {
- // In theory, we would have to clean up here. But since we were
- // only initializing memory in the ctor and that memory is reclaimed
- // anyways by the OS when the program exits, we skip this.
+ // It's really necessary to clean up, since the program
+ // lifetime might not be the same as libginac.{so,dll} one
+ // (e.g. consider // dlopen/dlsym/dlclose sequence).
+ delete _num120_p;
+ delete _num_120_p;
+ delete _num60_p;
+ delete _num_60_p;
+ delete _num48_p;
+ delete _num_48_p;
+ delete _num30_p;
+ delete _num_30_p;
+ delete _num25_p;
+ delete _num_25_p;
+ delete _num24_p;
+ delete _num_24_p;
+ delete _num20_p;
+ delete _num_20_p;
+ delete _num18_p;
+ delete _num_18_p;
+ delete _num15_p;
+ delete _num_15_p;
+ delete _num12_p;
+ delete _num_12_p;
+ delete _num11_p;
+ delete _num_11_p;
+ delete _num10_p;
+ delete _num_10_p;
+ delete _num9_p;
+ delete _num_9_p;
+ delete _num8_p;
+ delete _num_8_p;
+ delete _num7_p;
+ delete _num_7_p;
+ delete _num6_p;
+ delete _num_6_p;
+ delete _num5_p;
+ delete _num_5_p;
+ delete _num4_p;
+ delete _num_4_p;
+ delete _num3_p;
+ delete _num_3_p;
+ delete _num2_p;
+ delete _num_2_p;
+ delete _num1_p;
+ delete _num_1_p;
+ delete _num1_2_p;
+ delete _num_1_2_p;
+ delete _num1_3_p;
+ delete _num_1_3_p;
+ delete _num1_4_p;
+ delete _num_1_4_p;
+ delete _num0_p;
}
}
#ifndef __GINAC_UTILS_H__
#define __GINAC_UTILS_H__
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include <string>
#include <functional>
+#ifdef HAVE_STDINT_H
+#include <stdint.h> // for uintptr_t
+#endif
#include "assertion.h"
return 0;
}
-#if SIZEOF_VOID_P == SIZEOF_INT
-typedef unsigned int p_int;
-#elif SIZEOF_VOID_P == SIZEOF_LONG
-typedef unsigned long p_int;
-#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG
-typedef unsigned long long p_int;
+#ifdef HAVE_STDINT_H
+typedef uintptr_t p_int;
#else
typedef unsigned long p_int;
#endif
{
// This function works much better when fast arithmetic with at
// least 64 significant bits is available.
-#if SIZEOF_LONG >= 8
+ if (sizeof(long) >= 8) {
// So 'long' has 64 bits. Excellent! We prefer it because it might be
// more efficient than 'long long'.
unsigned long l = n * 0x4f1bbcddUL;
return (unsigned)l;
-#elif SIZEOF_LONG_LONG >= 8
+ }
+#ifdef HAVE_LONG_LONG
+ else if (sizeof(long long) >= 8) {
// This requires 'long long' (or an equivalent 64 bit type)---which is,
// unfortunately, not ANSI-C++-compliant.
// (Yet C99 demands it, which is reason for hope.)
unsigned long long l = n * 0x4f1bbcddULL;
return (unsigned)l;
-#else
+ }
+#endif
// Without a type with 64 significant bits do the multiplication manually
// by splitting n up into the lower and upper two bytes.
const unsigned n0 = (n & 0x0000ffffU);
const unsigned n1 = (n & 0xffff0000U) >> 16;
return (n0 * 0x0000bcddU) + ((n1 * 0x0000bcddU + n0 * 0x00004f1bU) << 16);
-#endif
}
/* Compute the sign of a permutation of a container, with and without an
.BI transpose( matrix )
\- transpose of a matrix
.br
-.BI unassign( symbol )
-\- unassign an assigned symbol
+.BI unassign( 'symbol' )
+\- unassign an assigned symbol (mind the quotes, please!)
.br
.BI unit( expression ", " symbol )
\- unit part of a polynomial
#define YYERROR_VERBOSE 1
-#ifdef REALLY_HAVE_LIBREADLINE
+#ifdef HAVE_LIBREADLINE
// Original readline settings
static int orig_completion_append_character;
-#if (GINAC_RL_VERSION_MAJOR < 4) || (GINAC_RL_VERSION_MAJOR == 4 && GINAC_RL_VERSION_MINOR < 2)
-static char *orig_basic_word_break_characters;
-#else
static const char *orig_basic_word_break_characters;
-#endif
-#if (GINAC_RL_VERSION_MAJOR >= 5)
+#if (RL_VERSION_MAJOR >= 5)
#define GINAC_RL_COMPLETER_CAST(a) const_cast<char *>((a))
#else
#define GINAC_RL_COMPLETER_CAST(a) (a)
#endif
-#endif // REALLY_HAVE_LIBREADLINE
+#endif // HAVE_LIBREADLINE
// Expression stack for %, %% and %%%
static void push(const ex &e);
static ex exstack[3];
+// Assigned symbols
+static exmap assigned_symbol_table;
// Start and end time for the time() function
#ifdef HAVE_RUSAGE
;
exp : T_NUMBER {$$ = $1;}
- | T_SYMBOL {$$ = $1.eval();}
+ | T_SYMBOL {
+ exmap::const_iterator i = assigned_symbol_table.find($1);
+ if (i == assigned_symbol_table.end())
+ $$ = $1;
+ else
+ $$ = i->second.eval();
+ }
| '\'' T_SYMBOL '\'' {$$ = $2;}
| T_LITERAL {$$ = $1;}
| T_DIGITS {$$ = $1;}
}
}
| T_DIGITS '=' T_NUMBER {$$ = $3; Digits = ex_to<numeric>($3).to_int();}
- | T_SYMBOL '=' exp {$$ = $3; const_cast<symbol&>(ex_to<symbol>($1)).assign($3);}
+ | T_SYMBOL '=' exp {$$ = $3; assigned_symbol_table[$1] = $3; }
| exp T_EQUAL exp {$$ = $1 == $3;}
| exp T_NOTEQ exp {$$ = $1 != $3;}
| exp '<' exp {$$ = $1 < $3;}
static ex f_unassign(const exprseq &e)
{
CHECK_ARG(0, symbol, unassign);
- const_cast<symbol&>(ex_to<symbol>(e[0])).unassign();
+ exmap::iterator i = assigned_symbol_table.find(e[0]);
+ if (i != assigned_symbol_table.end())
+ assigned_symbol_table.erase(i);
return e[0];
}
return NULL;
}
-#ifdef REALLY_HAVE_LIBREADLINE
+#ifdef HAVE_LIBREADLINE
static char **fcn_completion(const char *text, int start, int end)
{
if (rl_line_buffer[0] == '!') {
rl_completion_append_character = orig_completion_append_character;
rl_basic_word_break_characters = orig_basic_word_break_characters;
rl_completer_word_break_characters = GINAC_RL_COMPLETER_CAST(rl_basic_word_break_characters);
-#if (GINAC_RL_VERSION_MAJOR < 4) || (GINAC_RL_VERSION_MAJOR == 4 && GINAC_RL_VERSION_MINOR < 2)
- return completion_matches(const_cast<char *>(text), (CPFunction *)filename_completion_function);
-#else
return rl_completion_matches(text, rl_filename_completion_function);
-#endif
} else {
// Otherwise, complete function names
rl_completion_append_character = '(';
rl_basic_word_break_characters = " \t\n\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~";
rl_completer_word_break_characters = GINAC_RL_COMPLETER_CAST(rl_basic_word_break_characters);
-#if (GINAC_RL_VERSION_MAJOR < 4) || (GINAC_RL_VERSION_MAJOR == 4 && GINAC_RL_VERSION_MINOR < 2)
- return completion_matches(const_cast<char *>(text), (CPFunction *)fcn_generator);
-#else
return rl_completion_matches(text, fcn_generator);
-#endif
}
}
-#endif // REALLY_HAVE_LIBREADLINE
+#endif // HAVE_LIBREADLINE
+
+static void ginsh_readline_init(char* name)
+{
+#ifdef HAVE_LIBREADLINE
+ // Init readline completer
+ rl_readline_name = name;
+ rl_attempted_completion_function = fcn_completion;
+ orig_completion_append_character = rl_completion_append_character;
+ orig_basic_word_break_characters = rl_basic_word_break_characters;
+#endif // HAVE_LIBREADLINE
+}
void greeting(void)
{
// Print banner in interactive mode
if (isatty(0))
greeting();
+ assigned_symbol_table = exmap();
// Init function table
insert_fcns(builtin_fcns);
insert_help("print_latex", "print_latex(expression) - prints a LaTeX representation of the given expression");
insert_help("print_csrc", "print_csrc(expression) - prints a C source code representation of the given expression");
-#ifdef REALLY_HAVE_LIBREADLINE
- // Init readline completer
- rl_readline_name = argv[0];
-#if (GINAC_RL_VERSION_MAJOR < 4) || (GINAC_RL_VERSION_MAJOR == 4 && GINAC_RL_VERSION_MINOR < 2)
- rl_attempted_completion_function = (CPPFunction *)fcn_completion;
-#else
- rl_attempted_completion_function = fcn_completion;
-#endif
- orig_completion_append_character = rl_completion_append_character;
- orig_basic_word_break_characters = rl_basic_word_break_characters;
-#endif
+ ginsh_readline_init(argv[0]);
// Init input file list, open first file
num_files = argc - 1;