cadabra-0.115/0000700000077000007700000000000010623023726012444 5ustar kantorkantorcadabra-0.115/AUTHORS0000600000077000007700000000005410437256622013523 0ustar kantorkantorKasper Peeters, cadabra-0.115/cadabra.desktop0000600000077000007700000000036010612672007015415 0ustar kantorkantor[Desktop Entry] Encoding=UTF-8 Name=Cadabra GenericName=Cadabra computer algebra system Comment=Computer algebra system for field theory problems Icon=cadabra Type=Application Categories=Math;Science;Education Exec=xcadabra Terminal=false cadabra-0.115/ChangeLog0000600000077000007700000002444610622301155014224 0ustar kantorkantor2007-05-07 Kasper Peeters * Line spacing in input widgets fixed. * Input cells now always scroll into view when being edited. 2007-05-06 Kasper Peeters * Fixed a bug handling a NonCommuting property when the objects in the list would only differ by the name of an index. This now allows {\psi_{\mu}, \psi_{\nu}}::NonCommuting, even though this is more elegantly written using SelfNonCommuting. 2007-05-04 Kasper Peeters * Released 0.114. * Made cut-n-paste of output cells to input cells work as expected: it pastes the internal cadabra format, not the TeX format as it used to do. Pasting to external applications still pastes the TeX format. 2007-04-30 Kasper Peeters * Released 0.113. * Added @sumsort. 2007-04-27 Kasper Peeters * Released 0.112. * Fixed a bug in @expand_power which gave bogus results for powers <=1. 2007-04-25 Kasper Peeters * Fixed a bug in @join which showed up when using numerical indices or indices which are composite objects. 2007-04-20 Kasper Peeters * Added an option to change the font size in the GUI. * Added more information dialogs (printing, citation info) to the GUI. 2007-04-15 Kasper Peeters * Fixed a bug in @sym/@asym which occurred when the arguments could not be found in the expression. * Fixed stopwatch code and timer updates for the progress bars. 2007-04-13 Kasper Peeters * Fixed a bug in @proplist. 2007-04-11 Kasper Peeters * Released 0.111. * Added some functionality to @join. * Removed spurious debugging output. 2007-04-10 Kasper Peeters * Released 0.110. * Fixed a pattern matching bug with wildcard indices. 2007-04-09 Kasper Peeters * Released 0.109. * Fixed a brown-paper-bag bug in dealing with zero exponents. 2007-04-07 Kasper Peeters * Improved progress indicators. * Rewritten main loop to make it more robust about handling Ctrl-C. Added exception class for Ctrl-C signal handling. 2007-04-06 Kasper Peeters * Better handling of "document modified" flag in the GUI. * Protected the GUI against excessively long output cells which made LaTeX and/or dvipng fail. * Added 'divide cell' option to the GUI. 2007-04-05 Kasper Peeters * Released 0.107. 2007-03-23 Kasper Peeters * Released 0.105. * Fixed a serious bug in @eliminate_metric. 2007-03-22 Kasper Peeters * Released 0.104. 2007-03-20 Kasper Peeters * Canonicalise now generates a strong generating set directly, speeding up the process considerably. 2007-03-19 Kasper Peeters * Fixed a bug in impose_bianchi and updated the routines to use index iterators so they work on proper derivative operators too. 2007-03-16 Kasper Peeters * Added handling of selfdual and anti-selfdual tensors to @all_contractions. * Fixed a bug in searching of properties which would give properties with index wildcard patterns priority over explicit those with explicit patterns. 2007-03-14 Kasper Peeters * Released 0.103. * Added handling of selfdual and anti-selfdual tensors to the Young tableau routines. 2007-03-10 Kasper Peeters * Submitted to Fink. * Released 0.102. * Fixed a bug which made the frontend make a backup of the wrong file upon save or export. 2007-03-09 Kasper Peeters * Fixed a bug in substitute which would leave numerical factors uncollected inside products. * Released 0.101. * Several updates to the reference manual. 2007-03-08 Kasper Peeters * Added logic to deal with arbitrary names for generalised Kronecker delta symbols in handling of EpsilonTensors, as well as the logic to deal with different signatures more consistently (now part of the Metric property). 2007-03-05 Kasper Peeters * Added quit safeguard to the new & open menu items to prevent work from getting lost. 2007-03-03 Kasper Peeters * Added infrastructure for progress bar logic to the gui and kernel (implementation not yet complete). 2007-02-21 Kasper Peeters * Released 0.100. * Fixed a bug which made replacements involving Coordinates do the wrong thing with sub/superscripts and brackets. * Fixed a bug which made \partial_{0}{...} become zero. * Fixed a bug in handling of --input in combination with -F. 2007-02-14 Kasper Peeters * Made parser errors show up correctly in the GUI. 2007-02-07 Kasper Peeters * Released 0.99. 2007-02-06 Kasper Peeters * Removed dependence on the expect library (this was causing too much trouble on many Linux and OS X systems). 2007-02-04 Kasper Peeters * Fixed two errors to make the kernel 64-bit clean. 2007-01-29 Kasper Peeters * Released 0.98. * Added more keyboard shortcuts to the GUI. * Removed the annoying debugging output of the GUI. 2007-01-28 Kasper Peeters * Save/Open dialogs now have default actions. * When starting LaTeX or dvipng inside the GUI, an error could occur which had to do with modglue cleaning up the terminating process (ECHLD returned). Fixed. * Calling @canonicalise on an expression with indices without an index set name would trigger a failed assert. Fixed (thanks to Jeremy Michelson for the bug report). * Fixed various problems in the configure script. 2007-01-25 Kasper Peeters * Released 0.97 and the paper on hep-th 2007-01-25 Kasper Peeters * Fixed a problem in combinatorics.hh related to clear(), which would show up in young_project_tensor. * Fixed bugs in @expand. 2007-01-23 Kasper Peeters * Released 0.96 * Many bug fixes to the kernel and gui, and new examples added. * Debian and RPM packages added. 2007-01-04 Kasper Peeters * Made @young_project use index iterators. 2006-12-12 Kasper Peeters * Released 0.94 to limited audience. * Improvement of the Makefiles and versioning mechanism. * Many improvements to the gui. 2006-12-10 Kasper Peeters * Fixed output of \arrow nodes. * Fixed another missing Inherit in Derivative. 2006-12-07 Kasper Peeters * Changed to the more commonly available Google pcre wrapper for C++ (which is also available as Debian package). 2006-11-30 Kasper Peeters * Released 0.93 * Enabled the graphical frontend (requires the --enable-gui flag to configure). 2006-11-16 Kasper Peeters * Fixed a bug in unwrap which would leave a nested \prod{\prod{}} structure in the tree. 2006-11-16 Kasper Peeters * Released 0.92 * Corrected the documentation and texmacs sample files for the change in the @rename algorithm. * Added the 3rd tutorial as a test case. 2006-11-15 Kasper Peeters * Fixed a bug in @rewrite_diracbar which made the tutorial example 3 fail to run. 2006-11-13 Kasper Peeters * Released 0.91 2006-11-12 Kasper Peeters * Fixed a bug in canonicalise which would not handle equal-length columns of a Young tableau correctly. 2006-11-10 Kasper Peeters * Removed most of PropertyInherit in favour of the new Inherit. 2006-11-09 Kasper Peeters * Finally fixed the bug which made index checking of newly input expressions go wrong. Now always enabled, the CDB_CHECK_INPUT environment variable has gone away. * Fixed a bug which would give wildcard property declarations preference over explicit property declarations, thereby disabling "property specialisation". 2006-11-08 Kasper Peeters * Removed \diff from the defaults. * Fixed several bugs related to the symmetry handling of derivatives and partial derivatives. 2006-10-25 Kasper Peeters * Fixed a bug in handling of bracket types in @distribute. Removed hard-coded node names from @distribute. 2006-10-24 Kasper Peeters * The @prodrule algorithm did not properly un-nest in all cases, now fixed. 2006-10-18 Kasper Peeters * Added a @take_match algorithm to select terms from a sum or list which match a given pattern. 2006-10-15 Kasper Peeters * Added the @take algorithm. * Documented the list algorithms. 2006-10-13 Kasper Peeters * An "infinite recursion" error is now thrown whenever an expression contains a '@' reference to itself. * Rewrote @eliminate_kr to make use of index_iterators, so that it handles indices hidden inside nested operators. 2006-10-11 Kasper Peeters * Made "DiracBar" derive from "Distributable". * Fixed a bug in TeXmacs output for indices. 2006-08-18 Kasper Peeters * Removed dependence on glib. * Various small changes in order to enable compilation on OS X machines. * Version 0.90 released. 2006-08-15 Kasper Peeters * Fixed bug in handling of different index types in canonicalise. * Version 0.88 released. 2006-08-14 Kasper Peeters * Fixed a bug in prodrule with multiple derivatives. * Fixed a bug in handling of nested derivatives. * Version 0.87 released. 2006-08-11 Kasper Peeters * Fixed a bug in substitute which made it forgot to relabel indices already used in subtrees matched by object wildcards. * Version 0.85 released. 2006-08-07 Kasper Peeters * Changed the default logging behaviour to be "off". Setting CDB_LOG now turns on logging. 2006-08-06 Kasper Peeters * Fixed a bug in the property pattern matcher. * Fixed a bug in "unwrap" related to its handling of multiple-argument objects. * Version 0.84 released. 2006-08-03 Kasper Peeters * Some errors in the manual fixed. * Removed all references to the proj++ library. * Now check for gmp in the configure script. * Version 0.83 released. 2006-08-02 Kasper Peeters * Paper submitted to cs.SC. * Version 0.82 released. cadabra-0.115/configure0000700000077000007700000054112110567371725014373 0ustar kantorkantor#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59. # # Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= ac_unique_file="src/storage.cc" ac_default_prefix=/usr/local # Factoring default headers for most tests. ac_includes_default="\ #include #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_STAT_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_STRING_H # if !STDC_HEADERS && HAVE_MEMORY_H # include # endif # include #endif #if HAVE_STRINGS_H # include #endif #if HAVE_INTTYPES_H # include #else # if HAVE_STDINT_H # include # endif #endif #if HAVE_UNISTD_H # include #endif" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX LN_S SET_MAKE install_flags LIE CXXCPP EGREP PKG_CONFIG ac_pt_PKG_CONFIG sigc_CFLAGS sigc_LIBS modglue_CFLAGS modglue_LIBS PTYWRAP gtk_CFLAGS gtk_LIBS pango_CFLAGS pango_LIBS gtkmm_CFLAGS gtkmm_LIBS pangomm_CFLAGS pangomm_LIBS DVIPNG LATEX enable_gui MAC_OS_X pcrecpp NESTED LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS ac_env_CXX_set=${CXX+set} ac_env_CXX_value=$CXX ac_cv_env_CXX_set=${CXX+set} ac_cv_env_CXX_value=$CXX ac_env_CXXFLAGS_set=${CXXFLAGS+set} ac_env_CXXFLAGS_value=$CXXFLAGS ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} ac_cv_env_CXXFLAGS_value=$CXXFLAGS ac_env_CXXCPP_set=${CXXCPP+set} ac_env_CXXCPP_value=$CXXCPP ac_cv_env_CXXCPP_set=${CXXCPP+set} ac_cv_env_CXXCPP_value=$CXXCPP ac_env_PKG_CONFIG_set=${PKG_CONFIG+set} ac_env_PKG_CONFIG_value=$PKG_CONFIG ac_cv_env_PKG_CONFIG_set=${PKG_CONFIG+set} ac_cv_env_PKG_CONFIG_value=$PKG_CONFIG ac_env_sigc_CFLAGS_set=${sigc_CFLAGS+set} ac_env_sigc_CFLAGS_value=$sigc_CFLAGS ac_cv_env_sigc_CFLAGS_set=${sigc_CFLAGS+set} ac_cv_env_sigc_CFLAGS_value=$sigc_CFLAGS ac_env_sigc_LIBS_set=${sigc_LIBS+set} ac_env_sigc_LIBS_value=$sigc_LIBS ac_cv_env_sigc_LIBS_set=${sigc_LIBS+set} ac_cv_env_sigc_LIBS_value=$sigc_LIBS ac_env_modglue_CFLAGS_set=${modglue_CFLAGS+set} ac_env_modglue_CFLAGS_value=$modglue_CFLAGS ac_cv_env_modglue_CFLAGS_set=${modglue_CFLAGS+set} ac_cv_env_modglue_CFLAGS_value=$modglue_CFLAGS ac_env_modglue_LIBS_set=${modglue_LIBS+set} ac_env_modglue_LIBS_value=$modglue_LIBS ac_cv_env_modglue_LIBS_set=${modglue_LIBS+set} ac_cv_env_modglue_LIBS_value=$modglue_LIBS ac_env_gtk_CFLAGS_set=${gtk_CFLAGS+set} ac_env_gtk_CFLAGS_value=$gtk_CFLAGS ac_cv_env_gtk_CFLAGS_set=${gtk_CFLAGS+set} ac_cv_env_gtk_CFLAGS_value=$gtk_CFLAGS ac_env_gtk_LIBS_set=${gtk_LIBS+set} ac_env_gtk_LIBS_value=$gtk_LIBS ac_cv_env_gtk_LIBS_set=${gtk_LIBS+set} ac_cv_env_gtk_LIBS_value=$gtk_LIBS ac_env_pango_CFLAGS_set=${pango_CFLAGS+set} ac_env_pango_CFLAGS_value=$pango_CFLAGS ac_cv_env_pango_CFLAGS_set=${pango_CFLAGS+set} ac_cv_env_pango_CFLAGS_value=$pango_CFLAGS ac_env_pango_LIBS_set=${pango_LIBS+set} ac_env_pango_LIBS_value=$pango_LIBS ac_cv_env_pango_LIBS_set=${pango_LIBS+set} ac_cv_env_pango_LIBS_value=$pango_LIBS ac_env_gtkmm_CFLAGS_set=${gtkmm_CFLAGS+set} ac_env_gtkmm_CFLAGS_value=$gtkmm_CFLAGS ac_cv_env_gtkmm_CFLAGS_set=${gtkmm_CFLAGS+set} ac_cv_env_gtkmm_CFLAGS_value=$gtkmm_CFLAGS ac_env_gtkmm_LIBS_set=${gtkmm_LIBS+set} ac_env_gtkmm_LIBS_value=$gtkmm_LIBS ac_cv_env_gtkmm_LIBS_set=${gtkmm_LIBS+set} ac_cv_env_gtkmm_LIBS_value=$gtkmm_LIBS ac_env_pangomm_CFLAGS_set=${pangomm_CFLAGS+set} ac_env_pangomm_CFLAGS_value=$pangomm_CFLAGS ac_cv_env_pangomm_CFLAGS_set=${pangomm_CFLAGS+set} ac_cv_env_pangomm_CFLAGS_value=$pangomm_CFLAGS ac_env_pangomm_LIBS_set=${pangomm_LIBS+set} ac_env_pangomm_LIBS_value=$pangomm_LIBS ac_cv_env_pangomm_LIBS_set=${pangomm_LIBS+set} ac_cv_env_pangomm_LIBS_value=$pangomm_LIBS # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] _ACEOF cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-gui Enable building of the graphical front-end (default is yes) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor PKG_CONFIG path to pkg-config utility sigc_CFLAGS C compiler flags for sigc, overriding pkg-config sigc_LIBS linker flags for sigc, overriding pkg-config modglue_CFLAGS C compiler flags for modglue, overriding pkg-config modglue_LIBS linker flags for modglue, overriding pkg-config gtk_CFLAGS C compiler flags for gtk, overriding pkg-config gtk_LIBS linker flags for gtk, overriding pkg-config pango_CFLAGS C compiler flags for pango, overriding pkg-config pango_LIBS linker flags for pango, overriding pkg-config gtkmm_CFLAGS C compiler flags for gtkmm, overriding pkg-config gtkmm_LIBS linker flags for gtkmm, overriding pkg-config pangomm_CFLAGS C compiler flags for pangomm, overriding pkg-config pangomm_LIBS linker flags for pangomm, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_srcdir/configure.gnu; then echo $SHELL $ac_srcdir/configure.gnu --help=recursive elif test -f $ac_srcdir/configure; then echo $SHELL $ac_srcdir/configure --help=recursive elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd "$ac_popdir" done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF Copyright (C) 2003 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` hostinfo = `(hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_sep= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= # b.out is created by i960 compilers. for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; conftest.$ac_ext ) # This is the source file. ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool, # but it would be cool to find out if it's true. Does anybody # maintain Libtool? --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std1 is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std1. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF # Don't try gcc -ansi; that turns off useful extensions and # breaks some systems' header files. # AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 # HP-UX 10.20 and later -Ae # HP-UX older versions -Aa -D_HPUX_SOURCE # SVR4 -Xc -D__EXTENSIONS__ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext done rm -f conftest.$ac_ext conftest.$ac_objext CC=$ac_save_CC fi case "x$ac_cv_prog_cc_stdc" in x|xno) echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CXX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then echo "$as_me:$LINENO: result: $CXX" >&5 echo "${ECHO_T}$CXX" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 echo "${ECHO_T}$ac_ct_CXX" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CXX" && break done test -n "$ac_ct_CXX" || ac_ct_CXX="g++" CXX=$ac_ct_CXX fi # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C++ compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 if test "${ac_cv_cxx_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 GXX=`test $ac_compiler_gnu = yes && echo yes` ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS CXXFLAGS="-g" echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cxx_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cxx_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cxx_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu echo "$as_me:$LINENO: checking whether ln -s works" >&5 echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no, using $LN_S" >&5 echo "${ECHO_T}no, using $LN_S" >&6 fi echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftest.make fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 SET_MAKE= else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 SET_MAKE="MAKE=${MAKE-make}" fi ac_config_headers="$ac_config_headers src/config.h" ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # Extract the first word of "lie", so it can be a program name with args. set dummy lie; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_LIE+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$LIE"; then ac_cv_prog_LIE="$LIE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIE="yes" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_LIE" && ac_cv_prog_LIE="no" fi fi LIE=$ac_cv_prog_LIE if test -n "$LIE"; then echo "$as_me:$LINENO: result: $LIE" >&5 echo "${ECHO_T}$LIE" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test "${LIE}" == "no" then { { echo "$as_me:$LINENO: error: Need the LiE program; get it from http://young.sp2mi.univ-poitiers.fr/~marc/LiE/ ." >&5 echo "$as_me: error: Need the LiE program; get it from http://young.sp2mi.univ-poitiers.fr/~marc/LiE/ ." >&2;} { (exit 1); exit 1; }; } fi ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6 if test -z "$CXXCPP"; then if test "${ac_cv_prog_CXXCPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi echo "$as_me:$LINENO: result: $CXXCPP" >&5 echo "${ECHO_T}$CXXCPP" >&6 ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu echo "$as_me:$LINENO: checking for egrep" >&5 echo $ECHO_N "checking for egrep... $ECHO_C" >&6 if test "${ac_cv_prog_egrep+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi fi echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 echo "${ECHO_T}$ac_cv_prog_egrep" >&6 EGREP=$ac_cv_prog_egrep echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in pcre.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done if test "${ac_cv_header_pcre_h}" == "no" then { { echo "$as_me:$LINENO: error: Need the pcre library; get it from http://www.pcre.org/ . Make sure to set CPPFLAGS if necessary." >&5 echo "$as_me: error: Need the pcre library; get it from http://www.pcre.org/ . Make sure to set CPPFLAGS if necessary." >&2;} { (exit 1); exit 1; }; } fi for ac_header in gmpxx.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done if test "${ac_cv_header_gmpxx_h}" == "no" then { { echo "$as_me:$LINENO: error: Need the gmp and gmpxx library; get them from http://www.swox.com/gmp/ and configure them with --enable-cxx. Also make sure to set CPPFLAGS if necessary." >&5 echo "$as_me: error: Need the gmp and gmpxx library; get them from http://www.swox.com/gmp/ and configure them with --enable-cxx. Also make sure to set CPPFLAGS if necessary." >&2;} { (exit 1); exit 1; }; } fi for ac_header in pcrecpp.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done if test "${ac_cv_header_pcrecpp_h}" == "no" then { { echo "$as_me:$LINENO: error: Need the pcrecpp library; get it from http://www.pcre.org . Make sure to set CPPFLAGS if necessary." >&5 echo "$as_me: error: Need the pcrecpp library; get it from http://www.pcre.org . Make sure to set CPPFLAGS if necessary." >&2;} { (exit 1); exit 1; }; } fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_PKG_CONFIG+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 echo "${ECHO_T}$PKG_CONFIG" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5 echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi PKG_CONFIG=$ac_pt_PKG_CONFIG else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5 echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6 if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 PKG_CONFIG="" fi fi pkg_failed=no echo "$as_me:$LINENO: checking for sigc" >&5 echo $ECHO_N "checking for sigc... $ECHO_C" >&6 if test -n "$PKG_CONFIG"; then if test -n "$sigc_CFLAGS"; then pkg_cv_sigc_CFLAGS="$sigc_CFLAGS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"sigc++-2.0\"") >&5 ($PKG_CONFIG --exists --print-errors "sigc++-2.0") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_sigc_CFLAGS=`$PKG_CONFIG --cflags "sigc++-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$sigc_LIBS"; then pkg_cv_sigc_LIBS="$sigc_LIBS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"sigc++-2.0\"") >&5 ($PKG_CONFIG --exists --print-errors "sigc++-2.0") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_sigc_LIBS=`$PKG_CONFIG --libs "sigc++-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then sigc_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "sigc++-2.0"` else sigc_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "sigc++-2.0"` fi # Put the nasty error message in config.log where it belongs echo "$sigc_PKG_ERRORS" >&5 { { echo "$as_me:$LINENO: error: Package requirements (sigc++-2.0) were not met: $sigc_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 echo "$as_me: error: Package requirements (sigc++-2.0) were not met: $sigc_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&2;} { (exit 1); exit 1; }; } elif test $pkg_failed = untried; then { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&5 echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else sigc_CFLAGS=$pkg_cv_sigc_CFLAGS sigc_LIBS=$pkg_cv_sigc_LIBS echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 : fi pkg_failed=no echo "$as_me:$LINENO: checking for modglue" >&5 echo $ECHO_N "checking for modglue... $ECHO_C" >&6 if test -n "$PKG_CONFIG"; then if test -n "$modglue_CFLAGS"; then pkg_cv_modglue_CFLAGS="$modglue_CFLAGS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"modglue\"") >&5 ($PKG_CONFIG --exists --print-errors "modglue") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_modglue_CFLAGS=`$PKG_CONFIG --cflags "modglue" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$modglue_LIBS"; then pkg_cv_modglue_LIBS="$modglue_LIBS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"modglue\"") >&5 ($PKG_CONFIG --exists --print-errors "modglue") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_modglue_LIBS=`$PKG_CONFIG --libs "modglue" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then modglue_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "modglue"` else modglue_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "modglue"` fi # Put the nasty error message in config.log where it belongs echo "$modglue_PKG_ERRORS" >&5 { { echo "$as_me:$LINENO: error: Package requirements (modglue) were not met: $modglue_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables modglue_CFLAGS and modglue_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 echo "$as_me: error: Package requirements (modglue) were not met: $modglue_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables modglue_CFLAGS and modglue_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&2;} { (exit 1); exit 1; }; } elif test $pkg_failed = untried; then { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables modglue_CFLAGS and modglue_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&5 echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables modglue_CFLAGS and modglue_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else modglue_CFLAGS=$pkg_cv_modglue_CFLAGS modglue_LIBS=$pkg_cv_modglue_LIBS echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 : fi # Extract the first word of "ptywrap", so it can be a program name with args. set dummy ptywrap; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_PTYWRAP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$PTYWRAP"; then ac_cv_prog_PTYWRAP="$PTYWRAP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PTYWRAP="yes" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_PTYWRAP" && ac_cv_prog_PTYWRAP="no" fi fi PTYWRAP=$ac_cv_prog_PTYWRAP if test -n "$PTYWRAP"; then echo "$as_me:$LINENO: result: $PTYWRAP" >&5 echo "${ECHO_T}$PTYWRAP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test "${PTYWRAP}" == "no" then { { echo "$as_me:$LINENO: error: You have the modglue library, but the \"ptywrap\" tool which comes with it is not installed or executable." >&5 echo "$as_me: error: You have the modglue library, but the \"ptywrap\" tool which comes with it is not installed or executable." >&2;} { (exit 1); exit 1; }; } fi MAC_OS_X="" if test "`uname`" == "Darwin" then MAC_OS_X="1" echo "checking system type... Darwin" else echo "checking system type... Unix" fi echo -n "Checking whether to use -fnested-functions..." echo "main() {};" > conftmp.c NESTED=-fnested-functions if gcc -fnested-functions -c -o conftmp.o conftmp.c 1>/dev/null 2>&1 then echo " yes" else NESTED="" echo " no" fi rm -f conftmp.c conftmp.o echo "$as_me:$LINENO: checking whether to build the GUI" >&5 echo $ECHO_N "checking whether to build the GUI... $ECHO_C" >&6 # Check whether --enable-gui or --disable-gui was given. if test "${enable_gui+set}" = set; then enableval="$enable_gui" else enable_gui=yes fi; if test "$enable_gui" == "no" then echo "no" else echo "yes" pkg_failed=no echo "$as_me:$LINENO: checking for sigc" >&5 echo $ECHO_N "checking for sigc... $ECHO_C" >&6 if test -n "$PKG_CONFIG"; then if test -n "$sigc_CFLAGS"; then pkg_cv_sigc_CFLAGS="$sigc_CFLAGS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"sigc++-2.0\"") >&5 ($PKG_CONFIG --exists --print-errors "sigc++-2.0") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_sigc_CFLAGS=`$PKG_CONFIG --cflags "sigc++-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$sigc_LIBS"; then pkg_cv_sigc_LIBS="$sigc_LIBS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"sigc++-2.0\"") >&5 ($PKG_CONFIG --exists --print-errors "sigc++-2.0") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_sigc_LIBS=`$PKG_CONFIG --libs "sigc++-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then sigc_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "sigc++-2.0"` else sigc_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "sigc++-2.0"` fi # Put the nasty error message in config.log where it belongs echo "$sigc_PKG_ERRORS" >&5 { { echo "$as_me:$LINENO: error: Package requirements (sigc++-2.0) were not met: $sigc_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 echo "$as_me: error: Package requirements (sigc++-2.0) were not met: $sigc_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&2;} { (exit 1); exit 1; }; } elif test $pkg_failed = untried; then { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&5 echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else sigc_CFLAGS=$pkg_cv_sigc_CFLAGS sigc_LIBS=$pkg_cv_sigc_LIBS echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 : fi pkg_failed=no echo "$as_me:$LINENO: checking for gtk" >&5 echo $ECHO_N "checking for gtk... $ECHO_C" >&6 if test -n "$PKG_CONFIG"; then if test -n "$gtk_CFLAGS"; then pkg_cv_gtk_CFLAGS="$gtk_CFLAGS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0\"") >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_gtk_CFLAGS=`$PKG_CONFIG --cflags "gtk+-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$gtk_LIBS"; then pkg_cv_gtk_LIBS="$gtk_LIBS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0\"") >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_gtk_LIBS=`$PKG_CONFIG --libs "gtk+-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then gtk_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtk+-2.0"` else gtk_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtk+-2.0"` fi # Put the nasty error message in config.log where it belongs echo "$gtk_PKG_ERRORS" >&5 { { echo "$as_me:$LINENO: error: Package requirements (gtk+-2.0) were not met: $gtk_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables gtk_CFLAGS and gtk_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 echo "$as_me: error: Package requirements (gtk+-2.0) were not met: $gtk_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables gtk_CFLAGS and gtk_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&2;} { (exit 1); exit 1; }; } elif test $pkg_failed = untried; then { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables gtk_CFLAGS and gtk_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&5 echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables gtk_CFLAGS and gtk_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else gtk_CFLAGS=$pkg_cv_gtk_CFLAGS gtk_LIBS=$pkg_cv_gtk_LIBS echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 : fi pkg_failed=no echo "$as_me:$LINENO: checking for pango" >&5 echo $ECHO_N "checking for pango... $ECHO_C" >&6 if test -n "$PKG_CONFIG"; then if test -n "$pango_CFLAGS"; then pkg_cv_pango_CFLAGS="$pango_CFLAGS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"pango\"") >&5 ($PKG_CONFIG --exists --print-errors "pango") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_pango_CFLAGS=`$PKG_CONFIG --cflags "pango" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$pango_LIBS"; then pkg_cv_pango_LIBS="$pango_LIBS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"pango\"") >&5 ($PKG_CONFIG --exists --print-errors "pango") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_pango_LIBS=`$PKG_CONFIG --libs "pango" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then pango_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "pango"` else pango_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "pango"` fi # Put the nasty error message in config.log where it belongs echo "$pango_PKG_ERRORS" >&5 { { echo "$as_me:$LINENO: error: Package requirements (pango) were not met: $pango_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables pango_CFLAGS and pango_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 echo "$as_me: error: Package requirements (pango) were not met: $pango_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables pango_CFLAGS and pango_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&2;} { (exit 1); exit 1; }; } elif test $pkg_failed = untried; then { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables pango_CFLAGS and pango_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&5 echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables pango_CFLAGS and pango_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else pango_CFLAGS=$pkg_cv_pango_CFLAGS pango_LIBS=$pkg_cv_pango_LIBS echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 : fi pkg_failed=no echo "$as_me:$LINENO: checking for gtkmm" >&5 echo $ECHO_N "checking for gtkmm... $ECHO_C" >&6 if test -n "$PKG_CONFIG"; then if test -n "$gtkmm_CFLAGS"; then pkg_cv_gtkmm_CFLAGS="$gtkmm_CFLAGS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4\"") >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_gtkmm_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$gtkmm_LIBS"; then pkg_cv_gtkmm_LIBS="$gtkmm_LIBS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4\"") >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_gtkmm_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then gtkmm_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4"` else gtkmm_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4"` fi # Put the nasty error message in config.log where it belongs echo "$gtkmm_PKG_ERRORS" >&5 { { echo "$as_me:$LINENO: error: Package requirements (gtkmm-2.4) were not met: $gtkmm_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables gtkmm_CFLAGS and gtkmm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 echo "$as_me: error: Package requirements (gtkmm-2.4) were not met: $gtkmm_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables gtkmm_CFLAGS and gtkmm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&2;} { (exit 1); exit 1; }; } elif test $pkg_failed = untried; then { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables gtkmm_CFLAGS and gtkmm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&5 echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables gtkmm_CFLAGS and gtkmm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else gtkmm_CFLAGS=$pkg_cv_gtkmm_CFLAGS gtkmm_LIBS=$pkg_cv_gtkmm_LIBS echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 : fi pkg_failed=no echo "$as_me:$LINENO: checking for pangomm" >&5 echo $ECHO_N "checking for pangomm... $ECHO_C" >&6 if test -n "$PKG_CONFIG"; then if test -n "$pangomm_CFLAGS"; then pkg_cv_pangomm_CFLAGS="$pangomm_CFLAGS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"pangomm-1.4\"") >&5 ($PKG_CONFIG --exists --print-errors "pangomm-1.4") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_pangomm_CFLAGS=`$PKG_CONFIG --cflags "pangomm-1.4" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$pangomm_LIBS"; then pkg_cv_pangomm_LIBS="$pangomm_LIBS" else if test -n "$PKG_CONFIG" && \ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"pangomm-1.4\"") >&5 ($PKG_CONFIG --exists --print-errors "pangomm-1.4") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_pangomm_LIBS=`$PKG_CONFIG --libs "pangomm-1.4" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then pangomm_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "pangomm-1.4"` else pangomm_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "pangomm-1.4"` fi # Put the nasty error message in config.log where it belongs echo "$pangomm_PKG_ERRORS" >&5 { { echo "$as_me:$LINENO: error: Package requirements (pangomm-1.4) were not met: $pangomm_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables pangomm_CFLAGS and pangomm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 echo "$as_me: error: Package requirements (pangomm-1.4) were not met: $pangomm_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables pangomm_CFLAGS and pangomm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&2;} { (exit 1); exit 1; }; } elif test $pkg_failed = untried; then { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables pangomm_CFLAGS and pangomm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&5 echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables pangomm_CFLAGS and pangomm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else pangomm_CFLAGS=$pkg_cv_pangomm_CFLAGS pangomm_LIBS=$pkg_cv_pangomm_LIBS echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 : fi # Extract the first word of "dvipng", so it can be a program name with args. set dummy dvipng; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_DVIPNG+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$DVIPNG"; then ac_cv_prog_DVIPNG="$DVIPNG" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DVIPNG="yes" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_DVIPNG" && ac_cv_prog_DVIPNG="no" fi fi DVIPNG=$ac_cv_prog_DVIPNG if test -n "$DVIPNG"; then echo "$as_me:$LINENO: result: $DVIPNG" >&5 echo "${ECHO_T}$DVIPNG" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test "${DVIPNG}" == "no" then { { echo "$as_me:$LINENO: error: Need the dvipng program; get it from http://sourceforge.net/projects/dvipng/ ." >&5 echo "$as_me: error: Need the dvipng program; get it from http://sourceforge.net/projects/dvipng/ ." >&2;} { (exit 1); exit 1; }; } fi # Extract the first word of "latex", so it can be a program name with args. set dummy latex; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_LATEX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$LATEX"; then ac_cv_prog_LATEX="$LATEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LATEX="yes" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_LATEX" && ac_cv_prog_LATEX="no" fi fi LATEX=$ac_cv_prog_LATEX if test -n "$LATEX"; then echo "$as_me:$LINENO: result: $LATEX" >&5 echo "${ECHO_T}$LATEX" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test "${LATEX}" == "no" then { { echo "$as_me:$LINENO: error: Need a working LaTeX installation." >&5 echo "$as_me: error: Need a working LaTeX installation." >&2;} { (exit 1); exit 1; }; } fi echo "\nonstopmode\\documentclass{article}\\usepackage{breqn}\\begin{document}\\begin{dmath*}x^2\\end{dmath*}\\end{document}\n" > conftmp.tex echo -n "checking for breqn package..." if latex conftmp.tex > /dev/null 2>&1 then echo " yes" else echo " no" { { echo "$as_me:$LINENO: error: Need the breqn LaTeX package; get it from ftp://ftp.ams.org/pub/tex/ ." >&5 echo "$as_me: error: Need the breqn LaTeX package; get it from ftp://ftp.ams.org/pub/tex/ ." >&2;} { (exit 1); exit 1; }; } fi rm -f conftmp.tex conftmp.log conftmp.dvi conftmp.aux fi ac_config_files="$ac_config_files Makefile src/Makefile src/modules/Makefile tests/Makefile gui/Makefile doc/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` ac_shift=: ;; -*) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "src/modules/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/modules/Makefile" ;; "tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; "gui/Makefile" ) CONFIG_FILES="$CONFIG_FILES gui/Makefile" ;; "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "src/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t s,@CXX@,$CXX,;t t s,@CXXFLAGS@,$CXXFLAGS,;t t s,@ac_ct_CXX@,$ac_ct_CXX,;t t s,@LN_S@,$LN_S,;t t s,@SET_MAKE@,$SET_MAKE,;t t s,@install_flags@,$install_flags,;t t s,@LIE@,$LIE,;t t s,@CXXCPP@,$CXXCPP,;t t s,@EGREP@,$EGREP,;t t s,@PKG_CONFIG@,$PKG_CONFIG,;t t s,@ac_pt_PKG_CONFIG@,$ac_pt_PKG_CONFIG,;t t s,@sigc_CFLAGS@,$sigc_CFLAGS,;t t s,@sigc_LIBS@,$sigc_LIBS,;t t s,@modglue_CFLAGS@,$modglue_CFLAGS,;t t s,@modglue_LIBS@,$modglue_LIBS,;t t s,@PTYWRAP@,$PTYWRAP,;t t s,@gtk_CFLAGS@,$gtk_CFLAGS,;t t s,@gtk_LIBS@,$gtk_LIBS,;t t s,@pango_CFLAGS@,$pango_CFLAGS,;t t s,@pango_LIBS@,$pango_LIBS,;t t s,@gtkmm_CFLAGS@,$gtkmm_CFLAGS,;t t s,@gtkmm_LIBS@,$gtkmm_LIBS,;t t s,@pangomm_CFLAGS@,$pangomm_CFLAGS,;t t s,@pangomm_LIBS@,$pangomm_LIBS,;t t s,@DVIPNG@,$DVIPNG,;t t s,@LATEX@,$LATEX,;t t s,@enable_gui@,$enable_gui,;t t s,@MAC_OS_X@,$MAC_OS_X,;t t s,@pcrecpp@,$pcrecpp,;t t s,@NESTED@,$NESTED,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;t t s,@srcdir@,$ac_srcdir,;t t s,@abs_srcdir@,$ac_abs_srcdir,;t t s,@top_srcdir@,$ac_top_srcdir,;t t s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t s,@builddir@,$ac_builddir,;t t s,@abs_builddir@,$ac_abs_builddir,;t t s,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # # CONFIG_HEADER section. # # These sed commands are passed to sed as "A NAME B NAME C VALUE D", where # NAME is the cpp macro being defined and VALUE is the value it is being given. # # ac_d sets the value in "#define NAME VALUE" lines. ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' ac_dB='[ ].*$,\1#\2' ac_dC=' ' ac_dD=',;t' # ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_uB='$,\1#\2define\3' ac_uC=' ' ac_uD=',;t' for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } # Do quote $f, to prevent DOS paths from being IFS'd. echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } # Remove the trailing spaces. sed 's/[ ]*$//' $ac_file_inputs >$tmp/in _ACEOF # Transform confdefs.h into two sed scripts, `conftest.defines' and # `conftest.undefs', that substitutes the proper values into # config.h.in to produce config.h. The first handles `#define' # templates, and the second `#undef' templates. # And first: Protect against being on the right side of a sed subst in # config.status. Protect against being in an unquoted here document # in config.status. rm -f conftest.defines conftest.undefs # Using a here document instead of a string reduces the quoting nightmare. # Putting comments in sed scripts is not portable. # # `end' is used to avoid that the second main sed command (meant for # 0-ary CPP macros) applies to n-ary macro definitions. # See the Autoconf documentation for `clear'. cat >confdef2sed.sed <<\_ACEOF s/[\\&,]/\\&/g s,[\\$`],\\&,g t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp t end s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp : end _ACEOF # If some macros were called several times there might be several times # the same #defines, which is useless. Nevertheless, we may not want to # sort them, since we want the *last* AC-DEFINE to be honored. uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs rm -f confdef2sed.sed # This sed command replaces #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. cat >>conftest.undefs <<\_ACEOF s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, _ACEOF # Break up conftest.defines because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS echo ' :' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.defines >/dev/null do # Write a limited-size here document to $tmp/defines.sed. echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#define' lines. echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/defines.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail rm -f conftest.defines mv conftest.tail conftest.defines done rm -f conftest.defines echo ' fi # grep' >>$CONFIG_STATUS echo >>$CONFIG_STATUS # Break up conftest.undefs because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #undef templates' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.undefs >/dev/null do # Write a limited-size here document to $tmp/undefs.sed. echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#undef' echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/undefs.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail rm -f conftest.undefs mv conftest.tail conftest.undefs done rm -f conftest.undefs cat >>$CONFIG_STATUS <<\_ACEOF # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then echo "/* Generated by configure. */" >$tmp/config.h else echo "/* $ac_file. Generated by configure. */" >$tmp/config.h fi cat $tmp/in >>$tmp/config.h rm -f $tmp/in if test x"$ac_file" != x-; then if diff $ac_file $tmp/config.h >/dev/null 2>&1; then { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } rm -f $ac_file mv $tmp/config.h $ac_file fi else cat $tmp/config.h rm -f $tmp/config.h fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi cadabra-0.115/configure.in0000600000077000007700000000741110573032605014762 0ustar kantorkantor AC_INIT(src/storage.cc) AC_PROG_CC AC_PROG_CXX AC_PROG_LN_S AC_PROG_MAKE_SET AC_PREFIX_DEFAULT(/usr/local) AC_SUBST(install_flags) AC_CONFIG_HEADER(src/config.h) AC_LANG(C++) dnl EXPECTPATH="" dnl AC_CHECK_HEADER(expect.h, AC_DEFINE(EXPECTPATH, )) dnl if test "$ac_cv_header_expect_h" != "yes" dnl then AC_CHECK_HEADER(tcl8.4/expect.h, AC_DEFINE(EXPECTPATH, )) dnl if test "$ac_cv_header_tcl8_4_expect_h" != "yes" dnl then AC_MSG_ERROR([Need the expect library; get it from http://expect.nist.gov/ .]) dnl fi dnl fi AC_CHECK_PROG(LIE, lie, yes, no) if test "${LIE}" == "no" then AC_MSG_ERROR([Need the LiE program; get it from http://young.sp2mi.univ-poitiers.fr/~marc/LiE/ .]) fi AC_CHECK_HEADERS(pcre.h) if test "${ac_cv_header_pcre_h}" == "no" then AC_MSG_ERROR([Need the pcre library; get it from http://www.pcre.org/ . Make sure to set CPPFLAGS if necessary.]) fi AC_CHECK_HEADERS(gmpxx.h) if test "${ac_cv_header_gmpxx_h}" == "no" then AC_MSG_ERROR([Need the gmp and gmpxx library; get them from http://www.swox.com/gmp/ and configure them with --enable-cxx. Also make sure to set CPPFLAGS if necessary.]) fi dnl AC_CHECK_HEADERS(pcre++.h) AC_CHECK_HEADERS(pcrecpp.h) dnl if test "${ac_cv_header_pcrecpp_h}" == "no" -a "${ac_cv_header_pcrepp_h}" == "no" if test "${ac_cv_header_pcrecpp_h}" == "no" then AC_MSG_ERROR([Need the pcrecpp library; get it from http://www.pcre.org . Make sure to set CPPFLAGS if necessary.]) fi dnl if test "${ac_cv_header_pcre++_h}" == "no" dnl then pcrecpp=yes dnl else pcrecpp=no dnl fi PKG_CHECK_MODULES([sigc], [sigc++-2.0]) PKG_CHECK_MODULES([modglue], [modglue]) AC_CHECK_PROG(PTYWRAP, ptywrap, yes, no) if test "${PTYWRAP}" == "no" then AC_MSG_ERROR([You have the modglue library, but the "ptywrap" tool which comes with it is not installed or executable.]) fi MAC_OS_X="" if test "`uname`" == "Darwin" then MAC_OS_X="1" echo "checking system type... Darwin" else echo "checking system type... Unix" fi echo -n "Checking whether to use -fnested-functions..." echo "main() {};" > conftmp.c NESTED=-fnested-functions if gcc -fnested-functions -c -o conftmp.o conftmp.c 1>/dev/null 2>&1 then echo " yes" else NESTED="" echo " no" fi rm -f conftmp.c conftmp.o dnl Optional configuration of the experimental GUI AC_MSG_CHECKING([whether to build the GUI]) AC_ARG_ENABLE([gui], [AS_HELP_STRING([--enable-gui], [Enable building of the graphical front-end (default is yes)])], , enable_gui=yes) if test "$enable_gui" == "no" then echo "no" else echo "yes" PKG_CHECK_MODULES([sigc], [sigc++-2.0]) PKG_CHECK_MODULES([gtk], [gtk+-2.0]) PKG_CHECK_MODULES([pango], [pango]) PKG_CHECK_MODULES([gtkmm], [gtkmm-2.4]) PKG_CHECK_MODULES([pangomm], [pangomm-1.4]) AC_CHECK_PROG(DVIPNG, dvipng, yes, no) if test "${DVIPNG}" == "no" then AC_MSG_ERROR([Need the dvipng program; get it from http://sourceforge.net/projects/dvipng/ .]) fi AC_CHECK_PROG(LATEX, latex, yes, no) if test "${LATEX}" == "no" then AC_MSG_ERROR([Need a working LaTeX installation.]) fi echo "\nonstopmode\\documentclass{article}\\usepackage{breqn}\\begin{document}\\begin{dmath*}x^2\\end{dmath*}\\end{document}\n" > conftmp.tex echo -n "checking for breqn package..." if latex conftmp.tex > /dev/null 2>&1 then echo " yes" else echo " no" AC_MSG_ERROR([Need the breqn LaTeX package; get it from ftp://ftp.ams.org/pub/tex/ .]) fi rm -f conftmp.tex conftmp.log conftmp.dvi conftmp.aux fi AC_SUBST([enable_gui]) AC_SUBST([MAC_OS_X]) AC_SUBST([pcrecpp]) AC_SUBST([NESTED]) dnl The output files AC_OUTPUT( Makefile src/Makefile src/modules/Makefile tests/Makefile gui/Makefile doc/Makefile ) cadabra-0.115/COPYING0000600000077000007700000003543110574526441013516 0ustar kantorkantor GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS cadabra-0.115/doc/0000700000077000007700000000000010622301155013203 5ustar kantorkantorcadabra-0.115/doc/cadabra.tex0000600000077000007700000051276310622301155015322 0ustar kantorkantor\documentclass[11pt]{article} \usepackage[textwidth=420pt,textheight=650pt,headheight=13.6pt,nofoot,includehead]{geometry} \usepackage{bm} \usepackage{amsmath} \usepackage{amssymb} \usepackage{hyperref} \usepackage{relsize} \usepackage{xspace} \usepackage{multicol} \usepackage{nomencl} \usepackage{titlesec} \usepackage{titletoc} \usepackage[bottom]{footmisc} \usepackage{makeidx} \usepackage{charter} \usepackage{textfit} \usepackage[numbers,sort&compress]{natbib} \usepackage{hypernat} \usepackage{fancyhdr} \usepackage{fancyvrb} \usepackage{bbold} \usepackage[usenames]{color} \usepackage{caption2} \renewcommand\captionlabelfont{\footnotesize\upshape\bfseries} \renewcommand\captionfont{\footnotesize} \makeindex \newcommand{\dcite}[1]{{\citeauthor{#1}~\cite{#1}}} \newcommand{\ddcite}[2]{{\citeauthor{#1}~\cite{#1,#2}}} \setlength{\skip\footins}{15pt plus 4pt minus 2 pt} \DeclareMathOperator{\sgn}{sgn} % Screen environment, for display of verbatim material. \makeatletter \newcommand{\kcomment}[2]{{\bf [#1: #2]}} \newcommand{\bfcomment}[2]{{\bf [#1: #2]}} \newcommand{\outdated}{{\bfseries (documentation no longer correct!)}} \fvset{frame=lines,framerule=0.1pt,framesep=6pt,numbers=none,xleftmargin=5ex,fontfamily=tt,fontsize=\small} \newenvironment{screen}[1]{\hilitelines(#1)\Verbatim}{\endVerbatim} \makeatother \newif\ifhilite \def\hilitelines(#1){% \def\FancyVerbFormatLine##1{% \def\fancylineinput{##1}% \hilitefalse \splitfirst #1,\relax,% \ifhilite\else \fancylineinput \fi}} \def\splitfirst#1,{% \ifx\relax#1\empty\else \hiliteline{#1}{\fancylineinput}\expandafter\splitfirst \fi} \def\hiliteline#1#2{% \ifhilite\else \ifnum\value{FancyVerbLine} = #1 \llap{{\smaller\smaller \raisebox{.8ex}{$\vartriangleright$}}\,\,\,}% \fi \fi} % \colourcmd{#2}\hilitetrue %\def\colourcmd{\colorbox{red}} % List layout. \makeglossary \setlength{\nomitemsep}{-\parsep} %\renewcommand{\nomname}{\hspace{-3mm}\raisebox{3.2mm}{\hbox{\normalsize\it % % List of algorithms and properties:}}\vspace{-7mm}} \renewcommand{\nomname}{\vspace{-17mm}} \renewcommand{\nomlabel}[1]{{\tt \def\cdbat{@}\def\cdbcc{::}#1}\hfill} \renewcommand{\pagedeclaration}[1]{#1~~~} \renewcommand\descriptionlabel[1]{\hbox to \textwidth{\quad\quad\bf {#1}\hfill}} \newcommand{\cdb}{{cadabra}\xspace} \newcommand{\Cdb}{{Cadabra}\xspace} \newcommand{\Cpp}{\leavevmode\rm{\hbox{C\hskip -0.1ex\raise 0.5ex\hbox{\tiny ++}}}\xspace} % Three macros to declare the main usage of a command, property or % member function (to appear in the table of contents of the module % section), and commands to use for every subsequent use in the % text (which may at some stage end up in the index at the end). \newcommand{\cdbcommand}[2]{\nomenclature{\cdbat#1}{\hfill\refpage}{\tt @#1}} \newcommand{\subscommand}[1]{{\tt @#1}} \newcommand{\cdbprop}[2]{\nomenclature{\cdbcc#1}{\hfill\refpage}{\tt ::#1}} \newcommand{\subsprop}[1]{{\tt #1}} \newcommand{\cdbclass}[1]{{\tt #1}} \newcommand{\cdbfile}[1]{{\tt #1}} \newcommand{\member}[1]{{\tt #1}} \newcommand{\subsmember}[1]{{\tt #1}} \newcommand{\deprecated}{\marginpar{{\bf\smaller deprecated}}} \newcommand{\inertcommand}[1]{{\tt @@#1}} \newcommand{\texcommand}[1]{{\tt $\backslash$#1}} \newcommand{\ctri}{{\smaller\smaller$\blacktriangleright$}} \newcommand{\boolargs}{{\it true\/}$|${\it false\/}} \newcommand{\listargs}{{\it expression list\/}} \numberwithin{equation}{section} \newenvironment{props}{\par\noindent{\bf properties:}\description}{\enddescription} \newenvironment{algs}{\par\noindent{\bf algorithms:}\description}{\enddescription} \def\mystrut{\vbox to 8.5pt{}\vtop to 3.5pt{}} \def\V{\hskip10pt\vrule\hskip10pt} \def\T{\hskip10pt\vrule\vrule height2.5pt depth -2.1pt width 10pt} \def\L{\hskip10pt\vrule height 8.5pt depth -2.1pt \vrule height2.5pt depth -2.1pt width 10pt} \def\N{\hskip10pt\phantom{\vrule}\hskip10pt} \def\hw{\hskip-1000pt plus 1fil} % Courtesy of Donald Arsenau. \makeatletter \newenvironment{descerate} {\enumerate \@noitemargtrue \let\@noitemargfalse\relax \renewcommand\makelabel[1]{% \hspace\labelwidth \llap{\@itemlabel}% \hspace\labelsep \textbf{##1}% }% }% {\endenumerate} \makeatother %\renewcommand{\contentsname}{\vspace{-3ex}} % Page layout style % \pagestyle{fancy} \renewcommand{\sectionmark}[1]{\markboth{{\it\small #1}}{}}% \renewcommand{\subsectionmark}[1]{\markboth{{\it\small \thesubsection.~#1}}{}}% \fancyhf{}% \fancyhead[L]{\leftmark\hspace{3cm}} \fancyhead[R]{\thepage}% \renewcommand{\headrulewidth}{.1pt} \renewcommand{\footrulewidth}{0pt} \fancypagestyle{plain}{% \fancyhead{} } % % Neat Young tableau macro (taken from Distler & Zamora [hep-th/9810206]) % Usage: $\tableau{2 1 1}$ % \newdimen\tableauside\tableauside=.8ex %1.0ex \newdimen\tableaurule\tableaurule=.32pt %0.4pt \newdimen\tableaustep \def\phantomhrule#1{\hbox{\vbox to0pt{\hrule height\tableaurule width#1\vss}}} \def\phantomvrule#1{\vbox{\hbox to0pt{\vrule width\tableaurule height#1\hss}}} \def\sqr{\vbox{% \phantomhrule\tableaustep \hbox{\phantomvrule\tableaustep\kern\tableaustep\phantomvrule\tableaustep}% \hbox{\vbox{\phantomhrule\tableauside}\kern-\tableaurule}}} \def\squares#1{\hbox{\count0=#1\noindent\loop\sqr \advance\count0 by-1 \ifnum\count0>0\repeat}} \def\tableau#1{\vcenter{\offinterlineskip \tableaustep=\tableauside\advance\tableaustep by-\tableaurule \kern\normallineskip\hbox {\kern\normallineskip\vbox {\gettableau#1 0 }% \kern\normallineskip\kern\tableaurule}% \kern\normallineskip\kern\tableaurule}} \def\gettableau#1 {\ifnum#1=0\let\next=\null\else \squares{#1}\let\next=\gettableau\fi\next} %\newcommand{\sectionformat}[1]{\colorbox[rgb]{.84,.84,.95}{$\vcenter to 2.5ex{\vspace{-.45ex}\hbox % to 444pt{\bfseries\textcolor[rgb]{0,0,0}{\Huge\bfseries \hspace{3mm}#1\strut\hfill}}}$}} %\newcommand{\subsectionformat}[1]{\colorbox[rgb]{.9,.9,.98}{$\vcenter to 1.5ex{\hbox % to 444pt{\bfseries\textcolor[rgb]{0,0,0}{\large\bfseries \hspace{3mm}\thesubsection~~#1\strut\hfill}}}$}} \newcommand{\sectionformat}[1]{\Huge\bfseries \hspace{3mm}#1} \newcommand{\subsectionformat}[1]{\large\bfseries \hspace{3mm}\thesubsection~~#1} % \titlecontents{section}[0pt]{\addvspace{1pc}\itshape}% % {\contentsmargin{0pt}\bfseries% % \makebox[0pt][r]{\large\thecontentslabel\enspace}\large}% % {\contentsmargin{0pt}\large} % {\quad\thepage}[\addvspace{.5pc}] \renewcommand{\contentsname}{\hspace{-30pt}Table of Contents} \titleformat{\section}[block] {\normalfont\bfseries}{}{-30pt}{\sectionformat} \titleformat{\subsection}[block] {\bfseries}{}{-30pt}{\subsectionformat} \begin{document} \pagestyle{empty} \begin{flushright} July 2006\\ AEI-2006-038 \end{flushright} \vspace{6ex} \hspace{-3mm}{\bf \scaletowidth{7cm}{Cadabra}}~\\[.8ex] {\it A field-theory motivated approach to symbolic computer algebra}\\[6ex] {\large\bf Copyright \copyright~2001--2007 ~Kasper Peeters}\\[25ex] {\huge\bf Tutorial and reference guide} \vfill \noindent {\smaller This manual is available under the terms of the GNU Free Documentation License, version 1.2.\\ The accompanying software is available under the terms of the GNU General Public License, version 2.} \newpage \pagestyle{fancy} \noindent \Cdb is a computer algebra system for the manipulation of tensorial mathematical expressions such as they occur in ``field theory problems''. It is aimed at, but not necessarily restricted to, high-energy physicists. It is constructed as a simple tree-manipulating core, a large collection of standalone algorithmic modules which act on the expression tree, and a set of modules responsible for output of nodes in the tree. All of these parts are written in \Cpp. The input and output formats closely follow \TeX, which in many cases means that \cdb is much simpler to use than other similar programs. It intentionally does not contain its own programming language; instead, new functionality is added by writing new modules in \Cpp.\\[2ex] This document contains a description of the core program as well as a detailed listing of the functionality of the currently available algorithm modules. Given the origin of \cdb, the bias is currently towards algorithms for problems in (quantum) field theory, general relativity, group theory and related areas. The last part of this text consists of a user guide on how to implement new algorithmic and display modules and thereby extend the functionality of \cdb.\\[3ex] The software is available for download under the terms of the GNU General Public License from \url{http://www.aei.mpg.de/~peekas/cadabra/} .\\[3ex] \noindent A paper introducing \cdb to high-energy physicists is available as \begin{center} \begin{minipage}{.8\textwidth} ``\emph{Introducing Cadabra: a symbolic computer algebra system for\\ field theory problems}'',\\ Kasper Peeters, preprint SPIN-06/46, ITP-UU-06/56, {\tt hep-th/0701238}. \end{minipage} \end{center} Furthermore, a short paper describing the motivation and key technical aspects of \cdb is available as \begin{center} \begin{minipage}{.8\textwidth} ``\emph{A field-theory motivated approach to symbolic computer algebra}'',\\ Kasper Peeters,\\ \emph{Comp.~Phys.~Comm.}~{\bf 176} (2007) 550-558 (title changed in print),\\ {\tt cs.CS/0608005}.\\ \end{minipage} \end{center} Both papers can be obtained from the \cdb web site or the arXiv. \vfill \noindent {\large\bf Copyright \copyright~2001--2007 ~Kasper Peeters}\\[5ex] Max-Planck-Institut f\"ur Gravitationsphysik\\ Albert-Einstein-Institut\\ Am M\"uhlenberg 1\\ 14476 Golm, GERMANY\\[3ex] {\tt kasper.peeters@aei.mpg.de} \newpage \pagestyle{empty} \tableofcontents \cleardoublepage \pagestyle{fancy} \section{Overview and motivation} % http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=281120021009129275%25sowell2%40cox.net % \begin{flushright} {\smaller\smaller ``\,}\begin{minipage}[t]{220pt} \smaller\smaller{\it I think that several of you are missing the obvious. The majority of people use these programs as symbolic calculators -- occasionally. As such they want their input and output to match what they would have written with pencil and paper.''}~ \hfill {\tt soft-sys.math.maple},~2002 \end{minipage} \end{flushright} % %------------ % % Things to be stressed here: % % - Declaring a variable to be equal to something else and % automatically substituting this something else for every % occurence of the variable are two different things. You % want to be able to write % % W_{m} -> A_{m n} C^{n}; % % W_{m}; % @(W_{m}); % % or something like that. Aha erlebnis: yes, we will do it this % way... % % - Intro: % % - tensor expressions not trees, taking this into account afterwards is kludgy % (automatic dummy index renaming, canonicalisation of expressions, % handling of 'indexbracket' constructions; see the RuleUnique % hack in MathTensor). % - property lists are an essential ingredient in writing compact mathematical % notation. They should be builtin, rather than added in the user-space language, % because the algorithms need this property information. % - tensor expressions are not naturally written in functional notation. % - many _programming_ problems are not easiest to solve in Math or % Maple language; a system that has open internals is required. \noindent \Cdb is a computer algebra system for the manipulation of what could loosely be called \emph{tensorial expressions}. It is aimed at, but not necessarily restricted to, theoretical high-energy physicists. The program's interface, storage system and underlying philosophy differ substantially from other computer algebra systems. Its main characteristics are: \begin{itemize} \item[\ctri] Usage of \TeX{} notation for both input and output, which eliminates many errors in transcribing problems from paper to computer and back. \item[\ctri] Built-in understanding of dummy indices and dummy symbols, including their automatic relabelling when necessary. Powerful algorithms for canonicalisation of objects with index symmetries, both mono-term and multi-term. \item[\ctri] A new way to deal with products of non-commuting objects, enabling a notation which is identical to standard physicist's notation (i.e.~no need for special non-commuting product operators). \item[\ctri] A flexible way to associate meaning (``type information'') to tensors by attaching them to ``properties''. \item[\ctri] An optional unlimited undo system. Interactive calculations can be undone to arbitrary level without requiring a full re-evaluation of the entire calculation. \item[\ctri] A simple and documented way to add new algorithms in the form of \Cpp modules, which directly operate on the internal expression tree. \item[\ctri] A command line interface as well as a graphical one, and a \TeX{}macs frontend. \end{itemize} % There is a certain (large) class of problems in high-energy physics, % often classified as ``simple but tedious algebra'', for which existing % computer algebra systems are not very well suited. The most annoying % issues are typically related to the conversion of the physics problem % into computer language, and to the handling of expressions with many, % often implicit indices of various types. \Cdb differs in essential % aspects from other systems, to take away these problems. The program % is somewhere in the middle between a general purpose system like % Mathematica and programs specialised for very particular tasks. % \medskip % The design of \cdb borrows many ideas from other computer algebra % programs. The user interface was inspired to some extent by % H\"oglund's {\tt Tensign}~\cite{hogl1}. Another source of ideas, in % particular concerning the interactive user interface and the ``formula % history'' was the program {\tt Abra}, written by de Roo. The idea of % using \Cpp as the implementation language for algorithms (rather than % a home-brew language like most computer algebra systems do, or a % variant of LISP) can also be found in {\tt GiNaC}, written by % \dcite{e_baue1}. The use of one generic internal representation can % also be found in {\tt Mathematica} and in fact most LISP-like systems, % although the one used by \cdb is more tuned towards flexibility for % the user. Some ideas about symbols being a-priori separate from their % meaning can also be found in {\tt Yacas} by~\dcite{e_pink1} and this % has to some extent been implemented as ``domains'' in {\tt MuPAD}. % Finally, several of the modules were inspired by existing % software. For the manipulation of gamma matrix algebra, I have % borrowed from {\tt GAMMA} by \dcite{Gran:2001yh} as well as {\tt % Abra}. The general relativity module uses many ideas of the {\tt % GRtensorII} software by~\dcite{e_grte1}. % \medskip This document contains a small tutorial, an extensive reference guide and a technical summary of the program's internals together with a guide on how to write new algorithm modules in \Cpp. %Still discuss: Theorist (now Live Math Maker)~\dcite{http://www.livemath.com/} %which has a mouse-based interface. % %\url{http://poisson.dm.unipi.it/~cerulli/LAlgebrista/its2000.php?lang=en} % % Tensorial for mathematica: % http://home.earthlink.net/~djmp/Mathematica.html % See also the 'expression manipulation' thing there. \vfill \noindent\begin{minipage}{\textwidth} \noindent {\bfseries\large Acknowledgements} \medskip \noindent This program uses code written by several other people. The tensor monomial canonicalisation routines rely on the {\tt xPerm} code written by Jos\'e Martin-Garcia~\cite{e_xact}). All representation-theory related problems are handled by the {\tt LiE} software by Marc van Leeuwen, Arjeh Cohen and Bert Lisser~\cite{e_cohe1}. \medskip \noindent The name \Cdb is an implicit acknowledgement to Mees de Roo, who introduced me to his (so far unpublished) Pascal program {\tt Abra} in the fall of 2000. This program has an extremely physicist-friendly way of dealing with fermions and tensor symmetries, and a formula history mechanism still not found in any other comparable computer algebra system. \Cdb was originally planned to be ``my private \Cpp version of {\tt Abra}'', and even though it does not show much similarity anymore, the development was to a large extent inspired by {\tt Abra}. \end{minipage} \eject \section{Tutorial} The best way to explain the advantages of a new computer algebra system is to demonstrate its ease-of-use for a real-world problem. But if you lack the patience to even read the tutorial on the next few pages, at least read the remainder of this page for an absolute minimum of information. All input in the examples is prefixed with a ``$\vartriangleright$'' symbol. \begin{itemize} \item[\ctri] Start the program by typing ``{\tt prompt cadabra}''. Quit with the ``\subscommand{quit}'' command. \item[\ctri] Tensor expressions are entered as in \TeX{}, with subscripts and superscripts as you know them, e.g. \begin{screen}{1} A_{m n} B^{m q} R^{n}_{q}; \end{screen} Input lines are terminated with ``;'', ``:'' or ``.'' punctuation; see section~\ref{s:input_format} on page~\pageref{s:input_format} for information on what these characters mean. \item[\ctri] Tensors carry properties, such as ``being a Riemann tensor''. These properties are attached by using a double-double dot notation, \begin{screen}{1,2,3} R_{m n p q}::RiemannTensor. g_{m n}::Metric. \psi::Spinor. \end{screen} A list of all properties and the place where they are described in this manual can be found on page~\pageref{s:modules}. \item[\ctri] For many operations \cdb needs to know about the names which it can use for `dummy' indices. You declare dummy indices as \begin{screen}{1} {m,n,p,q}::Indices(vector). \end{screen} where ``{\tt vector}'' is a chosen name for this index set. See section~\ref{s:automaticdummies} on page~\pageref{s:automaticdummies}. \item[\ctri] For many other operators, \cdb needs to know the range over which indices run. Set these index ranges by attaching the \subsprop{Integer} property to the indices, e.g. \begin{screen}{1} {m,n,p,q}::Integer(0..10). \end{screen} \item[\ctri] Expressions can be given a label so you can refer to them again later; you do this by writing the label before the expression and a ``:='' in between, \begin{screen}{1} MaxwellEom:= \diff{F^{m n}}_{n} = 0; \end{screen} \item[\ctri] All things starting with `@' are commands (also called ``active nodes''). Some of the frequently used commands are \subscommand{substitute} (page~\pageref{loc_substitute}), \subscommand{canonicalise} (page~\pageref{loc_canonicalise}) and \subscommand{collect\_terms} (page~\pageref{loc_collect_terms}). \end{itemize} \eject % \subsection{Kaluza-Klein gravity} % % Starting from the Einstein-Hilbert action in four dimensions, a % reduction on a circle produces a theory in three dimensions which % contains two vector fields (one from the Kaluza-Klein vector and one % from the dualised Kaluza-Klein scalar). % % The interactive form of the program is started using the command % \begin{screen}{0} % prompt cadabra % \end{screen} % This produces a startup message and a prompt. We will go through a % simple example in general relativity to get used to the program. % First, we associate properties to the symbols which we will use: % \begin{screen}{0} % m::Integer(0..d-1). % n::Integer(0..d-1). % g_{m n}::Metric. % \Gamma^{m}_{n p}::ChristoffelSymbol. % R_{m n p q}::RiemannTensor. % \end{screen} % In these expressions, the symbols {\tt Integer}, {\tt % ChristoffelSymbol} and {\tt RiemannTensor} are so-called % ``properties'', which are known to \cdb. A list of all known % properties can be found in section~\ref{s:modules}. They are always % associated to names by using the ``::'' notation. The names to which % we associate these properties are arbitrary and we could have % e.g.~used a different symbol to denote a Riemann tensor. For more on % the input format, see section~\ref{s:input_format}. % % % % (for more on the way in which active nodes act, see section~\ref{s:active_nodes}). % % (this algorithm is provided by one of the many separate modules, see % section~\ref{s:modules} for a description of the ones presently available). % \subsection{Tutorial 1: Tensor monomials and multi-term symmetries} \Cdb contains powerful algorithms to bring any tensorial expression into a canonical form. For multi-term symmetries, \cdb relies on Young tableau methods to generate a canonical form for tensor monomials. \footnote{The user interface for multi-term symmetries is under active development and will simplify substantially in upcoming releases.} As an example, consider the identity \begin{multline} W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} \\[1ex] = W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a} - \frac{1}{4} W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}\,. \end{multline} in which~$W_{m n p q}$ is a Weyl tensor (all contracted indices have been written as subscripts for easier readability). Proving this identity requires multiple uses of the Ricci cyclic identity, \begin{equation} W_{m [n p q]} = 0 \,. \end{equation} With \cdb's Young tableau methods the proof is simple. We first declare our objects and input the identity which we want to prove, \begin{screen}{1,2,4} {m,n,p,q,r,s,t,u,v,w,a,b,c,d,e,f}::Indices(vector). W_{m n p q}::WeylTensor. W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} - W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a} + (1/4) W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}; \end{screen} Using a Young projector to project all Weyl tensors onto a form which shows the Ricci symmetry in manifest form is done with \hilitelines(0) \begin{screen}{1} @young_project_tensor!(%){ModuloMonoterm}; \end{screen} This algorithm knows that the Weyl tensor sits in the~$\displaystyle\tilde{\tableau{2 2}}$ representation of the rotation group~SO($d$), and effectively leads to a replacement \begin{equation} W_{m n p q} \rightarrow \frac{2}{3} W_{m n p q} - \frac{1}{3} W_{m q n p} + \frac{1}{3} W_{m p n q}\,. \end{equation} We then expand the products of sums and canonicalise using mono-term symmetries, \begin{screen}{1,2,3,4} @distribute!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{screen} The last line produces the expected ``zero''. A slightly more complicated multi-term example can be found in \TeX{}macs format in {\tt texmacs/showcase1.tm}. \subsection{Tutorial 2: Tensor monomials, part two} It is easy to generate complete bases of tensor monomials, for any arbitrary tensors (not necessarily for tensors in irreps, as in the previous example). As an example, let us show how this works for a basis constructed from three powers of the Riemann tensor. All that is required is \begin{screen}{1,2,4,6,7} {m,n,p,q,r,s,t,u,v,w,a,b}::Indices(vector). {m,n,p,q,r,s,t,u,v,w,a,b}::Integer(0..9). R_{m n p q}::RiemannTensor. basisR3:= R_{m n p q} R_{r s t u} R_{v w a b}; @all_contractions(%); \end{screen} The result can be further simplified using \begin{screen}{1,2,3,4,5} @canonicalise!(%): @substitute!(%)( R_{m n m n} -> R ): @substitute!(%)( R_{m n m p} -> R_{n p} ): @substitute!(%)( R_{n m p m} -> R_{n p} ): @substitute!(%)( R_{n m m p} -> R_{n p} ); \end{screen} which leads something like\footnote{The algorithm involves a random step which implies that the basis is not always the same, though it is always complete. Further improvements are in preparation which will eliminate this randomness (and also lead to a speedup).} \begin{screen}{0} basisR3:= \{ R_{m n p q} * R_{m p r s} * R_{n r q s}, R * R_{q r} * R_{q r}, R_{n p} * R_{n q p r} * R_{q r}, R_{n p} * R_{n q r s} * R_{p r q s}, R * R_{p q r s} * R_{p q r s}, R_{n p} * R_{n r} * R_{p r}, R_{m n p q} * R_{m r p s} * R_{n r q s}, R * R * R \}; \end{screen} This result is equivalent to the basis given in the ``${\cal R}^0_{6,3}$'' table on page~1184 of~\cite{Fulling:1992vm}. \subsection{Tutorial 3: World-sheet supersymmetry} \label{s:tut_worldsheet} \Cdb not only deals with bosonic tensors, but also with fermionic objects, i.e.~anti-commuting variables. A simple example on which to illustrate their use is the Ramond-Neveu-Schwarz superstring action. We will here show how one uses \cdb to show invariance of this action under supersymmetry (a calculation which is easy to do by hand, but illustrates several aspects of \cdb nicely). We will use a conformal gauge and complex coordinates. We first define the properties of all the symbols which we will use, \begin{screen}{1,2,3,4,5} {\del{#}, \delbar{#}}::Derivative. {\Psi_\mu, \Psibar_\mu, \eps, \epsbar}::AntiCommuting. {\Psi_\mu, \Psibar_\mu, \eps, \epsbar}::SelfAntiCommuting. {\Psi_\mu, \Psibar_\mu, X_\mu}::Depends(\del,\delbar). {\Psi_\mu, \Psibar_\mu, \eps, \epsbar, X_\mu, i}::SortOrder. \end{screen} All objects are by default commuting, so the bosons do not have to be declared separately. You can at any time get a list of the declared properties by using the command \subscommand{proplist}. Now we have to input the action density (see~\cite{kas_kystring} for the conventions used here) \begin{screen}{1} action:= \del{X_\mu} \delbar{X_\mu} + i \Psi_\mu \delbar{\Psi_\mu} + i \Psibar_\mu \del{\Psibar_\mu}; \end{screen} Observe how we wrapped the \texcommand{del} and \texcommand{delbar} operators around the objects on which they are supposed to act. We are now ready to perform the supersymmetry transformation. This is done by using the \subscommand{substitute} algorithm, \begin{screen}{1,5,6} @vary!(%)( X_\mu -> i \epsbar \Psi_\mu + i \eps \Psibar_\mu, \Psi_\mu -> - \epsbar \del{X_\mu}, \Psibar_\mu -> - \eps \delbar{X_\mu} ); @distribute!(%); @prodrule!(%); \end{screen} The \subscommand{prodrule} command has applied the Leibnitz rule on the derivatives, so that the derivative of a product becomes a sum of terms. We expand again the products of sums, and use \subscommand{unwrap} to take everything out of the derivatives which does not depend on it, \begin{screen}{1,2,3} @distribute!(%); @unwrap!(%); @prodsort!(%); \end{screen} At this stage we are left with an expression which still contains double derivatives. In order to write this in a canonical form, we eliminate all double derivatives by doing one partial integration. This is done by first marking the derivatives which we want to partially integrate, and then using \subscommand{pintegrate}, \begin{screen}{1,2,3,4,5,6,7,8,9,10} @substitute!(%)( \del{\delbar{X_{\mu}}} -> \pdelbar{\del{X_{\mu}}} ); @substitute!(%)( \delbar{\del{X_{\mu}}} -> \pdel{\delbar{X_{\mu}}} ); @pintegrate!(%){ \pdelbar }; @pintegrate!(%){ \pdel }; @rename!(%){"\pdelbar"}{"\delbar"}; @rename!(%){"\pdel"}{"\del"}; @prodrule!(%); @distribute!(%); @unwrap!(%); @prodsort!(%); \end{screen} Notice how, after the partial integration, we renamed the partially integrated derivatives back to normal ones (and again apply Leibnitz' rule). If we now collect terms, \begin{screen}{1} @collect_terms!(%); \end{screen} we indeed find that the total susy variation vanishes. \subsection{Tutorial 4: Super-Maxwell} The following example illustrates the use of a somewhat more complicated set of object properties. A \TeX{}macs version of this problem can be found in the distribution tarball in the file {\tt texmacs/showcase3.tm}. We start with the super-Maxwell action, given by \begin{equation} S = \int\!{\rm d^4}x\, \Big[ -\frac{1}{4} (F_{ab})^2 - \frac{1}{2}\bar{\lambda}\gamma^a \partial_a \lambda\Big]\,, \end{equation} It is supposed to be invariant under the transformations \begin{equation} \delta A_a = \bar{\epsilon}\gamma_a \lambda\,,\quad \delta \lambda = -\frac{1}{2} \gamma^{a b} \epsilon\, F_{a b}\,. \end{equation} The object properties for this problem are \begin{screen}{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} { a,b,c,d,e }::Indices(vector). \bar{#}::DiracBar. { \partial{#}, \ppartial{#} }::PartialDerivative. { A_{a}, f_{a b} }::Depends(\partial, \ppartial). { \epsilon, \gamma_{#} }::Depends(\bar). \lambda::Depends(\bar, \partial). { \lambda, \gamma_{#} }::NonCommuting. { \lambda, \epsilon }::Spinor(dimension=4, type=Majorana). { \epsilon, \lambda }::SortOrder. { \epsilon, \lambda }::AntiCommuting. \lambda::SelfAntiCommuting. \gamma_{#}::GammaMatrix(metric=\delta). \delta{#}::Accent. f_{a b}::AntiSymmetric. \delta_{a b}::KroneckerDelta. \end{screen} Note the use of two types of properties: those which apply to a single object, like {\tt Depends}, and those which are associated to a list of objects, like {\tt AntiCommuting}. Clearly $\partial_a \lambda$ and $\bar{\epsilon}$ are anti-commuting too, but the program figures this out automatically from the fact that {\tt $\backslash$partial} has an associated {\tt PartialDerivative} property associated to it.\footnote{This is similar to Macsyma's types and features: the property which is attached to a symbol is like a `type', while all properties which the symbol inherits from child nodes are like `features'.} The actual calculation is an almost direct transcription of the formulas above. First we define the supersymmetry transformation rules, \begin{screen}{1} susy:= { \delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = -(1/2) \gamma_{a b} \epsilon f_{a b} }; \end{screen} The action is also written just as it is typed in~\TeX, \begin{screen}{1} S:= -(1/4) f_{a b} f_{a b} - (1/2) \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{screen} Showing invariance starts by applying a variational derivative, \begin{screen}{1,5,6,7} @vary!(%)( f_{a b} -> \partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}, \lambda -> \delta{\lambda} ); @distribute!(%): @substitute!(%)( @(susy) ): @prodrule!(%): @distribute!(%): @unwrap!(%); \end{screen} After these steps, the result is (shown exactly as it appears in the \TeX{}macs~\cite{vdH:Gut} frontend) \begin{equation} S = \bar{\epsilon} \gamma_{a} \partial_{b} \lambda\, f_{ab} + \frac{1}{4} \overline{\gamma_{cb} \epsilon} \gamma_{a} \partial_a\lambda\, f_{cb} + \frac{1}{4} \bar{\lambda}\gamma_a \gamma_{cd} \epsilon \partial_a f_{cb}\,. \end{equation} Since the program knows about the properties of gamma matrices it can rewrite the Dirac bar, and then we do one further partial integration, \begin{screen}{1,2,3,4,5} @rewrite_diracbar!(%); @substitute!(%)( \partial_{c}{f_{a b}} -> \ppartial_{c}{f_{a b}} ): @pintegrate!(%){\ppartial}: @rename!(%){"\ppartial"}{"\partial"}: @prodrule!(%): @unwrap!(%); \end{screen} What remains is the gamma matrix algebra, sorting of spinors (which employs inheritance of the {\tt Spinor} and {\tt AntiCommuting} properties as already alluded to earlier) and a final canonicalisation of the index contractions, \begin{screen}{1,2,4,5} @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @prodsort!(%); @substitute!(%)( \partial_{a}{\bar{\lambda}} -> \bar{\partial_{a}{\lambda}} ); @spinorsort!(%): @rename_dummies!(%): @canonicalise!(%): @collect_terms!(%); \end{screen} The result is a Bianchi identity on the field strength, and thus invariance of the action. % \subsection{BRST transformations} % % \begin{equation} % \begin{aligned} % \delta A_\mu^a &= \epsilon D_\mu^{ab} c^b\,,\\[1ex] % \delta \psi &= i g\, \epsilon c^a t^a \psi\,,\\[1ex] % \delta c^a &= -\tfrac{1}{2} g \epsilon f^{abc} c^b c^c\,,\\[1ex] % \delta \hat{c}^a &= \epsilon B^a\,,\\[1ex] % \delta B^a &= 0\,. % \end{aligned} % \end{equation} % % \begin{screen}{0} % {a, b, c, d, e, f, g}::Indices. % f^{a b c}::AntiSymmetric. % C^{a}::SelfAntiCommuting. % R_{a b d e}::RiemannTensor. % % #f^{a b c} f^{c d e} ( A_\mu^b C^d C^e + A_\mu^d C^e C^b + A_\mu^e C^b C^d ); % R_{a b d e} ( A_\mu^b C^d C^e + A_\mu^d C^e C^b + A_\mu^e C^b C^d ); % @distribute!(%); % @canonicalise!(%); % @rename_dummies!(%); % @collect_terms!(%); % \end{screen} % %R_{a b d e} A_\mu^b C^d C^e; % \subsection{Perturbative gravity} % % % Perhaps the four-point vertex is nice to derive? % In perturbative Einstein gravity, we expand the metric around a fixed % background metric. This can get quite tedious at higher orders. Let us % first illustrate how such a perturbative expansion works at the lowest % order, for instance for~$R_{m n p q} R^{m n p q}$. This is obtained % with % \begin{screen}{0} % {l, m, n, s, t, u, v}::Indices(vector). % R_{l m n s}::RiemannTensor. % h_{m n}::Symmetric. % \diff{#}::PartialDerivative. % % 4 R_{l m n s} R_{l m n s}; % % @substitute!(%)( R_{l m n s} -> % @asym[ \diff{ h_{l s} }_{m n} - \diff{ h_{m s} }_{l n}]{_n, _s} ); % % @distribute!(%): % @canonicalise!(%): % @collect_terms!(%); % \end{screen} % The result is correct, but only because the inverse metrics which % contract the two Riemann tensors do % For next version: some way to write integrals and the like in % a natural notation. % % \begin{screen}{0} % {l, m, n, r, s, t, u, v, w}::Indices(vector, position=fixed). % R_{l m n s}::RiemannTensor. % R::RicciScalar. % R_{l m n s}::Depends(x). % R::Depends(x). % % \int_0^\infty R dx; % \end{screen} % some default input file which does collect_factors, collect_terms, % and so on as people expect. % ::PostDefaultRules( @@sumflatten!(%), @@prodsort!(%), @@collect_factors!(%), @@collect_terms!(%) ). % % ( eta_{n m} + k h_{n m} ) ( eta^{m p} + k h0^{m p} + k**2 h1^{m p} + k**3 h2^{m p}) = \delta_{n}^{p}; % @distribute!(%); % @substitute!(%)( eta_{n m} eta^{m p} -> \delta_{n}^{p} ); % # something to absorb eta, more elegantly than this. @eliminate_metric % # would do, since we already have @eliminate_kr. That could handle all % # such things, together with @eliminate_vielbein. % @substitute!(%)( eta_{n m} A?^{m p} -> A?_{n}^{p} ); % @substitute!(%)( eta^{m n} A?_{p m} -> A?_{p}^{n} ); % @factorise!(%){ h0_{n}^{p}, h_{n}^{p}, h1_{n}^{p}, h2_{n}^{p} }; % @substitute!(%)( A?? = B?? -> A?? - B?? = 0 ); % # Raise indices with eta. % # Some way to create substitution rules out of this. % # so that we end up with { h0_{n}^{p} -> h_{n}^{p}, h1_{n}^{p} -> % @coefficients(%){k}; % \begin{screen}{0} % {l, m, n, r, s, t, u, v, w}::Indices(vector, position=fixed). % R_{l m n s}::RiemannTensor. % R_{l m n s}::Depends(x). % h_{m n}::Symmetric. % g^{m n}::InverseMetric. % \diff{#}::PartialDerivative. % % 4 R_{l m n s} R^{l m n s}; % @rewrite_indices!(%){ R_{m n r s} }{ g^{m n} }; % % @substitute!(%)( R_{l m n s} -> % @asym[ \diff{ h_{l s} }_{m n} - \diff{ h_{m s} }_{l n}]{_n, _s} ); % % @distribute!(%): % @canonicalise!(%): % @collect_terms!(%); % \end{screen} % % % % \subsection{Super-QED in two-component language} % % This example follows the example in appendix C of~\cite{Lucic:1994nc}, % see also \cite{Ichinose:2006pc}. % % \begin{screen}{0} % {\alpha, \gamma, \delta, \beta }::Indices(spinor). % {\dot{\delta}, \dot{\gamma}, \dot{\alpha}, \dot{\beta}}::Indices(dottedspinor). % {\theta^{\alpha}, \psi^{\beta}}::SelfAntiCommuting. % {\theta^{\alpha}, \psi^{\beta}}::AntiCommuting. % \epsilon_{\alpha\beta}::AntiSymmetric. % {\theta^{\alpha}, \epsilon_{\alpha\beta}, \psi^{\alpha}}::SortOrder; % % \theta^{\gamma} \psi^{\beta} \epsilon_{\delta\gamma} \theta^{\delta}; % @prodsort!(%); % @canonicalise!(%); % % {\delta, \gamma, \alpha, \beta}::SelfAntiCommuting. % % {m,n,p}::Indices(flat). % % D( \theta^\delta \theta_\delta F )_\gamma; % @substitute!(%)( D( A?? )_{\gamma} -> \diff{ A?? }_{\gamma} % + i \bar{\theta}^{\dot{\alpha}} \diff{ A?? }_{m} \sigma^{m}_{\gamma \dot{\alpha}} ); % % @prodrule!(%); % @substitute!(%)( \diff{\theta^\alpha}_{\beta} = \delta^{\alpha}_{\beta} ); % @substitute!(%)( \diff{\theta^\alpha}_{m} = 0 ); % \end{screen} % % % \subsection{Eleven-dimensional supergravity} % % The eleven-dimensional supergravity action was first worked out % by~\dcite{crem1}. We would like to derive their form of the action by % constructing the most general supersymmetric action at two-derivative % level. % % The key new ingredient in this example is the use of the % \subscommand{@canonicalise} algorithm. % \vfill\eject % \subsection{Frequently asked questions} % % % This section discusses issues which rely on information from various % parts of the manual and are therefore less easy to find. % \begin{descerate} % \item[``How do \cdb's expression lists compare to notebooks?'']~\\ In % \cdb calculations are organised in a different way from standard % notebook-based computer algebra systems. The main feature is that % there is a more natural way of combining, into a group, all steps that % lead to the derivation of a certain result. In \cdb, this is done by % having each expression carry with it a history of manipulations that % led to it. This structure mimicks more closely what one is used to do % when one manipulates expressions by hand: one takes a given expression % as input, and applies successive algorithms to it (using externally % derived other expressions) until a final form has been arrived at. % % Compare the following two common constructions:\\[-2ex] % \begin{center} % \begin{minipage}{.4\textwidth} % \begin{screen}{0} % expr:= (x+y)^2; % @expand(expr); % @factor(expr); % \end{screen} % \end{minipage} % \begin{minipage}{.4\textwidth} % \begin{screen}{0} % expr:=(x+y)^2; % expr:=expand(expr); % expr:=factor(expr); % \end{screen} % \end{minipage} % \end{center} % \Cdb's form (on the left) more logically groups the manipulations of a % single expression. A different way to understand the organisation is % to think of each expression (together with its history) as a % mini-notebook. Within each such mini-notebook you do calculations just % like in Maple or Mathematica. The starting input of each mini-notebook % can be a newly entered expression or something copied from the result % of a previously evaluated mini-notebook. % \item[``How do I speed up large calculations?'']~\\ Turn off the % history. By default, a history is kept of all expressions, and the % {\tt @pop} command can be used to access previous forms of an % expression. When a calculation contains large expressions and many % algorithms acting on them, this history quickly consumes a lot of % memory. Use the setting {\tt ::KeepHistory(false)} to turn this off % altogether (see section~\ref{s:builtin} for details). Also, turn off % expression printing. By using the ``:'' delimiter instead of the ``;'' % one, output is suppressed (see section~\ref{s:input_format} for more % details). Not only does this make the output less messy, it also % speeds up the program. % % \item[``Why did you not implement this in Mathematica?'']~\\ % Many of the algorithms present in \cdb could have been implemented in % an existing symbolic manipulator such as Mathematica. However, there % is a certain point beyond which the Mathematica code would become more % and more ugly and harder to maintain. Take for instance the example of % the rule {\tt @eliminate\_kr}. This one could be implemented as % \begin{screen}{0} % eliminate_kr := { Delta[m_, m_] -> D } % \end{screen} % But \cdb does much more than this. It allows you to specify the % range of the indices (i.e.~the value of ``{\tt D}'' above) and it also % does not require you to use {\tt Delta} to represent the Kronecker % delta. So the appropriate rule is more like % \begin{screen}{0} % eliminate_kr := { D_?deltaset[m_, m_] -> ... } % \end{screen} % This becomes more and more complicated, and more importantly, diverges % more and more from an efficient and transparent rule-based system when % additional \cdb features are implemented. At some point one reaches a % stage where a conventional programming language like \Cpp shows its % advantages. % % \item[``Why not a separate data and meta language?'']~\\ (The data % language is the language used to write the objects we want to % manipulate; the expression~\verb|R_{m n p q}| is for instance part of % the data language. The meta language is the language which % describes what we want to do with these objects, % i.e.~\verb|ricci_cycle|). In many cases, the input files would look % nicer if we would have a separate data and meta language. Compare % \begin{center} % \begin{minipage}{.4\textwidth} % \begin{screen}{0} % expr:= A+B; % @substitute!(expr)( B -> C ); % \end{screen} % \end{minipage} % \begin{minipage}{.4\textwidth} % \begin{screen}{0} % expr:= A+B; % substitute B -> C into expr; % \end{screen} % \end{minipage} % \end{center} % However, the capability to pass any command or series of commands as % an argument to another command has great advantages (in fact, this is % one of the strengths of e.g.~LISP). Note that because \cdb does not do % automatic substitution of expressions, you can write both \verb|expr| % and \verb|@(expr)| and these mean something different. This is not quite % possible in other systems which have the same data and meta % language. Thinking in terms of pointers (and pointers to algorithm % nodes) is very useful in this respect. % \end{descerate} % % % % \vfill\eject \section{Graphical user interface} \subsection{General information} The graphical user interface is called {\tt xcadabra}. \subsection{Editing, loading, saving} % Use some screenshots to illustrate this. The file format used by the front-end is a \LaTeX{} compatible file. If necessary, it can be edited by hand using a text editor. \subsection{Evaluating cells} In order to evaluate cells, press {\tt ctrl-enter} in an input cell. This will send the input to the kernel and display any results or informal messages below the input cell. \subsection{Printing and exporting} As the file format which the front-end uses to save notebooks is a \LaTeX{} compatible file, it is simple to print a notebook: simply save it and run it through \LaTeX{} as usual. \subsection{The \TeX{}macs frontend} \label{s:texmacs} The program also comes with a \TeX{}macs frontend. If everything is installed correctly, the ``Insert $\rightarrow$ Session'' submenu of \TeX{}macs should contain an entry for \Cdb. A few sample \TeX{}macs files can be found in the {\tt texmacs} subdirectory of the source tarball. \Cdb sends its output more-or-less unchanged to the \TeX{}macs frontend. It is therefore useful to use tensor names which have a meaning in \TeX{}. For example, if you declare a derivative operator, you might be tempted to use \begin{screen}{1} \diff{#}::Derivative. \end{screen} (perhaps because you want to mimic Maple's notation). However, this will lead to ugly output since \texcommand{diff} is not a \TeX{} symbol and \TeX{}macs does not know what to do with it. A better choice would be \begin{screen}{1} \nabla{#}::Derivative. \end{screen} since \texcommand{nabla} actually prints as a nice symbol in \TeX{}macs. If you want to cut-and-paste formulas from a \TeX{} document into a \TeX{}macs notebook, you will encounter the problem that all backslashes get swallowed. To avoid this, choose the menu entry \begin{equation*} \text{Edit}\quad\rightarrow\quad \text{Paste from}\quad\rightarrow\quad \text{Verbatim} \end{equation*} which pastes text unmodified. You can make this the default for middle-button paste by choosing \begin{equation*} \text{Tools}\quad\rightarrow\quad \text{Selections}\quad\rightarrow\quad \text{Import}\quad\rightarrow\quad \text{Verbatim} \end{equation*} which will remain active during the current session. In order to make PDF output work, you have to have {\tt pfbtops}\index{pfbtops} installed (it is usually part of the {\tt groff} package). \section{Reference guide} \subsection{Startup and program options} If present, a startup file {\tt \verb|~/.cadabra|} \index{.cadabra}\index{startup file} will be read when the program is started. This file can contain any \cdb input. \begin{description} \item[{\tt -{}-{}bare}] Disable reading of the startup file \verb|~/.cadabra|. \item[{\tt -{}-{}silent}] Disable normal output (so that the only remaining output is through output redirection into files). \item[{\tt -{}-{}input [filename]}] Before switching to interactive mode, first read and process the indicated file. \item[{\tt -{}-{}prompt [string]}] Set the \cdb prompt to the given string. \item[{\tt -{}-{}silentfail}] Silently fail (i.e. do not complain) if an algorithm is activated which cannot be applied. \item[{\tt -{}-{}loginput}] Write the input into the debug file as well. \item[{\tt -{}-{}nowarnings}] Suppress displaying of any warnings which are not fatal errors. \item[{\tt -{}-{}texmacs}] Send output in TeXmacs format. \end{description} In order to have command-line editing functionality, the {\tt prompt} program is provided. So the two ways of starting \cdb are \begin{screen}{0} cadabra prompt cadabra \end{screen} the second of which gives cursor control and an editing history. There are various other settings of \cdb which can be influenced through environment variables; see section~\ref{s:environment_variables} for details. \subsection{Basics about the input format} \label{s:input_format} The input format of \cdb is closely related to the notation used by \TeX{} to denote tensorial expressions. That is, one can use not only bracketed notation to denote child objects, like in \begin{screen}{0} object[child,child] \end{screen} but also the usual sub- and superscript notation like \begin{screen}{0} object^{child child}_{child} \end{screen} One can use backslashes in the names of objects as well, just as in \TeX{}. All of the symbols that one enters this way are considered ``passive'', that is, they will go into the expression tree just like one has entered them. ``Active nodes'', on the other hand, are symbols pre-fixed with a ``@'' symbol. These are nodes which lead to an algorithm being applied to their children; they will thus not end up in the actual tree stored in memory, but instead get replaced with the output that their algorithm produces (if any). Finally, every non-empty expression that one enters will labelled by a number. Additionally, one can give an expression a label by entering it as ``\mbox{{\tt label-text:=~expression;}}''. One can use either the expression number or the label to refer to an expression. Names of objects can contain any printable character, except for brackets, sub- and super-script symbols and backslash characters (the latter can only occur at the beginning of a name). The sole exception to this rule is the names of active nodes: these names \emph{can} contain underscores to separate words. The program can also deal with ``accents'' added to symbol names, like \begin{screen}{0} \hat{A} \bar{B} \prime{Q} \end{screen} The precise way in which this works is explained in section~\ref{s:accents}. Input lines always have to be terminated with either a ``;'', a ``:'' or a ``.''. The first two of these delimiting symbols act in the same way as in Maple: the second form suppresses the output of the entered expression (see section~\ref{s:inputoutput} for additional information on how to redirect output to files). The last delimiter has the effect of evaluating the resulting expression, and immediately discarding it, also disabling printing. Long expressions can, because of these delimiters, be spread over many subsequent input lines. Any line starting with a ``\#'' sign is considered to be a comment (even when it appears within a multi-line expression). Comments are always ignored completely (they do not end up in the expression tree).\index{comments} All internal storage is in prefix notation, but a converter is applied to the input which transforms normal infix notation for products and sums to prefix notation. %Objects do not have to be declared before they can be used, although %some algorithmic modules may not work in this case. See %section~\ref{s:objprop} for more details. % TODO: - dX for differentials perhaps? % - dX.Psi for inner products? \subsection{Active nodes or ``commands''} \label{s:active_nodes} Active nodes are nodes which lead to immediate evaluation after the input has been entered; these could thus be called ``commands''. Commands always start with a ``@'' symbol, to distinguish them from normal, unevaluated input. Used in the standard ``notebook'' way, active nodes act on their first argument and get replaced with the result that they compute. This form uses square brackets to denote the argument on which to act: \begin{screen}{0} @command[expression]{arg1}{arg2}...{argn} \end{screen} If you want to re-use an existing expression as the argument, this can be cloned by using the ``@'' operator itself: \begin{screen}{0} @[equation number or label] \end{screen} or (for convenience, as a single exception to the square bracket rule) \begin{screen}{0} @(equation number or label) \end{screen} both evaluate to a copy of the expression to which they refer (one can use the ``\%'' character to denote the number of the last-used expression). Note that all of these forms create a \emph{new} expression. One is advised \emph{not} to refer to equation numbers using this command, as this makes expressions tied together in a rather fragile way. Algorithms can also be made to act on existing expressions such as to modify the expression history (i.e.~in the language of the previous section, to stay within a ``mini-notebook''). This is done by using round brackets instead of square ones: \begin{screen}{0} @command(expression number or label){arg1}{arg2}...{argn} \end{screen} Here it is no longer problematic to refer to equation numbers, as the result of this command will appear in the history list of the indicated expression (and is therefore not tied to the particular number of the expression). % Finally, there is a form which acts on % ``marked'' expressions, which will be discussed later. This form does % not have any reference to an object on which to act, since there is % only one ``marker''; it thus looks like % \begin{screen}{0} % @command{arg1}{arg2}...{argn} % \end{screen} % The way in which (parts of) expressions get marked depends on the % particular user interface; more information can be found in % section~\ref{s:marks}. All of these commands act on the top of the argument subtree. You can make them act subsequently on all nodes to which they apply by postfixing the name with an exclamation mark, as in \begin{screen}{0} @command![expression]{arg1}{arg2}...{argn} \end{screen} This will search the tree in pre-order style, applying the algorithm on every node to which the algorithm applies. Instead of acting only at the top of the argument subtree, or acting on all nodes individually, it is also possible to act only a specific level of the expression. The notation for this is an exclamation mark with an extra number attached to it, which indicates the level (starting at 1 for the highest level), \begin{screen}{0} @command!level(expression number of label){arg1}{arg2}...{argn} \end{screen} There is currently no way to apply algorithms until they no longer change the expression; such functionality will be added in a later release. \subsection{Object properties and declaration} \label{s:objprop} Symbols in \cdb have no a-priori ``meaning''. If you write \verb|\Gamma|, the program will not know that it is supposed to be, for instance, a Clifford algebra generator. You will have to declare the properties of symbols, i.e.~you have to tell \cdb explicitly that if you write \verb|\Gamma|, you actually mean a Clifford algebra generator. This indirect way of attaching a meaning to a symbol has the advantage that you can use whatever notation you like; if you prefer to write \verb|\gamma|, or perhaps even \verb|\rho| if your paper uses that, then this is perfectly possible (object properties are a bit like ``attributes'' in {\tt Mathematica} or ``domains'' in {\tt Axiom} and {\tt MuPAD}). Properties are all written using capitals to separate words, as in {\tt AntiSymmetric}. This makes it easier to distinguish them from commands (the fact that they do not have underscores also helps for the parser). Properties of objects are declared by using the ``::'' characters. This can be done ``at first use'', i.e.~by just adding the property to the object when it first appears in the input. As an example, one can write \begin{screen}{1} F_{m n p}::AntiSymmetric; \end{screen} This declares the object to be anti-symmetric in its indices and at the same time creates a new expression with this object. The property information is stored separately, so that further appearances of the ``\verb|F_{m n p}|'' object will automatically share this property. It is of course also possible to keep object property declarations separated (for instance at the top of an input file). This is done as follows: \begin{screen}{1,2} F_{m n p}::AntiSymmetric. F_{m n p}; \end{screen} For more information about this and other commands related to object properties, refer to the documentation about the {\tt properties} module in section~\ref{s:properties}. Note that properties are attached to patterns. Therefore, you can have \begin{screen}{1,2} R::RicciScalar. R_{m n p q}::RiemannTensor. \end{screen} at the same time. The program will not warn you if you use incompatible properties, so if you make a declaration like above and then later on do \begin{screen}{1} R::Coordinate. \end{screen} this may lead to weird results. The fact that objects are attached to patterns also means that you can use something like wildcards. In the following declaration, \begin{screen}{1} { m#, n# }::Indices(vector). \end{screen} the entire infinite set of objects $m1, m2, m3, \ldots$ and $n1, n2, n3, \ldots$ are declared to be in the dummy index set ``vector''.\footnote{This way of declaring ranges of objects is similar to the \index{autodeclare}``autodeclare'' declaration method of FORM~\cite{Vermaseren:2000nd}.}\index{autodeclare}\index{\#} Range wildcards can also be used to match one or more objects of a specific type. In this case, they always start with a ``\#'' sign, followed by optional additional information to specify the type of the object and the number of them. The declaration \begin{screen}{0} {m,n,p,q,r,s}::Indices(vector). A_{ #{m, 1..3} }::AntiSymmetric. B_{ #{m} }::Symmetric. \end{screen} indicates that whenever the object \verb|A| appears with one to three indices of the vector type, it is antisymmetric. If the index type does not match, or if there are zero or more than three indices, the property does not apply. Similarly, \verb|B| is always symmetric when all of its indices are of the vector type.\index{\#}\index{range wildcards} Properties can be assigned to an entire list of symbols with one command, namely by attaching the property to the list. For example, \begin{screen}{1} {n, m, p, q}::Integer(1..d). \end{screen} This associates the property ``Integer'' to each and every symbol in the list. However, there is also a concept of ``list properties'', which are properties which are associated to the list as a whole. Examples of list properties are ``AntiCommuting'' or ``Indices''. See for a discussion of list properties section~\ref{s:list_properties}. Objects can have more than one property attached to them, and one should therefore not confuse properties with the ``type'' of the object. Consider for instance \begin{screen}{1,2,3} x::Coordinate. W_{m n p q}::WeylTensor. W_{m n p q}::Depends(x). \end{screen} This attaches two completely independent properties to the pattern $W_{m n p q}$. In the examples above, several properties had arguments (e.g. ``\verb|vector|'' or ``\verb|1..d|''). The general form of these arguments is a set of key-value pairs, as in \begin{screen}{1} T_{m n p q}::TableauSymmetry(shape={2,1}, indices={0,2,1}). \end{screen} In the simple cases discussed so far, the key and the equal sign was suppressed. This is allowed because one of the keys plays the role of the default key. Therefore, the following two are equivalent, \begin{screen}{1,2} { m, n }::Integer(range=0..d). { m, n }::Integer(0..d). \end{screen} See the detailed documentation of the individual properties for allowed keys and the one which is taken as the default. Finally, there is a concept of ``inherited properties''. Consider e.g.~a sum of spinors, declared as\index{properties!inheritance} \begin{screen}{1,2} {\psi1, \psi2, \psi3}::Spinor. \psi1 + \psi2 + \psi3; \end{screen} Here the sum has inherited the property ``Spinor'', even though it does not have normal or intrinsic property of this type. Properties can also inherit from each other, e.g. \begin{screen}{1,2,3} \Gamma_{#}::GammaMatrix. \Gamma_{p o i u y}; @indexsort!(%); \end{screen} The \subsprop{GammaMatrix} property inherits from \subsprop{AntiSymmetric} property, and therefore the {\tt $\backslash$Gamma} object is automatically anti-symmetric in its indices. A list of all properties known to \cdb can be obtained by using the \subscommand{proplist} command.\index{properties!list of all} % @exchange, which exchanges two terms in a product, should know % something about the commutator rule for two objects. But this is a % property of \prod? NO, that leads to putting many rules on prod, % exactly the kind of problem Mathematica is also facing. % Refer to DeWitt's compact index notation; indices can take values in % the integers or in any continuous set. \subsection{List properties and symbol groups} \label{s:list_properties} Some properties are not naturally associated to a single symbol or object, but have to do with collections of them. A simple example of such a property is \subsprop{AntiCommuting}. Although it sometimes makes sense to say that ``$\psi_m$ is anticommuting'' (meaning that $\psi_m \psi_n = - \psi_n \psi_m$), it happens just as often that you want to say ``$\psi$ and $\chi$ anticommute'' (meaning that $\psi\chi = - \chi\psi$). The latter property is clearly relating two different objects. Another example is dummy indices. While it may make sense to say that ``$m$ is a dummy index'', this does not allow the program to substitute $m$ with another index when a clash of dummy index names occurs (e.g.~upon substitution of one expression into another). More useful is to say that ``$m$, $n$, and $p$ are dummy indices of the same type'', so that the program can relabel a pair of $m$'s into a pair of $p$'s when necessary. In \cdb such properties are called ``list properties''. You can associate a list property to a list of symbols by simply writing, e.g. for the first example above, \begin{screen}{1} { \psi, \chi }::AntiCommuting. \end{screen} Note that, as described in section~\ref{s:objprop}, you can also attach normal properties to multiple symbols in one go using this notation. The program will figure out automatically whether you want to associate a normal property or a list property to the symbols in the list. Lists are ordered, although the ordering does not necessarily mean anything for all list properties (it is relevant for e.g.~\subsprop{SortOrder} but irrelevant for e.g.~\subsprop{AntiCommuting}). \subsection{Indices, dummy indices and automatic index renaming} \label{s:automaticdummies} In \cdb, all objects which occur as subscripts or superscripts are considered to be ``indices''. The names of indices are understood to be irrelevant when they occur in a pair, and automatic relabelling will take place whenever necessary in order to avoid index clashes. \Cdb knows about the differences between free and dummy indices. It checks the input for consistency and displays a warning when the index structure does not make sense. Thus, the input \begin{screen}{1} A_{m n} + B_{m} = 0; \end{screen} results in an error message. The location of indices is, by default, not considered to be relevant. That is, you can write \begin{screen}{1,2} A_{m} + A^{m}; A_{m} B_{m}; \end{screen} as input and these are considered to be consistent expressions. If, however, the position of an index means something (like in general relativity, where index lowering and raising implies contraction with a metric), then you can declare index positions to be ``fixed''. This is done using \begin{screen}{1} {m, n, p}::Indices(position=fixed). \end{screen} When substituting an expression into another one, dummy indices will automatically be relabelled when necessary. To see this in action, consider the following example: \begin{screen}{1,2,5} {p,q}::Indices(vector). F_{m n} F^{m n}; F_{m n} F^{m n} G_{m n} @(1); G_{m n} F_{p q} F^{p q} \end{screen} The $m$ and $n$ indices have automatically been converted to $p$ and $q$ in order to avoid a conflict with the free indices on the $G_{m n}$ object. Refer to section~\ref{s:dummies} for commands that deal with dummy indices. %\bfcomment{KP}{Explain the canonicalisation algorithm and compare with %other approaches in the literature} \begin{table}[t] \begin{center} \begin{tabular}{rlll} argument & whitespace & dummy & example \\[1ex] \verb|{}| & separator & & \verb|alg{a b} = alg{a}{b}|\\ \verb|()| & product & & \verb|sin(a b) = sin(a * b)|\\ \verb|_{}| & separator & yes & \verb|M_{a b} = M_{a}_{b}|\\ \verb|^{}| & separator & yes & \verb|M^{a b} = M^{a}^{b}|\\ \verb|_()| & separator & & \verb|M_(a b) = M_(a)_(b)|\\ \verb|^()| & separator & & \verb|M^(a b) = M^(a)^(b)|\\ \verb|[]| & product & & \verb|[a b, c] = [a * b, c]| \end{tabular} \caption{The implicit meaning of objects and whitespace inside the various types of brackets.} \label{t:argtypes} \end{center} \end{table} \subsection{Exponents, indices and labels} Exponents, indices and labels are traditionally all placed using super- or subscript notation, making these slightly ambiguous for a computer algebra system. Since this situation can become quite complex (how do you represent the third power of the first element of a vector?) \cdb requires all powers to be entered with a double-star ``$**$'' notation: \begin{screen}{1,2} a**2; a**(2 + 3b); \end{screen} In addition, %\item All superscripts that are enclosed in \emph{round} %brackets denote exponents, i.e.~\verb|a^(-c)| means $a$ raised to the %power $-c$. all sub- or superscripts with \emph{curly} braces indicate indices, to which the summation convention applies. In particular, there are not allowed to be more than two identical indices in a single product. The summation convention does not apply to arguments with any other bracket types. In particular, sub- or superscripts with \emph{square} or \emph{pointy} brackets have (as of yet) no fixed meaning. \subsection{Spacing and brackets} \Cdb is reasonably flexible as far as spacing and brackets are concerned, but the fact that objects do not have to be declared before they can be used means that spaces have to be introduced in some cases to avoid ambiguity. As a general rule, all terms in a product have to be separated by at least one whitespace character. Thus, \begin{quote} \begin{tabular}{ll} {\tt A(B+C)} & incorrect, (interpreted as {\tt A} with argument {\tt B+C}), \\[1ex] {\tt AB} & incorrect, (interpreted as one object, not two) \\[1ex] {\tt A (B+C)} & correct, \\[1ex] {\tt A*(B+C)} & correct. \end{tabular} \end{quote} If a whitespace character is absent, all brackets are interpreted as enclosing \emph{argument} groups. Products of variables (e.g.~$AB$) have to be separated by a space, otherwise the input will be read as the name of a single variable. However, spaces will automatically be inserted after numbers, between a closing bracket and a name or number, and between two names if the second name starts with a backslash. The following expressions are therefore interpreted as one would expect: \begin{quote} \begin{tabular}{ll} {\tt 3A} & interpreted as {\tt 3*A}\\[1ex] {\tt (A+B)C} & interpreted as {\tt (A+B)*C}\\[1ex] {\tt (A+B)3} & interpreted as {\tt (A+B)*3}\\[1ex] {\tt A$\backslash$Gamma}& interpreted as {\tt A*$\Gamma$}\\[1ex] \end{tabular} \end{quote} This conversion is done by the preprocessor. Finally, note that brackets in the input \emph{must} be balanced (a decision made to simplify the parser; it means that \cdb uses a different way to indicate groups of symmetric or anti-symmetric indices than one often encounters in the literature; see section~\ref{s:tensor}). \subsection{Implicit versus explicit indices} \subsection{Indexbrackets} Indices can be associated to tensors, as in~$T_{\mu\nu}$, but it often also happens that we want to associate indices to a sum or product of tensors, without writing all indices out explicitly. Examples are \begin{equation} (A + B + C)_{\alpha\beta}\,,\quad\text{or}\quad (\psi \Gamma_{m n} \Gamma_{p})_{\beta}\,. \end{equation} Here the objects $A$, $B$, $C$ and~$\Gamma$ are matrices, while~$\psi$ is a vector. Their explicit components are labelled with~$\alpha$ and~$\beta$ indices, but the notation above keeps most of these vector indices implicit. \Cdb can deal with such expressions through a construction which is called the ``indexbracket''. It is possible to convert from one form to the other by using the \subscommand{combine} and \subscommand{expand} algorithms. Combining terms goes like this, \begin{screen}{1,2} (\Gamma_r)_{\alpha\beta} (\Gamma_{s t u})_{\beta\gamma}: @combine!(%); (\Gamma_r \Gamma_{s t u})_{\alpha\gamma}; \end{screen} or as in \begin{screen}{1,2} (\Gamma_r)_{\alpha\beta} Q_\beta: @combine!(%); (\Gamma_r Q)_{\alpha}; \end{screen} If the index bracket has only one index, either the first or the last argument should be a matrix, but not both: \begin{screen}{1,2,4} A::Matrix. {m,n,p}::Indices(vector). (A B)_{m}; @expand(%); A_{m n} B_{n}; \end{screen} If the index bracket has two indices, all arguments should be matrices, \begin{screen}{1,2,3} {A,B}::Matrix. {m,n,p}::Indices(vector). (A B)_{m n}; @expand(%); A_{m p} B_{p n}; \end{screen} If there are more arguments inside the bracket, these of course all need to be matrices (and are assumed to be so by default). \subsection{Derivatives and implicit dependence on coordinates} \label{s:derivatives} There is no fixed notation for derivatives; as with all other objects you have to declare derivatives by associating a property to them, in this case the \subsprop{Derivative} property. \begin{screen}{1} \nabla{#}::Derivative. \end{screen} Derivative objects can be used in various ways. You can just write the derivative symbol, as in \begin{screen}{1} \nabla{ A_{\mu} }; \end{screen} (a notation used e.g.~in the tutorial example in section~\ref{s:tut_worldsheet}). Or you can write the coordinate with respect to which the derivative is taken, \begin{screen}{1,2,3} s::Coordinate. A_{\mu}::Depends(s). \nabla_{s}{ A_{\mu} }; \end{screen} Finally, you can use an index as the subscript argument, as in \begin{screen}{1,2} { \mu, \nu }::Indices(vector). \nabla_{\nu}{ A_{\mu} }; \end{screen} (in which case the first line is, for the purpose of using the derivative operator, actually unnecessary). The main point of associating the \subsprop{Derivative} property to an object is to make the object obey the Leibnitz or product rule, as illustrated by the following example, \begin{screen}{1,2,3} \nabla{#}::Derivative. \nabla{ A_{\mu} * B_{\nu} }; @prodrule!(%); \nabla{A_{\mu}} B_{\nu} + A_{\mu} \nabla{B_{\nu}}; \end{screen} This behaviour is a consequence of the fact that \subsprop{Derivative} derives from \subsprop{Distributable}. Note that the \subsprop{Derivative} property does not automatically give you commuting derivatives, so that you can e.g.~use it to write covariant derivatives. More specific derivative types exist too. An example are partial derivatives, declared using the \subsprop{PartialDerivative} property. Partial derivatives are commuting and therefore automatically symmetric in their indices, \begin{screen}{1,2,3,5,6} \partial{#}::PartialDerivative. {a,b,m,n}::Indices(vector). C_{m n}::Symmetric. T^{b a} \partial_{a b}( C_{m n} D_{n m} ); @canonicalise!(%); T^{a b} \partial_{a b}( C_{m n} D_{m n} ); \end{screen} \subsection{Accents} \label{s:accents} It often occurs that you want to put a hat or tilde or some other accent on top of a symbol, as a means to indicate a slightly different object. In most of these cases, the properties of the normal symbol and the accented symbol are identical. Such accents are declared using the \subsprop{Accent} property, as in \begin{screen}{0} \hat{#}::Accent. \end{screen} This automatically makes all symbols with hats inherit the properties of the unhatted symbols, \begin{screen}{1,2,3,4,5} \hat{#}::Accent. {\psi, \chi}::AntiCommuting. {\psi, \chi}::SortOrder. \hat{\chi} \psi: @prodsort!(%); (-1) \psi \hat{\chi}; \end{screen} If you want to put an accent on an object with indices, wrap the accent around the entire object, do not leave the indices outside. Note that it is also possible to mark objects by attaching sub- or superscripted symbols to them, as in e.g.~$A^\dagger$. This can be done by declaring these symbols explicitly using the \subsprop{Symbol} property, \begin{screen}{1} \dagger::Symbol. \end{screen} If you do not do this, \texcommand{dagger} will be seen as an index and an error will be reported if it appears more than twice. \subsection{Symbol ordering and commutation properties} \label{s:symbol_ordering} A conventional way to sort factors in a product is to use lexographical ordering. However, this is almost never what one wants when transcribing a physics problem to the computer. Therefore, \cdb allows you to specify the sort order of symbols yourself. This is done by associating the \subsprop{SortOrder} list property to a list of symbols, as in \begin{screen}{1,2,3} {X,G,Y,A,B}::SortOrder. A*B*G*X*A*X: @prodsort(%); X*X*G*A*A*B; \end{screen} More complicated objects with indices are of course also allowed, such as in \begin{screen}{1,2,3} { W_{m n}, W_{m} }::SortOrder. W_{m n} W_{p} W_{q r} W_{s} W_{t}: @prodsort(%); W_{m n} * W_{q r} * W_{p} * W_{s} * W_{t}; \end{screen} For the time being, it is not allowed to have more than one such set contain the same symbol. Thus, \begin{screen}{1,2} {X,G}::SortOrder. {X,A,B}::SortOrder. \end{screen} is not allowed (and will, in fact, take $X$ out of the first list). %> A*B*G*X: %@prodsort(%); %X*A*B*G; %Beware that the program does not prevent you from constructing %mutually contradictory sort orders: when a product sort is performed %and two factors have to be compared, the program will simply look in %the lists until it finds one particular list which contains the two %factors. Apart from the preferred sort order, there are more properties which influence the way in which products can be sorted. In particular, sort order is influenced by whether symbols commute or anti-commute with each other. Physicists in general use a very implicit notation as far as commutativity of objects in a product is concerned. Consider for instance a situation in which we deal with two operators $\hat M$ and $\hat N$, as well as some constants $q$ and $p$. These two expressions are equivalent: \begin{equation} 2q\, \hat M p \hat N \quad\text{and}\quad 2pq\, \hat M \hat N \,. \end{equation} But this is not obvious from the notation that has been used to indicate the product. In fact, the product symbol is usually left out completely. In many other computer algebra systems, you have to introduce special types of ``non-commuting'' products (e.g.~the \verb|&*| operator in Maple or the \verb|**| operator in Mathematica). This can be rather cumbersome, for a variety of reasons. The main reason, however, is that it does not match with what you do on paper. On paper, you never write special product symbols for objects which do not commute. You just string them together, and know from the properties of the symbols whether objects can be moved through each other or not. In order to make these sort of things possible in \cdb, it is necessary to declare ``sets'' of objects which mutually do not commute (i.e.~for which the order inside a product cannot be changed without consequences) but which commute with objects of other sets. Many computer algebra systems only use one such set: objects are either ``commuting'' or ``non-commuting''. This is often too restrictive. For instance, when $\Psi$ is a fermion and $\Gamma$ denotes a Clifford algebra element, a system with only one set of non-commuting objects is unable to see that \begin{equation} \bar\Psi_a (\Gamma_n\Gamma_m)_{ab} \Psi_b \quad\text{and}\quad \bar\Psi_a \Psi_b (\Gamma_n\Gamma_m)_{ab} \end{equation} are equivalent. In \cdb, one would simply put $\Psi_{a}$ and $\Gamma_{m}$ in two different sets, mutually commuting, but non-commuting among themselves. To be precise, the example above is reproduced by \begin{screen}{1,2,3,4,5} \bar{#}::Accent. \Psi_{a}::SelfNonCommuting. \Gamma_{#}::GammaMatrix. \bar{\Psi_a} (\Gamma_n \Gamma_m)_{ab} \Psi_b: @prodsort(%); \bar{\Psi_a} \Psi_b (\Gamma_n \Gamma_m)_{ab}; \end{screen} (see section~\ref{s:accents} for an explanation of the \subsprop{Accent} property). Commutation properties always refer to components. If you associate an \subsprop{ImplicitIndex} property to an object, then it will never commute with itself or with any other such object. You can see this in the example above, as the \subscommand{prodsort} command kept the order of the two gamma matrices unchanged. %\subsection{Component values and calculations} %\label{s:component_values} % %(This section is preliminary and experimental.) % gammacomponents: { \Gamma^{1}_{a b} = {{1,2,3},{1,2,4},..}, % \Gamma^{2}_{a b} = {{....} } % % \bar{\psi} \Gamma^\mu \psi V_{\mu} % @expand_index_bracket % @write_out!(%){ @(gammacomponents) }{ \mu }; % If you write out R_{m n p q} R_{m n p q} in components this leads % to d^4 terms. How can we reduce this so we do not double count? % The best way to minimise the number of terms is to assume that % we are, most of the time, contracting mostly-empty tensors. % (if you do not make that assumption then the computation will be % horrible anyway). % % R_{m n p q} T_{m n p q} % {1,3,2,5}=exp1 {2,4,3,5}=exp2 % {2,4,3,5}=exp3 {6,4,3,2}=exp3 % ... % % determine the number of non-zero components for % each tensor, taking into account Young projection. % Use this to sort the loop order below (use tensor % with lowest number of components in outer loop). % for(all non-zero components in tensor 1) % for(all non-zero components in tensor 2) % ... % if(the index values match) % multiply and store in sum. % % How do we instruct the program to compute components of % composite tensors? % % \Gamma_{m n}^{p} = 1/2 g^{p q} (\partial_{n}{g_{m q}} + % \partial_{m}{g_{n q}} - % \partial_{q}{g_{m n}} ); % % Here we need to associate coordinates to indices. % % {t,r,phi,theta}::Coordinate(polar). % {m,n,p,q,r}::Indices(vector, basis=polar). % g_{m n}::Metric(polar). % % R_{m n p}^{q} = \partial_{m}{\Gamma \subsection{Input and output redirection} \label{s:inputoutput} By default, all generated output is displayed on the screen. As mentioned in section~\ref{s:input_format}, the delimiter of a line determines whether output is suppressed or not. It is, however, also possible to write output to a file, by appending a file name to the line delimiter, as in \begin{screen}{1} a^2+b^2 = c^2; "output_file" \end{screen} (note that there is no semi-colon following the file name). This shows the filename ``output\_file'' on the display, and writes to this file the expression \begin{screen}{0} 1:= a^{2}+b^{2}=c^{2} \end{screen} This is exactly as it would have appeared on the display. If you need a different kind of output, use the algorithms provided in the {\tt output} module (see section~\ref{s:output}). It is also possible to read input from files instead of from the terminal: \begin{screen}{1} < "input_file" \end{screen} reads from the file ``input\_file'' until the end or until a line \verb|@end;| is found, whichever comes first. Input redirect can be nested. In case an error occurs, reading from the file is also aborted and input is taken from the terminal again. \subsection{Default rules} By default, \cdb does very few things ``by itself'' with your expressions. This goes as far as not collecting equal terms, so that you can write \begin{screen}{1} A + A; \end{screen} and have this stored as a sum of two terms. However, you can add an arbitrary number of default commands, which are run just after you have entered an expression on the command line (\subsprop{PreDefaultRules}) or just before the output is returned to you (\subsprop{PostDefaultRules}). So if you want terms to be collected automatically, just enter \begin{screen}{1} ::PostDefaultRules( @@collect_terms!(%) ). \end{screen} Note the double ``@@'' symbol, which prevents immediate execution of the command. This post default rule will collect equal terms before they ever make it to internal storage. Many more complicated things can be achieved with this feature. You can, for instance, also use complicated substitution commands as arguments to \subsprop{PreDefaultRules} or \subsprop{PostDefaultRules}. An example is \begin{screen}{1,2,4} {m,n,p,q}::Indices(vector). ::PreDefaultRules( @@substitute!(%)( A_{m n} -> B_{m q} B_{q n} ). A_{m n} A_{n m}; \end{screen} which immediately returns \begin{screen}{0} B_{m q} B_{q n} B_{n p} B_{p m}; \end{screen} As usual dummy indices have been relabelled appropriately. \subsection{Patterns, conditionals and regular expressions} Patterns in \cdb are quite a bit different from those in other computer algebra systems, because they are more tuned towards the pattern matching of objects common in tensorial expressions, rather than generic tree structures. Name patterns are constructed by writing a single question mark behind the name, as in \begin{screen}{1} @substitute!(%)( A? + B? -> 0 ); \end{screen} which matches all sums with two terms, each of which is a single symbol without indices or arguments. If you want to match instead any object, with or without indices or arguments, use the double question mark instead. To see the difference more explicitly, compare the two substitute commands in the following example:\index{?}\index{??} \begin{screen}{1,2,4} A_{m n} + B_{m n}: @substitute!(%)( A? + B? -> 0 ); A_{m n} + B_{m n}; @substitute!(%)( A?? + B?? -> 0 ); 0; \end{screen} Note that it does not make sense to add arguments or indices to object patterns; a construction of the type ``\verb|A??_{\mu}(x)|'' is meaningless and will be flagged as an error. % There are many situations in which There is a special handling of objects which are dummy objects in the classification of section~\ref{s:automaticdummies} (see table~\ref{t:argtypes}). Objects of this type do not need the question mark, as their explicit name is never relevant. You can therefore write \begin{screen}{1} @substitute!(%)( A_{m n} -> 0 ); \end{screen} to set all occurrances of the tensor~$A$ with two subscript indices to zero, regardless of the names of the indices (i.e.~this command sets $A_{p q}$ to zero). When replacing object wildcards with something else that involves these objects, use the question mark notation also on the right-hand side of the rule. For instance, \begin{screen}{1} @substitute!(%)( A? + B? -> A? A? ); \end{screen} replaces all sums with two elements by the square of the first element. The following example shows the difference between the presence or absence of question marks on the right-hand side: \begin{screen}{1,2,4,5} C + D: @substitute!(%)( A? + B? -> A? A? ); C * C; @pop(%); @substitute!(%)( A? + B? -> A A ); A * A; \end{screen} In many algorithms, patterns can be supplemented by so-called conditionals. These are constraints on the objects that appear in the pattern. For instance, the substitution command\index{conditionals} \begin{screen}{1} @substitute!(%)( A_{m n} B_{p q} | n!=p -> 0 ); \end{screen} applies the substitution rule only if the second index of $A$ and the first index of $B$ do not match. Note that the conditional follows directly after the pattern, not after the full substitution rule. A way to think about this is that the conditional is part of the pattern, not of the rule. The reason why the conditional follows the full pattern, and not directly the symbol to which it relates, is clear from the example above: the conditional is a ``global'' constraint on the pattern, not a local one. These conditions can be used to match names of objects using regular\index{regular expressions} expressions. Consider the following example: \begin{screen}{1,2} A + B3 + C7: @substitute!(%)( A + M? + N? | { \regex{M?}{"B[0-9]*"}, \regex{N?}{"[A-Z]7"} } -> sin(M? N?)/N? ); sin(B3 C7)/C7; \end{screen} It is also possible to select objects based on whether or not they are associated with a particular property, e.g.\footnote{More compact notations may look tempting, but were abandoned in favour of the constraint-based notation because it makes patterns potentially much harder to read.} \begin{screen}{1,2,3} A::SelfAntiCommuting. A A + B B; @substitute!(%)( Q?? Q?? | \hasprop{Q??}{SelfAntiCommuting} -> 0 ); B B; \end{screen} Combinations of different types of conditionals are of course also possible. %Note that declarations and substitution both use patterns, but the %latter are a superset of the former. That is, declarations at present %only accept dummy index patterns and range wildcards. A construction like %\begin{screen}{0} %{ m? | \regex{m?}{"a[0-9]*"} }::Integer. INVALID %\end{screen} %is not yet allowed. % This makes the symbols $a0$, $a1$, $a2$ and so on integers. Here one % sees once more that the conditional is part of the full pattern. The % entire expression inside the curly brackets should be considered a % pattern. Note that the following expressions are all equivalent: % \begin{screen}{0} % { R?_{m? n? p? q?} | \regex{R?}{"R"} }::RiemannTensor. % { R?_{m n p q} | \regex{R?}{"R"} }::RiemannTensor. % R_{m? n? p? q?}::RiemannTensor. % R_{m n p q}::RiemannTensor. % \end{screen} % The versions without the question marks on the indices match % any index names by virtue of the rule in section~\ref{s:automaticdummies}. \subsection{Environment variables} \label{s:environment_variables} \index{environment variables}There are a few environment variables which may be set to influence the behaviour of cadabra: \begin{descerate} \item[CDB\_LOG] \index{CDB\_LOG} When set, debug logging will be enabled. %\item[CDB\_CHECK\_INPUT] \index{CDB\_CHECK\_INPUT} If set, check all % input lines for index consistency. \item[CDB\_ERRORS\_ARE\_FATAL] \index{CDB\_ERRORS\_ARE\_FATAL} If this variable is set, errors (inconsistency of the tree or attempted use of non-existing algorithm) will abort the program (the default action, when this variable is unset, is to ignore the offending input line). \item[CDB\_PARANOID] \index{CDB\_PARANOID} Perform extensive consistency checks on the internal data format after each algorithm has been applied (only useful for debugging). \item[CDB\_PRINTSTAR] \index{CDB\_PRINTSTAR} Determines whether or not multiplication star symbols are displayed. \item[CDB\_TIGHTSTAR] \index{CDB\_TIGHTSTAR} Make output of multiplication symbols more compact. \item[CDB\_TIGHTBRACKETS] \index{CDB\_TIGHTBRACKETS} Make output of bracketed expressions more compact. \item[CDB\_USE\_UTF8] \index{CDB\_USE\_UTF8} Use UTF8 line breaking characters in the output. \end{descerate} \subsection{Known bugs} \begin{itemize} \item Inside curly brackets, products which are written without the ``$*$'' symbol are not parsed correctly. Use an explicit ``$*$'' symbol as a temporary workaround. \end{itemize} \subsection{Future plans} Now that the program is beginning to reach a usable and stable state, a number of directions for future work suggest themselves: \begin{itemize} \item A new parser; the current one was hand-written for many reasons, and is messy and not entirely correct. Now that the input format has stabilised it is time for a parser which is easier to debug, e.g.~one based on {\tt lex} \& {\tt yacc}. \item Inclusion of proper program flow including loops and subroutines. \end{itemize} Any suggestions on these or other topics are welcome. %----------------------------------------------------------------- \vfill\eject \section{Algorithm modules} \label{s:modules} All algorithms are stored in modules separate from the core of the program. These are at present all distributed together with the main program, but will in the future be available separately as binary or source plugin modules that can be loaded on demand. Any expression that starts with a name beginning with an ``@'' symbol is interpreted as a command. Commands act on the currently selected objects in an expression or on the expression for which the label or number is given as the first argument. See section~\ref{s:active_nodes} for more details on how to apply algorithms to expressions. \begin{multicols}{2} \printglossary \end{multicols} \vfill\eject \subsection{Builtin core algorithms} \label{s:builtin} There is a very small number of properties and algorithms built into the core program. These have to do with global memory management and global output settings. \bigskip \begin{props} \item[\cdbprop{KeepHistory}{}(\boolargs)] When set to false, only the last version of each expression is kept in memory, thereby reducing memory usage for very large expressions. The default is ``true''. \item[\cdbprop{PreDefaultRules}{}(\listargs)] Set the default rules to be executed on all input \emph{before} the active nodes in that input are expanded. \item[\cdbprop{PostDefaultRules}{}(\listargs)] Set the default rules, to be applied \emph{after} every new input has been processed and active nodes have been executed. Use the inert form of active nodes for those ones that only have to be come active upon actual evaluation of the rule, i.e.~\inertcommand{collect\_terms!(\%)}. \end{props} \bigskip \begin{algs} \item[\cdbcommand{pop}{}] Remove the last step of the indicated expression history. \item[\cdbcommand{amnesia}{}] Forget the history of the indicated expression, that is, remove all previous forms of the expression from memory. \item[\cdbcommand{algorithms}{}] Shows a list of all algorithms in the various modules, together with the time spent in them since the start of the program. \item[\cdbcommand{output\_format}{}] Sets the output format type according to the argument given. This can take one of the three values {\tt cadabra}, {\tt mathematica} or {\tt reduce}. \item[\cdbcommand{print\_status\{true|false\}}{}] Toggles printing of status information. Status output is always enclosed inside easily distinguished \verb|| and \verb|| marks. \item[\cdbcommand{quit}{}] Exits the program. \item[\cdbcommand{end}{}] Stop reading the current input file/stream. \item[\cdbcommand{reset}{}] Erases all expressions and object properties (but does not change any of the global flags). \item[\cdbcommand{utf8\_output\{true|false\}}{}] Determines whether the output should contain UTF8 encoded Unicode control characters for line-breaking and object grouping. This output format is used by the graphical front-end. \item[\cdbcommand{xterm\_title}{}] Set the title of the xterm to the given argument. \end{algs} \vfill\eject % \subsection{Selection and history manipulation} % % The history of a \cdb session is encoded in the expression tree. All % expressions (``equations'') are siblings of each other at the head of % the tree. When an equation is modified, two child nodes are % created. The first one contains the command that has produced the % expression, while the second child contains the new expression. % \bigskip % % \begin{algs} % \item[\cdbcommand{select}{}] Select the entire expression (selected parts of % the expression appear in bold-face). % \item[\cdbcommand{select}{}\{{\tt arg1}\}$\cdots$\{{\tt argn}\}] Select all % occurrences of the arguments. % \item[\cdbcommand{unselect}{}] Unselect the entire expression. % \item[\cdbcommand{history}{}] Print the list of previous expressions. %\end{algs} %\vfill\eject \subsection{Rationals, complex numbers and other numerics} \begin{props} \item[\cdbprop{ImaginaryI}{}] Indicates that the object squares to $-1$. \item[\cdbprop{Real}{}] \item[\cdbprop{Imaginary}{}] \item[\cdbprop{Complex}{}] \item[\cdbprop{Integer}{}] Indicates that the object takes values in the integers. An optional range can be specified, \begin{screen}{1,2,3} p::Integer; m::Integer(1..10); n::Integer(1..d-p); \end{screen} \end{props} \bigskip %\begin{algs} %\item[\cdbcommand{eval\_factorial}{}] Evaluate the numerical value of %a factorial expression, e.g.~turn $5!$ into $120$.\kcomment{KP}{Not %yet implemented} %\end{algs} \vfill\eject \subsection{Sums and products} \label{m:algebra} This module handles expansion of sums and products as well as distributing products over sums and similar algorithms. It recognises \bigskip \begin{props} \item[\cdbprop{ImplicitIndex}{}] Indicates that the object carries implicit indices, e.g.~for objects representing matrices or vectors. Such objects will not be moved through each other, i.e.~they are mutually noncommuting. \item[\cdbprop{Matrix}{}] \item[\cdbprop{CommutingAsProduct}{}] \item[\cdbprop{CommutingAsSum}{}] \item[\cdbprop{AntiCommuting}{}] \item[\cdbprop{NonCommuting}{}] \item[\vtop{\hbox{\cdbprop{SelfCommuting}{}}\hbox{\cdbprop{SelfAntiCommuting}{}}\hbox{\cdbprop{SelfNonCommuting}{}}}] Properties which determine the exchange properties of objects with indices. Example, \begin{screen}{1,2,3,5,6} \psi^{\mu}::SelfAntiCommuting. \psi^{\nu} \psi^{\mu}: @prodsort!(%); (-1) \psi^{\mu} \psi^{\nu}; \psi^{\mu} \psi^{\mu}: @canonicalise!(%); 0; \end{screen} \item[\cdbprop{Distributable}{}] Makes the object distributable. When the object has a sum as argument, it can be distributed over the terms with \subscommand{distribute}, as in \begin{screen}{1,2,3} \hat{#}::Distributable. \hat{A+B+C D}: @distribute!(%); \hat{A} + \hat{B} + \hat{C D}; \end{screen} \item[\vtop{\hbox{\cdbprop{Symmetric}{}}\hbox{\cdbprop{AntiSymmetric}{}}}] Makes an object symmetric resp.~antisymmetric in all its indices. For more complicated symmetries, use \subsprop{TableauSymmetry}. \item[\cdbprop{TableauSymmetry}{}] Takes lists of two key-value pairs as arguments, indicating the shape of the Young tableau and the index slots associated to each box in the tableau. For instance \begin{screen}{1} R_{a b c d}::TableauSymmetry( shape={2,2}, indices={0,2,1,3} ). \end{screen} yields the symmetries of the Riemann tensor. Note that indices are counted from zero. \item[\cdbprop{DAntiSymmetric}{}] For objects which are derivatives of fully anti-symmetric objects and satisfy a Bianchi-identity, i.e.~which are zero when anti-symmetrised over all indices. This is a shorthand for a TableauSymmetry with a ``hook'' shape. \item[\cdbprop{Commuting}{}] Makes components commuting. Note that this property always refers to components; if you attach it to an object with \subsprop{ImplicitIndex} property, the commutation property does not refer to the object as a whole, but rather to its components. \item[\cdbprop{Traceless}{}] Indicates that the tensor is traceless: any internal index contraction makes the tensor vanish. \item[\cdbprop{KroneckerDelta}{}] Denotes a generalised Kronecker delta symbol. When the symbol carries two indices, it is the usual Kronecker delta. When the number of indices is larger, the meaning is \begin{equation} \delta_{m_1}{}^{n_1}{}_{m_2}{}^{n_2}{}_{\ldots m_k}{}^{n_k} = \delta_{[m 1}{}^{n_1} \delta_{m_2}{}^{n_2} \cdots \delta_{m_k]}{}^{n_k} \,, \end{equation} with unit weight anti-symmetrisation. A symbol which is declared as a Kronecker delta has the property that it can be taken in and out of derivatives. The algorithm \subscommand{eliminate\_kr} eliminates normal Kronecker deltas by appropriately renaming indices (in order to eliminate Kronecker deltas with more than two indices, first use \subscommand{breakgendelta}). \item[\cdbprop{EpsilonTensor}{}({\it metric={\sf tensor}}, {\it delta={\sf tensor}})] A fully anti-symmetric tensor, defined by \begin{equation} \epsilon_{m_1\ldots m_k} := \varepsilon_{m_1\ldots m_k}\,\sqrt{|g|}\,, \end{equation} where the components of~$\varepsilon_{m_1\ldots m_k}$ are 0, $+1$ or $-1$ and~$\varepsilon_{01\cdots k}=1$, independent of the basis, and~$g$ denotes the metric determinant. Optionally takes a tensor which indicates the \subsprop{Metric} (so that the signature can be extracted) or a \subsprop{KroneckerDelta} (so that the product of two epsilon tensors can be written in terms of KroneckerDeltas, see the \subscommand{epsprod2gendelta} command). When the indices are in different positions it is understood that they are simply raised with the metric. This in particular implies \begin{equation} \epsilon^{m_1\ldots m_k} := g^{m_1 n_1} \cdots g^{m_k n_k} \epsilon_{n_1\ldots n_k} = \frac{\varepsilon^{m_1\ldots m_k}}{\sqrt{|g|}}\,, \end{equation} again with~$\varepsilon^{m_1\ldots m_k}$ taking values 0, $+1$ or $-1$ and $\varepsilon^{01\cdots k}=\pm 1$ depending on the signature of the metric. \item[\cdbprop{SortOrder}{}] A list property which determines the preferred order of objects when a \subscommand{prodsort} command is used. See section~\ref{s:symbol_ordering} for examples. \item[\cdbprop{Derivative}{}] An generic derivative object, satisfying the Leibnitz rule. These generic derivatives do not have to commute. \item[\cdbprop{PartialDerivative}{}] Makes an object a partial derivative, i.e.~a derivative which commutes. The object on which it acts has to be a non-sub/superscript child, while all the sub- or superscript child nodes are interpreted to be the variables with respect to which the derivative is taken. \begin{screen}{1,2,3,4} \partial{#}::PartialDerivative. A_{\mu}::Depends(\partial). \partial_{\nu}{A_{\mu} B_{\rho}}; @prodrule!(%); \partial_{\nu}{A_\mu} B_{\rho} \end{screen} Note that derivative objects do not necessarily need to have a sub- or superscript child, they can be abstract derivatives as in \begin{screen}{1,2,3} D(d?)::Derivative. D(c d e); @prodrule!(%); D(c) d e + c D(d) e + c d D(e); \end{screen} \end{props} \begin{algs} \item[\cdbcommand{prodflatten}{}] Removes brackets in a product, that is, makes changes of the type \begin{equation} a*(b*c) \rightarrow a*b*c\, . \end{equation} Also performs the same flattening for nested \subscommand{diff} nodes. \item[\cdbcommand{sumflatten}{}] Removes brackets in a sum, that is, makes changes of the type \begin{equation} a+(b+c) \rightarrow a+b+c\, . \end{equation} \item[\cdbcommand{remove\_indexbracket}{}] When a single symbol-with-indices is entered as \begin{screen}{1} (A)_{\mu\nu}; \end{screen} it gets wrapped in an \texcommand{indexbracket} node. In order to remove this node again, and produce \begin{screen}{0} A_{\mu\nu} \end{screen} again, use \subscommand{remove\_indexbracket}. This is also useful after a \subscommand{distribute} has been called on an \texcommand{indexbracket} node which contained a sum; the command \subscommand{remove\_indexbracket} will then remove the superfluous brackets around the single symbols. \item[\cdbcommand{expand\_power}{}] Expand powers into repeated products, e.g. \begin{screen}{1,2,4,5,7} (A B)**3: @expand_power!(%); (A * B) * (A * B) * (A * B); @prodflatten!(%): @prodsort!(%); A A A B B B; @collect_factors!(%); A**3 * B**3; \end{screen} This command automatically takes care of index relabelling when necessary, as in the following example, \begin{screen}{1,2,3,4} {m,n,p,q,r}::Indices(vector). (A_m B_m)**3: @expand_power!(%): @prodflatten!(%); A_{m} * B_{m} * A_{n} * B_{n} * A_{p} * B_{p}; \end{screen} \item[\cdbcommand{drop}{}] Removes terms for which a product contains the indicated number of factors, with indicated weight factors. Example: \begin{screen}{1,2} A B B + A A A + A B + B: @drop!(%){A,B}{1,2}{3}; A B B + B; \end{screen} In this example, the weight of A is 1 and the weight of B is 2, and all terms for which the total weight adds up to 3 have been removed. \item[\cdbcommand{keep}{}] The opposite of \subscommand{drop}: keep only those terms for which a product contains the indicated number of factors. \begin{screen}{1,2} A B B + A A A + A B + B: @keep!(%){A,B}{1,2}{3}; A A A + A B; \end{screen} \item[\cdbcommand{distribute}{}] Rewrite a product of sums as a sum of products, as in \begin{equation} a\,(b+c) \rightarrow a\,b + a\,c\, . \end{equation} For this rule to apply, the selection should contain a product, each factor of which can be a sum. All sums will be distributed. \item[\cdbcommand{prodrule}{}] Apply the product rule or ``Leibnitz identity'' to an object which has the ``Derivative'' property, i.e. \begin{equation} D(f\, g) = D(f)\, g + f\, D(g)\, . \end{equation} % We may even do the one for generic n-th order derivatives, see % % http://mathworld.wolfram.com/LeibnizIdentity.html % \item[\cdbcommand{sumsort}{}] Sort terms in a sum, taking into account any \subsprop{SortOrder} properties, or else sorting lexographically. \label{loc_sumsort} \begin{screen}{1,2,4,5} a**(-1+d) - a**(d-1); @collect_terms!(%); a**(-1+d) - a**(d-1); @sumsort!(%); @collect_terms!(%); 0; \end{screen} \item[\cdbcommand{prodsort}{}] Sort factors in a product, taking into account any \subsprop{SortOrder} properties. Also takes into account commutativity properties, such as \subsprop{Commuting} and \subsprop{SelfCommuting}. If no sort order is given, it first does a lexographical sort based on the name of the factor, and if two names are identical, does a sort based on the number of children and (if this number is equal) a lexographical comparison of the names of the children. \kcomment{KP}{Warning! Does not yet know about {$\backslash$pow}} \item[{\cdbcommand{collect\_terms}{}}] \label{loc_collect_terms} Collect terms in a sum that differ only by their numerical pre-factor. This is called automatically on all new input, and also by some algorithms (in which case it will be indicated in the description of the command), but in general has to be called by hand. Note that this command only collects terms which are identical, it does not collect terms which are different but mathematically equivalent. See~\subscommand{sumsort} on page~\pageref{loc_sumsort} for an example. \item[{\cdbcommand{collect\_factors}{}}] Collect factors in a product that differ only by their exponent. Note that factors containing sub- or superscripted indices do not get collected (i.e.~$A_m A^m$ does not get reduced to $(A_m)^2$). \item[\cdbcommand{factorise}{}] Given a list of symbols, this algorithm collects terms in a sum that only differ by pre-factors consisting of these given symbols. As an example, \begin{screen}{1,2} a b + a c + a d: @factorise!(%){b,c}; (b + c) a + a d; \end{screen} This is like the {\tt antibracket} statement of FORM. \item[\cdbcommand{canonicalise}{}] \label{loc_canonicalise} Canonicalise a product of tensors, using the mono-term\index{mono-term symmetries} index symmetries of the individual tensors and the exchange symmetries of identical tensors. Tensor exchange takes into account commutativity properties of identical tensors. Note that this algorithm does not take into account multi-term symmetries such as the Ricci identity of the Riemann tensor. If you have symmetric or anti-symmetric tensors with many indices, it sometimes pays off to sort them to the end of the expression (this may speed up the canonicalisation process considerably). \item[\cdbcommand{reduce}{}] Reduce a sum of tensor monomials of the same type, taking into account mono-term as well as multi-term symmetries. This does not aim for a canonical form, but rather for a form in which no monomials occur which can be expressed (using mono- and multi-term symmetries) as a linear combination of other monomials appearing in the sum. An example makes this more clear: \begin{screen}{0,1} {m,n,p,q}::Indices(vector). {m,n,p,q}::Integer(0..10). R_{m n p q}::RiemannTensor. R_{m n q p} R_{m n p q} + R_{m p n q} R_{m n p q}; @reduce!(%); \end{screen} \item[\cdbcommand{young\_project}{}] Project the indicated expression onto a Young tableau representation. This includes the normalisation factor, such that applying the operation twice does not change the result anymore. For example, \begin{screen}{1,2,5,6} A_{m n} B_{p}: @young_project!(%){2,1}{0,1,2}; 1/3 A_{m n} B_{p} + 1/3 A_{n m} B_{p} - 1/3 A_{p n} B_{m} - 1/3 A_{n p} B_{m}; @young_project!(%){2,1}{0,1,2}: @collect_terms!(%); 1/3 A_{m n} B_{p} + 1/3 A_{n m} B_{p} - 1/3 A_{p n} B_{m} - 1/3 A_{n p} B_{m}; \end{screen} The index positions given in the second argument count from zero. %\item[\cdbcommand{bracket}{}] Acts on sums. \cite{Edgar:2001vv} . \item[\cdbcommand{all\_contractions}{}] Construct all full contractions of the given tensors, taking into account mono-term symmetries. Example, \begin{screen}{1,2,3,4,5} A_{m n}::Symmetric. A_{m n}::Traceless. {m,n,p,q,r,s,t,u}::Indices(vector). {m,n,p,q,r,s,t,u}::Integer(0..9). obj14:= A_{m n} A_{p q} A_{r s} A_{t u}; @all_contractions(%){2}; A_{m n} A_{m n} A_{p q} A_{p q} + A_{m n} A_{m p} A_{n q} A_{p q}; \end{screen} \end{algs} \vfill\eject \subsection{Lists and ranges} When using list algorithms, be aware of the fact that when they act on an argument, they actually replace the argument, not generate a new one. Therefore, to generate a new expression which contains the length of another expression, \begin{screen}{1,3} A+B+C+D; 1:= A+B+C+D; @length[@(1)]; 2:= 4; \end{screen} This is to be compared with \begin{screen}{1,3} A+B+C+D; 1:= A+B+C+D; @length(1); 1:= 4; \end{screen} in which case the first expression gets replaced by its length. \medskip \begin{algs} \item[\cdbcommand{length}{}] Replaces the expression with its length, that is, the number of terms in a sum, the number of factors in a product or the number of elements in a list. \item[\cdbcommand{take}{}] Replace a sum, product or list with a subset of its terms, factors or elements. Example, \begin{screen}{1,2,4,5,7,8} A+B+C+D+E; @take(%){1,3}; B+D; {A,B,C,D,E}; @take(%){4}; \{ E \}; A*B*C*D*E; @take(%){2..\infty}; C*D*E; \end{screen} As usual, a range can be open by setting the second boundary to \texcommand{infty}. See also \subscommand{take\_match}. \item[\cdbcommand{range}{}] Replaces a two-element list of integers with the elements in the range, \begin{screen}{1,3} {-3,2}; @range(%); \{ -3,-2,-1,0,1,2 \} @range[{1,3}]; \{ 1,2,3 \} \end{screen} When the list has three elements, the algorithm generates a list consisting of a number of copies of the third element of the given list, \begin{screen}{1} @range[{1,3,c}]; {c,c,c}; \end{screen} When the list contains four elements, the first one is used as a counter, and can appear in the fourth element to generate different list elements, \begin{screen}{1} @range[{i, 1, 5, c_{i} }]; { c_1, c_2, c_3, c_4, c_5 } \end{screen} \item[\cdbcommand{inner}{}] Construct an inner product between two lists appearing in a list, \begin{screen}{1,2,4} lst1:= {a_m, b_m ,c_m ,d_m ,e_m }: lst2:= @range[{1, @length[@(lst1)]}]; \{ 1,2,3,4,5 \}; @inner[ { @(lst1), @(lst2) } ]; a_m + 2 b_m + 3 c_m + 4 d_m + 5 e_m; \end{screen} \item[\cdbcommand{list\_sum}{}] In an expression containing sums of identical-length lists, create one new list constructed by adding the elements at the same position in each list. Example, \begin{screen}{1,2,3} {a, b, 7 c + q, d, e} - {-f, g, h, i, j}: @list_sum!(%): @sumflatten!(%); \{ a + f, b - g, 7c + q - h, d - i, e - j \}; \end{screen} % \item[\cdbcommand{coefficients}{}] \end{algs} \vfill\eject \subsection{Differential geometry} \label{s:diff_geom} \begin{props} \item[\cdbprop{DifferentialForm}{}] \end{props} \bigskip %\begin{algs} %\end{algs} \subsection{Properties} \label{s:properties} \begin{algs} \item[\cdbcommand{extract\_properties}{}] An algorithm mainly useful in internal routines: it extracts properties attached to a symbol and adds them to the global property list. Gets called automatically on input. \end{algs} \vfill\eject \subsection{Dummy indices} \label{s:dummies} Dummy indices are a subject by itself. There are various problems with most implementations of dummy indices in computer algebra software. In many cases, dummy indices are added as an afterthought, leading to situations were illegal expressions (e.g. with a more than twice repeated dummy index) can be entered. Even if this is flagged, most programs do not know about different index types (which leads to problems when there is more than one type of contraction, or a sum over only part of the index range). In \cdb, the system knows about dummy index \emph{sets}, and all algorithms can request new dummy indices very easily. This is handled through the {\tt dummies} module. \bigskip \begin{props} \item[\cdbprop{Indices}{}]Declare index names to be usable for dummy index purposes. Typical usage is of the form \begin{screen}{1,2} {r,s,t}::Indices(vector). {a,b,c,d}::Indices(spinor). \end{screen} This indicates the name of the index set (``vector'' resp.~``spinor'' in the example above). \end{props} \begin{algs} \item[\cdbcommand{rename\_dummies}{}] Rename the dummy indices in an expression. \end{algs} \vfill\eject \subsection{Symmetrisation and anti-symmetrisation} % This is actually implemented in algebra.cc, the sym.cc is empty This module contains algorithms for the symmetrisation or anti-symmetrisation of expressions in their elements, and for the inverse procedure, whereby object trees are identified when they differ only by certain symmetrisations or anti-symmetrisations. %This module relies strongly on the {\tt combinatorics.hh} header file, %which contains algorithms that generate various combinations and %permutations of sets. %\url{http://dogma.net/markn/articles/Permutations/} \bigskip \begin{algs} \item[\cdbcommand{sym}{}] Symmetrise a product in the indicated objects. \item[\cdbcommand{asym}{}] Anti-symmetrise a product in the indicated objects. \item[\vbox{\hbox{\cdbcommand{canonicalorder}{}} \hbox{\cdbcommand{acanonicalorder}{}}}] Orders the indicated objects in the expression in canonical order, taking into account permutation signs (symmetric in case of \subscommand{canonicalorder}, antisymmetric in case of \subscommand{acanonicalorder}). Example: \begin{screen}{1,2} A^{m n p} B^{q r} + A^{q m} B^{n p r}; @acanonicalorder!(%)( ^{m}, ^{n}, ^{p}, ^{r}, ^{q} ); - A^{m n p} B^{r q} + A^{m n} B^{p r q}; \end{screen} \item[{\cdbcommand{impose\_asym}{}}] Impose anti-symmetry in external indices, that is, remove terms in the expression which have anti-symmetry imposed on more than one index sitting on a symmetric object. \item[{\cdbcommand{asymprop}{}}] Remove all traces of anti-symmetric tensors. \end{algs} \vfill\eject \subsection{Field theory} \label{s:tensor} \bigskip \begin{props} \item[\cdbprop{SelfDual}{}] \item[\cdbprop{AntiSelfDual}{}] These two properties declare that a tensor is fully anti-symmetric, but in addition satisfies a selfduality or anti-selfduality condition. \item[\cdbprop{Depends}{}] Makes an object implicitly dependent on other objects, i.e.~assumes that the indicated object is a function of the arguments of the property. For example, \begin{screen}{1,2} x::Coordinate. \phi::Depends(x). \end{screen} makes $\phi$ an implicit function of $x$. Instead of indicating the coordinate on which the object depends, it is also possible to indicate which derivatives would yield a non-zero answer, as in \begin{screen}{1,2} \nabla{#}::Derivative. \phi::Depends(\nabla). \end{screen} Finally, it is possible to use an index name to indicate on which coordinates a field depends, \begin{screen}{1,2} {m,n,p,q}::Indices(vector). \phi::Depends(m). \end{screen} \item[\cdbprop{Weight}{}] \item[\cdbprop{Symbol}{}] If you want to attach symbols to tensors in sub- or superscript, as in~$A^\dagger$, you need to tell \cdb that this symbol is not an index (otherwise it may interpret~$A^\dagger A^\dagger$ as two contracted vectors with vector indices~$\dagger$). This is done by associating the \subsprop{Symbol} property to the symbol; in this example \begin{screen}{1,2} \dagger::Symbol. A^\dagger A^\dagger; \end{screen} \item[\cdbprop{Coordinate}{}] Declare a symbol to be a coordinate label (useful in combination with \subsprop{Depends}). This is required if you want to write a derivative with respect to a coordinate: the input \begin{screen}{1} A(x,x') + \diff{B(x,x')}_{x}; \end{screen} will by default be seen as incorrect because the $x$ in the second term will be considered an index label, not a coordinate. The input \begin{screen}{1,2} { x, x' }::Coordinate. A(x,x') + \diff{B(x,x')}_{x}; \end{screen} is allowed and interpreted in the right way. \item[\cdbprop{Accent}{}] \end{props} \bigskip \begin{algs} \item[\cdbcommand{unwrap}{}] Move objects out of \subsprop{Derivative}s or \subsprop{Accent}s when they do not depend on these operators. Accents will get removed, as in the following example, \begin{screen}{1,2,3,5,6,8} \hat{#}::Accent. \hat{#}::Distributable. B::Depends(\hat). \hat{A+B+C}: @distribute!(%); \hat{A} + \hat{B} + \hat{C}; @unwrap!(%); A + \hat{B} + C; \end{screen} Derivatives will be set to zero if an object inside does not depend on it, \begin{screen}{1,2,4,5} \partial{#}::PartialDerivative. x::Coordinate. B::Depends(\partial). \partial_{x}( A B C ): @unwrap!(%); A C \partial_{x}{B}; \end{screen} Here is another example, \begin{screen}{1,2,3,4,6} \del{#}::Derivative. X::Depends(\del). \del{X*Y*Z}: @prodrule!(%); \del{X} * Y * Z + X * \del{Y} * Z + X * Y * \del{Z}; @unwrap!(%); \del{X}*Y*Z; \end{screen} Note that all objects are by default constants for the action of \subsprop{Derivative} operators. If you want objects to stay inside derivative operators you have to explicitly declare that they depend on the derivative operator or on the coordinate with respect to which you take a derivative. \item[\cdbcommand{eliminate\_kr}{}] Eliminates kronecker delta symbols in the selection by performing index contractions. Also replaces contracted kronecker delta symbols with the range over which the index runs, if known. \item[\cdbcommand{eliminateeps}{}] \kcomment{KP}{Stupid name} Given an epsilon tensor and a self-dual tensor contracted with it, rewrite the self-dual tensor as epsilon times itself, so that at a further stage one can use the command \subscommand{epsprod2gendelta} to remove the epsilons altogether the arguments contain a list of all tensors for which self-duality can be applied). Uses the the tensor with the largest number of indices in common with the epsilon symbol (can be more than one, in which case more terms are generated). \item[{\cdbcommand{epsprod2gendelta}{}}] Replace a product of two epsilon tensors with a generalised delta according to the expression \begin{equation} \epsilon^{r_1\cdots r_{d}} \epsilon_{s_1\cdots s_{d}} = \frac{1}{\sqrt{|g|}}\varepsilon^{r_1 \cdots r_{d}} \sqrt{|g|}\varepsilon_{s_1\cdots s_{d}} = \sgn g\, d!\, \delta^{r_1 \cdots r_{d}}_{s_1\cdots s_{d}}\, , \end{equation} where~$\sgn g$ denotes the signature of the metric~$g$ used to raise/lower the indices (see \subsprop{Epsilon} for conventions on the epsilon tensor). When the indices are not ocurring up/down as in this expression, and the index position is not free, metric objects will be generated instead. Contracted indices inside the generalised delta are automatically eliminated, as the command \subscommand{reduce\_gendelta} is called automatically; if you do not want this use the optional argument ``\mbox{noreduce}''. \item[{\cdbcommand{dualise\_tensor}{}}] Dualises tensors which have been declared \subsprop{SelfDual} according to the formula \begin{equation} F_{\mu_{n+1}\cdots \mu_{d}}\;\; \rightarrow\;\; *F_{\mu_{n+1}\cdots \mu_{d}} = \frac{1}{n!} \epsilon_{\mu_{n+1}\cdots\mu_d}{}^{\mu_1\cdots\mu_n} F_{\mu_1\cdots \mu_n}\, . \end{equation} In order for this to work the indices on the tensor have to be declared with \subsprop{Indices} and their range should have been specified with \subsprop{Integer}. \item[{\cdbcommand{reduce\_gendelta}{}}] Convert generalised delta symbols which contain contracted indices to deltas with fewer indices, according to the formula \begin{equation} n! \, \delta^{a_1\cdots a_n}_{b_1\cdots b_n}\, \delta^{b_1}_{a_1} \cdots \delta^{b_m}_{a_m} = \Big[\prod_{i=1}^m \big( d-(n-i) \big) \Big] \, (n-m)!\, \delta^{a_{m+1}\cdots a_n}_{b_{m+1}\cdots b_n}\, . \end{equation} \item[{\cdbcommand{product\_shorthand}{}}] Rewrites the product of two fully symmetric or anti-symmetric tensors in a compact form by removing the contracting dummy indices. \begin{screen}{1,2,3} F_{m n p q}::Symmetric. G_{m n p q}::Symmetric. @product_shorthand![ F_{a b c d} G_{a b d f} ]{F}{G}; F_{c} G_{f}; \end{screen} The two arguments denote the tensors to which the algorithm should apply. \item[{\cdbcommand{expand\_product\_shorthand}{}}] Reverse of the previous algorithm. In addition to the two tensor names, it takes a number denoting the total number of indices. \item[{\cdbcommand{impose\_bianchi}{}}] Removes terms which are proportional to the (Garnir generalised) Bianchi identity. It removes all products for which a set of indices in Garnir hook form is contracted with an anti-symmetric set. \item[{\cdbcommand{einsteinify}{}}] In an expression containing dummy indices at the same position (i.e.~either both subscripts or both superscripts), raise one of the indices. If an additional argument is given to this command, it instead inserts ``inverse metric'' objects, with the name as indicated by the additional argument. \item[{\cdbcommand{combine}{}}] Combine two consecutive objects with indexbrackets and consecutive contracted indices into one object with an indexbracket. Example \begin{screen}{1,2} (\Gamma_r)_{\alpha\beta} (\Gamma_{s t u})_{\beta\gamma}; @combine!(%); (\Gamma_r \Gamma_{s t u})_{\alpha\gamma}; \end{screen} \item[{\cdbcommand{expand}{}}] Write out products of matrices inside indexbrackets, inserting new dummy indices for the contraction. \end{algs} \vfill\eject \subsection{Output routines} \label{s:output} The core of \cdb only knows how to output its internal tree format in infix notation, and by default displays the result of every input line in this way (labelled by the expression number and label, if any). For more complicated output, for instance to feed \cdb expressions to other programs, or to see the internal tree form, routines are available in the {\tt output} module. Note that these modules do not transform the tree or generate new expressions; they \emph{only} generate output. Related but \emph{different} functionality is present in the {\tt convert} module, which contains transformation algorithms which transform the internal tree to other conventions (e.g.~in order to convert a \cdb tree to a tree which can be understood by Maple or Mathematica). \bigskip \begin{algs} \item[\cdbcommand{depprint}{}] Display an expression together with all properties of the symbols that appear in this expression. This is a very useful command if you want to extract a result from a long calculation and write it in a separate file for further processing. \item[\cdbcommand{print}{}] Construct output from strings and \cdb expressions. As an example, the command \begin{screen}{1} @print["tst := " ~ @join[\Gamma^{a b}\Gamma_{c}] ~ ";"]; \end{screen} will show the output \begin{screen}{0} tst := \Gamma^{a b}*\Gamma_{c}; \end{screen} As you can see in this example, expressions are joined together into one printable string by using the tilde character. Note that this completely overrides the normal output of expressions: there is no expression number for instance. Also note that all active nodes are (as usual) completely expanded before the print algorithm is called. \item[\cdbcommand{number\_of\_terms}{}] Returns the number of terms in a sum. \item[\cdbcommand{proplist}{}] Show all properties and the patterns to which they are associated. \item[\cdbcommand{assert}{}] Checks whether the indicated expression equals zero. If not, the program will be terminated. This command is used e.g.~in the test suite. \end{algs} \bigskip\bigskip \noindent Furthermore, there are a few algorithms which are mainly useful for debugging purposes, as they display information about the internal representation of the expression tree. More information on the internal data structures can be found in section~\ref{s:internal_storage}. \bigskip \begin{algs} \item[\cdbcommand{tree}{}] Display the internal tree form of a given expression. Can be used on a single expression or on an entire tree, \begin{screen}{1,2} @tree(3); @tree; \end{screen} shows the tree form of expression~(3) and the whole expression tree respectively. Most expressions lead to extremely lengthy output, so it is useful to redirect it to a file using the standard output redirection mechanism described in section~\ref{s:inputoutput}. \item[\cdbcommand{indexlist}{}] Displays a list of all indices in an expression, together with their type (dummy or free). % \item[\cdbcommand{adjmatrix}{}] Displays the adjacency matrix form of % a product. This form does not use explicit index names for tensor % contractions, and is used in the canonicalisation algorithms to avoid % having to do dummy index relabelling. \end{algs} \vfill\eject % \subsection{Perturbative string theory ({\tt pertstring})} % % % This module contains useful routines for the computation of % perturbative string amplitudes, that is, it contains information about % Jacobi theta functions and assorted things. % \bigskip % \begin{algs} % \item[\cdbcommand{aticksen}{}] Work out a fermionic correlator according to % \dcite{Atick:1987rs}. These correlators contain SO(2) spinors % represented in the form of a complex fermion $\Psi$ and $\bar\Psi$, as % well as spin fields $S_+$ and $S_-$ \kcomment{KP}{Lacking % ``properties'', these currently have to be written as {\tt Psi}, {\tt % Psibar}, {\tt Splus} and {\tt Sminus}.}. Correlators of these are written as % {\tt \\corr\{...\}}, where the dots contain an arbitrary number of these % fermionic fields, together with their dependence on insertion points. % The algorithm converts these correlators to Jacobi theta function expressions, % (ignoring a normalisation constant) using the expression % \begin{equation} % \begin{aligned}[t] \Big\langle \prod_{i=1}^{N_1}& S^+(\tilde y_i) % \prod_{i=1}^{N_2} S^-(y_i) \prod_{i=1}^{N_3} \bar\Psi(\tilde z_i) % \prod_{i=1}^{N_4} \Psi(z_i)\Big\rangle_\nu \\[1ex] % {} & = K_\nu \frac{\displaystyle \prod_{i A_{mu nu} B_{rho} ); G_{mu nu rho} + A_{mu nu} B_{rho}; \end{screen} \begin{screen}{1,2} A_{mu nu} B_{nu rho} C_{rho sigma}; @substitute!(%)( A_{m n} C_{p q} -> D_{m q} ); D_{mu sigma} B_{nu rho}; \end{screen} This command takes full care of dummy index relabelling, as the following example shows: \begin{screen}{1,2,3} {m,n,q,d1,d2,d3,d4}::Indices(vector). a_{m} b_{n}; @substitute!(%)( a_{q} -> c_{m n} d_{m n q} ); c_{d1 d2} * d_{d1 d2 m} * b_{n}; \end{screen} By postfixing a name with a question mark, it becomes a pattern. \item[\cdbcommand{take\_match}{}] Select a subset of terms in a sum or list which match the given pattern. \end{algs} \vfill\eject \subsection{Linear algebra} \begin{algs} \item[\cdbcommand{lsolve}{}] Solve a system of linear equations. Example, \begin{screen}{1,2} { a0+2*a2 + a3= 3, -a0 - a2 + a3= - (8/3) , a3 = 3}; @lsolve(%){a0,a2,a3}; {a0 = 34/3, a2 = (-17/3), a3 = 3}; \end{screen} Underdetermined and inconsistent systems are handled as expected: either some coefficients are left unfixed or the system is returned and an error message is printed. \item[\cdbcommand{decompose}{}] Decompose a tensor monomial on a given basis of monomials. The basis should be given in the second argument. All tensor symmetries, including those implied by Young tableau Garnir symmetries, are taken into account. Example,\footnote{Note that this algorithm does not yet take into account dimension-dependent identities, but it is nevertheless already required that the index range is specified.} \begin{screen}{0,1,2,4,5} {m,n,p,q}::Indices(vector). {m,n,p,q}::Integer(0..10). R_{m n p q}::RiemannTensor. R_{m n q p} R_{m p n q}; @decompose!(%)( R_{m n p q} R_{m n p q} ); \{ -1/2 \}; \end{screen} \end{algs} \vfill\eject \subsection{Gamma matrix algebra and fermions} This module deals with manipulations of the Clifford algebra, spinor representations of the Lorentz group and related issues. Cadabra follows the conventions of Sevrin's appendix~1.5, except for the fact that we call the time-like component zero and the product of all gamma matrices~$\tilde\Gamma$. \bigskip \begin{props} \item[\cdbprop{GammaMatrix}{}] A generalised generator of a Clifford algebra. With one vector index, it satisfies \begin{equation} \{ \Gamma^m, \Gamma^n \} = 2\,\eta^{mn}\,. \end{equation} The objects with more vector indices are defined as \begin{equation} \Gamma^{m_1\ldots m_n} = \Gamma^{[m_1}\cdots \Gamma^{m_n]}\,, \end{equation} where the anti-symmetrisation includes a division by~$n!$. If you intend to use the \subscommand{join} algorithm, you have to add a key/value pair \verb|metric| to set the name of the tensor which acts as the unit element in the Clifford algebra. \item[\cdbprop{Spinor}{}] \item[\cdbprop{DiracBar}{}] Declares an object to be the operator which applies the Dirac bar to a spinor, i.e.~an operator which acts according to \begin{equation} \bar{\psi} = i \psi^\dagger \Gamma^0\,. \end{equation} \item[\cdbprop{GammaTraceless}{}] Declares a spinor object with a vector index to be zero when it is contracted with a gamma matrix. \item[\vtop{\hbox{\cdbprop{SigmaMatrix}{}}\hbox{\cdbprop{SigmaBarMatrix}{}}}] These are the invariant tensors relating the~$(\tfrac{1}{2},\tfrac{1}{2})$ to the vector representation of SO(3,1). \Cdb uses the Wess~\& Bagger conventions~\cite{b_bagg1}, which means that the metric has signature~$\eta = {\rm diag}(-1,1,1,1)$ and \begin{equation} (\sigma^{\mu})_{\alpha\dot{\beta}} = ( -{\mathbb 1}, \vec\sigma )_{\alpha\dot{\beta}}\,,\quad (\bar{\sigma}^{\mu})^{\dot{\alpha}\beta} = (-{\mathbb 1}, -\vec\sigma)^{\dot{\alpha}\beta}\,. \end{equation} When the objects carry two vector indices, they are understood to be \begin{equation} (\sigma^{m n})_{\alpha}{}^{\beta} \equiv \frac{1}{4}( \sigma^m \bar{\sigma}^n - \sigma^n \bar{\sigma}^m)_{\alpha}{}^{\beta}\,,\quad\quad (\bar{\sigma}^{m n})^{\dot{\alpha}}{}_{\dot{\beta}} \equiv \frac{1}{4}(\bar{\sigma}^m \sigma^{n} - \bar{\sigma}^n \sigma^{m})^{\dot{\alpha}}{}_{\dot{\beta}}\,. \end{equation} See below for algorithms dealing with the conversion from indexed to index-free notation. \end{props} \bigskip \begin{algs} \item[\cdbcommand{join}{}] Join two fully anti-symmetrised gamma matrix products according to the expression \begin{equation} \Gamma^{b_{1}\dots b_{n}}\Gamma_{a_{1}\dots a_{m}} = \sum_{p=0}^{\text{min}(n,m)}\ \frac{n! m!}{(n-p)! (m-p)! p!} \Gamma^{[b_{1}\ldots b_{n-p}}{}_{[a_{p+1}\ldots a_{m}} \eta^{b_{n-p+1}\ldots b_{n}]}{}_{a_{1}\ldots a_{m-p}]} \, . \end{equation} Without further arguments, the anti-symmetrisations will be left implicit. The argument ``{\tt expand}'' instead performs the sum over all anti-symmetrisations, which may lead to an enormous number of terms if the number of indices on the gamma matrices is large. In order to reduce the number somewhat, one can instruct the algorithm to make use of generalised Kronecker delta symbols in the result; these symbols are defined as \begin{equation} \delta^{r_1}{}_{s_1}{}^{r_2}{}_{s_2}\cdots{}^{r_n}{}_{s_n} = \delta^{[r_1}{}_{s_1}\delta^{r_2}{}_{s_2}\cdots {}^{r_n]}{}_{s_n}\, . \end{equation} Anti-symmetrisation is implied in the set of even-numbered indices. The use of these symbols is triggered by the ``{\tt gendelta}'' option. Finally, to select only a single term (for a given $p$) in this expansion, give the join an argument with the value of $p$. \item[\cdbcommand{gammasplit}{}] The opposite of \cdbcommand{join}: splits off a gamma matrix from a totally anti-symmetrised product, e.g. \begin{equation} \Gamma^{mnp} = \Gamma^{mn}\Gamma^p - 2\,\Gamma^{[m} \eta^{n]}{}_p\, . \end{equation} By default it splits of the one from the back, like in the example above, but with argument {\tt front} it will split from the front. \item[\cdbcommand{rewrite\_diracbar}{}] Rewrite the Dirac conjugate of a product of spinors and gamma matrices as a product of Dirac and hermitean conjugates. This uses \begin{equation} \bar\psi = i \psi^\dagger\Gamma^0\,, \end{equation} together with \begin{equation} \Gamma_m^{\dagger} = \Gamma_0\Gamma_m\Gamma_0 \,. \end{equation} For example, \begin{screen}{1,2,3,4,5} \bar{#}::DiracBar. \psi::Spinor(dimension=10). \Gamma{#}::GammaMatrix. \bar{\Gamma^{m n p} * \psi}; @rewrite_diracbar!(%); \end{screen} \item[\cdbcommand{projweyl}{}] Projects an expression onto Weyl spinors of positive chirality (this algorithm only works in even dimensions). On such a subspace, we have \begin{equation} \label{e:g10toeps} \Gamma^{r_1 \cdots r_{d}}\Big|_{\text{Weyl}} = \frac{1}{\sqrt{-g}}\epsilon^{r_1\cdots r_{d}} \, ,\quad \epsilon^{0\cdots (d-1)} = +1\, , \end{equation} and therefore all gamma matrices with more than $d/2$ indices can be converted to their ``dual'' gamma matrices. By repeated contraction of~\eqref{e:g10toeps} with gamma matrices on the left one deduces that \begin{equation} \Gamma^{r_1\cdots r_n}\Big|_{\text{Weyl}} = \frac{1}{\sqrt{-g}} \frac{(-1)^{\frac{1}{2}n(n+1)+1}}{(d-n)!} \Gamma_{s_1\cdots s_{d-n}}\Big|_{\text{Weyl}} \epsilon^{s_1\cdots s_{d-n} r_1\cdots r_n}\, . \end{equation} \item[\cdbcommand{spinorsort}{}] Sorts Majorana spinor bilinears using the Majorana flip property \begin{equation} \bar\psi_1 \Gamma_{r_1\cdots r_n}\psi_2 = \alpha \beta^n (-)^{\frac{1}{2}n(n-1)}\, \bar\psi_1 \Gamma_{r_1\cdots r_n}\psi_2\, . \end{equation} Here $\alpha$ and $\beta$ determine the properties of the charge conjugation matrix, \begin{equation} {\cal C}^T = \alpha {\cal C}\,,\quad {\cal C}\Gamma_r {\cal C}^{-1} = \beta \Gamma_r^T\, . \end{equation} % These depend on dimension and are given by (some of these are choices) % \kcomment{KP}{signature dependence!} % \begin{equation} % \begin{matrix} % & \alpha & \beta \\ % d=4 & - & - \\ % d=5 & - & + \\ % d=6,1 & + & - \\ % d=8 & + & - \\ % d=10,1 & - & - % \end{matrix} % \end{equation} \end{algs} \vfill\eject \subsection{Conversion from/to other formats} \Cdb's syntax is a superset of the Maple and Mathematica formats, in the sense that the internal tree representation of \cdb can store input for both of these systems. However, this may not always be the most convenient way of storage, as \cdb often has more compact or expressive ways to store tensors. The {\tt convert} module provides conversion algorithms from and to these two formats. \bigskip \begin{algs} \item[{\cdbcommand{from\_math}{}[expression]}] Reads mathematica input format as used by GAMMA~\cite{Gran:2001yh}. Fully anti-symmetric tensors are denoted with \begin{screen}{0} Tensor[name,{indices}] \end{screen} Tensors with property ``weyltensor'' are printed as \begin{screen}{1} W_{r1 r2 r3 r4} Weyl[{r1,r2}, {r3,r4}] \end{screen} (warning, this removes the tensor name). \item[{\cdbcommand{to\_math}{}[expression]}] Converts the mathematica expression to a \cdb one. See above for details about the conversion process. \end{algs} \vfill\eject \section{Core functionality} \subsection{Source file description} The files in the {\tt src} directory build up the core of the program and are described below. Algorithm-specific code is in the {\tt src/modules} subdirectory and a description of those files can be found in section~\ref{s:modules}. The files below should not be changed when adding new modules. \begin{description} \item[{\tt main.cc}] Startup routines; initialises the I/O streams, sets up the signal handlers for control-C and window resize signals and starts the main event loop. \item[{\tt manipulator.cc}, {\tt manipulator.hh}] Contains the object that processes the input line by line, activates the parser on it, and scans the tree for active nodes. A few very low-level commands (see section~\ref{s:builtin}) are handled in this class, while the other ones are dispatched to external modules. \item[{\tt preprocessor.cc}, {\tt preprocessor.hh}] The code for conversion of human editable infix input to the tree-form handled by the other parts of the program. This is a text-to-text filter forming the first pass of the parser. All functionality can be tested using \verb|test_preprocessor.cc|. \item[{\tt storage.cc}, {\tt storage.hh}] The node and tree classes for storage of the tree form of expressions. These are the classes on which actual symbolic manipulation takes place. See also the separate \verb|tree.hh| class. \item[{\tt parser.cc}, {\tt parser.hh}] The class which contains the parsing algorithms that turns output of the preprocessor class into a tree form. \item[{\tt algorithm.cc}, {\tt algorithm.hh}] The base class for all the classes defined in the modules subdirectory. Plus the implementation of scanning for command arguments and the necessary logic to create the undo information, apply an algorithm until it no longer changes the expression and other things which are independent of the particular command. \item[{\tt combinatorics.hh}] General routines for the generation of combinations and permutations of elements in a vector. Consists of a single class {\tt combinations<$\ldots$>} templated over the type of the objects to be permuted. This class acts as a container holding both the original vector (in the {\tt storage} member), the permutation patterns (in the {\tt sublengths} vector, more on this later) as well as the resulting permuted vectors (accessible through {\tt operator[]}; the total number of combinations is given by {\tt size()}). \end{description} \subsection{Tree representation of expressions} \label{s:internal_storage} Expressions are internally stored in a tree container class, based on the {\tt tree.hh} library~\cite{kas_tree}. The present section describes the tree format in some more detail. Let us start with a couple of remarks on the motivation which has led to the current implementation. An important requirement for the storage format is that symbols should not have a fixed meaning, but rather be like variables in a computer program: they can be declared to represent objects of a certain type. Similarly, the user should be free to use arbitrary bracket types and sub- and superscript indicators (these should in addition be kept during the algebraic manipulations). The first issue is resolved with the property system, but the second one needs support directly in the storage tree. Secondly, storage should be such that a trivial (often occurring) extensions from one object to another should not lead to blowup. For instance, the difference between \verb|A_\mu| and \verb|A_{\mu \nu}| should preferably not introduce a new layer between the \verb|A| node and the \verb|\mu| node. This is achieved by adding the bracket type to the \emph{child} node rather than the parent (in the example above, the curly brackets are part of the \verb|\mu| and \verb|\nu| nodes). This applies also to e.g.~sums: in \verb|(A+B)| (which is converted by the preprocessor to \verb|\sum(A)(B)| ), the round brackets are part of the child nodes of the \verb|\+| node.\footnote{Subsequent child nodes with the same bracket type associated to them are taken to be part of the same group; the input {\tt A\_\{$\backslash$mu\}\_\{$\backslash$nu\}} will therefore be printed as {\tt A\_\{$\backslash$mu $\backslash$nu\}}. Similarly, there is no way to represent $(a)+(b)$ since the internal storage format automatically turns this into $(a+b)$.} Similarly, extending \verb|q| to \verb|3q| should not introduce new intermediate layers to group the two symbols together. This has been achieved by giving each node a multiplier field (this holds true even for products, i.e.~\verb|3(a+b)| is represented as a sum node with multiplier 3 (in addition, such numerical factors are always commuted to the front of the expression).\footnote{The multiplier field is a rational, and is intended to stay that way. It is not a good idea to make it complex, otherwise we will end up with octonionic multipliers at some stage. } %We need some pre-defined symbols %for $i$ and so on though, and rules to simplify products of %them. These rules can be kept explicit and user-switchable to be %automatic.} It should also be possible to make expressions arbitrarily deeply nested; one should be able to write \verb|a+b| as well as \verb|\sin(a+b)|. This is in contrast to programs such as {\tt Abra} and {\tt FORM} which store their input as sums of products of factors, i.e.~without further nesting. Finally, tt should be posssible to store the history of an expression, in order to implement unlimited undo. The data stored at each tree node is further explained in section~\ref{s:writing_new}, see in particular the excerpt from the {\tt storage.hh} file in figure~\ref{f:str_node}. The structure of the actual tree is illustrated in figure~\ref{f:example_history}. Each expression starts with a {\tt history} node. The label of the expression is given in a subnode {\tt label}. All remaining child nodes of the {\tt history} nodes represent the history of the expression. The most often encountered node here is the {\tt expression} node, which contains the actual expression. However, there are other nodes as well, for instance {\tt asymimplicit} which contains information about the symmetry structure of an expression (this feature is not yet enabled). \begin{figure}[t] \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr \texcommand{history} \cr \T \texcommand{label}\cr \V \L apple \cr \T \texcommand{expression} \cr \V \L \texcommand{prod} \cr \V \N \T a \cr \V \N \L \texcommand{sum} \cr \V \N \N \T b \cr \V \N \N \L c \cr \L \texcommand{expression} \cr \N \L \texcommand{sum} \cr \N \N \T \texcommand{prod} \cr \N \N \V \T a \cr \N \N \V \L b \cr \N \N \L \texcommand{prod} \cr \N \N \N \T a \cr \N \N \N \L c \cr }} \end{equation*} \caption{Example history tree for a single expression. Here, the program started with the user entering the expression $a (b+c)$. This expression was then manipulated by applying the \subscommand{distribute} algorithm. The nodes at the top of the expression tree are all of the {\tt history} type. \label{f:example_history}} \end{figure} % \T \texcommand{action}\cr % \V \T \subscommand{exchange}\cr % \V \N \T a\cr % \V \N \L b\cr % \quad\quad\longleftrightarrow\quad\quad % \vcenter{ % \offinterlineskip % \halign{&#\mystrut\hfil\cr % (1) $a+b$ \cr % \T exchange \cr % \V \L \,$b+a$\cr % \V \N \,rmult $d$\cr % \V \N \L \,$(b+a) d$ $\bullet$\cr % \L lmult $c$\cr % \N \L \,$c(a+b)$ \cr}} \subsection{Nested sums, products and pure numbers} Nested sum and product nodes require some explanation, as the way in which \cdb handles and stores these determines how brackets can appear in sums and products. As a general rule, sums within sums which are such that all child nodes have the same, non-visible bracket are not allowed, and automatically converted to a single sum. In other words \begin{screen}{0} (\sum{a}{b}+\sum{c}{d}) \end{screen} is not allowed, since it would print as \verb|(a+b+c+d)| which is indistinguishable from \begin{screen}{0} (\sum{a}{b}{c}{d}) . \end{screen} The first expression is therefore internally always converted to the second one before it is stored. A similar situation occurs with products, where \begin{screen}{0} \prod{a}{\prod{b}{c}} \end{screen} is not allowed and ``flattened'' to the simpler \begin{screen}{0} \prod{a}{b}{c} . \end{screen} The general rule is that nested sums and products are converted to flattened form if these two forms are indistinguishable in the standard output format. Nested sums and products can occur, but they have to have different or non-empty bracket types for their children. An example is \begin{screen}{0} \prod{a}{\prod(b)(c)} \end{screen} which prints as \verb|a*(b*c)|. This is not automatically converted to \verb|a*b*c|. Note that this form is \emph{not} represented as \begin{screen}{0} \prod{a}(b)(c) (wrong) \end{screen} This is a consequence of the second rule: all child nodes of product or sum nodes must have the same bracket type. In summary, automatic flattening of nested sum or product trees do not automatically occur over bracket boundaries. You can then write and keep $(\sin(x)+\cos(x)) + (\sin(x) + 3 \cos(x))$, which will be stored as \begin{screen}{0} \sum{\sum(sin(x))(cos(x))}{\sum(sin(x))(cos(x))} \end{screen} In order to remove brackets, one uses the \subscommand{sumflatten} and \subscommand{prodflatten} commands, see section~\ref{m:algebra}. Products and sums with sub- or superscripts which apply to one or more of the child nodes are internally represented using \verb|\indexbracket| nodes. That is, the input \begin{screen}{0} q (a+b)_\mu \end{screen} is represented as \begin{screen}{0} \prod{q}{\indexbracket{\sum(a)(b)}_{\mu}} \end{screen} (note the way in which the bracket types are inherited). In fact, such indexbracket constructions apply for any content inside the brackets; in the example above, an indexbracket would be generated even without the \verb|\sum| node: the input \begin{screen}{0} q (\Gamma^r)_{a b} \end{screen} is stored as \begin{screen}{0} \prod{q}{\indexbracket(\Gamma^r)_{a b}} \end{screen} The result of the indexbracket way of storing expressions is that ``index free'' manipulations apply directly inside the indexbracket argument and no special algorithms are needed. Input will automatically be converted to this form. Getting rid of indexbrackets around single symbols is done using \subscommand{remove\_indexbracket}. Another issue is the storage of numbers. Since pure numerical factors are only allowed to appear in the multiplier field of a node, a pure number is stored as ``1'' with its multiplier equal to the number. Product nodes with two arguments of which one is a number are not allowed and will be converted to a single node with multiplier field, automatically. In order to eliminate ambiguities concerning multipliers in sum and product nodes, the following rules should be obeyed: sum nodes always have unit multiplier (i.e.~non-trivial multipliers are associated to the children) and children of product nodes should also always have unit multiplier (i.e.~the multipliers of all the children should in this case be collected in the prod node itself). \vfill\eject \section{Module implementation guide} \subsection{Storage of numbers and strings} There is a special memory area for the storage of rational numbers (with arbitrary-length integers for the numerator and denominator) as well as for the storage of strings. \subsection{Accessing indices} Indices are stored as ordinary child nodes. However, there are various ways to iterate over all indices in a factor, which are more useful than a simple iteration over all child nodes. \subsection{Object properties} The properties attached to a node in the tree can be queried by using a lookup method in the {\tt properties} namespace. Object properties are child classes of the {\tt property} class, and contain the property information in a parsed form. The following code snippet illustrates how properties are dealt with: \begin{screen}{0} AntiSymmetry *s=properties::get(it) if(s) { // do something with the property info } \end{screen} Here we used a property called {\tt AntiSymmetry}, which is declared in the the module header {\tt modules/algebra.hh} (see the other header files of the various modules for information about the available property types). If the node pointed to by {\tt it} has this property associated to it, the pointer {\tt s} will be set to point to the associated property node. \bfcomment{KP}{Better to use a property example where the property node contains some additional information, which can then be used.} It is also possible to do this search in the other direction, that is, to find an object with a given property. \begin{screen}{0} properties::property_map_t::iterator it=properties::get_pattern(); if(it!=properties::props.end()) { // Now *(it->first) contains the name of a GammaMatrix object. } \end{screen} \bfcomment{KP}{Instead of checking these things, it is better to throw exceptions, since that will make the code more readable and also the error handling more uniform (it can go in one place instead of being repeated).} Sums and products inherit, in a certain way, properties of the terms and factors from which they are built up. This is true also for other functions. If you want to know whether a given node has such \emph{inherited properties}, a simple call to \verb|get<...>| is not sufficient. Instead, use the following construction: \begin{screen}{0} Matrix *m=properties::get_composite(it) if(m) { // do something with the property info } \end{screen} These inheritance rules for composite objects are at present hard-coded but will be user-defineable at a later stage. % \begin{sectionunit} % \title{Labelling and selection of expressions} % % % The kernel of \cdb is completely separated from its user interface, % but the communication between the two uses a human-readable format. % In order to allow the front-end to refer to individual elements of % the expressions, a simple labelling scheme is used for every % node in an expression. The \cdb kernel output thus looks like % \begin{screen}{0} % \Gamma@1_{m@2} \Gamma@3_{n@4} \Gamma@5_{p@6} % \end{screen} % All symbols have been labelled with a unique % numerical identifier. When you select the two gamma symbols, the % front-end notifies the core of this action by sending back the % identifiers ``1'' and ``3''. Upon receipt of the command {\tt @join} % the core then knows to which objects this algorithm should apply. In % the absence of a front-end, you can do the selection by hand: just % send the command {\tt @select} to the core, followed by a comma % separated bracketed argument list of numerical identifiers. There also % exist an {\tt @unselect} command. % % % \subsection{Writing a new algorithm module} \label{s:writing_new} All functionality of cadabra that goes beyond storage of the expression trees is located in separate modules, stored in the \verb|src/modules| subdirectory. New functionality can easily be added by writing new modules. All algorithm objects derive from the \verb|algorithm| object defined in \verb|src/algorithm.hh|, and only a couple of virtual members have to be implemented. \begin{figure}[p!] \begin{screen}{0} class str_node { public: ... }; \end{screen} \caption{The node class.\label{f:str_node}} \end{figure} \begin{figure}[p!] \begin{screen}{0} class algorithm { public: typedef exptree::iterator iterator; typedef exptree::sibling_iterator sibling_iterator; algorithm(exptree&, iterator&); virtual void description() const=0; virtual bool can_apply(iterator&); virtual bool can_apply(sibling_iterator&, sibling_iterator&); virtual result_t apply(iterator&); virtual result_t apply(sibling_iterator&, sibling_iterator&); sibling_iterator args_begin() const; sibling_iterator args_end() const; unsigned int number_of_args() const; exptree& tr; iterator this_command; }; \end{screen} \caption{The relevant members of the class interface for the {\tt algorithm} object. The virtual members and the constructor have to be implemented in new algorithm objects; see the main text for an explanation of the two versions of {\tt can\_apply} and {\tt apply}.} \label{f:algorithm} \end{figure} \begin{figure}[p!] \begin{screen}{0} class exptree { public: sibling_iterator arg(iterator, unsigned int) const; unsigned int arg_size(sibling_iterator) const; multiplier_t arg_to_num(sibling_iterator, unsigned int) const; }; \end{screen} \caption{The relevant members of the class interface for the {\tt exptree} object.} \end{figure} The class interface for the algorithm object is shown in figure~\ref{f:algorithm}. The members which any class derived from {\tt algorithm} should implement are described below. \begin{description} \item[{\tt constructor(exptree\&, iterator)}] Algorithm objects get initialised with a reference {\tt tr} to the expression tree on which they act, together with an iterator {\tt this\_command} pointing to the associated command node. By looking at the child nodes of the latter, the arguments of the command can be obtained. The simplest way to do this is to use the sibling iterators returned by \verb|args_begin()| and \verb|args_end()|; these automatically skip the argument which refers to the equation number (i.e.~they skip the \verb|(5)| argument in \verb|@command(5){arg1}{arg2}|). The constructor is a good place to parse the command arguments, since that will in general only be required once. Do not do anything in the constructor that has to be done on every invocation of the same command on different expressions. If you discover that the arguments passed to an algorithm are not legal, you have to throw an {\tt algorithm::constructor\_error} exception. \item[{\tt description()}] Should display an explanation of the functionality of the algorithm on the {\tt txtout} stream. Do not add \verb|std::endl| newlines by hand, these will be inserted automatically. \item[\vbox{\hbox{\tt bool can\_apply(iterator)} \hbox{\tt bool can\_apply(sibling\_iterator, sibling\_iterator)}}] Determines whether the algorithm has a chance of acting on the given expression. This is an \emph{estimate} but is required to return {\tt true} if there is a possibility that the algorithm would yield a change. It takes two sibling\_iterators as arguments, which indicate a node or a range of nodes on which the algorithm is supposed to act. Since {\tt can\_apply} is guaranteed to be called before {\tt apply}, it is allowed for the {\tt can\_apply} member to store results for later use in {\tt apply}. However, multiple calls to can be made to this combo, so any data stored should be erased upon each call to {\tt can\_apply}. \item[\vbox{\hbox{\tt apply\_result apply(iterator\&)} \hbox{\tt apply\_result apply(sibling\_iterator\&, sibling\_iterator\&)}}] Before exiting this function, the member variable {\tt expression\_modified} has to be set according to whether or not the apply call made any changes to the expression. If the algorithm can take a long time to complete and you want to give the user the option of interrupting it with control-C, you can check (at points where the algorithm can be interrupted) the global variable {\tt interrupted}. If it is set, you should immediately throw an exception of type {\tt algorithm\_interrupted}, preferably with a short string describing the location or algorithm at which the interrupt occurred. The exception will be handled at the top level in the {\tt manipulator.cc} code, where the current expression will be removed. % %Do not forget to unset it afterwards. If you exit an %algorithm this way, your module should leave the expression tree in %exactly the same way as it was when the {\tt apply} member was %entered. Return \verb|l_error| to signal failure. Algorithms can write progress information to the stream {\tt txtout} and debug information (which will go into a separate file on disk) to {\tt debugout}. These are global objects. Do not use the \Cpp streams {\tt std::cout} and {\tt std::cerr} for this purpose. \end{description} An algorithm is \emph{never} allowed to modify the tree above the node or range of sibling nodes which were passed to the \verb|apply| call. In other words, siblings and parent nodes should never be touched, and the nodes should not be removed from the tree directly. If you want to remove nodes, this can be done by setting their multiplier field to zero; the core routines will take care of actually removing the nodes from the tree. It is allowed to inspect the tree above the given nodes, but this is discouraged. Upon any exit from an algorithm module, the tree is required to be in a valid state. In many cases, it is useful to clean up modifications to the tree by calling the utility function {\tt cleanup\_expression} (see section~\ref{s:utility} for more information). \subsection{Adding the module to the system} Once you have written the \verb|.hh| and \verb|.cc| files associated to your new algorithm, it has to be added to the build process and the core program. First, add the header to the master header file \verb|src/modules/modules.hh| file; this one looks like \begin{screen}{0} src/modules/modules.hh: #include "algebra.hh" #include "pertstring.hh" #include "select.hh" ... \end{screen} You also have to add it to the \verb|src/Makefile.in|. Near the top of this file you find a line looking somewhat like \begin{screen}{0} src/Makefile.in: ... MOBJS=modules/algebra.o modules/pertstring.o modules/convert.o \ modules/field_theory.o modules/select.o modules/dummies.o \ modules/properties.o modules/relativity.o modules/substitute.o ... \end{screen} and this is where your module has to be added. Finally, you have to make the algorithm visible to the core program. This is done in the \verb|src/manipulator.cc| file. In the constructor of the \verb|manipulator| class (defined somewhere near the top), you see a map of names to algorithm classes. A small piece is listed below: \begin{screen}{0} src/manipulator.cc: ... // pertstring algorithms["@aticksen"] =&create; algorithms["@riemannid"] =&create; // algebra algorithms["@distribute"] =&create; ... \end{screen} Add your algorithm here; it does not have to have the same name as the object class name. Once this is all done, rerun configure and make. \subsection{Adding new properties} \begin{figure}[t] \begin{screen}{0} class property { public: virtual bool parse(exptree&, iterator pat, iterator prop); virtual std::string name() const=0; virtual void display(std::ostream&) const; }; \end{screen} \caption{The relevant members of the class interface for the {\tt property} object.} \end{figure} \bfcomment{KP}{Discuss the various member functions of property, in particular the way in which parse is supposed to behave, and the way in which properties should be registered.} Since algorithms rely crucially on a \emph{fixed} set of properties which they provide themselves, we store these things in a \Cpp way, rather than using strings. Another motivation: we do not want to parse (and check) these property trees every time they are accessed. Properties typically carry key/value pairs which further specify the characteristics of the property. When the property object is created, the core calls the \verb|parse()| method of the property, in which you are responsible for scanning through the list of key/value pairs. This is rather simple: just call the \verb|find()| member of the \verb|keyval| argument, \begin{screen}{0} keyval_t::iterator ki=keyvals.find("dimension"); if(ki!=keyvals.end()) { // now ki->second is an iterator to an expression subtree } \end{screen} If the new property is derived from existing ones, do not forget to call the \verb|parse()| method of all parent classes at the end. Once this is all done, register the property with the system by adding an appropriate call to the module's \verb|register_properties()| method, found at the top of each module. \subsection{Throwing errors} If, at any stage, an inconsistent expression is encountered, the safe way to return to the top level of the manipulator is to throw the exception class \cdbclass{consistency\_error} (defined in \cdbfile{algorithm.hh}). \subsection{Manipulating the expression tree} The \cdbclass{exptree} class contains a number of tree access routines which enhance the functionality of the {\tt tree.hh} library. \begin{description} \item[\member{index\_iterator}] \item[\member{index\_map\_t}] \end{description} \subsubsection{Acting on products or single terms} use \member{is\_single\_term} and \member{prod\_wrap\_single\_term}. \subsubsection{Reserved node names} There is a small number of node names which is reserved to always mean the same thing, i.e.~for which the properties are not determined by the property system. These are \begin{description} \item[\texcommand{prod}] \item[\texcommand{div}] \item[\texcommand{sum}] \item[\texcommand{pow}] \item[\texcommand{indexbracket}] \item[\texcommand{factorial}] \item[\texcommand{equals}] \item[\texcommand{unequals}] \item[\texcommand{sequence}] \item[\texcommand{comma}] \item[\texcommand{infty}] \end{description} Some properties of these nodes are still obtained from the property system in order to make algorithms look more uniform, but the names of these reserved nodes can not be changed. \subsection{Utility functions} \label{s:utility} There are also various useful helper functions in the {\tt exptree} class, mainly dealing with the conversion of expression numbers or labels to iterators that point to the actual expression in the tree. \begin{description} \item[\vbox{\hbox{\member{cleanup\_expression(exptree\&)}} \hbox{\member{cleanup\_expression(exptree\&, iterator)}}}] Converts an expression (or part of it below the indicated node) to a valid form. That is, it calls various simplification algorithms on the expression, among which {\tt sumflatten} and {\tt prodcollectnum}. \item[\member{cleanup\_nests}] When called on a product inside a product, or a sum inside a sum, and the bracket types of both node and parent are the same, flatten the tree. Adjusts the iterator to point to the product or sum node which remains. \item[\member{equation\_by\_number\_or\_name}] Given an iterator to a node that represents an expression number or expression label, this member returns an iterator that points to the actual node (to be precise: to the \verb|\history| node of the expression). \item[\vbox{\hbox{\member{arg\_size(sibling\_iterator)}} \hbox{\member{arg(iterator, unsigned int)}}}] Many algorithms require one \emph{or more} objects as arguments. These are usually passed as lists, and therefore end up being of two forms: either they are single objects or they are {\tt comma} objects representing a list. In order to avoid having to check for these two cases, one can use these two member functions. The iterator arguments of these two member functions should point to the child which is either a single argument or a \texcommand{comma} node. \item[\member{pushup\_multiplier}] Can be called on any node. If the node has a non-unit multiplier and the storage conventions exclude this, the algorithm will push the multiplier up the tree. \end{description} % \begin{itemize} % \item The various comparison functions in str\_node. % \item Members of active\_node and algorithm. % \item Multiply, add, zero and one in these classes. % \end{itemize} \subsection{Writing a new output module} \kcomment{KP}{Structure is different now: one inherits from {\tt output\_exptree} and then has printing stuff at ones disposal. Still would be nice to be able to change the printing objects for a given node type, i.e.~modify the map of node names to printing objects.} \kcomment{KP}{Also do something intelligent with the Mathematica output flags}. \subsection{Namespaces and global objects} The following objects are global: \begin{description} \item[{\tt modglue::opipe txtout}] The normal output stream, to which you should communicate with the user. \item[{\tt std::ofstream debugout}] The debug output stream, which normally writes to a file, and should only be used to write output which is useful for debugging purposes. \item[{\tt nset\_t name\_set}] The global collection of all strings. Nodes in the expression tree contain an iterator into this map (see in particular figure~\ref{f:str_node}). \item[{\tt rset\_t rat\_set}] The global collection of all rational numbers. Nodes in the expression tree contain an iterator into this map (see in particular figure~\ref{f:str_node}). \item[{\tt bool interrupted}] A global flag which indicates that the user has requested the computation to be interrupted. See section~\ref{s:writing_new} for more information on this variable. \item[{\tt stopwatch globaltime}] The wall time since program start. \item[{\tt unsigned int size\_x, size\_y}] The size of the current output window. \end{description} % \subsection{Troubleshooting} % % \begin{description} % \item[Problems getting expressions in canonical form] % There are various canonical places to look for errors. One of % them is the routine {\tt propagate\_zeroes}, which may still not remove % zeroes properly but leave an inconsistent tree. Another place % is {\tt cleanup\_nests}. % \end{description} \vfill\eject % \section{Future plans} % \subsection{Front-ends} % % % %The text-mode front-end will be based on {\tt eqascii} by % %\dcite{e_bori1}, while the graphical front-end will use % %\TeX{} for typesetting. % % \subsection{Component calculations} %\vfill\eject % \begin{sectionunit} % \title{Using the history mechanism} % % Let us first discuss an example which shows the way in which the \cdb % history mechanism works, and also exhibits the selection mechanism. % As with all other data structures in \cdb, the history is also a % tree-like structure. Expressions and commands get appended as children % of each other. When you backtrack by going to a previous expression in % the history, any new commands get added as child, thereby keeping % the previous calculations based on that node accessible. An % example illustrates how this works. % \begin{screen}{0} % > \Gamma_{m} \Gamma_{n} % (1) : \Gamma_{m} \Gamma_{n} % > @join{(1), 1, 2} % (1) : \Gamma_{m n} + \eta_{m n} % > \Gamma_{m n} = \epsilon_{p q r s} \Gamma^{p q r s} \tilde\Gamma % (1) : \Gamma_{m n} + \eta_{m n} % (2) : \Gamma_{m n} = \epsilon_{p q r s m n} \Gamma^{p q r s} \tilde\Gamma % > @subs{(2), (1)} % (1) : \epsilon_{p q r s m n}\Gamma^{p q r s}\tilde\Gamma + \eta_{m n} % (2) : \Gamma_{m n} = \epsilon_{p q r s} \Gamma^{p q r s} \tilde\Gamma % > \eta_{m n} = 0 % (1) : \epsilon_{p q r s m n}\Gamma^{p q r s}\tilde\Gamma + \eta_{m n} % (2) : \Gamma_{m n} = \epsilon_{p q r s} \Gamma^{p q r s} \tilde\Gamma % (3) : \eta_{m n} = 0 % > @up((1)) % (1) : \Gamma_{m n} + \eta_{m n} % > @subs{(3), (1)} % (1) : \Gamma_{m n} % (2) : \Gamma_{m n} = \epsilon_{p q r s} \Gamma^{p q r s} \tilde\Gamma % (3) : \eta_{m n} = 0 % \end{screen} % Notice how the modification of equation~(1) has produced a new % equation, but it has kept the original expression in memory as well. % You can see the history of an equation by doing % \begin{screen}{0} % > @showtree((1)) % input % (1) : \Gamma_{m} \Gamma_{n} % join % (1.1) : \Gamma_{m n} + \eta_{m n} % subs % (1.1.1) : \epsilon_{p q r s m n}\Gamma^{p q r s}\tilde\Gamma + \eta_{m n} % subs % (1.1.2)*: \Gamma_{m n} % \end{screen} % The star indicates which equation is currently denoted with~(1) in the % compact output. If you are not interested in the paths that led to % other expressions, then it is sufficient to do % \begin{screen}{0} % > @showhistory((1)) % input : \Gamma_{m} \Gamma_{n} % join : \Gamma_{m n} + \eta_{m n} % subs : \Gamma_{m n} % \end{screen} % This can be used to generate a clean report of all the manipulations % that lead up to a certain result. If you are confident that you do not % anymore need any of the branches except the one that leads to the % last result, you can enter the \verb|@cleanhistory| command. % \printindex \bibliographystyle{kasper} \bibliography{kasbib} \end{document} % \begin{sectionunit} % \title{Cursor mode} % % At any time, pressing `escape' will jump to the `cursor' mode. In this % mode, one can select and unselects parts of the expression. Available % commands: % \begin{center} % \begin{tabular}{ll} % cursor-right & move cursor to next object on this level \\[1ex] % cursor-left & move cursor to previous object on this level \\[1ex] % cursor-down & move cursor to the arguments of the current % objects\\[1ex] % cursor-up & move cursor to the parent of the current object\\[1ex] % page-down & enlarge cursor size \\[1ex] % page-up & shrink cursor size \\[1ex] % e & remove all selections \\[1ex] % space & select the objects currently under the cursor % \end{tabular} % \end{center} % \begin{enumerate} \item Work both with abstract component tensors as well as individual components. The algorithms for e.g.~gamma matrix manipulation have to recognise this (not just flip indices around, but actually use $\Gamma^1 \Gamma^1=1$ and so on). \end{enumerate} cadabra-0.115/doc/ChangeLog0000600000077000007700000001770410555362625015006 0ustar kantorkantor2007-01-19 Kasper Peeters * Fixed a bug in "replace" which appeared when trying to replace a head node (it tried to access the parent). 2006-11-29 Kasper Peeters * Release 2.3 Fixed a bug in number_of_siblings which only counted siblings in one direction (thanks to Fanzhe Cui for pointing this out). 2006-08-20 Kasper Peeters * Released 2.2. * Added operator== and operator!= for fixed_depth_iterator. 2006-08-07 Kasper Peeters * Released 2.1. * Added leaf iterators, code contributed by Peter Wienemann. * Fixed a bug in is_valid (thanks to Antonio Morillas). 1.131. 2006-07-19 Kasper Peeters * Fixed bugs in move_before and move_after which would show up when the node was already in the right place. 1.130. 2006-03-02 Kasper Peeters * Added the "wrap" member function. 2006-03-01 Kasper Peeters * Added a simple queue-based breadth-first iterator. 2006-01-31 Kasper Peeters * Fixed move_before to work when the target is a sibling_iterator pointing to the end of a range of siblings. 2005-11-20 Kasper Peeters * Added move_after, which for some mysterious reason was missing. Thanks to Dennis Jones for pointing this out. * Fixed a bug in operator++ for post_order iterators (skip_children could remain set if no next sibling present). Thanks to Ohad for pointing out the bug. 2005-10-12 Kasper Peeters * Fixed a bug in the 'sort' member which takes a Comparator function object (thanks to Robin Taylor for the patch). 2005-09-14 Kasper Peeters * Doxygen documentation added, plus a new web page. 2004-11-05 Kasper Peeters * Fixed a bug which shows up when inserting nodes at the top of the tree (thanks to Matthias Bernt for pointing me at this one). 2004-07-21 Kasper Peeters * Fixed kp::destructor -> destructor. * Moved body of 'compare_nodes::operator()' into the class declaration in order to satisfy buggy Borland compilers (and stop regular email messages about this problem). * Fixed a completely buggy number_of_siblings() (thanks to Caleb Epstein for the patch). 2004-02-04 Kasper Peeters * Released 1.106 * Fixed a bug in insert(sibling_iterator, const T&) (thanks to Maxim Yegorushkin for the patch). 2003-11-21 Kasper Peeters * Put some things in a namespace to avoid clashes with other libraries. 2003-10-13 Kasper Peeters * Released 1.102. * Fixed return type of postincrement/decrement operators (thanks to Yevhen Tymokhin for pointing this out). 2003-09-18 Kasper Peeters * Fixes for standard compliance, as required to compile with gcc 3.4 and later. 2003-08-12 Kasper Peeters * Added 'empty' member (patch by Michael Vogt). 2003-08-01 * Released 1.95 * Fixed two bugs in sort (which were corrupting the tree); thanks to Michael Vogt for informing me about the problem. 2003-07-17 * Added a hack to enable compilation with STLport. 2003-07-11 * Released 1.90 * Added postfix increment and decrement operators; thanks to Claudio Andreatta for sending the patch. * Fixed a bug in reparent(iter pos, iter from). Thanks to Claudio Andreatta for fixing this. 2003-06-25 Kasper Peeters * Many bug fixes for fixed depth iterators, thanks to Ruben Niederhagen for pointing out several problems (a few still exist, see the 'TODO' part of tree.hh). 2003-04-17 Kasper Peeters * Released 1.85 * Corrected return type of operator++ and friends. * Added preliminary support for 'fixed_depth_iterator' to iterate over children at a given level. Not quite finished yet, sorry. 2003-03-24 Kasper Peeters * Released 1.83 * Changed return type of 'child' member function to be a sibling iterator instead of a reference to the actual node (sorry for the incompatibility with previous versions). Change also propagated to tree_msvc.hh. 2003-02-07 * Released 1.80 * Fixed another bug in sort (thanks to Tony Cook for fixing this bug). 2003-01-29 Kasper Peeters * Released 1.78. * Fixed a bug in sort, which resulted in a corrupt tree (thanks to Michael Vogt for fixing this bug). 2003-01-07 Kasper Peeters * Released 1.75 and msvc version 1.72 * Fixed a wrongly specialised 'insert' method for sibling_iterators (thanks to Tony Cook for pointing this out). 2002-11-15 Kasper Peeters * Released 1.72 * Fixed a bug in 'index' when called on nodes at the top level of the tree (thanks to David Zajic for the bug report). Be warned that the top level is a bit special at the moment; the end sibling_iterator is ill-defined for siblings there (to be fixed in a future version). 2002-10-31 Kasper Peeters * Released 1.70. * Finished the merge algorithm, updated the documentation with examples about its use, and added a test-case to the test_tree.cc program. * Fixed a bug in pre_order_iterator::operator--. 2002-10-20 Kasper Peeters * Released 1.66. 2002-10-15 Kasper Peeters * Code for post_order_iterator implemented. 2002-10-13 Kasper Peeters * Rewrote large parts of the code to allow for multiple iterator types, such as pre_order_iterator (which was the previous iterator type), post_order_iterator and so on. This required small changes to the interface, the most visible one being - insert(iterator, iterator) for the insertion of a subtree is now called insert_subtree(iterator, iterator). Apologies if this breaks your code. 2002-10-11 Kasper Peeters * Removed '(void)' type declarations in favour of the C++ standard empty brackets '()'. 2002-10-10 Kasper Peeters * Added 'index' in response to a discussion on the Boost mailing list. 2002-10-03 Kasper Peeters * reparent(iterator,sibling_iterator,sibling_iterator) now accepts an empty range, in which case it does nothing (request by Jos de Laender). * Fixed a bug in the iterator(sibling_iterator) constructor (thanks to Jos de Laender for pointing this out). 2002-09-04 Kasper Peeters * Fixed a bug in insert_after (thanks to Carl Blanchette for the patch). 2002-08-29 Kasper Peeters * The problem in test_tree of the previous item was actually do to tree::end(iterator) returning the end of the tree, not the end of the current sibling list. Fixed now, released 1.55. 2002-08-26 Kasper Peeters * Released 1.54. * Printing a single-node tree in test_tree would result in a segfault; more robust now (thanks to Yutaka Sato for the bug report). 2002-05-07 Kasper Peeters * Fixed a bug in "sort" which would remove duplicate nodes altogether. 2002-03-24 Kasper Peeters * Added "append_child" without child argument, to add empty child node. 2002-05-04 Kasper Peeters * Released 1.45. * Removed restriction of having only a single node at the top of the tree (associated with this, the top nodes should now be inserted with "insert", not with "append_child"). * Fixes for ISO compatibility (now works with gcc-3.1). Thanks to Olivier Verdier. cadabra-0.115/doc/combinatorics.tex0000600000077000007700000000665310555362625016613 0ustar kantorkantor\documentclass[11pt]{kasper} \usepackage{relsize} \begin{document} \title{{\tt combinatorics.hh} documentation} \author{Kasper Peeters} \address{1}{{\it MPI/AEI f\"ur Gravitationsphysik, Am M\"uhlenberg 1, 14476 Potsdam, Germany}} \email{k.peeters@damtp.cam.ac.uk} \maketitle \begin{abstract} The {\tt combinatorics.hh} class is bla bla \end{abstract} \begin{sectionunit} \title{Reference guide} \maketitle The {\tt combinatorics.hh} class library contains two classes for the generation of combinations \begin{sectionunit} \title{The {\tt combinations} class} \maketitle The {\tt combinations} class takes a vector of elements, and generates combinations of a subset of these elements that satisfy several requirements. \begin{description} \item[{\tt sublengths}]~\\ Stores the lengths of the object ranges in which objects can only appear in increasing order. The usual concepts of ``combinations and permutations'' translate to the following content of the {\tt sublengths} vector: \begin{equation} \begin{aligned} \text{combinations:} &\quad \text{one element, $v$=total length}\, ,\\ \text{permutations:} &\quad \text{$n$ elements, all equal to $1$}. \end{aligned} \end{equation} However, many more general situations are possible with {\tt combinatorics.hh}. See the examples below. \item[{\tt input\_asym}] ~\\ Stores sets of objects which have to be ``implicitly permuted''. That is, permutations are done only modulo the permutations of the objects in these sets. An example may help: \begin{equation} \begin{aligned} \{a,b,c\} &\rightarrow \frac{1}{6}(a,b,c + a,c,b + b,a,c + c,a,b + b,c,a + c,b,a)\\ \{a,b,c\}_{\{0,1\}} &\rightarrow \frac{1}{3}(a,b,c + a,c,b + c,a,b)\\ \{a,b,c\}_{\{0,2\}} &\rightarrow \frac{1}{3}(a,b,c + a,c,b + b,a,c)\\ \{a,b,c\}^{\{2,1\}} &\rightarrow \frac{1}{3}(a,b,c + a,c,b + c,a,b) \end{aligned} \end{equation} Note that this does not just remove terms, it also corrects the multiplicative factor. \end{description} \end{sectionunit} \begin{sectionunit} \title{The {\tt symmetriser} class} \maketitle The {\tt symmetriser} class takes a vector of elements, and applies permutations or combinations to it. The difference with {\tt combinations} is that {\tt symmetriser} can be used to apply several permutations successively. Here is an example, \begin{screen} symmetriser sm; sm.original.push_back("r1"); sm.original.push_back("r2"); sm.original.push_back("r3"); sm.original.push_back("r4"); sm.original.push_back("r5"); sm.block_length=1; sm.permutation_sign=-1; sm.permute_blocks.push_back(1); sm.permute_blocks.push_back(2); sm.apply_symmetry(); \end{screen} This permutes the {\tt r2} and {\tt r3} items, with a minus sign under exchange, leaving the other elements unchanged. \begin{description} \item[set storage] \item[result storage] \item[permuting by position] \item[permuting by value] \item[weights] \item[input symmetries] Just as with the {\tt combinations} class, the {\tt symmetriser} class can be told to apply symmetries only modulo given symmetries. Take care when permuting objects by value: the \verb|input\_asym| data still refer to object locations, not object values (this may be a tricky bug to find when you are permuting integers). The object locations are always relative to the set of permuted values, not with respect to the complete set of original values. \end{description} \end{sectionunit} \end{sectionunit} \begin{sectionunit} \title{Examples} \maketitle \end{sectionunit} \end{document} cadabra-0.115/doc/doxygen_cadabra.config0000600000077000007700000002351410367614263017530 0ustar kantorkantor# Doxyfile 1.4.4 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = cadabra PROJECT_NUMBER = "development" OUTPUT_DIRECTORY = doxygen CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ../src FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.C \ *.CC \ *.C++ \ *.II \ *.I++ \ *.H \ *.HH \ *.H++ \ *.CS \ *.PHP \ *.PHP3 \ *.M \ *.MM RECURSIVE = YES EXCLUDE = ../src/tree.hh \ ../src/tree_util.hh \ ../src/tree_new.hh \ ../src/tree_msvc.hh EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO USE_HTAGS = NO VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO cadabra-0.115/doc/doxygen_tree.config0000600000077000007700000002333610323711231017075 0ustar kantorkantor# Doxyfile 1.4.4 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = tree PROJECT_NUMBER = "release 2.0" OUTPUT_DIRECTORY = doxygen CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = tree.hh FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.C \ *.CC \ *.C++ \ *.II \ *.I++ \ *.H \ *.HH \ *.H++ \ *.CS \ *.PHP \ *.PHP3 \ *.M \ *.MM RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO USE_HTAGS = NO VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO cadabra-0.115/doc/exp1.eps0000600000077000007700000001065310463334117014607 0ustar kantorkantor%!PS-Adobe-2.0 EPSF-2.0 %%Title: exp1.fig %%Creator: fig2dev Version 3.2 Patchlevel 5-alpha7 %%CreationDate: Sun Jul 30 23:11:05 2006 %%BoundingBox: 0 0 213 153 %Magnification: 1.0000 %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save newpath 0 153 moveto 0 0 lineto 213 0 lineto 213 153 lineto closepath clip newpath -101.1 312.8 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def $F2psBegin 10 setmiterlimit 0 slj 0 slc 0.06299 0.06299 sc % % Fig objects follow % % % here starts figure with depth 50 % Polyline 0 slj 0 slc 7.500 slw n 4410 2790 m 3825 2925 l gs col0 s gr % Polyline n 4410 2790 m 4905 2925 l gs col0 s gr % Polyline n 3690 3240 m 3150 3375 l gs col0 s gr % Polyline n 3690 3240 m 4140 3375 l gs col0 s gr % Polyline n 3015 3645 m 2655 3825 l gs col0 s gr % Polyline n 3015 3645 m 3465 3825 l gs col0 s gr % Polyline n 2610 4140 m 3015 4275 l gs col0 s gr % Polyline n 2115 4590 m 2115 4770 l gs col0 s gr % Polyline n 2115 4590 m 1755 4770 l gs col0 s gr % Polyline n 2115 4590 m 2520 4770 l gs col0 s gr % Polyline n 3015 4590 m 3015 4770 l gs col0 s gr % Polyline n 4095 3690 m 4095 3870 l gs col0 s gr % Polyline n 2610 4140 m 2160 4275 l gs col0 s gr /Times-Roman ff 190.50 scf sf 3600 3150 m gs 1 -1 sc (prod) col0 sh gr /Times-Roman ff 190.50 scf sf 4050 3600 m gs 1 -1 sc (psi) col0 sh gr /Times-Roman ff 190.50 scf sf 4860 3150 m gs 1 -1 sc (x) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 3600 m gs 1 -1 sc (diff) col0 sh gr /Times-Roman ff 190.50 scf sf 2070 4500 m gs 1 -1 sc (F) col0 sh gr /Times-Roman ff 190.50 scf sf 1620 4950 m gs 1 -1 sc (mu) col0 sh gr /Times-Roman ff 190.50 scf sf 2070 4950 m gs 1 -1 sc (nu) col0 sh gr /Times-Roman ff 190.50 scf sf 2430 4950 m gs 1 -1 sc (rho) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 4500 m gs 1 -1 sc (psi) col0 sh gr /Times-Roman ff 190.50 scf sf 2430 4050 m gs 1 -1 sc (prod) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 4950 m gs 1 -1 sc (mu) col0 sh gr /Times-Roman ff 190.50 scf sf 4050 4050 m gs 1 -1 sc (nu) col0 sh gr /Times-Roman ff 190.50 scf sf 4320 2700 m gs 1 -1 sc (int) col0 sh gr /Times-Roman ff 190.50 scf sf 3375 4050 m gs 1 -1 sc (lam) col0 sh gr % here ends figure; $F2psEnd rs showpage %%Trailer %EOF cadabra-0.115/doc/exp1.fig0000600000077000007700000000313410463334117014561 0ustar kantorkantor#FIG 3.2 Produced by xfig version 3.2.5-alpha5 Portrait Center Metric A4 100.00 Single -2 1200 2 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 4410 2790 3825 2925 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 4410 2790 4905 2925 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3690 3240 3150 3375 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3690 3240 4140 3375 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3015 3645 2655 3825 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3015 3645 3465 3825 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2610 4140 3015 4275 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2115 4590 2115 4770 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2115 4590 1755 4770 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2115 4590 2520 4770 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3015 4590 3015 4770 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 4095 3690 4095 3870 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2610 4140 2160 4275 4 0 0 50 -1 0 12 0.0000 4 180 375 3600 3150 prod\001 4 0 0 50 -1 0 12 0.0000 4 180 240 4050 3600 psi\001 4 0 0 50 -1 0 12 0.0000 4 90 105 4860 3150 x\001 4 0 0 50 -1 0 12 0.0000 4 135 285 2970 3600 diff\001 4 0 0 50 -1 0 12 0.0000 4 135 105 2070 4500 F\001 4 0 0 50 -1 0 12 0.0000 4 90 255 1620 4950 mu\001 4 0 0 50 -1 0 12 0.0000 4 90 210 2070 4950 nu\001 4 0 0 50 -1 0 12 0.0000 4 135 270 2430 4950 rho\001 4 0 0 50 -1 0 12 0.0000 4 180 240 2970 4500 psi\001 4 0 0 50 -1 0 12 0.0000 4 180 375 2430 4050 prod\001 4 0 0 50 -1 0 12 0.0000 4 90 255 2970 4950 mu\001 4 0 0 50 -1 0 12 0.0000 4 90 210 4050 4050 nu\001 4 0 0 50 -1 0 12 0.0000 4 135 225 4320 2700 int\001 4 0 0 50 -1 0 12 0.0000 4 135 300 3375 4050 lam\001 cadabra-0.115/doc/exp2.eps0000600000077000007700000012017610537234067014617 0ustar kantorkantor%!PS-Adobe-2.0 EPSF-2.0 %%Creator: dvips(k) 5.95a Copyright 2005 Radical Eye Software %%Title: /home/kasper/tmp/kt_temp/kt_temp_makefig/makefig.dvi %%BoundingBox: 80 572 300 721 %%DocumentFonts: CMR10 CMMI10 CMMI7 %%EndComments %DVIPSWebPage: (www.radicaleye.com) %DVIPSCommandLine: dvips -E %+ /home/kasper/tmp/kt_temp/kt_temp_makefig/makefig.dvi -o exp2.eps %DVIPSParameters: dpi=600 %DVIPSSource: TeX output 2006.12.11:1148 %%BeginProcSet: tex.pro 0 0 %! /TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin /FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array /BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get }B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr 1 add N}if}B/CharBuilder{save 3 1 roll S A/base get 2 index get S /BitMaps get S get/Cd X pop/ctr 0 N Cdx 0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx sub Cy .1 sub]{Ci}imagemask restore}B/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn /BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put }if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X 1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N /p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ /Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) (LaserWriter 16/600)]{A length product length le{A length product exch 0 exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end %%EndProcSet %%BeginProcSet: psfrag.pro 0 0 %% %% This is file `psfrag.pro', %% generated with the docstrip utility. %% %% The original source files were: %% %% psfrag.dtx (with options: `filepro') %% %% Copyright (c) 1996 Craig Barratt, Michael C. Grant, and David Carlisle. %% All rights reserved. %% %% This file is part of the PSfrag package. %% userdict begin /PSfragLib 90 dict def /PSfragDict 6 dict def /PSfrag { PSfragLib begin load exec end } bind def end PSfragLib begin /RO /readonly load def /CP /currentpoint load def /CM /currentmatrix load def /B { bind RO def } bind def /X { exch def } B /MD { { X } forall } B /OE { end exec PSfragLib begin } B /S false def /tstr 8 string def /islev2 { languagelevel } stopped { false } { 2 ge } ifelse def [ /sM /tM /srcM /dstM /dM /idM /srcFM /dstFM ] { matrix def } forall sM currentmatrix RO pop dM defaultmatrix RO idM invertmatrix RO pop srcFM identmatrix pop /Hide { gsave { CP } stopped not newpath clip { moveto } if } B /Unhide { { CP } stopped not grestore { moveto } if } B /setrepl islev2 {{ /glob currentglobal def true setglobal array astore globaldict exch /PSfrags exch put glob setglobal }} {{ array astore /PSfrags X }} ifelse B /getrepl islev2 {{ globaldict /PSfrags get aload length }} {{ PSfrags aload length }} ifelse B /convert { /src X src length string /c 0 def src length { dup c src c get dup 32 lt { pop 32 } if put /c c 1 add def } repeat } B /Begin { /saver save def srcFM exch 3 exch put 0 ne /debugMode X 0 setrepl dup /S exch dict def { S 3 1 roll exch convert exch put } repeat srcM CM dup invertmatrix pop mark { currentdict { end } stopped { pop exit } if } loop PSfragDict counttomark { begin } repeat pop } B /End { mark { currentdict end dup PSfragDict eq { pop exit } if } loop counttomark { begin } repeat pop getrepl saver restore 7 idiv dup /S exch dict def { 6 array astore /mtrx X tstr cvs /K X S K [ S K known { S K get aload pop } if mtrx ] put } repeat } B /Place { tstr cvs /K X S K known { bind /proc X tM CM pop CP /cY X /cX X 0 0 transform idtransform neg /aY X neg /aX X S K get dup length /maxiter X /iter 1 def { iter maxiter ne { /saver save def } if tM setmatrix aX aY translate [ exch aload pop idtransform ] concat cX neg cY neg translate cX cY moveto /proc load OE iter maxiter ne { saver restore /iter iter 1 add def } if } forall /noXY { CP /cY X /cX X } stopped def tM setmatrix noXY { newpath } { cX cY moveto } ifelse } { Hide OE Unhide } ifelse } B /normalize { 2 index dup mul 2 index dup mul add sqrt div dup 4 -1 roll exch mul 3 1 roll mul } B /replace { aload pop MD CP /bY X /lX X gsave sM setmatrix str stringwidth abs exch abs add dup 0 eq { pop } { 360 exch div dup scale } ifelse lX neg bY neg translate newpath lX bY moveto str { /ch X ( ) dup 0 ch put false charpath ch Kproc } forall flattenpath pathbbox [ /uY /uX /lY /lX ] MD CP grestore moveto currentfont /FontMatrix get dstFM copy dup 0 get 0 lt { uX lX /uX X /lX X } if 3 get 0 lt { uY lY /uY X /lY X } if /cX uX lX add 0.5 mul def /cY uY lY add 0.5 mul def debugMode { gsave 0 setgray 1 setlinewidth lX lY moveto lX uY lineto uX uY lineto uX lY lineto closepath lX bY moveto uX bY lineto lX cY moveto uX cY lineto cX lY moveto cX uY lineto stroke grestore } if dstFM dup invertmatrix dstM CM srcM 2 { dstM concatmatrix } repeat pop getrepl /temp X S str convert get { aload pop [ /rot /scl /loc /K ] MD /aX cX def /aY cY def loc { dup 66 eq { /aY bY def } { % B dup 98 eq { /aY lY def } { % b dup 108 eq { /aX lX def } { % l dup 114 eq { /aX uX def } { % r dup 116 eq { /aY uY def } % t if } ifelse } ifelse } ifelse } ifelse pop } forall K srcFM rot tM rotate dstM 2 { tM concatmatrix } repeat aload pop pop pop 2 { scl normalize 4 2 roll } repeat aX aY transform /temp temp 7 add def } forall temp setrepl } B /Rif { S 3 index convert known { pop replace } { exch pop OE } ifelse } B /XA { bind [ /Kproc /str } B /XC { ] 2 array astore def } B /xs { pop } XA XC /xks { /kern load OE } XA /kern XC /xas { pop ax ay rmoveto } XA /ay /ax XC /xws { c eq { cx cy rmoveto } if } XA /c /cy /cx XC /xaws { ax ay rmoveto c eq { cx cy rmoveto } if } XA /ay /ax /c /cy /cx XC /raws { xaws { awidthshow } Rif } B /rws { xws { widthshow } Rif } B /rks { xks { kshow } Rif } B /ras { xas { ashow } Rif } B /rs { xs { show } Rif } B /rrs { getrepl dup 2 add -1 roll //restore exec setrepl } B PSfragDict begin islev2 not { /restore { /rrs PSfrag } B } if /show { /rs PSfrag } B /kshow { /rks PSfrag } B /ashow { /ras PSfrag } B /widthshow { /rws PSfrag } B /awidthshow { /raws PSfrag } B end PSfragDict RO pop end %%EndProcSet %%BeginProcSet: texps.pro 0 0 %! TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2 index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]FontType 0 ne{/Metrics exch def dict begin Encoding{exch dup type/integertype ne{ pop pop 1 sub dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get div def}ifelse}forall Metrics/Metrics currentdict end def}{{1 index type /nametype eq{exit}if exch pop}loop}ifelse[2 index currentdict end definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{dup sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1 roll mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def dup[ exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}if} forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}def end %%EndProcSet %%BeginProcSet: special.pro 0 0 %! TeXDict begin/SDict 200 dict N SDict begin/@SpecialDefaults{/hs 612 N /vs 792 N/ho 0 N/vo 0 N/hsc 1 N/vsc 1 N/ang 0 N/CLIP 0 N/rwiSeen false N /rhiSeen false N/letter{}N/note{}N/a4{}N/legal{}N}B/@scaleunit 100 N /@hscale{@scaleunit div/hsc X}B/@vscale{@scaleunit div/vsc X}B/@hsize{ /hs X/CLIP 1 N}B/@vsize{/vs X/CLIP 1 N}B/@clip{/CLIP 2 N}B/@hoffset{/ho X}B/@voffset{/vo X}B/@angle{/ang X}B/@rwi{10 div/rwi X/rwiSeen true N}B /@rhi{10 div/rhi X/rhiSeen true N}B/@llx{/llx X}B/@lly{/lly X}B/@urx{ /urx X}B/@ury{/ury X}B/magscale true def end/@MacSetUp{userdict/md known {userdict/md get type/dicttype eq{userdict begin md length 10 add md maxlength ge{/md md dup length 20 add dict copy def}if end md begin /letter{}N/note{}N/legal{}N/od{txpose 1 0 mtx defaultmatrix dtransform S atan/pa X newpath clippath mark{transform{itransform moveto}}{transform{ itransform lineto}}{6 -2 roll transform 6 -2 roll transform 6 -2 roll transform{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll curveto}}{{closepath}}pathforall newpath counttomark array astore/gc xdf pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack} if}N/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1 -1 scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip yflip not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub neg 0 TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{ noflips{TR pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop 90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr 1 get neg sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr 2 get ppr 0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4 -1 roll add 2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S TR}if}N/cp{pop pop showpage pm restore}N end}if}if}N/normalscale{ Resolution 72 div VResolution 72 div neg scale magscale{DVImag dup scale }if 0 setgray}N/psfts{S 65781.76 div N}N/startTexFig{/psf$SavedState save N userdict maxlength dict begin/magscale true def normalscale currentpoint TR/psf$ury psfts/psf$urx psfts/psf$lly psfts/psf$llx psfts /psf$y psfts/psf$x psfts currentpoint/psf$cy X/psf$cx X/psf$sx psf$x psf$urx psf$llx sub div N/psf$sy psf$y psf$ury psf$lly sub div N psf$sx psf$sy scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub TR/showpage{}N/erasepage{}N/setpagedevice{pop}N/copypage{}N/p 3 def @MacSetUp}N/doclip{psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2 roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath moveto}N/endTexFig{end psf$SavedState restore}N /@beginspecial{SDict begin/SpecialSave save N gsave normalscale currentpoint TR @SpecialDefaults count/ocount X/dcount countdictstack N} N/@setspecial{CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury lineto closepath clip}if/showpage{}N/erasepage{}N /setpagedevice{pop}N/copypage{}N newpath}N/@endspecial{count ocount sub{ pop}repeat countdictstack dcount sub{end}repeat grestore SpecialSave restore end}N/@defspecial{SDict begin}N/@fedspecial{end}B/li{lineto}B /rl{rlineto}B/rc{rcurveto}B/np{/SaveX currentpoint/SaveY X N 1 setlinecap newpath}N/st{stroke SaveX SaveY moveto}N/fil{fill SaveX SaveY moveto}N/ellipse{/endangle X/startangle X/yrad X/xrad X/savematrix matrix currentmatrix N TR xrad yrad scale 0 0 1 startangle endangle arc savematrix setmatrix}N end %%EndProcSet %%BeginFont: CMMI7 %!PS-AdobeFont-1.1: CMMI7 1.100 %%CreationDate: 1996 Jul 23 07:53:53 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI7) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMMI7 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 110 /n put readonly def /FontBBox{0 -250 1171 750}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE 3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B 532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470 B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B 986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE D919C2DDD26BDC0D99398B9F4D03D77639DF1232A4D6233A9CAF69B151DFD33F C0962EAC6E3EBFB8AD256A3C654EAAF9A50C51BC6FA90B61B60401C235AFAB7B B078D20B4B8A6D7F0300CF694E6956FF9C29C84FCC5C9E8890AA56B1BC60E868 DA8488AC4435E6B5CE34EA88E904D5C978514D7E476BF8971D419363125D4811 4D886EDDDCDDA8A6B0FDA5CF0603EA9FA5D4393BEBB26E1AB11C2D74FFA6FEE3 FAFBC6F05B801C1C3276B11080F5023902B56593F3F6B1F37997038F36B9E3AB 76C2E97E1F492D27A8E99F3E947A47166D0D0D063E4E6A9B535DC9F1BED129C5 123775D5D68787A58C93009FD5DA55B19511B95168C83429BD2D878207C39770 012318EA7AA39900C97B9D3859E3D0B04750B8390BF1F1BC29DC22BCAD50ECC6 A3C633D0937A59E859E5185AF9F56704708D5F1C50F78F43DFAC43C4E7DC9413 44CEFE43279AFD3C167C942889A352F2FF806C2FF8B3EB4908D50778AA58CFFC 4D1B14597A06A994ED8414BBE8B26E74D49F6CF54176B7297CDA112A69518050 01337CBA5478EB984CDD22020DAED9CA8311C33FBCC84177F5CE870E709FC608 D28B3A7208EFF72988C136142CE79B4E9C7B3FE588E9824ABC6F04D141E589B3 914A73A42801305439862414F893D5B6C327A7EE2730DEDE6A1597B09C258F05 261BC634F64C9F8477CD51634BA648FC70F659C90DC042C0D6B68CD1DF36D615 24F362B85A58D65A8E6DFD583EF9A79A428F2390A0B5398EEB78F4B5A89D9AD2 A517E0361749554ABD6547072398FFDD863E40501C316F28FDDF8B550FF8D663 9843D0BEA42289F85BD844891DB42EC7C51229D33EE7E83B1290404C799B8E8C 889787CDC194F782420BB447DE705EAE7963391B36647C8B3796E8E8774CD38D 675A89E8D077644F37FBFE9EB36C5B4455A94D61E2EC58C4544B2714F8B66FF5 D09FF25507481406F93BD74C2F14785C9AFFC6458E10A133E0ECD17301B2B5DF DE0C0D73DED3F4BE21027581FC25B49D6B1F1934F8745C4CE9610BE5A10F91C3 561C994E4BCD46A084D51E268092BEA0AB544F91C9CA2692A02575863E04350D 23051121C2B09186AE02C550040C09905EBFAAB4859901E0D1349E104862C122 65A2855C94549313EA44C9D9F1B3EB99D644FA8FE08D5F40A506639B0344B894 882ED4C0BBCFE4A30B6DA93BE0DCA9671E984F279295B45C8DED7D77BA7874AE 8B21F1148B253610333230100049EEBB1D4D58E17059C374AC2AF9CEE11B4D59 A7281AB04644DE042145245F04DE6CB5413889575CD415C721A7C18B3C3FE177 2FD7256E2E686938E36AC765FAF48D83C561C2E25807CDA6087E4A3B1E82216B A3609E28E6B58E3F36CB36315314A72CC7EC4ED8CF2E6761EC6409A74339CAF5 D148FFFAF620CE77 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMMI10 %!PS-AdobeFont-1.1: CMMI10 1.100 %%CreationDate: 1996 Jul 23 07:53:57 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMMI10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 21 /lambda put dup 22 /mu put dup 23 /nu put dup 26 /rho put dup 32 /psi put dup 70 /F put dup 120 /x put readonly def /FontBBox{-32 -250 1048 750}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE 3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B 532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470 B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B 986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958 9E394A533A081C36D456A09920001A3D2199583EB9B84B4DEE08E3D12939E321 990CD249827D9648574955F61BAAA11263A91B6C3D47A5190165B0C25ABF6D3E 6EC187E4B05182126BB0D0323D943170B795255260F9FD25F2248D04F45DFBFB DEF7FF8B19BFEF637B210018AE02572B389B3F76282BEB29CC301905D388C721 59616893E774413F48DE0B408BC66DCE3FE17CB9F84D205839D58014D6A88823 D9320AE93AF96D97A02C4D5A2BB2B8C7925C4578003959C46E3CE1A2F0EAC4BF 8B9B325E46435BDE60BC54D72BC8ACB5C0A34413AC87045DC7B84646A324B808 6FD8E34217213E131C3B1510415CE45420688ED9C1D27890EC68BD7C1235FAF9 1DAB3A369DD2FC3BE5CF9655C7B7EDA7361D7E05E5831B6B8E2EEC542A7B38EE 03BE4BAC6079D038ACB3C7C916279764547C2D51976BABA94BA9866D79F13909 95AA39B0F03103A07CBDF441B8C5669F729020AF284B7FF52A29C6255FCAACF1 74109050FBA2602E72593FBCBFC26E726EE4AEF97B7632BC4F5F353B5C67FED2 3EA752A4A57B8F7FEFF1D7341D895F0A3A0BE1D8E3391970457A967EFF84F6D8 47750B1145B8CC5BD96EE7AA99DDC9E06939E383BDA41175233D58AD263EBF19 AFC0E2F840512D321166547B306C592B8A01E1FA2564B9A26DAC14256414E4C8 42616728D918C74D13C349F4186EC7B9708B86467425A6FDB3A396562F7EE4D8 40B43621744CF8A23A6E532649B66C2A0002DD04F8F39618E4F572819DD34837 B5A08E643FDCA1505AF6A1FA3DDFD1FA758013CAED8ACDDBBB334D664DFF5B53 956017667C419C4021DA92976C7550A196C257FC2124FAD5E653AFE71A185EEB 32D003E13145A2B8230CFA65B8B8C55DD032F84307FE53FDB700A58C7546787D F306D3D7E14C9D301B79DD47D3141BACD987E3690D86AA69CF7722AE378E8106 F3B49F218B58AB401B1788AED031850B2079110EA4525D966384CF6A866894D5 FCE658FEDD8BB4F5AF7DC0C604BCCD85B7B4DD35403C23FE5ADC9EB8DAEC97F9 13E08ACDB69680FEAC82AC424C125AD328E3855A52124AAF3C324D93EBE9D9AD 1AE1B26E8C743773A084881C44536F54945D8168D8E40C4CA01914744E49FAE6 A27ABF29EA34543B8DEEB025DCD05DBC3BCB8C107836E2E97F863E543FC13BB9 481424298C5AB72CC44DAE649D4A16224352E91DA24A564DB9370A34155495EF 0EB287BE20162E9DB950508E4FB8C5CFE5B6A062D3016E2E1A15E03F915C8025 5843D5316A69BA43C57AA2A13991ED11D6931378A73F95FE3797BA7977E0FADF F95AF97E568E59CCEF1036DE58BA2D7629F058E39CA08E94B2B08D202603F2A2 63E01E2A74F2D18DFAE6DC8BFA435CA36E98EE1F6E5B92D449AFBCF623404F16 06B5D0E252F57A667A7E17600492A31A1BC8A03ABCE2F8FB82F38728550FD88E DEA92F6BD0B42BD28704228DD83DF9CBC64511CEECEDF681E689DC9C5B141741 0244E24785B7B13C298F7184F0F386105DD3FCD7AF22F27AEE2DFBA7185C6A26 7C108B92357FE952CFDBCB02F45959E3D0F730E75E8A2867DD9D4FCA3987FDC4 C062FFD0B4525D1E45261282D83CE455AF1EA5098E5BA1F4053EDA544D1B3045 74E741AC7D61C398361958DFF4E3F89160A6FC6E4073DA3D98E8260B1F83952E C7AE56387BF58B0956CBCFDD0BCE334E9A2AC8EDA303679218B2192B28CA3A54 6E07FFFB11FEB487F472F3BA46D45FB57E2875F40994041BCB961E08D3DD9C26 98DD85308B7C1059B032D56DFDC2EDA51ACF55F6050BF6A6C85A4AD188B68C1B 5C69B21A58076CF11C4D54E4A0FB814E7B0AF87AC3D7DD4FC210997C639E6EA7 30B3D4D98343685C5022835F83BB3723BF9EDB784B9C27B3E061F80CA99F2ED7 BFAA1514BEDAF44D7739747033811C07E6F26F74EDC3F52CA75AC4CB45D98D65 DF1D012F72033A5426C6346003C27A70B937D5CD9124FA6C8BFCC506C6043319 7F97A41A0E56D28DDEC3DFE291378A182CC97CEFFC995544B4789BC55712FD70 CDA866003EF8BC18E5D768F0F28E24C4DC790DF7BC60688C2C034A80031789E9 BDF8293E12533F0D027CFC6BD9ACD7FD8DC3113D7E69430F31A2D2141306EC6D C40898CDCF1FEA68BBEE05A44899317003EAF3B392D21DA573792C658F6197B2 9A9AF98D38F447ED02155258DA18568C5D8A8DF457539C071F5C441B46B6880B 95D16DD7AD26B90992996E17C2518AEEEC158794B33D9C67BD42D3A2769FD0B0 38BA341767B4A776094DAA95CAE2E22206167901F4CF9C1F1D12E4F4FE2CF1E5 73EFF0D3B67ED7C2BA3D48D22E185B2D49BFF2B9317FAEEA390A56874C56281A AA894B305C8F4EC9C068B687DC999928815C9B6A15E286734E36C810FF7F28F2 7EF1CE4F0D8E9E2DEDDBCDD6ED9B23B26E84D397277D2E1AE6D5941D5837DD63 D852964583EB15AD46B8003E587AE79C46A0B6CFFEF307CA0737DE04707C94D1 5C1AA6D885D1AB3A3D289CA8D67F250A2B4B56CF0FE10D0AC8C78D5D85AFD3CA 97353AFB3750E645E7BE25957720365488B7E24F51F38DE612EEC02DB6A77B77 A51DDC9A4A3ADB8C4013638FD29C1320E6A8689AF95891A648EF1411E5C00A64 9F86FBDDD8771832F0FF485D9C1EE01C18F362E45716D38CE66648E8164C1579 BE0CBFD457660E803AE6437B0F73A4FCDD1D27671FC3187E8FB62CAA700BCFEE 3CF4D2B21AEB2783366A43C7139DD1962B082CAC832939CD5B3A59897E932C66 82BADB43A097341294BEC25F3A49D4AE220167B1E9592131748ADFB765D417B9 9497BC86C8371BFDB710BB5C0BF8F420A29E8227E58CBE5D639299F0960C3CD0 4EB3D7B804A687F005773EFAE75DA459F27DB446CFEB5F5B809EB5736F05828A 0B8F45D88551DBA6A6EE56AC0B6BCC03E804ED78CBD811D84D59ACA5A4A48187 6FD975A3311F2693C7460AFE73C20B8C83887835F06D664FD3D796BD64E4C822 545FBCA53D881EA8989B963808F984A4C7DB63A430EE68142228E86821290ED7 508EC2EB07929B488E718188CBA54E14C6525209 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMR10 %!PS-AdobeFont-1.1: CMR10 1.00B %%CreationDate: 1992 Feb 19 19:54:52 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.00B) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMR10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 11 /ff put dup 80 /P put dup 83 /S put dup 97 /a put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 105 /i put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 114 /r put dup 115 /s put dup 116 /t put readonly def /FontBBox{-251 -250 1009 969}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 2BDBF16FBC7512FAA308A093FE5CF7158F1163BC1F3352E22A1452E73FECA8A4 87100FB1FFC4C8AF409B2067537220E605DA0852CA49839E1386AF9D7A1A455F D1F017CE45884D76EF2CB9BC5821FD25365DDEA6E45F332B5F68A44AD8A530F0 92A36FAC8D27F9087AFEEA2096F839A2BC4B937F24E080EF7C0F9374A18D565C 295A05210DB96A23175AC59A9BD0147A310EF49C551A417E0A22703F94FF7B75 409A5D417DA6730A69E310FA6A4229FC7E4F620B0FC4C63C50E99E179EB51E4C 4BC45217722F1E8E40F1E1428E792EAFE05C5A50D38C52114DFCD24D54027CBF 2512DD116F0463DE4052A7AD53B641A27E81E481947884CE35661B49153FA19E 0A2A860C7B61558671303DE6AE06A80E4E450E17067676E6BBB42A9A24ACBC3E B0CA7B7A3BFEA84FED39CCFB6D545BB2BCC49E5E16976407AB9D94556CD4F008 24EF579B6800B6DC3AAF840B3FC6822872368E3B4274DD06CA36AF8F6346C11B 43C772CC242F3B212C4BD7018D71A1A74C9A94ED0093A5FB6557F4E0751047AF D72098ECA301B8AE68110F983796E581F106144951DF5B750432A230FDA3B575 5A38B5E7972AABC12306A01A99FCF8189D71B8DBF49550BAEA9CF1B97CBFC7CC 96498ECC938B1A1710B670657DE923A659DB8757147B140A48067328E7E3F9C3 7D1888B284904301450CE0BC15EEEA00E48CCD6388F3FC3BEE09555C11E6E295 71B219B380EE9E5BB17AD84B4E8AED35880BD88E5AC7D9FE25C46889CD093396 F0E34A62F93E64C8E7975CFD617121244AB09FF9A4F73F8166197D0CDE2EEBB3 81AB9BD8329579C2122368F56DEB89BA6E42C5D9E20F2789CC4A89E4AD9B877F 8A0ACB84936F109D86211169257C19756A97E682601F4D1E7ED950A351C14DAC 4BEA7FB0E58FB5AEB55BC09B1253748B61B4E00C448F263458BF958D3986BF18 9636037E95FB425AAC96FCED5B4C766F93041FAA0DBB196B0A220B8E3A9FCA6E B4F5C0C775C25AFF4F5099CD3A2FA59ACA735718F8E90B351B015320794A89E8 4C34F32B465E201008CCC0A15C2DEE572BDA14D8BDDFCF2743A15F8A93386861 828F6251F206B9131C951D1ED4364A9CCE507E2959A1DA04A777B592888D38ED E68FFB3EFE83870BA8E04B88C9EEEB2DB80D4D07B52CE914D9DADF825A5301AC C64063909D6C1DC84C274C90004F41A1FAFD450805C5DD2A8E4F4C23E114246F C103EB63B58F33E44DD04F6367E04C3CBB3400BA3C1943B874CFB7DBF6A3EB5A 3F665C5A98F578A03948821E40D1608FB70C5915CA0DE369A0D7112BFF6CAE56 CB9BF699DAF3859F2B46DF97AE05915E791F1CE849154C53C4403EFD6F1A44EF 78C167190F3326BA35B2A0F95CD03492DBA2903489ABB6B2EB9F977F3F4D690B 31E8F6E32F83D91F721ABD116A40698F26610853E7FD075478979BEF42166C1B 312E8C20CB3F080B08A69416DA402D336C627BABC4737FC72F8F4F6BB7D73551 EE33D3CEA9052546399CE5FF4996968D1EF09B7C19995C083E727D2398021CAE 6B824B074160730AE1D61010FB6167E8AC42145BCE800A58D221004F6B953F48 B4A99CBF85F829F34F76B02D02D956F2D9710B38FE827FE961A3BA3E78F64ECD DADF68975D97F94EA8A698A5C6C48DFFF960EE628E8515535F59220FCB5E7EBA 98EFC03380413965B0498C169ECE75E7981C6BFBD64D544B919570F297C004CE 0C3B1A7E5D3C322887DDB7AA315551E09616F5D1E4FF1E7506494F362B124790 B10F52C94E6609CB9ADAEFE74528C271FCA5710E67DB9A31A4EE5E8B068DC248 F98C0675DCF2EC93227746654ED73ED27B057EDD4280D406B7201ACE79B44665 3B433E622C7260EC370B378BA1B72470FD7A76128EF6906B32D2B9FB28B1B955 6C528D23962F76D5E96E6D46864CCE7F859C7FC333EE98134E1C275D017B3EC5 E6ACB222D33909711D32D380BCFE49B06461B8B9D06A47C601860487F717AA6C EA7C03055A933CAA161CE580F3450B0BDBA1789FBF48822B33BFC5FAD73A5F02 7EDF4AFB79B876CA70C352F1711466C1C680D7B512B75A5719B5C85CF6F2FB9A 6F974915BA9F3DBB83596C2A63EC5D2AF5209E601909E3FD7466D32533A8D4CD 69B5619E01C6F9F2C6E16AA685CBB41EF8C185095565C48E21AF24A1018AD349 63A4B5CF7F80881B6D35808FFA6C1451E5168F7BBE77E25C3A1C2E407EFAFDBB 4F917C49D468A22DDECEC9A3A1FF3D279BB3D9BC351FAAC787C547EB9DB5B49D 0E6E89F4156AD627997804ECD5547A106EFC52EA95952F3B2F3653648E14B6A2 0EFE133E059B49EF76D8B0B9A6734B160AA3D4EE66DCEE0CCF3A559A1F5B9A17 BEFFE89C9AC2EA49668C017472AEFA0143072B9762D554AF4AE52A703DDE0F42 8E156F823103EDB2D0B475415FCBF7E031B8363C9C318D396D77100C0F05DE27 A57F813EC8FC949A6409A837245C5AE75F47120F9ABF8A144B7194615983703C 8530C9A661EEC72E94D525C176FB0CB2E753316267FB9628C583FB1E8A917929 BE657AE4CAD788A304D20E3B8BE0B8AB2D43BDA040B2ADF4B52C9D7AEC628D61 29CCE50223F113D55423532EAFE56F39264A3FE995DCF052DB9A5B81D518C916 4CFC640AD12970EEF33C45A8FE6F12D0A65B5C31D31B9626F4D9128494DB3198 C2F6B35AAF020C4FE30946D4DC525DC3C8C99BB3D99B5BA0F1C30E28651C635F 3630C72C015B53B0AD16BCE319499FFEA5CA909497591B58EB970719C9B9ECCA 190D4B57DFD7FB841247C96750840D8E38B4D15D13BF0A1695015C0942B9B6C8 9780AAE344387B2B303F54C4CC0A03739531DB46E00C408CD0081FA59047DF2C 884EA1704F9A131C580B7F9F7005974794F9F0D67E5D99156DD610B5B5E99111 EBFFE160EAFB50D998220BD0436A6EB83787F8DBDD0453195BA81597051FFFC5 15190CE23F15CD662B3C55BC6F6080C3E8CCDACD951173A36C9EEDDEA0DDAD59 9591AE0FE218A738BEFE329C4FEFA47B402A2A36ED0204CD49C25C4D9C614F2F 7BFCA7780AA6EDE2748AD6D7F44D38D94B5261F55C482CEE244542BFF2E0C33C A7C5E36BFF9B970A99C766B423F84A7220A882B03A55389E008196EB1CE9C217 7CE9908868E87C2E249BA31169FABBC8DBE26275AB3604499B9E636C2E0EB879 BAEF7336259124FE3BFF7722D0014ED7FBDDAB47E102B0C252C1AE5048C75A0A 9E833BA3A779D8EE03050402C2FD34249E6129536DC5BCEF2FB6F6A121593799 37D5027D95A75B42C380C9F236E2F98D7F4DB8ACFFEE09DFA0A107DC4A6FB537 9EA4229F0BC07695D1472A1C0FAD646CBCB92C4A76EFA91DA6725EBACB3FB9B5 FC788E53EB917A2FC558AF7F53AF3CED7EAD84B0B997ADD1585CBD2E9E41B87D 6097F74D8F06A18302A349B92AB855888C0ECFCD9CB1A1440BBE58C4EF9160D0 0B78AF901A8ADAD550ECE4F393AA07D85F786090BC217FC59744577996EE8571 9E4820752F8EAC0CB795047DD76A4CBDBBDDB48350FAF52323FB172E6FEED926 A361B77ABFA6EFB73851F9F802CCEB2798746B2EC8B43FB801E0553D034A0132 3905BA38C3124DC5E0E9C51045015817AD5FC750924158CEF440054FADB0FC02 C3E330F90CD86847AA59C94F5EA4626E10AF33CBADC593764BFE51E712968F6C B63B997B6A4FB61F8F6220E18735647506FA4A0AD227A69DCE4AB979753BEA1A A3590F7BFC682D1E2509995E5F567549E36FE6675C47749AAD14CB2112854FE6 59FE56D9C4DFC06B21B6F7DD421CAE134A29A061DCD4490F81F71D0780BDE07B 0920F2543D775054BCA2BF888CBD0B08E6CF8B099BBBD91146C4577959FEB436 3413979503B3562A50278E6B43A87AC37C2B68A351DBC54936B9152B7D56A526 691F507C42E94024409306790E89070C4D0CA5FD98018BF2CD734D30AD2D2AE5 50E9580F7B3A028C1F260D5A60F03EFEA40DA432FE47125AD29DD6778F58F0EF B37DE5C14DDF2789585D1FC076490EB83C4B864849C42BEBF86BA27C9BAC2F23 ABC7D954A13F5FB724E4B2189FEC5F4650EEA7A797E8B031C5CC8AC1C5819185 3595BA9A366AE3569DC8C95164978DE77FAD5F770CD87A121A2BAAD175AE1547 60930A498AC81BAB2BB25F4CC1C300823ECAD33FC04EC1A4A665BCE6C0420DD6 2F1A030DA0B1AFF0DD3443EC28BD6E47524FFFC53A40757609505802BCE97D01 30F10E38C726D5554EE81B8C47F78DB35C282ED1696DDD300531AF4E11F8926C 2EFF8FA61826ACC189B2902AEB87CB48D352B4B10423FD06A91FB953672CA8D3 D4C517E3ED112B41434F715364CFDE6C849CC26CA8AD724E28EDF71DA21EC234 B9641433564CD8F816630AC04EA580B5DBF4B0BD56E69D65293E8DAFFE140911 65003FF43DB40A9AFE05690FD3BC6CD7C997DFB450DBFD29734D4856711934C9 EFA0C0EF473BE66B036A32D5F10B589ACE6FBBA0D0574DE6539DE1A4E62E1C3E E2507D3B7F6D8ED3169CE5461B9C1EFCE26FF600D8B46836DF30FF74D0524A88 D6BDD9D996B4D3963DBC949551933A87A872BE6CE51184DF5657ECF24367EB14 A7814BEDDC85137F40B1A8F7245584DAA752B0C26BD1B160DD331FB94B2027EA D470CB8705F1BCF75375E46CA5E8C105A5483DDB620D225D916B496058A1B307 9120D9199CE413BE4941364C0F3ADA50AE291A517B3F95D67761BE18033554AB 1351A1F87DE1989437A2F775A894EEEE906DB9F946CE8D0B6EAE3DFB4A79BAF2 AB27DFCF79FB1175F1C0072A663A10CEE197E6B191DAA644A4A0BCFB87EAF4D2 D158EB86B5183EF7608147EFB2F1CB2DCB0051F2AE6585AF4736679ECDE5B502 CD2DEA962727A6994C04AA09C6716BF5B3713BF8DE70875670DA5A1CAA9B2159 ABCDA4503F12060F81B289B6D19708A31A7FA8BDAEB65F1D7543505D26CB3E8A F056FC84FCB45C6895EE4A34BDC1949E7E124F1E1FF63D03970CAE45A26B204B 45EBA6BFDF5E0F11FCF8724AB4B201C6F2768C5AACC6309F2D135D9969C0714E E51DF14121BAC17618A4792F697E1B6C3AD3485F0927FDD53FD0567E56D7A152 DE6A8BFF2A941D6156EFAAAC7170A665CF57A0B9FD242829349F267EAB9C2296 4DB761395FFBD75DE58AB7481A561CEE5372E454D903ECEC26A777B5C4AC5227 C0B6E5FB982C1BD627339C4990FD414588D05A5FAA441A3FB35A3BA363761EAF D4AB19C7874CD87267E59394D0B09CB36F0F9CBF0573E411FCF0ECC81388AB66 7BA3759B86B4DACDE1ECD71A49B76E3BDB415361B2312BB2C72D850BBF35AF4F 8F5BF0A277A7D0FD46DC3054B81DBD44C99E8002A43A0A354B78EDD192FF1E2E 8FC01D71641733D8241EC4E0ABE635C97C8133304F094B5BE9A47F13B7489CF5 42F18F2D72C59DCFE3A4A26331AA8EEBBC26D41CCF34BD10850D6EC8729C2911 55394002DF4820BC2CEBE107AD66C7F1EB1B7B887C06F37A5A2B1979D4BF01B2 4EC9ED746D1D904C58C59F8B783DE3630B44905C93780CD0CE3005D77E2DFA40 3B8DF0E0CDDA7AEDB5E495AF1B9ED2B928BA26A47076AEDC234F3D659CCB0534 02BE5739BC3B73A58C600714CC593D66508A9716EC6338EBD103E0799A168E15 98C3311F473F8FBDF5630F726AEC51265AFEBB6C2412082BAA93504247199BC1 8FF8E99410D87D06F90ABEE08C4E4CB26EB6F9CEEBF42DA2C6778E0A6A7FACCD CC8CE175CCDE5AA28061DA2B2BB6664C9DEB4423F6EF3B2A23F00B9B4F197022 29E4DA035A3BFD78AF62F864CE839EBA53754A3A1589C8E781EC0785E1196AF1 0060D953C6DDED44CFE8ED5340D198941ED0F8D8259FEC912B70FBF47BB19E92 F80B5D829B1AC466776C1182BF76D23CEB0FA832CBE0653E03850C48F9F428AB 16CD80233322C1063127B42E16F395D92132CAE185D7230711171634B4FD4418 7DD4F3CC51046D3CA312EDCC6784C9843E6682E9D9EC3C8EA8C98B5E2626F227 C744E7C1B284EE0B75C913518C312CEC2BF5F9EEB138C6587422BA711462123D 3346589E4D4081EFEC2E86AF9DE6B7B824B91E95A345F3D6DF3E929676E667C6 7644C7ED5B191944C024193614441D7E1428343BD3FE7EA79C206350BABDF3E1 88A73FF53D0F25F0D4BB80AB45C84A5823012456C44366E64E7A8DA88875D92B 33E6C70BB9A1A19B451587608AFCEDBCE78C59739D4D29B4DAD9824C47D86634 2F32D68D2918D023FA6BBA0F2CFDDB7B6A6758D71F2AB38A89F3ABA72F23AA33 AF8AAB4AE56C6A32BEAF8B0A54530721E6D36352988B504A7B8902AFEC0761BB B1C1A154F598A52A0C35D8725FB0EF2750BCCA83980108E91D070124CA4043B3 0938932C9482342BB0713631224289265487E5588D51D0C1A0D5CF9812578DFC 4BBD2FEAEE32EF988716B638D3547870BFC23765295F342416A8BE03F7CF0F41 66C055B94B80DB53E00B705CEA4BF36EBC4F6C61E20A33F2C78DFCF955E45B12 7EB7BC582E6986731F18FA1469C00C05B78C7E5B119EC6E4673B9D874A0B0111 57B5B15EB0285848C2D61C87901517AA22568D2E4C3F40514C7F707B65747D37 00E1D8EB7FA348F9AED575F35C8BBD095658A26D0CF5C45E258F4BAF6D8A9BF1 391AEBB26B938245F37772515EA6BD760B72456657B0DA0AFC49C4D652F7F641 C99AB170CB821BD32A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont TeXDict begin 40258437 52099154 1000 600 600 (/home/kasper/tmp/kt_temp/kt_temp_makefig/makefig.dvi) @start /Fa 145[41 110[{}1 58.1154 /CMMI7 rf /Fb 135[47 49[53 37[54 5[43 2[41 50 48 21[{}7 83.022 /CMMI10 rf /Fc 139[32 33 33 1[46 42 46 69 23 2[23 1[42 25 37 46 37 1[42 13[46 2[57 68[48 11[{}18 83.022 /CMR10 rf end %%EndProlog %%BeginSetup %%Feature: *Resolution 600dpi TeXDict begin end %%EndSetup TeXDict begin 1 0 bop 166 1181 a /PSfrag where{pop(int)[[0(Bl)1 0]](prod)[[1(Bl)1 0]](diff)[[2(Bl)1 0]](psi)[[3(Bl)1 0]](F)[[4(Bl)1 0]](mu)[[5(Bl)1 0]](nu)[[6(Bl)1 0]](rho)[[7(Bl)1 0]](lam)[[8(Bl)1 0]](x)[[9(Bl)1 0]]10 0 -1/Begin PSfrag}{userdict /PSfrag{pop}put}ifelse 166 1181 a @beginspecial 0 @llx 0 @lly 213 @urx 153 @ury 1417 @rhi @setspecial %%BeginDocument: exp1.eps %!PS-Adobe-2.0 EPSF-2.0 %%Title: exp1.fig %%Creator: fig2dev Version 3.2 Patchlevel 5-alpha7 %%CreationDate: Sun Jul 30 23:11:05 2006 %%BoundingBox: 0 0 213 153 %Magnification: 1.0000 %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save newpath 0 153 moveto 0 0 lineto 213 0 lineto 213 153 lineto closepath clip newpath -101.1 312.8 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def $F2psBegin 10 setmiterlimit 0 slj 0 slc 0.06299 0.06299 sc % % Fig objects follow % % % here starts figure with depth 50 % Polyline 0 slj 0 slc 7.500 slw n 4410 2790 m 3825 2925 l gs col0 s gr % Polyline n 4410 2790 m 4905 2925 l gs col0 s gr % Polyline n 3690 3240 m 3150 3375 l gs col0 s gr % Polyline n 3690 3240 m 4140 3375 l gs col0 s gr % Polyline n 3015 3645 m 2655 3825 l gs col0 s gr % Polyline n 3015 3645 m 3465 3825 l gs col0 s gr % Polyline n 2610 4140 m 3015 4275 l gs col0 s gr % Polyline n 2115 4590 m 2115 4770 l gs col0 s gr % Polyline n 2115 4590 m 1755 4770 l gs col0 s gr % Polyline n 2115 4590 m 2520 4770 l gs col0 s gr % Polyline n 3015 4590 m 3015 4770 l gs col0 s gr % Polyline n 4095 3690 m 4095 3870 l gs col0 s gr % Polyline n 2610 4140 m 2160 4275 l gs col0 s gr /Times-Roman ff 190.50 scf sf 3600 3150 m gs 1 -1 sc (prod) col0 sh gr /Times-Roman ff 190.50 scf sf 4050 3600 m gs 1 -1 sc (psi) col0 sh gr /Times-Roman ff 190.50 scf sf 4860 3150 m gs 1 -1 sc (x) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 3600 m gs 1 -1 sc (diff) col0 sh gr /Times-Roman ff 190.50 scf sf 2070 4500 m gs 1 -1 sc (F) col0 sh gr /Times-Roman ff 190.50 scf sf 1620 4950 m gs 1 -1 sc (mu) col0 sh gr /Times-Roman ff 190.50 scf sf 2070 4950 m gs 1 -1 sc (nu) col0 sh gr /Times-Roman ff 190.50 scf sf 2430 4950 m gs 1 -1 sc (rho) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 4500 m gs 1 -1 sc (psi) col0 sh gr /Times-Roman ff 190.50 scf sf 2430 4050 m gs 1 -1 sc (prod) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 4950 m gs 1 -1 sc (mu) col0 sh gr /Times-Roman ff 190.50 scf sf 4050 4050 m gs 1 -1 sc (nu) col0 sh gr /Times-Roman ff 190.50 scf sf 4320 2700 m gs 1 -1 sc (int) col0 sh gr /Times-Roman ff 190.50 scf sf 3375 4050 m gs 1 -1 sc (lam) col0 sh gr % here ends figure; $F2psEnd rs showpage %%Trailer %EOF %%EndDocument @endspecial 166 1181 a /End PSfrag 166 1181 a 166 94 a /Hide PSfrag 166 94 a -574 152 a Fc(PSfrag)26 b(replacemen)n(ts)p -574 182 741 4 v 166 185 a /Unhide PSfrag 166 185 a 67 284 a { 67 284 a Fc(in)n(t)67 284 y } 0/Place PSfrag 67 284 a -3 368 a { -3 368 a Fc(pro)r(d)-3 368 y } 1/Place PSfrag -3 368 a 48 484 a { 48 484 a Fc(di\013)48 484 y } 2/Place PSfrag 48 484 a 109 567 a { 109 567 a Fb( )109 567 y } 3/Place PSfrag 109 567 a 101 683 a { 101 683 a Fb(F)101 683 y } 4/Place PSfrag 101 683 a 116 766 a { 116 766 a Fb(\026)116 766 y } 5/Place PSfrag 116 766 a 120 882 a { 120 882 a Fb(\027)120 882 y } 6/Place PSfrag 120 882 a 123 966 a { 123 966 a Fb(\032)123 966 y } 7/Place PSfrag 123 966 a 118 1081 a { 118 1081 a Fb(\025)118 1081 y } 8/Place PSfrag 118 1081 a 69 1181 a { 69 1181 a -42 w Fc(d)73 1151 y Fa(n)119 1181 y Fb(x)69 1181 y } 9/Place PSfrag 69 1181 a eop end %%Trailer userdict /end-hook known{end-hook}if %%EOF cadabra-0.115/doc/favicon.ico0000600000077000007700000000047610460734763015354 0ustar kantorkantor(( cadabra-0.115/doc/index.html0000600000077000007700000003117510537232531015217 0ustar kantorkantor Cadabra

Cadabra

A field-theory motivated approach to symbolic computer algebra

Copyright © 2001-2006 Kasper Peeters

Overview

Cadabra is a computer algebra system (CAS) for the manipulation of tensorial expressions. It is aimed at, though not necessarily restricted to, theoretical high-energy physicists. Because of its target audience, the program's interface, storage system and underlying philosophy differ substantially from other computer algebra systems. Its main characteristics are:

  • Usage of a TeX-like notation, which eliminates many errors in transcribing problems from paper to computer and back.
  • Built-in understanding of dummy indices and dummy symbols, including their automatic relabelling when necessary. Powerful algorithms for canonicalisation of objects with index symmetries, both mono-term and multi-term.
  • A typing system through properties, but freedom to dispense with this system entirely when it is not needed.
  • A new way to deal with products of non-commuting objects, enabling a notation which is identical to standard physicist's notation (i.e. no need for special non-commuting product operators).
  • A flexible optional undo system. Interactive calculations can be undone to arbitrary level without requiring a full re-evaluation of the entire calculation.
  • A simple and documented way to add new algorithms in the form of C++ modules, which directly operate on the internal expression tree.

Cadabra has been under development for some time now, but has never left my own computer. The current version is the first public release, intended to collect feedback from a wider audience. So, feel free to mail me at kasper.peeters (at) aei.mpg.de with suggestions or constructive criticism.

License and acknowledgements

If you use cadabra or even just play with it, I would like to hear about it. Please drop me an email so that I can get an idea of who is interested in this program.

Cadabra is available under the conditions of the GNU General Public License. If you use cadabra in your own work, please cite the paper mentioned below (to keep the bean counters happy).

Cadabra contains code taken from José Martin-Garcia's xPerm in order to canonicalise tensor expressions. Some of the algorithms rely on the LiE software by Marc van Leeuwen, Arjeh Cohen and Bert Lisser.

Screenshots

Cadabra comes with its own graphical frontend, which is based on the gtk toolkit (or rather its C++ wrapper gtkmm) and uses LaTeX to typeset expressions. This is a screenshot:

native gui

There is also a TeXmacs frontend, displayed in the screenshots below. The associated TeXmacs files can be found in the "texmacs" subdirectory of the source tarball.

screenshot 1  screenshot 2

Install a binary

(note: there are no binaries or packages yet for the new graphical frontend)

First check below whether there is a package for your system, which is always the easiest installation method.

If you are running Linux (on an Intel processor) or Mac OS X, the next simplest way to install cadabra is to install a statically linked binary. You need to download two programs,

Linux, i386Mac OS X, PPC
prompt.gz prompt.gz
CDBRELEASE.gz CDBRELEASE.gz

gunzip them both and make them executable with "chmod u+x prompt cadabra". Put them somewhere in your path. Then the command "prompt cadabra" should start the program (or ./prompt ./cadabra if the current directory is not in your path); if not, email me.

If you want to use the TeXmacs frontend, you will also need the following file:

Store this file in the directory ~/.TeXmacs/plugins/cadabra/progs/ and restart TeXmacs.

Alternatively you can try to locate the TeXmacs/plugins directory on your filesystem (it is usually something like /usr/share/TeXmacs/plugins), and make a (nested) subdirectory cadabra/progs below that. Then copy the init-cadabra.scm file to this directory and (re)start TeXmacs.

Install using Debian, Red Hat, MacPorts, ...

Thanks to Greg Wright, cadabra is available for Mac OS X users through MacPorts. Simply type sudo port install cadabra and all required software will be installed automatically. For questions about this port, please contact gwright (at) macports.org.

Debian and RPM packages will follow in the near future.

Install from source

Installing from source should be no harder than with any other well-behaved GNU tools, i.e. it should be as simple as configure/make/make install. However, you will need to have some additional libraries and tools installed before you can compile cadabra itself. In particular,

  • tcl8.4 with libexpect
  • (on Debian, apt-get install tcl8.4 expect-dev)
  • gmp (configured with --enable-cxx)
  • (on Debian, apt-get install libgmp3-dev libgmpxx3)
  • pcre with C++ wrapper enabled (on Debian, apt-get install libpcre3-dev lib)
  • LiE
  • (no Debian package available)

In order to compile the graphical front-end (add the --enable-gui flag to configure) you also need

  • gtk+
  • gtkmm
  • pangomm
  • dvipng
  • LaTeX
  • the breqn package for LaTeX

Cadabra's configure script will look for these libraries and programs, and tell you when you need to install them. Consult the documentation of these programs/libraries for installation instructions.

You then need to compile and install my modglue library, which is used to connect the various pieces of cadabra together. Download this version here, since it's tuned to cadabra:

This should be a matter of configure/make/make install. Finally, compile and install cadabra itself,

Again, this should be a matter of configure/make/make install. If compilation succeeds, you can also try "make test" for some self-tests (which should all pass).

Since this is the first public release, chances are that some people will encounter problems at one of these steps. Please mail me if you need help.

Documentation

There are currently two documents about cadabra. One is a paper explaining the motivation for writing this software, as well as sketching the internal structure:

Kasper Peeters

The second document is the reference guide and tutorial, available only from here, and still incomplete,

Kasper Peeters
preprint AEI-2006-038

Finally, if you are interested in the internals of the program, there is some doxygen documentation, though this is still in a rather preliminary stage.

For a history of the changes made since the first release, consult the ChangeLog.

Mailing list

There is a mailing list for discussions about cadabra and announcements of new versions (hosted by HEPforge). To subscribe, send an email to

majordomo@cedar.ac.uk

with a body containing the line

subscribe cadabra-discuss

You will receive a confirmation email to which you have to reply, quoting the given authentication key, in order to get subscribed.

There is also an archive of the mailing list available.

cadabra-0.115/doc/Makefile0000600000077000007700000000013410615347155014657 0ustar kantorkantor .PHONY: doxy all: doxy doxy: doxygen doxygen_cadabra.config distclean: rm -Rf doxygen cadabra-0.115/doc/Makefile.in0000600000077000007700000000013410566672014015264 0ustar kantorkantor .PHONY: doxy all: doxy doxy: doxygen doxygen_cadabra.config distclean: rm -Rf doxygen cadabra-0.115/doc/paper.tex0000600000077000007700000012174510565026170015057 0ustar kantorkantor\documentclass{elsart} \usepackage{yjsco} \usepackage{amsmath} \usepackage{fancyvrb} \usepackage[numbers,sort&compress]{natbib} \usepackage{hypernat} \usepackage{hyperref} \usepackage{graphicx} \usepackage{xspace} \newcommand{\bs}{$\backslash$} \newcommand{\Cpp}{\leavevmode\rm{\hbox{C\hskip -0.1ex\raise 0.5ex\hbox{\tiny ++}}}\xspace} \setlength{\skip\footins}{18pt plus 4pt minus 2 pt} %\makeatletter %\def\ps@copyright{} %\makeatother \fvset{frame=lines,framerule=0.1pt,framesep=8pt,numbers=none,xleftmargin=5ex,fontfamily=tt,fontsize=\small} \newenvironment{screen}{\vspace{1ex}\Verbatim}{\endVerbatim\vspace{1ex}} \begin{document} \begin{flushright} AEI-2006-037\\cs.SC/0608005 \end{flushright} \begin{frontmatter} \title{Cadabra: a field-theory motivated symbolic computer algebra system} \author{Kasper Peeters} \address{Max-Planck-Institut f\"ur Gravitationsphysik, Albert-Einstein-Institut\\Am M\"uhlenberg 1, 14476 Golm, GERMANY} \ead{kasper.peeters@aei.mpg.de} \begin{abstract} Field theory is an area in physics with a deceptively compact notation. Although general purpose computer algebra systems, built around generic list-based data structures, can be used to represent and manipulate field-theory expressions, this often leads to cumbersome input formats, unexpected side-effects, or the need for a lot of special-purpose code. This makes a direct translation of problems from paper to computer and back needlessly time-consuming and error-prone. A prototype computer algebra system is presented which features \TeX-like input, graph data structures, lists with Young-tableaux symmetries and a multiple-inheritance property system. The usefulness of this approach is illustrated with a number of explicit field-theory problems. \end{abstract} \end{frontmatter} % 11.10.-z Field theory (for gauge field theories, see 11.15.-q) % 02.70.Wz Symbolic computation (computer algebra) \section{Field theory versus general-purpose computer algebra} For good reasons, the area of general-purpose computer algebra programs has historically been dominated by what one could call ``list-based'' systems. These are systems which are centred on the idea that, at the lowest level, mathematical expressions are nothing else but nested lists (or equivalently: nested functions, trees, directed acyclic graphs,~\ldots). There is no doubt that a lot of mathematics indeed maps elegantly to problems concerning the manipulation of nested lists, as the success of a large class of LISP-based computer algebra systems illustrates (either implemented in LISP itself or in another language with appropriate list data structures). However, there are certain problems for which a pure list-based approach may not be the most elegant, efficient or robust one. That a pure list-based approach does not necessarily lead to the fastest algorithms is of course well-known. For e.g.~polynomial manipulation, there exists a multitude of other representations which are often more appropriate for the problem at hand. An area for which the limits of a pure list-based approach have received less attention consists of what one might call ``field theory'' problems. Without attempting to define this term rigorously, one can have in mind problems such as the manipulation of Lagrangians, field equations or symmetry algebras; the examples discussed later will define the class of problems more explicitly. The standard physics notation in this field is deceptively compact, and as a result it is easy to overlook the amount of information that is being manipulated when one handles these problems with pencil and paper. As a consequence, problems such as deriving the equations of motion from an action, or verifying supersymmetry or BRST invariance, often become a tedious transcription exercise when one attempts to do them with existing general-purpose computer algebra systems. Here, the inadequateness of simple lists is not so much that it leads to sub-optimal, slow solutions (although this certainly also plays a role at some stage), but rather that it prevents solutions from being developed at~all. To make the problems more concrete, let us consider a totally arbitrary example of the type of expressions which appear in field theory. A typical Lagrangian or Noether charge might contain terms of the type \begin{equation} \label{e:ex1} \int\!{\rm d}^nx\, \frac{\partial}{\partial x^\lambda} \Big(F_{\mu\nu\rho}\, \psi^{\mu} \Big)\, \psi^{\nu}\,. \end{equation} Let us take, purely as an example, ~$F_{\mu\nu\rho}$ to be a commuting field strength of some two-form field, $\psi^\mu$ an anti-commuting vector, and $x^\mu$ to label an~$n$-dimensional space. Traditionally, one would represent~\eqref{e:ex1} in the computer as a nested list, which in tree-form would take the form\vspace{2ex} \begin{center} \includegraphics[height=5cm]{exp2.eps}\\[2ex] \end{center} The precise details do not matter here; the important point is that the expression takes the form of a multiply nested list. However, this list can only be the starting point, since expression~\eqref{e:ex1} clearly contains much more information than just the tree structure. This leads to a number of ``standard'' problems which field-theory computer algebra systems have to face: \medskip \begin{itemize} \item The names of contracted indices do not matter, in fact, it is only the contraction which is relevant. The nested list structure does not capture the cyclic graph-structure inherent in the expression. How do we make a list-based program aware of this fact, especially when doing substitutions? (this problem is more colloquially known as the ``dummy index'' problem). \item The expression is, for the ``outside world'', an object with two free indices, $\lambda$ and $\rho$. However, these indices, or graph edges, occur at different depths in the tree. How can we access the nested list by the free edges of the tree? \item The reason why $F$ and $\psi$ should stay as children of the diff node is that they depend on~$x$. Where do we store this information? And how do we make algorithms aware of~it? \item The diff and $\psi$ child nodes of the prod node cannot be moved through each other, because the diff node contains a $\psi$. In other words, the diff node ``inherits'' the anti-commutativity from one of its child nodes. How do we handle this? \item The anti-symmetry of~$F$ relates several contraction patterns. However, there are more complicated symmetries present in the expression. The Bianchi identity on the field strength, for instance, is a multi-term relation involving the indices on~$F$ and the index on diff. How do we make the program aware of this identity, and how do we take it into account when reducing expressions to a canonical form? \item For physicists, the simplest way to write expressions such as~\eqref{e:ex1} is to use \TeX{} notation, for example \begin{equation*} \verb|\int d^nx \partial_{\lambda} ( F_{\mu\nu\rho} \psi^{\mu} ) \psi^{\nu}| \end{equation*} Being able to input expressions like this would eliminate a large number of errors in transcribing physics problems to computer algebra systems, and make it much easier to use the computer as a scratch pad for tedious calculations (in particular, it would eliminate a good part of the learning curve of the program). Although \TeX{} notation certainly lacks the semantics to be used as input language for a generic computer algebra system (see e.g.~\cite{fateman99parsing} for a discussion of this problem), it is not hard to come up with a subset of \TeX{} notation which is both easily understandable and mathematically unambiguous. But how do we teach an existing general purpose system to deal with input of this type? \end{itemize} \medskip This collection of problems suggest that a general-purpose system based on ``nested lists'' is a rather bare-bones tool to describe field-theory problems. The nested list is just one of the many possible views or representations of the (rather heavily labelled) graph structure representing the expression. While it is perfectly possible to tackle many of the problems mentioned above in a list-based system (as several tensor algebra packages for general purpose computer algebra systems illustrate~\cite{e_xact,e_balf1,Klioner:1997sv,parker1}), this may not be the most elegant, efficient or robust approach (the lack of a system which is able to solve all of the sample problems in section~\ref{s:examples} in an elegant way exemplifies this point). By endowing the core of the computer algebra system with data structures which are more appropriate for the storage of field-theory expressions, it becomes much simpler to write a computer algebra system which can resolve the problems listed above.\footnote{There are of course \emph{other subclasses} of field-theory problems for which some of the points raised here are irrelevant and efficient computer algebra systems have been developed; see e.g.~\cite{Vermaseren:2000nd} for an example.} The remainder of this paper describes the key ingredients in an approach taken in the prototype computer algebra system ``cadabra''. Full details of this program, including source code, binaries and a reference manual, can be found at the web site~\cite{kas_cdb}. \section{Design goals and implementation} \label{s:structure} This section describes in more detail the main features of the cadabra program: the internal graph views of the tree structure, its handling of node symmetries and the use of a multiple-inheritance property system. In addition to these features, cadabra also has a number of other characteristics which make it especially tuned to the manipulation of ``field theory'' problems. An important characteristic which should not remain unmentioned is the fact that cadabra accepts \TeX{}-like notation for tensorial expressions, making it much easier to transcribe problems from and to paper. The program can be used both from a text-based command-line interface as well as from a graphical front-end or from within \TeX{}macs~\cite{vdH:Gut}. I will not discuss the \TeX{} input/output in detail, but examples can be found in section~\ref{s:examples}. \subsection{Graph structure} \label{s:graph} Cadabra is a standalone program written in~\Cpp. As in most other computer algebra systems, the internal data storage used in cadabra is that of a tree. Concretely, this is implemented using a custom tree container class~\cite{kas_tree} based on STL ideas~\cite{b_muss1}. However, what sets the program apart from other systems is that a)~the tree structure contains more data than usual, to make it easier to represent field-theory problems in a compact way, and b)~the tree manipulation algorithms offer several ways of viewing and modifying this tree. In more detail: \medskip \begin{itemize} \item The nodes of the tree carry so-called ``parent-relation'' information, which determine how child nodes are related to parent nodes. As an example of such a relation, consider the expression~$T^{\mu}{}_{\nu}(x)$. This is stored as a node~$T$, with three children~$\mu$, $\nu$ and $x$, which have parent relations ``superscript'', ``subscript'' and ``argument'' respectively (more relations can easily be added in the future if necessary). A common way of storing this information is e.g.~\mbox{\tt T[mu, -nu, x]} or \mbox{\tt T[up[mu], dn[nu], x]}, but both have their disadvantages: the first form does not allow us to store~$T^{-\mu}{}_{\nu}(x)$, while the second form introduces an additional layer of overhead. A format similar to the second case is also used in Stensor~\cite{maccallum1}, albeit using a different syntax; it has the disadvantage that it is neither a very convenient representation for the computer (especially not when the implementation is in \Cpp), nor a representation which is convenient for the user, as it is quite distinct from \TeX{} notation. \item The tree class not only provides a way to access the nodes of the graph by pre- or post-order traversal, but also provides iterators which access e.g.~only all indices of a node. In the example~\eqref{e:ex1}, an index iterator acting on the {\tt diff} node would return, in turn, the~$\mu$, $\nu$, $\rho$, $\mu$ and $\lambda$ indices. This makes it easy to write fast low-level routines which deal directly with the tensor structure of an expression. \item The tree manipulation algorithms are aware of the meaning of ``contracted nodes'' (contracted indices). Whenever one expression graph is inserted into another one, the algorithms automatically ensure that labels which are used to denote contracted indices (i.e.~edges which connect two nodes) are relabelled appropriately. Names are chosen by using property lists (see section~\ref{s:properties}). \item The contraction detection mechanism can deal with sub- or superscripts which do not denote indices, as in e.g.~$A^\dagger$. This is achieved by attaching a special property to the symbol (see section~\ref{s:properties} for more details). \end{itemize} \medskip The enhanced tree structure can be modified at the level of the user interface through standard list manipulation commands, or at the level of custom modules written in~\Cpp. \subsection{Symmetries} \label{s:symmetries} A second issue which cadabra addresses differently from other computer algebra systems is that of node symmetries. It is common in computer algebra systems that there is a generic way to specify so-called \emph{mono-term} symmetries. These are symmetries which relate one particular ordering of arguments to another one, up to a possible overall sign. Cadabra can of course find canonical representations for tensors with mono-term symmetries (using an external implementation~\cite{e_xact} of the double-coset algorithm~\cite{port2}; an alternative backtracking algorithm for mono-term symmetries is described in~\cite{dres1}). However, mono-term symmetries do not exhaust the symmetries of tensors transforming in generic representations of the Lorentz group. They do not include Garnir symmetries of Young tableaux. Examples of such symmetries are the Ricci identity for Riemann tensors, \begin{equation} R_{m n p q} + R_{m p q n} + R_{m q n p} = 0\,, \end{equation} or the Bianchi identity for field strengths. These identities relate more than two terms, and are therefore also called \emph{multi-term} symmetries. Despite the clear importance of being able to take such identities into account, there are very few computer algebra systems which have implemented a solution. The implementation in~\cite{parker1} simply uses a large set of transformation rules for Riemann tensor monomials. These rules were constructed by hand, and are only available for Riemann tensor monomials up to third order (i.e.~it would require tedious work to construct such rules for more general expressions, involving more than just the Riemann or Ricci tensors). An alternative approach is taken in~\cite{maccallum1,ilyi1,e_balf1}, in which the set of all identities for a particular tensor is used to rewrite a given expression in canonical form. This idea of handling multi-term symmetries using a sum-substitution algorithm goes back to at least~\cite{hornf1}. Cadabra, instead, uses Young projector methods internally for all index symmetry handling. The underlying idea is that by applying a Young projector to a tensor, its multi-term symmetries become manifest. This allows one to construct a basis of tensor monomials constructed from arbitrary tensors, and to decompose a given monomial on any preferred basis.\footnote{In order to determine the number of terms in a basis of monomials of tensors, cadabra relies on an external program for the computation of tensor product representations (using the LiE program~\cite{e_cohe1}).} This method was first described in~\cite{Green:2005qr}. For e.g.~Riemann tensors, the idea is to replace all tensors by their equivalent form \begin{equation} \label{e:Rproj} R_{a b c d} \rightarrow \tfrac{1}{3}\big( 2\, R_{a b c d} - R_{a d b c} + R_{a c b d} \big)\,. \end{equation} The expression on the right-hand side manifestly satisfies the cyclic Ricci identity, even if one only knows about the mono-term symmetries of the Riemann tensor. Using the projector~\eqref{e:Rproj} it is easy to show e.g.~that~$2\,R_{a b c d} R_{a c b d} = R_{a b c d} R_{a b c d}$. The monomial on the left-hand side maps to \begin{equation} \begin{aligned} R_{a b c d} R_{a c b d} \rightarrow \tfrac{1}{3} \big( R_{a b c d} R_{a c b d} + R_{a b c d} R_{a b c d} \big)\,, \end{aligned} \end{equation} while $R_{a b c d} R_{a b c d}$ maps to twice this expression, thereby proving the identity. Writing each term in a sum in a canonical form by using~\eqref{e:Rproj} would typically lead to extremely large expressions, and not be very convenient for subsequent calculations. However, the same algorithm can also be used to write a sum in a ``minimal'' form.\footnote{``Minimal'' here does not necessarily mean that the expression has been reduced to the shortest possible form, which is a problem which to the best of my knowledge remains unresolved. That is, while the algorithm removes dependent terms, as in $2\,R_{a b c d} + 2\,R_{b c a d} + R_{c a b d} \rightarrow R_{a b c d} + R_{b c a d}$ (because the third term is found to be expressible as a linear combination of the first two), it does not reduce this further to $- R_{c a b d}$ (typical cases are of course more complicated than this example).} That is, by projecting each term using~\eqref{e:Rproj} the program can perform the simplification \begin{equation} R_{a b c d} R_{a c b d} + R_{a b c d} R_{a b c d} \rightarrow 3\,R_{a b c d} R_{a c b d}\,, \end{equation} i.e.~express the second term in terms of the first one. This does not define a canonical form (the expression could equally well have been written using~$R_{a b c d} R_{a b c d}$), but it does systematically eliminate terms which can be written as linear combinations of other terms. \subsection{Properties} \label{s:properties} A third problem for which cadabra takes a different approach from other systems is that of ``typing'' of symbols and expressions. In cadabra, the meaning of symbols or expressions is determined by associating \emph{properties} to them. Properties can be simple, such as ``being an integer'', or ``being anti-symmetric in all indices'', or ``being an index which is not to be summed over'' (cf.~the discussion in section~\ref{s:graph}). They can also be more complicated and composite, such as ``being an anti-commuting spinor in the left-handed Weyl representation of the eight-dimensional Lorentz group''. The general problem of deducing properties of composite objects from the properties of their constituents is a hard (see e.g~\cite{weib1}). Cadabra takes a pragmatic approach, trying to provide a useful property system for concrete problems rather than trying to be complete or mathematically rigorous. Properties are implemented as a standard multiple-inheritance tree of \Cpp objects. The association to symbols is stored in a map, which relates patterns to pointers to property objects.\footnote{It is important that such properties are implemented at a low level. Most computer algebra systems would allow one to implement e.g.~handling of sets of non-commuting objects using user-defined property testing functions and appropriate transformation rules. It is a much harder problem to make sure that all routines of the underlying system use these properties efficiently and correctly.} This makes it relatively easy to make properties inherit from each other. An example of an inherited property is the property {\tt PartialDerivative}, which inherits from {\tt TableauBase}, so that the symmetry information of objects on which a partial derivative acts are automatically propagated. Nodes can inherit properties from child nodes. A simple situation in which this is useful is for instance when one uses accents to mark symbols, as in e.g.~$\bar{\psi} \psi$. If {\tt \bs{}psi} is declared to be self-anticommuting, we obviously want the~{\tt \bs{}bar\{\bs{}psi\}} tree to have this property as well. When scanning for properties of nodes, the internal algorithms take into account such inheritance of properties. Inheritance of a property is, itself, again implemented as a property (in the example above, the {\tt \bs{}bar} node is declared to have the property {\tt PropertyInherit}, while more fine-tuned inheritance is implemented by deriving from a templated {\tt Inherit} class, as in e.g.~{\tt Inherit}).\footnote{This is similar to Macsyma's types and features: the property which is attached to a symbol is like a `type', while all properties which the symbol inherits from child nodes are like `features'. Property inheritance can also be found other systems, e.g.~Axiom~\cite{daly1}.} Not all property inheritance is, however, as simple as propagating the information up from a deeper lying node. More complicated property inheritance occurs when nodes have to ``compute'' their properties from properties of the child nodes. This occurs for instance when we want to know how products of symbols commute among each other. For such cases, there are more complicated property classes, for instance {\tt CommutingAsProduct} or {\tt CommutingAsSum}. Similarly, there is a property {\tt IndexInherit} which indicate that nodes should make the indices of their child nodes visible to the outside world. Other composite property objects can easily be added to the system. \section{Typical examples} \label{s:examples} In this section, the three main points discussed in the previous section main text (enhanced tree data structures \& algorithms, the use of representation theory to classify object symmetries, and the use of properties) will be illustrated with a number of explicit examples. These examples are meant to be readable without further information about the program language. As such, they also illustrate the ease with which tensorial expressions can be fed into the program. Full details of the input language and transformation algorithms can be found in the manual~\cite{kas_cdb}. \subsection{Index handling and substitution} When doing computations by hand, we do index relabelling almost automatically when a clash occurs. However, unless the computer program is aware of this problem at a low level, clashes are bound to occur frequently. Consider first the standard type of relabelling, illustrated by the expressions \begin{equation} C = A^2\,,\quad \text{with}\quad A = B_{m n} B_{m n}\quad\text{and}\quad B_{n p} = T_{m n} T_{m p}\,. \end{equation} In cadabra one can e.g.~do\footnote{As alluded to in the first section, the notation used here is not generic~\TeX{} but rather a well-defined subset, with some additional conventions required to make the input unambiguous. An example of such a convention is the use of spaces to separate indices; further details about the input format conventions can be found in the reference manual~\cite{kas_cdb}.} \begin{screen} {m,n,p,q#}::Indices(vector). C:= A A; @substitute!(%)( A = B_{m n} B_{m n} ); @substitute!(%)( B_{n p} = T_{m n} T_{m p} ); \end{screen} where the meaning of the hash symbol on the declaration of the~$q$ index (in the first line) will become clear soon. The result is \begin{screen} C:= T_{q2 m} T_{q2 n} T_{q3 m} T_{q3 n} T_{q4 p} T_{q4 q1} T_{q5 p} T_{q5 q1}; \end{screen} This type of relabelling and automatic index generation is not an entirely uncommon feature to find in tensor algebra systems, although it is often implemented in an add-on package. The situation becomes more complicated when we have indices which do not occur at the same level, for instance \begin{equation} C = A^2\,,\quad \text{with} \quad A = \partial_m (B_n B_p + C_{n p} ) B_{m n p}\quad\text{and}\quad B_n = T_{n m} S_{m}\,. \end{equation} Few systems know how to deal with these types of expressions elegantly (i.e.~without requiring a cumbersome input format). The reason is that the derivative carries an index, but the objects in the product on which it acts carry indices too, and these indices do not all occur at the same depth of the expression tree. The cadabra instructions, however, remain equally simple as in the previous example, \begin{screen} {m,n,p,q#}::Indices(vector). \partial{#}::Derivative. C:= A A; @substitute!(%)( A = \partial_{m}( B_n B_p + C_{n p} ) B_{m n p} ); @substitute!(%)( B_n = T_{n m} S_{m} ); \end{screen} The result comes out as the expected \begin{screen} C:= \partial_{m}(T_{n q4} S_{q4} T_{p q5} S_{q5} + C_{n p}) B_{m n p} \partial_{q1}(T_{q2 q6} S_{q6} T_{q3 q7} S_{q7} + C_{q2 q3}) B_{q1 q2 q3}; \end{screen} Finally, it of course happens frequently that more than one type of index appears in an expression, labelling tensors in different spaces. Consider for instance, \begin{equation} C = A^2\quad\text{with}\quad A_{m \mu} = \bar{\psi}\Gamma_{m p} \psi\, B_{p \mu}\,, \end{equation} where the roman and Greek indices cannot be interchanged at will, because they refer to flat and curved spaces respectively. This example translates to \begin{screen} {\mu, \rho, \nu#}::Indices(curved). {m, n, p, q#}::Indices(flat). C:= A_{m \nu} A_{m \nu}; @substitute!(%)( A_{m \mu} = \bar{\psi}\Gamma_{m p} \psi B_{p \mu \rho} C_{\rho}); \end{screen} with the expected result \begin{screen} C:= \bar{\psi} \Gamma_{m p} \psi B_{p \nu \rho} C_{\rho} \bar{\psi} \Gamma_{m n} \psi B_{n \nu \mu} C_{\mu}; \end{screen} All this type of relabelling is done by the internal tree manipulation algorithms, which ensures that no algorithm can lead to inconsistent expressions. New dummy indices are taken from the appropriate sets, using the property information associated to the various indices. \subsection{Canonicalisation and Young-tableaux methods} As long as one deals only with symmetric or antisymmetric tensors, many computer algebra systems are able to write tensor monomials in a canonical form (although efficient algorithms for very large numbers of indices or very large numbers of identical tensors have only surfaced relatively recently, see~\cite{Portugal:1998qi,port2,e_xact,e_canon}). Generic algorithms for multi-term Garnir symmetries, such as the Ricci or Bianchi identity, are much less widespread; see the discussion in section~\ref{s:symmetries}. Cadabra is the first system to label tensors by Young tableaux and to use Young projector methods to handle multi-term symmetries. A common problem in which multi-term symmetries play an important role is the construction of a basis of all tensor monomials of a given length dimension. Determining the number of elements of such a basis is a relatively straightforward exercise in group theory~\cite{Fulling:1992vm}. In order to actually construct the basis, cadabra uses the Young projector method described in the appendix of~\cite{Green:2005qr}. As an example, let us construct a basis of monomials cubic in the Riemann tensor, \begin{screen} {m,n,p,q,r,s,t,u,v,w,a,b}::Indices(vector). {m,n,p,q,r,s,t,u,v,w,a,b}::Integer(0..9). R_{m n p q}::RiemannTensor. basisR3:= R_{m n p q} R_{r s t u} R_{v w a b}; @all_contractions(%); @canonicalise!(%): @substitute!(%)( R_{m n m n} -> R ): @substitute!(%)( R_{m n m p} -> R_{n p} ); \end{screen} After a declaration of the objects to be used, the program determines in one step all possible independent contractions of three Riemann tensors. The last two lines only serve to rewrite the result in terms of Ricci tensors and scalars, after which the output takes the form \begin{screen} basisR3:= \{ R_{m n p q} R_{m p r s} R_{n r q s}, R R_{q r} R_{q r}, R_{n p} R_{n q p r} R_{q r}, R_{n p} R_{n q r s} R_{p r q s}, R R_{p q r s} R_{p q r s}, R_{n p} R_{n r} R_{p r}, R_{m n p q} R_{m r p s} R_{n r q s}, R R R \}; \end{screen} This result is equivalent to the basis given in the ``${\mathcal R}^0_{6,3}$'' table on page~1184 of~\cite{Fulling:1992vm}. It is also possible to decompose any given tensor monomial on a previously constructed basis. Take for example the basis of Weyl tensor monomials of fourth order. This basis can be read off from the tables of~\cite{Fulling:1992vm}, \begin{equation} \begin{aligned} W_1 &= W_{m n a b} W_{n p b c} W_{p s c d} W_{s m d a}\,,\\[1ex] W_2 &= W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a}\,,\\[1ex] W_3 &= W_{m n a b} W_{p s b a} W_{m n c d} W_{p s d c}\,,\\[1ex] W_4 &= W_{m n a b} W_{m n b a} W_{p s c d} W_{p s d c}\,,\\[1ex] W_5 &= W_{m n a b} W_{n p b a} W_{p s c d} W_{s m d c}\,,\\[1ex] W_6 &= W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}\,,\\[1ex] W_7 &= W_{m n}{}^{[m n} W_{p q}{}^{p q} W_{r s}{}^{r s} W_{t u}{}^{t u]}\,. \end{aligned} \end{equation} If we want to find the decomposition \begin{equation} W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w}- W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} = W_2 - \tfrac{1}{4} W_6\,, \end{equation} using ``classical'' methods, we would need to figure out the right way to repeatedly apply the Ricci cyclic identity to the left-hand side of this expression. The appropriate program to decompose the left-hand side on the seven-term basis and prove this identity is \begin{screen} {m,n,p,q,r,s,t,u,v,w,a,b,c,d,e,f}::Indices(vector). W_{m n p q}::WeylTensor. W1:= W_{m n a b} W_{n p b c} W_{p s c d} W_{s m d a}; W2:= W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a}; W3:= W_{m n a b} W_{p s b a} W_{m n c d} W_{p s d c}; W4:= W_{m n a b} W_{m n b a} W_{p s c d} W_{p s d c}; W5:= W_{m n a b} W_{n p b a} W_{p s c d} W_{s m d c}; W6:= W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}; W7:= W_{m n}^{m n} W_{p q}^{p q} W_{r s}^{r s} W_{t u}^{t u}; @asym!(%){^{m},^{n},^{p},^{q},^{r},^{s},^{t},^{u}}: @substitute!(%)( W_{a b}^{c d} -> W_{a b c d} ): @indexsort!(%): @collect_terms!(%): @canonicalise!(%): @collect_terms!(%); basisW4:= { @(W1), @(W2), @(W3), @(W4), @(W5), @(W6), @(W7) }; W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w}; @decompose!(%){ @(basisW4) }; @list_sum!(%); @collect_terms!(%); \end{screen} Most of this code is self-explanatory. The first two lines declare the symbols and objects to be used, the next block of lines declares the basis and performs the eight-fold anti-symmetrisation for the last basis element.\footnote{Commands such as {\tt @collect\_terms} can be added to a list of default rules to be applied automatically; they have been included here so that all steps are explicit.} The decomposition is done with the last three lines. The final output of this small program reads \begin{screen} {0, 1, 0, 0, 0, -1/4, 0 }; \end{screen} Internally, this involved a Young-projection of all tensors in the basis, a projection of the tensors in the expression which we want to decompose, and a solution of a system of linear equations~\cite{Green:2005qr}. The internal algorithm is completely generic and applies to tensor monomials with arbitrary symmetries. \subsection{Properties and property inheritance} A typical class of problems in which one handles tensors of both commuting and anti-commuting type is the construction of supersymmetric actions. This class of problems also shows the use of implicit dependence of tensors on coordinates, as well as inheritance of spinor and anti-commutativity properties. Consider as a trivial example -- which is nevertheless not easy to reproduce with other computer algebra systems -- the invariance of the super-Maxwell action \begin{equation} S = \int\!{\rm d^4}x\, \Big[ -\frac{1}{4} (f_{ab})^2 - \frac{1}{2}\bar{\lambda}\gamma^a \partial_a \lambda\Big]\,, \end{equation} (where~$f_{ab} = \partial_a A_b - \partial_b A_a$) under the transformations \begin{equation} \delta A_a = \bar{\epsilon}\gamma_a \lambda\,,\quad \delta \lambda = -\frac{1}{2} \gamma^{a b} \epsilon\, f_{a b}\,. \end{equation} The object properties for this problem are \begin{screen} { a,b,c,d,e }::Indices(vector). \bar{#}::DiracBar. { \partial{#}, \ppartial{#} }::PartialDerivative. { A_{a}, f_{a b} }::Depends(\partial, \ppartial). { \epsilon, \gamma_{#} }::Depends(\bar). \lambda::Depends(\bar, \partial). { \lambda, \gamma_{#} }::NonCommuting. { \lambda, \epsilon }::Spinor(dimension=4, type=Majorana). { \epsilon, \lambda }::SortOrder. { \epsilon, \lambda }::AntiCommuting. \lambda::SelfAntiCommuting. \gamma_{#}::GammaMatrix. \delta{#}::Accent. f_{a b}::AntiSymmetric. \delta_{a b}::KroneckerDelta. \end{screen} Note the use of two types of properties: those which apply to a single object, like {\tt Depends}, and those which are associated to a list of objects, like {\tt AntiCommuting}. Clearly $\partial_a \lambda$ and $\epsilon$ are anti-commuting too, but the program figures this out automatically from the fact that {\tt $\backslash$partial} has a {\tt PartialDerivative} property associated to it. The actual calculation is an almost direct transcription of the calculation one would do by hand.\footnote{This example makes use of a set of default rules, to wit ``{\tt ::PostDefaultRules( @@prodsort!(\%), @@rename\_dummies!(\%), @@canonicalise!(\%), @@collect\_terms!(\%) )}'', which mimick the automatic rewriting behaviour of many other computer algebra systems and get invoked automatically at each step. See~\cite{kas_cdb} for more details.} First we define the supersymmetry transformation rules and the action, which can be entered as in~\TeX{}, \begin{screen} susy:= { \delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = -(1/2) \gamma_{a b} \epsilon f_{a b} }; S:= -(1/4) f_{a b} f_{a b} - (1/2) \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{screen} Showing invariance starts by applying a variational derivative, \begin{screen} @vary!(%)( f_{a b} -> \partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}, \lambda -> \delta{\lambda} ); @distribute!(%); @substitute!(%)( @(susy) ): @prodrule!(%): @distribute!(%): @unwrap!(%); \end{screen} After these steps, the result is (shown exactly as it appears in the graphical and the \TeX{}macs~\cite{vdH:Gut} front-ends)% \begin{equation} S = \bar{\epsilon} \gamma_{a} \partial_{b} \lambda\, f_{ab} + \frac{1}{4} \overline{\gamma_{ab} \epsilon} \gamma_{c} \partial_c\lambda\, f_{ab} + \frac{1}{4} \bar{\lambda}\gamma_a \gamma_{bc} \epsilon \partial_a f_{bc}\,. \end{equation} Since the program knows about the properties of gamma matrices it can rewrite the Dirac bar, and then we do one further partial integration, \begin{screen} @rewrite_diracbar!(%); @substitute!(%)( \partial_{c}{f_{a b}} -> \ppartial_{c}{f_{a b}} ): @pintegrate!(%){\ppartial}: @rename!(%){"\ppartial"}{"\partial"}: @prodrule!(%): @unwrap!(%); \end{screen} What remains is the gamma matrix algebra, a rewriting of the derivative of the Dirac bar as the Dirac bar of a derivative, and sorting of spinors (which employs inheritance of the {\tt Spinor} and {\tt AntiCommuting} properties as already alluded to earlier), \begin{screen} @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @substitute!(%)( \partial_{a}{\bar{\lambda}} -> \bar{\partial_{a}{\lambda}} ); @spinorsort!(%): \end{screen} The result is (after partial integration) a Bianchi identity on the field strength, and thus invariance of the action. While this example is rather simple, and does not require a computer algebra system for its solution, it illustrates that the extended tree structure together with the property system make it possible to manipulate expressions in a way which closely resembles what one would do when solving the problem with pencil and paper. Several more complicated examples will be discussed in the upcoming~\cite{kas_cdb_hep}. \section{Summary} I have presented a new prototype computer algebra system which is designed to be an easy-to-use scratch pad for problems encountered in field theory. The current library of algorithms include functionality to deal with bosonic and fermionic tensors, spinors, gamma matrices, differential operators and so on, all through the use of a multiple-inheritance property mechanism. Cadabra is the first system which handles generic multi-term tensor symmetries using a Young-projector based algorithm. It is also the first system which accepts input in~\TeX{} form, eliminating tedious translation steps and making programs much easier to read for new users. Finally, the source code of the system is freely available and the reference guide contains extensive documentation explaining how to add new algorithm modules to the program. \section*{Acknowledgements} I am grateful to Jos\'e Martin-Garcia for inspiring discussions and for help with the use of his {\tt xPerm} code~\cite{e_xact} for mono-term canonicalisation. I thank the anonymous referee for extensive comments which have substantially improved this paper. \setlength{\bibsep}{4pt} %\bibliographystyle{kasper} %\bibliography{kasbib} \begingroup\raggedright\begin{thebibliography}{23} \expandafter\ifx\csname natexlab\endcsname\relax\def\natexlab#1{#1}\fi \bibitem[Fateman and Caspi(1999)]{fateman99parsing} R.~J. Fateman and E.~Caspi, ``Parsing {{\TeX}} into mathematics'', {\em SIGSAM Bulletin (ACM Special Interest Group on Symbolic and Algebraic Manipulation)} {\bf 33} (1999), no.~3, 26. \bibitem[Martin-Garcia(????)]{e_xact} J.~Martin-Garcia, ``{xPerm and xAct}'', \url{http://metric.iem.csic.es/Martin-Garcia/xAct/index.html}. \bibitem[{Balfag\'on} et~al.(????){Balfag\'on}, {Castellv\'\i}, and {Ja\'en}]{e_balf1} A.~{Balfag\'on}, P.~{Castellv\'\i}, and X.~{Ja\'en}, ``Tools of tensor calculus'', \url{http://baldufa.upc.es/xjaen/ttc/}. \bibitem[Klioner(1997)]{Klioner:1997sv} S.~A. Klioner, ``{EinS: A Mathematica package for computations with indexed objects}'', \href{http://xxx.lanl.gov/abs/gr-qc/0011012}{{\tt gr-qc/0011012}}. %%CITATION = GR-QC 0011012;%%. \bibitem[Parker and Christensen(1994)]{parker1} L.~Parker and S.~M. Christensen, ``Mathtensor : A system for doing tensor analysis by computer'', Addison-Wesley, 1994. \bibitem[Vermaseren(2000)]{Vermaseren:2000nd} J.~A.~M. Vermaseren, ``New features of {FORM}'', \href{http://xxx.lanl.gov/abs/math-ph/0010025}{{\tt math-ph/0010025}}. %%CITATION = MATH-PH 0010025;%%. \bibitem[Peeters(2006)]{kas_cdb} K.~Peeters, ``Cadabra: tutorial and reference guide'', 2006, \url{http://www.aei.mpg.de/~peekas/cadabra/}. \bibitem[van~der Hoeven(2001)]{vdH:Gut} J.~van~der Hoeven, ``{GNU TeXmacs: A free, structured, wysiwyg and technical text editor}'', in ``Le document au XXI-i\`eme si\`ecle'', D.~Flipo, ed., vol.~39--40, pp.~39--50. \newblock Metz, 14--17 mai 2001. \newblock Actes du congr\`es GUTenberg. \url{http://www.texmacs.org}. \bibitem[Peeters(2006)]{kas_tree} K.~Peeters, ``Tree.hh'', 2006, \url{http://www.aei.mpg.de/~peekas/tree/}. \bibitem[Musser and Saini(1996)]{b_muss1} D.~R. Musser and A.~Saini, ``{STL} tutorial and reference guide, {C++} programming with the standard template library'', Addison Wesley, 1996. \bibitem[MacCallum and Skea(1994)]{maccallum1} M.~A.~H. MacCallum and J.~E.~F. Skea, ``{SHEEP: A computer algebra system for general relativity}'', in ``Algebraic computing in general relativity'', M.~J. {Rebou\c{c}as} and W.~L. Roque, eds., pp.~1--172. \newblock Oxford, 1994. \bibitem[Portugal(1999)]{port2} R.~Portugal, ``Algorithmic simplification of tensor expressions'', {\em J.\ Phys.} {\bf A32} (1999) 7779--7789. \bibitem[Dresse(1993)]{dres1} A.~Dresse, ``Polynomial poisson structures and dummy variables in computer algebra'', PhD thesis, Universit\'e Libre de Bruxelles, 1993. \bibitem[Ilyin and Kryukov(1996)]{ilyi1} V.~A. Ilyin and A.~P. Kryukov, ``{ATENSOR} - {REDUCE} program for tensor simplification'', {\em Comp.\ Phys.\ Commun.} {\bf 96} (1996) 36--52. \bibitem[Hornfeldt(1979)]{hornf1} L.~Hornfeldt, ``A system for automatic generation of tensor algorithms and indicial tensor calculus, including substitution of sums'', in ``Proceedings of EUROSAM 79'', Ng, ed., vol.~72 of {\em Lecture Notes in Computer Science}, pp.~279--290. \newblock Springer, 1979. \bibitem[Cohen et~al.(1998)Cohen, van Leeuwen, and Lisser]{e_cohe1} A.~Cohen, M.~van Leeuwen, and B.~Lisser, ``{LiE} v.~2.2'', 1998, \url{http://wwwmathlabo.univ-poitiers.fr/~maavl/LiE/}. \bibitem[Green et~al.(2005)Green, Peeters, and Stahn]{Green:2005qr} M.~B. Green, K.~Peeters, and C.~Stahn, ``Superfield integrals in high dimensions'', {\em JHEP\,} {\bf 08} (2005) 093, \href{http://xxx.lanl.gov/abs/hep-th/0506161}{{\tt hep-th/0506161}}. %%CITATION = HEP-TH 0506161;%%. \bibitem[Weiberl and Gonnet(1991)]{weib1} T.~Weiberl and G.~H. Gonnet, ``An algebra of properties'', in ``Proceedings of the ISSAC-91 Conference, Bonn'', pp.~352--359. \newblock 1991. \bibitem[Daly(2005)]{daly1} T.~Daly, ``Axiom volume 1: tutorial'', Lulu press, 2005. \bibitem[Portugal(1998)]{Portugal:1998qi} R.~Portugal, ``An algorithm to simplify tensor expressions'', {\em Comp.\ Phys.\ Commun.} {\bf 115} (1998) 215--230, \href{http://xxx.lanl.gov/abs/gr-qc/9803023}{{\tt gr-qc/9803023}}. %%CITATION = GR-QC 9803023;%%. \bibitem[Portugal(????)]{e_canon} R.~Portugal, ``{The Canon package}'', \url{http://www.cbpf.br/~portugal/Canon.html}. \bibitem[Fulling et~al.(1992)Fulling, King, Wybourne, and Cummins]{Fulling:1992vm} S.~A. Fulling, R.~C. King, B.~G. Wybourne, and C.~J. Cummins, ``Normal forms for tensor polynomials. 1: The {Riemann} tensor'', {\em Class.\ Quant.\ Grav.} {\bf 9} (1992) 1151. %%CITATION = CQGRD,9,1151;%%. \bibitem[Peeters(????)]{kas_cdb_hep} K.~Peeters, ``{Introducing Cadabra: a symbolic computer algebra system for field theory problems}'', {\tt hep-th/0701238}. \end{thebibliography}\endgroup \end{document} cadabra-0.115/doc/showcase.tex0000600000077000007700000001644310460145266015564 0ustar kantorkantor\documentclass{beamer} \usepackage{fancyvrb} \usepackage{xspace} \usefonttheme[onlymath]{serif} %------------------------------------------------------------------------------ \fvset{frame=lines,framerule=0.1pt,framesep=5pt,numbers=none,xleftmargin=0ex,fontfamily=tt,fontsize=\scriptsize} \newenvironment{screen}{\vspace{1ex}\Verbatim}{\endVerbatim\vspace{1ex}} \setbeamertemplate{navigation symbols}{} \setbeamersize{text margin right=2em} \setbeamersize{text margin left=2em} \newcommand{\Cpp}{{\leavevmode\rm{\hbox{C\hskip -0.1ex\raise 0.5ex\hbox{\tiny ++}}}}\xspace} \newcommand{\Blue}[1]{{\color[named]{Blue} #1}} %------------------------------------------------------------------------------ %------------------------------------------------------------------------------ % % Young tableau macro (taken from Distler & Zamora [hep-th/9810206]) % Usage: $\tableau{2 1 1}$ % \newdimen\tableauside\tableauside=1ex %1.0ex \newdimen\tableaurule\tableaurule=.32pt %0.4pt \newdimen\tableaustep \def\phantomhrule#1{\hbox{\vbox to0pt{\hrule height\tableaurule width#1\vss}}} \def\phantomvrule#1{\vbox{\hbox to0pt{\vrule width\tableaurule height#1\hss}}} \def\sqr{\vbox{% \phantomhrule\tableaustep \hbox{\phantomvrule\tableaustep\kern\tableaustep\phantomvrule\tableaustep}% \hbox{\vbox{\phantomhrule\tableauside}\kern-\tableaurule}}} \def\squares#1{\hbox{\count0=#1\noindent\loop\sqr \advance\count0 by-1 \ifnum\count0>0\repeat}} \def\tableau#1{\vcenter{\offinterlineskip \tableaustep=\tableauside\advance\tableaustep by-\tableaurule \kern\normallineskip\hbox {\kern\normallineskip\vbox {\gettableau#1 0 }% \kern\normallineskip\kern\tableaurule}% \kern\normallineskip\kern\tableaurule}} \def\gettableau#1 {\ifnum#1=0\let\next=\null\else \squares{#1}\let\next=\gettableau\fi\next} %------------------------------------------------------------------------------ % add: indexbracket % (\Gamma_{m n} - \Gamma_{m} * \Gamma_{n})_{\alpha\beta} \psi_{\beta} % (fails to input correctly!!!) % @join!(%); % add: generate basis -> LiE % add: variational derivatives: see substitute.cdb % {m,n,p,q,r,s}::Indices(vector). % A_{m n} A_{m p} B_{p n}; % @vary!(%)( A_{m n} -> varA_{m n} ); % @factorise is now tricky, do we need a separate other one? %------------------------------------------------------------------------------ \begin{document} \begin{frame}{Cadabra overview\hspace{.52\textwidth}\raisebox{.2ex}{\hbox{\small Kasper Peeters}}} \medskip \Blue{Features}: \begin{small}\begin{itemize}\setlength{\itemsep}{-2pt} \item Designed for ``field theory problems'' {\scriptsize (general~rel., quantum field~th., \ldots)}. \item Dummy index problems handled at internal storage level. \item Multiple spaces, multiple index types, implicit dependence: $T^{\alpha \dot{\beta}}_{m}(x)$ \ldots \item Commuting \& non-commuting tensors, user-specified sort order. \item All tensor symmetries handled (monoterm $\rightarrow$ {\tt xPerm} \& multi-term). \end{itemize}\end{small} \medskip \Blue{Interface}: \begin{small}\begin{itemize}\setlength{\itemsep}{-2pt} \item {\rm \TeX} input language. Command line \& TeXmacs frontend. \item Object behaviour specified by ``properties'' which can inherit. \item Conservative: no hidden algorithms unless the user enables them. \item Unlimited undo (optional). \end{itemize}\end{small} \medskip \Blue{Implementation}: \begin{small}\begin{itemize}\setlength{\itemsep}{-2pt} \item Standalone \Cpp, GPL license, no dependence on non-free tools. \item Preliminary: \url{http://www.aei.mpg.de/~peekas/cadabra/} \end{itemize}\end{small} \end{frame} %------------------------------------------------------------------------------ \begin{frame}{Example I: Multi-term symmetries} \begin{itemize} \item \Blue{Given}: basis for 4-th order Weyl tensor monomials \begin{small} \begin{equation*} \begin{aligned} W_1 &= W_{m n a b} W_{n p b c} W_{p s c d} W_{s m d a}\,,\quad W_2 = W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a}\,,\\[1ex] W_3 &= W_{m n a b} W_{p s b a} W_{m n c d} W_{p s d c}\,,\quad W_4 = W_{m n a b} W_{m n b a} W_{p s c d} W_{p s d c}\,,\\[1ex] W_5 &= W_{m n a b} W_{n p b a} W_{p s c d} W_{s m d c}\,,\quad W_6 = W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}\,,\\[1ex] & \quad\quad\quad\quad W_7 = W_{m n}{}^{[m n} W_{p q}{}^{p q} W_{r s}{}^{r s} W_{t u}{}^{t u]}\,. \end{aligned} \end{equation*} \end{small} \medskip \item \Blue{Problem}: prove the identity \begin{equation*} W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w}- W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} = W_2 - \tfrac{1}{4} W_6 \end{equation*} Relies on the cyclic Ricci identity. \medskip \item \Blue{Algorithm}: project each Weyl with its Young projector~$\tableau{2 2}$, canonicalise using mono-term symmetries, decompose. \end{itemize} \end{frame} %------------------------------------------------------------------------------ \begin{frame}[fragile] \frametitle{Example I: Multi-term symmetries} \begin{screen} {m,n,p,q,r,s,t,u,v,w,a,b,c,d,e,f}::Indices(vector). W_{m n p q}::WeylTensor. W1: W_{m n a b} W_{n p b c} W_{p s c d} W_{s m d a}; ... W7: W_{m n}^{m n} W_{p q}^{p q} W_{r s}^{r s} W_{t u}^{t u}; @asym!(%){^{m},^{n},^{p},^{q},^{r},^{s},^{t},^{u}}: @substitute!(%)( W_{a b}^{c d} -> W_{a b c d} ): @canonicalise!(%): basisW4: { @(W1), @(W2), @(W3), @(W4), @(W5), @(W6), @(W7) }; W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w}; @decompose!(%){ @(basisW4) }; @list_sum!(%); \end{screen} \vspace{-3ex} \begin{screen} { 0, 1, 0, 0, 0, -1/4, 0 }; \end{screen} \end{frame} %------------------------------------------------------------------------------ \begin{frame}[fragile] \frametitle{Example II: Commuting \& non-commuting objects} \begin{itemize} \item Combinations of commuting and non-commuting tensors, e.g.~with~$\Gamma^m \psi_m = 0$ in 4d, \begin{equation*} \begin{aligned} \bar{\psi}_m (\Gamma_{m n} + A_{m} \Gamma_{n}) \Gamma_{p q r} \psi_{r} & = 6 \delta_{n p} \bar{\psi_{m}} \Gamma_{q} \psi_{m} - A_{m} \bar{\psi_{m}} \Gamma_{n p} \psi_{q} \\ & ~ + A_{m} \bar{\psi_{m}} \Gamma_{n q} \psi_{p} - A_{m} \bar{\psi_{m}} \Gamma_{p q} \psi_{n} \\ & ~ - 3 \delta_{n p} A_{m} \bar{\psi_{m}} \psi_{q}\,. \end{aligned} \end{equation*} \medskip \item Object properties: \begin{screen} {m,n,p,q,r}::Integer(0..3). \bar{#}::DiracBar. \Gamma{#}::GammaMatrix. \psi_{m}::Spinor(dimension=4). \psi_{m}::GammaTraceless. \delta_{m n}::KroneckerDelta. { \delta_{m n}, A_{m}, \psi_{m}, \Gamma_{#} }::SortOrder. \end{screen} \end{itemize} \end{frame} %------------------------------------------------------------------------------ \begin{frame}[fragile] \frametitle{Example II: Commuting \& non-commuting objects} \begin{itemize} \item The actual calculation (note the {\rm \TeX{}} input) \begin{screen} \bar{\psi_{m}} (\Gamma_{m n} + A_{m} \Gamma_{n}) \Gamma_{p q r} \psi_{r}; @distribute!(%); @join!(%); @distribute!(%); @prodsort!(%); @remove_gamma_trace!(%); @prodsort!(%); @remove_gamma_trace!(%); \end{screen} \medskip \item Output: \begin{screen} 6 \delta_{n p} * \bar{\psi_{m}} * \Gamma_{q} * \psi_{m} - A_{m} * \bar{\psi_{m}} * \Gamma_{n p} * \psi_{q} + A_{m} * \bar{\psi_{m}} * \Gamma_{n q} * \psi_{p} - A_{m} * \bar{\psi_{m}} * \Gamma_{p q} * \psi_{n} - 3 \delta_{n p} * A_{m} * \bar{\psi_{m}} * \psi_{q}; \end{screen} \end{itemize} \end{frame} \end{document} cadabra-0.115/doc/tree.html0000600000077000007700000002614510612672010015042 0ustar kantorkantor tree.hh: an STL-like C++ tree class

Overview

The tree.hh library for C++ provides an STL-like container class for n-ary trees, templated over the data stored at the nodes. Various types of iterators are provided (post-order, pre-order, and others). Where possible the access methods are compatible with the STL or alternative algorithms are available. The library is available under the terms of the GNU General Public License.
Documentation is available in the form of a postscript and a pdf file (also available in the tarball as a LaTeX file). This documentation is still a bit short and not entirely complete. See the test program (included in the distribution) for an example of how to use tree.hh. Also look at the simple example below. There is also some doxygen generated documentation.
The tree.hh code is available under the terms of the GNU General Public License. If you use tree.hh, please satisfy my curiosity and write me a small email with a bit of explanation of your software and the role of my tree class in it.
The tree.hh library is meant for generic n-ary trees. If you are only interested in AVL binary search trees (Adelson,Velskii & Landis), you may want to have a look at the C++ AVL tree template page.

Download

Everything (the header file, examples, documentation and all other things referred to on this page) is contained in the tarball
tree-VERSION.tar.gz
Feel free to copy the header tree.hh (which is all you need code-wise) into your own source directory as long as you respect the license (see above). The list of changes can be found in the ChangeLog.
See the intro above for links to the documentation. There is a very simple demonstration program available, tree_example.cc (also included in the tarball), which is discussed below. There is also a small test program, test_tree.cc, which makes use of the tree_util.hh utility functions by Linda Buisman; the output should be exactly identical to the test_tree.output file.
The current version works with GNU gcc 3.x and higher, Borland C++ builder and Microsoft Visual C++ 7.1 and higher. It is compatible with STLport.
Tony Cook has provided a version for the buggy Microsoft Visual C++ compilers up to version 7.0. You will have to use a special version of the header file, tree_msvc.hh (currently based on the original tree.hh version MSVC). The difference is that all members of the iterator and sibling_iterator subclasses have been moved inside the class definitions. If you get unresolved symbols in the linking phase, or other weird compiler errors, you should use this header. Microsoft users are urged to upgrade to version 7.1 which works with tree.hh out of the box.

Mailing list and update announcements

There is no mailing list, but I can send you an email whenever a new version of tree.hh becomes available. Just send me an email at kasper.peeters (at) aei.mpg.de and ask me to put you on the distribution list.
I also announce major updates on Freshmeat though not as often as by email.

Projects using tree.hh

The tree.hh library is used in various projects:
Cadabra
A field-theory motivated approach to symbolic computer algebra.
EChem++
A project realizing the idea of a Problem Solving Environment (PSE) in the field of computational electrochemistry. Computer controlled experimental measurements, numerical simulation and analysis of electrochemical processes will be combined under a common user interface.
LZCS
A semistructured document transformation tool. LZCS compresses structured documents taking advantage of the redundant information that can appear in the structure. The main idea is that frequently repeated subtrees may exist and these can be replaced by a backward reference to their first occurance. See the accompanying paper for more details.
libOFX
A parser and an API designed to allow applications to very easily support OFX command responses, usually provided by financial institutions for statement downloads.
A genetic programming project
See this paper for more information.
FreeLing
The FreeLing package consists of a library providing language analysis services (such as morfological analysis, date recognition, PoS tagging, etc.)
Let me know about your project when you are using tree.hh, so that I can add it to the list.

Simple example

The following program constructs a tree of std::string nodes, puts some content in it and applies the find algorithm to find the node with content "two". It then prints the content of all the children of this node. You can download the source tree_example.cc if you're too lazy to type it in.
#include <algorithm>
#include <string>
#include <iostream>
#include "tree.hh"

using namespace std;

int main(int, char **)
   {
   tree<string> tr;
   tree<string>::iterator top, one, two, loc, banana;

   top=tr.begin();
   one=tr.insert(top, "one");
   two=tr.append_child(one, "two");
   tr.append_child(two, "apple");
   banana=tr.append_child(two, "banana");
   tr.append_child(banana,"cherry");
   tr.append_child(two, "peach");
   tr.append_child(one,"three");

   loc=find(tr.begin(), tr.end(), "two");
   if(loc!=tr.end()) {
      tree<string>::sibling_iterator sib=tr.begin(loc);
      while(sib!=tr.end(loc)) {
         cout << (*sib) << endl;
         ++sib;
         }
      cout << endl;
      tree<string>::iterator sib2=tr.begin(loc);
      tree<string>::iterator end2=tr.end(loc);
      while(sib2!=end2) {
         for(int i=0; i<tr.depth(sib2)-2; ++i) 
            cout << " ";
         cout << (*sib2) << endl;
         ++sib2;
         }
      }
   }
The output of this program is
apple
banana
peach

apple
banana
 cherry
peach
Note that this example only has one element at the top of the tree (in this case that is the node containing "one") but it is possible to have an arbitary number of such elements (then the tree is more like a "bush"). Observe the way in which the two types of iterators work. The first block of output, obtained using the sibling_iterator, only displays the children directly below "two". The second block iterates over all children at any depth below "two". In the second output block, the depth member has been used to determine the distance of a given node to the root of the tree.

Data structure

The data structure of the tree class is depicted below (see the documentation for more detailed information). Each node contains a pointer to the first and last child element, and each child contains pointers to its previous and next sibling:
           first_child        first_child 
 root_node-+----------node--+----->-------node
           |           |    |               |   
           |           |    |               V   next_sibling
           |           |    |               |
                       |    |             node
                       |    |               |
                       |    |               V   next_sibling
                       |    | last_child    |
                       |    +----->-------node
                       |                        
                       V next_sibling           
                       |                       
                       |     first_child                  
                      node--+----->-------node
                       |    |               |   
                       |    |               V   next_sibling
                       |    |               |
                       |    +-------------node
                       .
                       .
Iterators come in two types. The normal iterator iterates depth-first over all nodes. The beginning and end of the tree can be obtained by using the begin() and end() members. The other type of iterator only iterates over the nodes at one given depth (ie. over all siblings). One typically uses these iterators to iterate over all children of a node, in which case the [begin,end) range can be obtained by calling begin(iterator) and end(iterator).
Iterators can be converted from one type to the other; this includes the `end' iterators (all intervals are as usual closed at the beginning and open at the end).

Webstats4U - Free web site statistics
Personal homepage website counter $Id: tree.html,v 1.56 2007/04/19 16:22:29 peekas Exp $ cadabra-0.115/doc/tree.tex0000600000077000007700000003534410465645232014713 0ustar kantorkantor\documentclass[11pt]{kasper} % % If you do not have 'kasper.cls', see % http://www.damtp.cam.ac.uk/user/kp229/texstuff . \usepackage{makeidx} \usepackage{verbatim} \usepackage{relsize} \makeindex %\newcommand{\toindex}[1]{#1\index{#1}} \newcommand{\member}[1]{{\tt #1}\index{#1}} %\newcommand{\member}[1]{{\tt #1}} \def\mystrut{\vbox to 8.5pt{}\vtop to 3.5pt{}} \def\V{\hskip10pt\vrule\hskip10pt} \def\T{\hskip10pt\vrule\vrule height2.5pt depth -2.1pt width 10pt} \def\L{\hskip10pt\vrule height 8.5pt depth -2.1pt \vrule height2.5pt depth -2.1pt width 10pt} \def\N{\hskip10pt\phantom{\vrule}\hskip10pt} \def\hw{\hskip-1000pt plus 1fil} % to test: insert before end of subtree \begin{document} \title{{\tt tree.hh} documentation} \author{Kasper Peeters} \address{1}{{\it MPI/AEI f\"ur Gravitationsphysik, Am M\"uhlenberg 1, 14476 Potsdam, Germany}} \email{k.peeters@damtp.cam.ac.uk} \maketitle \begin{abstract} The {\tt tree.hh} library for C++ provides an STL-like container class for n-ary trees, templated over the data stored at the nodes. Various types of iterators are provided (post-order, pre-order, and others). Where possible the access methods are compatible with the STL or alternative algorithms are available. The library is available under the terms of the GNU General Public License.\\[3ex] Code and examples available at: {\tt http://www.damtp.cam.ac.uk/user/kp229/tree/}\\[3ex] {\bf This documentation is not yet complete. Refer to the {\tt tree.hh} header file for a full list of member functions.} \end{abstract} \maketoc \begin{sectionunit} \title{Overview} \maketitle \begin{sectionunit} \title{The container class} \maketitle The tree class of {\tt tree.hh} is a templated container class in the spirit of the STL. It organises data in the form of a so-called n-ary tree. This is a tree in which every node is connected to an arbitrary number of child nodes. Nodes at the same level of the tree are called ``siblings'', while nodes that are below a given node are called its ``children''. At the top of the tree, there is a set of nodes which are characterised by the fact that they do not have any parents. The collection of these nodes is called the ``head'' of the tree. See figure~\ref{f:overview} for a pictorial illustration of this structure (90 degrees rotated for convenience). \begin{figure}[th] \begin{center} \includegraphics[width=.5\textwidth]{treefig} \caption{Overview of the tree structure. The elements at the top of the tree (here displayed at the left for convenience) are in the ``head'' (there can be more than one such element). Every node is linked to its children using the ``first child'' and ``last child'' links. In addition, all nodes on a given level are doubly-linked using the ``previous sibling'' and ``next sibling'' links. The ``depth'' of a given node refers to the horizontal distance from the head nodes.} \label{f:overview} \end{center} \end{figure} The tree class is templated over the data objects stored at the nodes; just like you can have a {\tt vector} you can now have a {\tt tree}. Many STL algorithms work on this data structure, and where necessary alternatives have been provided. \medskip \end{sectionunit} \begin{sectionunit} \title{Iterators} \maketitle The essential difference between a container with the structure of a tree and the STL containers is that the latter are ``linear''. While the STL containers thus only have essentially one way in which one can iterate over their elements, this is not true for trees. The {\tt tree.hh} library provides (at present) four different iteration schemes. To describe them, consider the following tree: \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr root \hw\cr \T A \cr \V \T B \cr \V \L C \cr \L D \cr \N \T E \cr \N \L F \cr}} \end{equation*} The three iteration types and the resulting order in which nodes are visited are tabulated below: \begin{center} \begin{tabular}{llll} pre-order (default) & ``element before children'' & \member{pre\_order\_iterator} & root A B C D E F \\ post-order & ``element after children'' & \member{post\_order\_iterator} & B C A E F D root \\ breadth-first & & \member{breadth\_first\_iterator} & root A D B C E F \\ sibling & ``only siblings'' & \member{sibling\_iterator} & (for ex.) A D \\ fixed-depth & & \member{fixed\_depth\_iterator} & (for ex.) A D \\ leaf & & \member{leaf\_iterator} & B C E F \end{tabular} \end{center} The pre-order ones are the default iterators, and therefore also known under the name of {\tt iterator}. Sibling iterators and fixed-depth iterators iterate only over the nodes at a given depth of the tree. The former restrict themselves to the child nodes of one given node, while the latter iterates over all child nodes at the given depth. Finally, leaf iterators iterate over all leafs (bottom-most) nodes of the tree. There are copy constructors that will convert iterators of the various types into each other. The post- and pre-order iterators are both also known as ``depth-first'', in contrast to the ``breadth-first'' iterator. The begin and end iterators of a tree can be obtained using \member{begin()} and \member{end()} (for pre-order iterators) or alternatively \member{begin\_post()} and \member{end\_post()} (for post-order iterators) and \member{begin\_leaf()} and \member{end\_leaf()} (for leaf iterators). Similarly, the begin and end sibling iterators can be obtained by calling \member{begin(iterator)} and \member{end(iterator)}. The range of children of a given node can also be obtained directly from an iterator, by using the {\tt iterator::begin()} and {\tt iterator::end()} member functions. If you want to (temporarily) make an iterator not go into the child subtree, call the member function \member{skip\_children}. This will only keep effect for a single increment or decrement of the iterator. Finally, whether or not an iterator is actually pointing at a node (i.e.~is not an ``end'' iterator) can be tested using the \member{is\_valid(iterator)} member of the tree class. \end{sectionunit} \end{sectionunit} \begin{sectionunit} \title{Basic operations} \maketitle \begin{description} \item[Initialising] There are two nontrivial constructors. One which takes a single node element as argument. It constructs a tree with this node begin the sole node in the head (in other words, it is a combination of a trivial constructor together with a \member{set\_head} call). The other non-trivial constructor takes an iterator, and copies the subtree starting at that node into the newly created tree (useful for constructing new tree objects given by subtrees of existing trees). \item[Tree traversal] Besides the \member{operator++} and \member{operator--} members for step-wise traversal through the tree, it is also possible to use the \member{operator+=} and \member{operator-=} member functions to make more than one step at the same time (though these are linear time, not amortized constant). The result of stepping beyond the end of the tree or stepping beyond the end of a sibling range (for sibling iterators) is undefined. The parent of a given node can be reached by calling the \member{parent} member of the tree object, giving it an iterator pointing to the node. If you know the number of children of a given node, you can get direct access to the $n$th child by using the \member{child} member function. Note that the value of the index is not checked and should therefore always be valid. \item[Appending child nodes] Nodes can be added as children of a given node using the \member{append\_child} member function. \item[Inserting nodes] Nodes can be inserted at the same depth as a given other node using the \member{insert} and \member{insert\_after} members functions. This is also how you insert the first node into a tree. \end{description} \end{sectionunit} \begin{sectionunit} \title{Other algorithms} \maketitle \begin{sectionunit} \title{Non-mutating algorithms} \maketitle \begin{description} \item[Counting nodes] The total number of nodes of a tree can be obtained using the \member{size} member function, while the number of children of a given node can be obtained with a call to \member{number\_of\_children(iterator)}. Similarly, the number of nodes at a given depth (the number of siblings of a given node) can be obtained using the \member{number\_of\_siblings} member function. \item[Determining depth] The \member{depth()} member function returns the distance of a node to the root. \item[Accessing siblings by their index] See the next item. \item[Determining index in a sibling range] In order to determine the index of a node in the range of siblings to which it belongs, use the \member{index(sibling\_iterator)} member function. The first sibling node has index 0. The reverse of this function (obtaining a sibling node given its index in the range of siblings) is called \member{child(const iterator\_base\&, unsigned int)}. \item[Comparing trees] While the STL \member{equal} algorithm can be used to compare the values of the nodes in two different trees, it does not know about the structure of the tree. If you want the comparison to take this into account, use the \member{equal(iterator, iterator, iterator, BinaryPredicate)} call of the tree class. As an addition to the STL algorithm, the length of the first range does not have to be equal to the length of the range pointed to by the second iterator. There is also an \member{equal\_subtree} algorithm which takes only two iterators, pointing to the (single-node) heads of two subtrees. \end{description} \end{sectionunit} \begin{sectionunit} \title{Mutating algorithms} \maketitle \begin{description} \item[Erasing nodes and subtrees] In order to remove a node including its children from the tree, use the \member{erase(iterator)} call. If you just want to erase the children, but not the node itself, use the \member{erase\_children(iterator)} call. \item[Replacing individual nodes or subtrees] \item[Flattening subtrees] The procedure of moving all children of a given node to be siblings of that node is called ``flattening''; it acts as \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T pear \cr \V \T strawberry \cr \V \L cherry \cr \L grape\cr}}\quad\rightarrow\quad \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \T pear \cr \T strawberry \cr \T cherry \cr \L grape\cr}} \end{equation*} % \begin{screen} % apple apple % banana banana % pear -> pear % strawberry strawberry % cherry cherry % grape grape % \end{screen} when the tree is flattened at the ``banana'' node. \item[Moving or exchanging subtrees] Simple exchange of one sibling node with the next one is done through the member function \member{swap(sibling\_iterator)}. The iterator remains valid and remains pointing to the moved subtree. More complicated move operations are the \member{move\_ontop}, \member{move\_before} and \member{move\_after} ones. These all take two iterators, a source and a target. The member \member{move\_ontop(target, source)} removes the `target' node and all its children, and replaces it with the `source' node and its children. The `source' subtree is removed from its original location. The other two move members do a similar thing, differing only in the node which is to be replaced. \item[Extracting subtrees] You can create a new tree object filled with the data of a subtree of the original tree. This is analogous to the extraction of a substring of a string. The relevant member function is \member{subtree(sibling\_iterator, sibling\_iterator)} which takes a range of siblings as argument. There is also a slight variation of this member, which does not return a tree object but instead populates one that is passed as an argument (useful if you want to call this on a tree object subclassed from {\tt tree}. \item[Sorting] The standard STL sort algorithm is not very useful for trees, because it only exchanges values, not nodes. Applying it to a tree would mean that the structure of the tree remains unmodified, only node values get moved around (not their subtrees). Therefore, the {\tt tree} class has its own sort member. It comes in two forms, just like the STL sort, namely \begin{screen} void sort(sibling_iterator from, sibling_iterator to, bool deep=false); template void sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering comp, bool deep=false); \end{screen} The result of a call to either of these is that the nodes in the range described by the two iterators get sorted. If the boolean {\tt deep} is true, the subtrees of all these nodes will get sorted as well (and so one can sort the entire tree in one call). As in the STL, you can use the second form of this function to pass your own comparison class. If the nodes to which the two iterators point are not in the same sibling range (i.e.~not at the same depth in the tree), the result is undefined. \item[Merging] One way in which one might think of indicating the position where new nodes are to be inserted, is to give the path that leads to the insertion point. For instance, given the tree \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T pear \cr \V \T strawberry \cr \V \L cherry \cr \L grape\cr}} \end{equation*} one could imagine using the sub-tree \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \L banana\cr \N \T coconut \cr \N \L raspberry \cr}} \end{equation*} to indicate that the nodes ``coconut'' and ``raspberry'' are to be inserted as new children of the ``banana'' node. In {\tt tree.hh} this process is called \emph{tree merging}. It can do the simple addition of children as above, but actually handles the generic case too: as an example consider the merge \begin{equation*} \text{\tt merge}\left[ \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T pear \cr \V \T strawberry \cr \V \L cherry \cr \T grape\cr blueberry \cr}}\quad, \quad \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T coconut \cr \V \L raspberry \cr \T tangerine \cr \V \L plum\cr blueberry \cr \N \L orange \cr}}\right]\quad\rightarrow\quad \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T pear\cr \V \T strawberry\cr \V \T cherry\cr \V \T coconut \cr \V \L raspberry \cr \T grape\cr \T tangerine \cr \V \L plum\cr blueberry \cr \N \L orange \cr}} \end{equation*} As is clear from the above, the arguments to \member{merge} are two sibling ranges. \end{description} \end{sectionunit} \end{sectionunit} \printindex \end{document} cadabra-0.115/doc/treefig.eps0000600000077000007700000001272207707433765015376 0ustar kantorkantor%!PS-Adobe-2.0 EPSF-2.0 %%Title: tree.eps %%Creator: fig2dev Version 3.2 Patchlevel 0-beta3 %%CreationDate: Fri May 3 12:41:08 2002 %%For: kp229@church.amtp.cam.ac.uk (Kasper Peeters) %%Orientation: Portrait %%BoundingBox: 0 0 324 252 %%Pages: 0 %%BeginSetup %%EndSetup %%Magnification: 1.0000 %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -126.0 342.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n -1000 6700 m -1000 -1000 l 8494 -1000 l 8494 6700 l cp clip 0.06000 0.06000 sc % Polyline 7.500 slw gs clippath 4380 3828 m 4350 3948 l 4320 3828 l 4320 3990 l 4380 3990 l cp 4320 3222 m 4350 3102 l 4380 3222 l 4380 3060 l 4320 3060 l cp clip n 4350 3075 m 4350 3975 l gs col0 s gr gr % arrowhead n 4320 3222 m 4350 3102 l 4380 3222 l 4350 3222 l 4320 3222 l cp gs 0.00 setgray ef gr col0 s % arrowhead n 4380 3828 m 4350 3948 l 4320 3828 l 4350 3828 l 4380 3828 l cp gs 0.00 setgray ef gr col0 s % Polyline [60] 0 sd n 4350 4350 m 4350 5475 l gs col0 s gr [] 0 sd % Polyline gs clippath 4021 5328 m 4039 5450 l 3966 5351 l 4028 5500 l 4083 5477 l cp clip n 2550 1875 m 4050 5475 l gs col0 s gr gr % arrowhead n 4021 5328 m 4039 5450 l 3966 5351 l 3993 5339 l 4021 5328 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 4380 2628 m 4350 2748 l 4320 2628 l 4320 2790 l 4380 2790 l cp 4320 2022 m 4350 1902 l 4380 2022 l 4380 1860 l 4320 1860 l cp clip n 4350 1875 m 4350 2775 l gs col0 s gr gr % arrowhead n 4320 2022 m 4350 1902 l 4380 2022 l 4350 2022 l 4320 2022 l cp gs 0.00 setgray ef gr col0 s % arrowhead n 4380 2628 m 4350 2748 l 4320 2628 l 4350 2628 l 4380 2628 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 3903 1695 m 4023 1725 l 3903 1755 l 4065 1755 l 4065 1695 l cp clip n 2550 1725 m 4050 1725 l gs col0 s gr gr % arrowhead n 3903 1695 m 4023 1725 l 3903 1755 l 3903 1725 l 3903 1695 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 6828 1695 m 6948 1725 l 6828 1755 l 6990 1755 l 6990 1695 l cp clip n 4725 1725 m 6975 1725 l gs col0 s gr gr % arrowhead n 6828 1695 m 6948 1725 l 6828 1755 l 6828 1725 l 6828 1695 l cp gs 0.00 setgray ef gr col0 s % Polyline [60] 0 sd n 7275 1950 m 7275 2625 l gs col0 s gr [] 0 sd /Times-Roman ff 180.00 scf sf 2100 1800 m gs 1 -1 sc (head) col0 sh gr /Times-Roman ff 180.00 scf sf 4200 1800 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 4200 3000 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 4200 4200 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 4200 5700 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 4575 2250 m gs 1 -1 sc (next sibling) col0 sh gr /Times-Roman ff 180.00 scf sf 4575 2475 m gs 1 -1 sc (prev sibling) col0 sh gr /Times-Roman ff 180.00 scf sf 4575 3450 m gs 1 -1 sc (next sibling) col0 sh gr /Times-Roman ff 180.00 scf sf 4575 3675 m gs 1 -1 sc (prev sibling) col0 sh gr /Times-Roman ff 180.00 scf sf 5850 1650 m gs 1 -1 sc (first child) col0 sh gr /Times-Roman ff 180.00 scf sf 2925 1650 m gs 1 -1 sc (first child) col0 sh gr /Times-Roman ff 180.00 scf sf 7125 1800 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 7125 2925 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 2550 3900 m gs 1 -1 sc (last child) col0 sh gr $F2psEnd rs cadabra-0.115/doc/treefig.fig0000600000077000007700000000260507707433765015353 0ustar kantorkantor#FIG 3.2 Landscape Center Inches Letter 100.00 Single -2 1200 2 2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 4350 3075 4350 3975 2 1 1 1 0 7 0 0 -1 4.000 0 0 -1 0 0 2 4350 4350 4350 5475 2 1 0 1 0 7 0 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2550 1875 4050 5475 2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 4350 1875 4350 2775 2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2550 1725 4050 1725 2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 4725 1725 6975 1725 2 1 1 1 0 7 0 0 -1 4.000 0 0 -1 0 0 2 7275 1950 7275 2625 4 0 0 0 0 0 12 0.0000 0 135 360 2100 1800 head\001 4 0 0 0 0 0 12 0.0000 4 135 360 4200 1800 node\001 4 0 0 0 0 0 12 0.0000 4 135 360 4200 3000 node\001 4 0 0 0 0 0 12 0.0000 4 135 360 4200 4200 node\001 4 0 0 0 0 0 12 0.0000 4 135 360 4200 5700 node\001 4 0 0 0 0 0 12 0.0000 4 180 870 4575 2250 next sibling\001 4 0 0 0 0 0 12 0.0000 4 180 870 4575 2475 prev sibling\001 4 0 0 0 0 0 12 0.0000 4 180 870 4575 3450 next sibling\001 4 0 0 0 0 0 12 0.0000 4 180 870 4575 3675 prev sibling\001 4 0 0 0 0 0 12 0.0000 4 135 720 5850 1650 first child\001 4 0 0 0 0 0 12 0.0000 4 135 720 2925 1650 first child\001 4 0 0 0 0 0 12 0.0000 4 135 360 7125 1800 node\001 4 0 0 0 0 0 12 0.0000 4 135 360 7125 2925 node\001 4 0 0 0 0 0 12 0.0000 4 135 690 2550 3900 last child\001 cadabra-0.115/doc/treefig.pdf0000600000077000007700000000307007707435227015347 0ustar kantorkantor%PDF-1.3 %쏢 6 0 obj <> stream xUK0WY}]HMPZ _hzE\/{b<{"?{($94lAjAh n NbNtJt%ʙƍ>v$+vjF_ŃSDRxqqXI3_k`?si*6:*=46cl%!HMpz$s>0RԕCKPcu[*5! Ƥ&˺c4@Nե.eΪipQT]h.̲I1N NH '׃sip.K٤Y rUB(!c7(]bIccX?فy VuAt43褙p 7YA/՜>xԠGwj VUju궕tES#됥HSwHo^6~+iܵ{gkR@voo ݲ.X̮ՋzΈ&~1$ ?w?G g[CO/|C |M I95_٩-kN)w-^cendstream endobj 7 0 obj 588 endobj 10 0 obj <> endobj 11 0 obj <> endobj 5 0 obj <> /Contents 6 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 4 0 obj <> endobj 9 0 obj <> endobj 8 0 obj <> endobj 2 0 obj <>endobj xref 0 12 0000000000 65535 f 0000000971 00000 n 0000001222 00000 n 0000000912 00000 n 0000001019 00000 n 0000000752 00000 n 0000000015 00000 n 0000000673 00000 n 0000001161 00000 n 0000001088 00000 n 0000000692 00000 n 0000000722 00000 n trailer << /Size 12 /Root 1 0 R /Info 2 0 R >> startxref 1274 %%EOF cadabra-0.115/doc/youngtab++.tex0000600000077000007700000001114610013201451015700 0ustar kantorkantor\documentclass{kasper} \usepackage{xspace} \usepackage{relsize} \renewcommand\descriptionlabel[1]{\hbox to \textwidth{\quad\quad\bf{#1}\hfill}} \newcommand{\ytt}{{\tt youngtab++}\xspace} \newcommand{\Ytt}{{\tt Youngtab++}\xspace} \begin{document} \title{\Ytt documentation} \maketitle \begin{abstract} The \ytt library is a small C++ library for the storage and manipulation of Young tableaux. Filled tableaux are supported with templates, allowing for any arbitrary object to be stored in the boxes that make up the tableaux. Several algorithms are included, among which an implementation of the Littlewood-Richardson algorithm for tensor products. Also included are pretty-print output functions acting on standard streams. \end{abstract} \begin{sectionunit} \title{Overview} \maketitle There are two tableau classes, one for tableaux without any information in the boxes and one for so-called filled tableaux. The latter are used just like STL containers. Two simple examples show the differences in initialisation. Unfilled tableaux only need to know about the row lengths and are therefore very quick to construct: \begin{screen} tableau tab; tab.add_row(3); tab.add_row(2); tab.add_row(2); \end{screen} Filled tableaux need to know about the content of each and every box: \begin{screen} filled_tableau ftab; ftab.add_box(0,''a''); ftab.add_box(0,''b''); ftab.add_box(0,''c''); ftab.add_box(1,''d''); ftab.add_box(1,''e''); ftab.add_box(2,''f''); ftab.add_box(2,''g''); \end{screen} There are many algorithms which do not act on a single tableau, but rather on a collection of them. There are special tableau containers to store such collections. For unfilled tableaux the canonical example is \begin{screen} tableaux tabs; tableau tab1, tab2; tabs.add_tableau(tab1); tabs.add_tableau(tab2); \end{screen} For filled tableaux, the container is templated over the tableau type (not over the data type stored in the boxes): \begin{screen} tableaux > ftabs; filled_tableau ftab1, ftab2; ftabs.add_tableau(ftab1); ftabs.add_tableau(ftab2); \end{screen} The tableaux added in this way are stored by value (just like in STL containers). \begin{sectionunit} \title{Tensor products} \maketitle The Littlewood-Richardson algorithm is implemented in two forms. The first one just takes two single tableaux and multiplies them, \begin{screen} tableau tab1,tab2; tableaux prod; LR_tensor(tab1, tab2, 10, prod.get_back_insert_iterator()); \end{screen} The ``10'' in the third argument indicates the maximum number of rows that is allowed. Observe that you give this algorithm an insert iterator to handle the storage of the tableaux in the product. In this way, it becomes independent of what you actually do with the tableaux in the product (you can store them, as in the example above, but you can also output them with an output iterator). In the second form, the Littlewood-Richardson algorithm takes a tableau container and a single tableau: \begin{screen} tableau tab1; tableaux tabs1, prod; LR_tensor(tabs1, tab1, 10, prod.get_back_insert_iterator()); \end{screen} The logic is the same, but now applied to a sum of representations as the first argument. \end{sectionunit} \begin{sectionunit} \title{Projectors} \maketitle \begin{screen} filled_tableau tab; tab.add_box(0, ``a''); tab.add_box(0, ``b''); tab.add_box(1, ``c''); symmetriser sym; tab.projector(sym); cout << sym << std::endl; \end{screen} This leads to \begin{screen} a b c 1 b a c 1 c b a -1 b c a -1 \end{screen} \end{sectionunit} \begin{sectionunit} \title{Canonicalisation and straightening} \maketitle Tableaux can be brought into canonical form by using anti-symmetry in sorting of the columns and symmetry under interchange of identical columns. For example, \begin{screen} filled_tableau tab; tab.add_box(0,4); tab.add_box(0,1); tab.add_box(1,3); tab.add_box(1,2); cout << tab << std::endl; tab.canonicalise(); cout << tab << std::endl; \end{screen} leads to the output \begin{screen} 4 1 3 2 1 3 (-1) 2 4 \end{screen} This was obtained by first sorting, using anti-symmetry, within the columns, and then sorting, using symmetry, the identical columns. Straightening of a tableau is canonicalisation plus a rewriting in terms of standard tableaux using Garnir symmetries. \end{sectionunit} \begin{description} \item[{\tt hook\_length(unsigned int row, unsigned int col)}] Compute the hook length of the hook with corner in the indicated box. \item[{\tt hook\_length\_prod}] Compute the product of all the hook lengths, giving the ``dimension'' of the tableau. \end{description} \end{sectionunit} \end{document} cadabra-0.115/examples/0000700000077000007700000000000010622301156014255 5ustar kantorkantorcadabra-0.115/examples/bianchi_identities.cnb0000600000077000007700000002133010622301156020560 0ustar kantorkantor% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\large\bfseries Proof of the higher-derivative identity in appendix A of {\tt hep-th/0111128}} % End TeX cell % Begin TeX cell closed The declaration of the indices, Weyl tensor and covariant derivative: % End TeX cell {\color[named]{Blue}\begin{verbatim} {i,j,m,n,k,p,q,l,r,r#}::Indices(vector). C_{m n p q}::WeylTensor. \nabla{#}::Derivative. \nabla_{r}{ C_{m n p q} }::SatisfiesBianchi. \end{verbatim}} \begin{verbatim} Assigning property Indices to i, j, m, n, k, p, q, l, r, r#. Assigning property WeylTensor to C. Assigning property Derivative to \nabla. Assigning property SatisfiesBianchi to \nabla. \end{verbatim} % Begin TeX cell closed The identity which we want to prove: % End TeX cell {\color[named]{Blue}\begin{verbatim} Eij:=- C_{i m k l} C_{j p k q} C_{l p m q} + 1/4 C_{i m k l} C_{j m p q} C_{k l p q} - 1/2 C_{i k j l} C_{k m p q} C_{l m p q}: E:= C_{j m n k} C_{m p q n} C_{p j k q} + 1/2 C_{j k m n} C_{p q m n} C_{j k p q}: exp:= \nabla_{i}{\nabla_{j}{ @(Eij) }} - 1/6 \nabla_{i}{\nabla_{i}{ @(E) }}; \end{verbatim}} % orig % \nabla_{i}{\nabla_{j}{( - C_{i m k l} C_{j p k q} C_{l p m q} + 1/4 C_{i m k l} C_{j m p q} C_{k l p q} - 1/2 C_{i k j l} C_{k m p q} C_{l m p q})}} - 1/6 \nabla_{i}{\nabla_{i}{(C_{j m n k} C_{m p q n} C_{p j k q} + 1/2 C_{j k m n} C_{p q m n} C_{j k p q})}}; % end_orig \begin{dmath*}[compact, spread=2pt] exp\specialcolon{}= \nabla_{i}{\nabla_{j}{( - C_{i m k l} C_{j p k q} C_{l p m q} + \frac{1}{4}\, C_{i m k l} C_{j m p q} C_{k l p q} - \frac{1}{2}\, C_{i k j l} C_{k m p q} C_{l m p q})}} - \frac{1}{6}\, \nabla_{i}{\nabla_{i}{(C_{j m n k} C_{m p q n} C_{p j k q} + \frac{1}{2}\, C_{j k m n} C_{p q m n} C_{j k p q})}}; \end{dmath*} % Begin TeX cell closed First apply the product rule to write out the derivatives, % End TeX cell {\color[named]{Blue}\begin{verbatim} @distribute!(%): @prodrule!(%): @distribute!(%): @prodrule!(%): @prodsort!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % orig % C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{j}{C_{n k p q}}} - C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{p}{C_{j q n k}} - 2 C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{p}{C_{j k n q}} - C_{i j m n} \nabla_{k}{C_{i k m p}} \nabla_{q}{C_{j p n q}} + C_{i j m n} C_{i k m p} \nabla_{j}{\nabla_{q}{C_{n k p q}}} - 2 C_{i j m n} \nabla_{i}{C_{j k m p}} \nabla_{q}{C_{n k p q}} - C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{p}{C_{j q n k}}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{m}{C_{n q k p}}} + 1/4 C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{p}{C_{m n k q}} - 1/2 C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{k}{C_{m n p q}} - 1/4 C_{i j m n} \nabla_{k}{C_{i j k p}} \nabla_{q}{C_{m n p q}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{m}{\nabla_{q}{C_{n q k p}}} - 1/2 C_{i j m n} \nabla_{i}{C_{m n k p}} \nabla_{q}{C_{j q k p}} + 1/4 C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{k}{C_{m n p q}}} - 1/2 C_{i j m n} C_{i j m k} \nabla_{p}{\nabla_{q}{C_{n p k q}}} + C_{i j m n} \nabla_{k}{C_{i j m p}} \nabla_{q}{C_{n q k p}} - C_{i j m n} \nabla_{k}{C_{i j m p}} \nabla_{q}{C_{n k p q}} + 1/2 C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{j}{C_{n k p q}}} + 1/2 C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{n}{C_{j k p q}} - 1/2 C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{m}{C_{n k p q}} + 1/2 C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{m}{C_{n k p q}}} + 1/2 C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{q}{C_{j k n p}}} + C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{k}{C_{j p n q}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{q}{C_{m n k p}}} - 1/2 C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{k}{C_{m n p q}}; % end_orig \begin{dmath*}[compact, spread=2pt] exp\specialcolon{}= C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{j}{C_{n k p q}}} - C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{p}{C_{j q n k}} - 2\, C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{p}{C_{j k n q}} - C_{i j m n} \nabla_{k}{C_{i k m p}} \nabla_{q}{C_{j p n q}} + C_{i j m n} C_{i k m p} \nabla_{j}{\nabla_{q}{C_{n k p q}}} - 2\, C_{i j m n} \nabla_{i}{C_{j k m p}} \nabla_{q}{C_{n k p q}} - C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{p}{C_{j q n k}}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{m}{C_{n q k p}}} + \frac{1}{4}\, C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{p}{C_{m n k q}} - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{k}{C_{m n p q}} - \frac{1}{4}\, C_{i j m n} \nabla_{k}{C_{i j k p}} \nabla_{q}{C_{m n p q}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{m}{\nabla_{q}{C_{n q k p}}} - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{m n k p}} \nabla_{q}{C_{j q k p}} + \frac{1}{4}\, C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{k}{C_{m n p q}}} - \frac{1}{2}\, C_{i j m n} C_{i j m k} \nabla_{p}{\nabla_{q}{C_{n p k q}}} + C_{i j m n} \nabla_{k}{C_{i j m p}} \nabla_{q}{C_{n q k p}} - C_{i j m n} \nabla_{k}{C_{i j m p}} \nabla_{q}{C_{n k p q}} + \frac{1}{2}\, C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{j}{C_{n k p q}}} + \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{n}{C_{j k p q}} - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{m}{C_{n k p q}} + \frac{1}{2}\, C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{m}{C_{n k p q}}} + \frac{1}{2}\, C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{q}{C_{j k n p}}} + C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{k}{C_{j p n q}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{q}{C_{m n k p}}} - \frac{1}{2}\, C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{k}{C_{m n p q}}; \end{dmath*} % Begin TeX cell closed Because the identity which we intend to prove is only supposed to hold on Einstein spaces, we set the divergence of the Weyl tensor to zero, % End TeX cell {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \nabla_{i}{C_{k i l m}} -> 0, \nabla_{i}{C_{k m l i}} -> 0 ); \end{verbatim}} % orig % C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{j}{C_{n k p q}}} - C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{p}{C_{j q n k}} - 2 C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{p}{C_{j k n q}} - C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{p}{C_{j q n k}}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{m}{C_{n q k p}}} + 1/4 C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{p}{C_{m n k q}} - 1/2 C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{k}{C_{m n p q}} + 1/4 C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{k}{C_{m n p q}}} + 1/2 C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{j}{C_{n k p q}}} + 1/2 C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{n}{C_{j k p q}} - 1/2 C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{m}{C_{n k p q}} + 1/2 C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{m}{C_{n k p q}}} + 1/2 C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{q}{C_{j k n p}}} + C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{k}{C_{j p n q}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{q}{C_{m n k p}}} - 1/2 C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{k}{C_{m n p q}}; % end_orig \begin{dmath*}[compact, spread=2pt] exp\specialcolon{}= C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{j}{C_{n k p q}}} - C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{p}{C_{j q n k}} - 2\, C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{p}{C_{j k n q}} - C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{p}{C_{j q n k}}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{m}{C_{n q k p}}} + \frac{1}{4}\, C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{p}{C_{m n k q}} - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{k}{C_{m n p q}} + \frac{1}{4}\, C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{k}{C_{m n p q}}} + \frac{1}{2}\, C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{j}{C_{n k p q}}} + \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{n}{C_{j k p q}} - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{m}{C_{n k p q}} + \frac{1}{2}\, C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{m}{C_{n k p q}}} + \frac{1}{2}\, C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{q}{C_{j k n p}}} + C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{k}{C_{j p n q}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{q}{C_{m n k p}}} - \frac{1}{2}\, C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{k}{C_{m n p q}}; \end{dmath*} % Begin TeX cell closed This expression should vanish upon use of the Bianchi identity. By expanding all tensors using their Young projectors, this becomes manifest, % End TeX cell {\color[named]{Blue}\begin{verbatim} @young_project_tensor!3(%){ModuloMonoterm}: @distribute!(%): @prodsort!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % orig % 0; % end_orig \begin{dmath*}[compact, spread=2pt] exp\specialcolon{}= 0; \end{dmath*} % Begin TeX cell closed This proves the identity. % End TeX cell \end{document} cadabra-0.115/examples/fierz.cnb0000600000077000007700000000747610541751335016110 0ustar kantorkantor% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\bfseries\large A Fierz identity in eleven dimensions} This notebook computes the Fierz identity (5.86) in my thesis. % End TeX cell {\color[named]{Blue}\begin{verbatim} {\mu,\nu,\rho}::Indices(curved, position=fixed). {m,n,p,q,r,s,t#}::Indices(flat). {m,n,p,q,r,s,t#}::Integer(0..10). T^{#{\mu}}::AntiSymmetric. \psi_{\mu}::SelfAntiCommuting. \psi_{\mu}::Spinor(dimension=11, type=Majorana). \theta::Spinor(dimension=11, type=Majorana). \epsilon::Spinor(dimension=11, type=Majorana). {\theta,\epsilon,\psi_{\mu}}::AntiCommuting \bar{#}::DiracBar. \delta^{m n}::KroneckerDelta. \Gamma^{#{m}}::GammaMatrix(metric=\delta). \end{verbatim}} \begin{verbatim} Assigning property Indices to \mu, \nu, \rho. Assigning property Indices to m, n, p, q, r, s, t#. Assigning property Integer to m, n, p, q, r, s, t#. Assigning property AntiSymmetric to T. Assigning property SelfAntiCommuting to \psi. Assigning property Spinor to \psi. Assigning property Spinor to \theta. Assigning property Spinor to \epsilon. Assigning property DiracBar to \bar. Assigning property AntiCommuting to \theta, \epsilon, \psi, {, \bar. Assigning property KroneckerDelta to \delta. Assigning property GammaMatrix to \Gamma. \end{verbatim} {\color[named]{Blue}\begin{verbatim} T^{\mu\nu\rho} e_{\nu}^{s} \bar{\theta} \Gamma^{r s} \psi_{\rho} \bar{\psi_{\mu}} \Gamma^{r} \epsilon; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \psi_{\rho} \bar{\psi_{\mu}} \Gamma^{r} \epsilon; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @fierz!(%)( \theta, \epsilon, \psi_{\mu}, \psi_{\nu} ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= - \frac{1}{32}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \psi_{\rho} - \frac{1}{32}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{m} \psi_{\rho} - \frac{1}{64}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m n} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{n m} \psi_{\rho} - \frac{1}{192}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m n p} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{p n m} \psi_{\rho} - \frac{1}{768}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m n p q} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{q p n m} \psi_{\rho} - \frac{1}{3840}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m n p q t1} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{t1 q p n m} \psi_{\rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @collect_terms!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= \frac{1}{4}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \Gamma^{m n} \epsilon \bar{\psi_{\nu}} \Gamma_{n} \psi_{\rho} + \frac{5}{16}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \epsilon \bar{\psi_{\nu}} \Gamma_{m} \psi_{\rho} + \frac{3}{32}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \Gamma^{m n}\,_{p} \epsilon \bar{\psi_{\nu}} \Gamma_{n p} \psi_{\rho} + \frac{1}{4}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \Gamma^{n} \epsilon \bar{\psi_{\nu}} \Gamma_{m n} \psi_{\rho} + \frac{1}{384}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \Gamma^{n}\,_{p q r} \epsilon \bar{\psi_{\nu}} \Gamma_{m n p q r} \psi_{\rho}; \end{dmath*} \end{document} cadabra-0.115/examples/maxwell.cnb0000600000077000007700000001057610622301156016425 0ustar kantorkantor% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} {\color[named]{Blue}\begin{verbatim} { a,b,c,d,e }::Indices(vector). {\partial{#}, \nabla{#}}::PartialDerivative. { A_{a}, F_{a b} }::Depends(\partial). { a,b,c,d,e }::Indices(vector). \delta{#}::Accent. F_{a b}::AntiSymmetric. \delta_{a b}::KroneckerDelta. \end{verbatim}} \begin{verbatim} Assigning property Indices to a, b, c, d, e. Assigning property PartialDerivative to \partial, \nabla. Assigning property Depends to A, F. Assigning property Indices to a, b, c, d, e. Assigning property Accent to \delta. Assigning property AntiSymmetric to F. Assigning property KroneckerDelta to \delta. \end{verbatim} {\color[named]{Blue}\begin{verbatim} S:= -(1/4) F_{a b} F_{a b}; \end{verbatim}} % orig % (-1/4) F_{a b} F_{a b}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= (\frac{-1}{4})\, F_{a b} F_{a b}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( F_{a b} -> \partial_{a}{A_{b}} - \partial_{b}{A_{a}} ); \end{verbatim}} % orig % (-1/4) (\partial_{a}{A_{b}} - \partial_{b}{A_{a}}) (\partial_{a}{A_{b}} - \partial_{b}{A_{a}}); % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= (\frac{-1}{4})\, (\partial_{a}{A_{b}} - \partial_{b}{A_{a}}) (\partial_{a}{A_{b}} - \partial_{b}{A_{a}}); \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} % orig % - 1/4 \partial_{a}{A_{b}} \partial_{a}{A_{b}} + 1/4 \partial_{a}{A_{b}} \partial_{b}{A_{a}} + 1/4 \partial_{b}{A_{a}} \partial_{a}{A_{b}} - 1/4 \partial_{b}{A_{a}} \partial_{b}{A_{a}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{4}\, \partial_{a}{A_{b}} \partial_{a}{A_{b}} + \frac{1}{4}\, \partial_{a}{A_{b}} \partial_{b}{A_{a}} + \frac{1}{4}\, \partial_{b}{A_{a}} \partial_{a}{A_{b}} - \frac{1}{4}\, \partial_{b}{A_{a}} \partial_{b}{A_{a}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @vary!(%)( A_{b} -> \delta{A_{b}}); \end{verbatim}} % orig % - 1/4 \partial_{a}{\delta{A_{b}}} \partial_{a}{A_{b}} - 1/4 \partial_{a}{A_{b}} \partial_{a}{\delta{A_{b}}} + 1/4 \partial_{a}{\delta{A_{b}}} \partial_{b}{A_{a}} + 1/4 \partial_{a}{A_{b}} \partial_{b}{\delta{A_{a}}} + 1/4 \partial_{b}{\delta{A_{a}}} \partial_{a}{A_{b}} + 1/4 \partial_{b}{A_{a}} \partial_{a}{\delta{A_{b}}} - 1/4 \partial_{b}{\delta{A_{a}}} \partial_{b}{A_{a}} - 1/4 \partial_{b}{A_{a}} \partial_{b}{\delta{A_{a}}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{4}\, \partial_{a}{\delta{A_{b}}} \partial_{a}{A_{b}} - \frac{1}{4}\, \partial_{a}{A_{b}} \partial_{a}{\delta{A_{b}}} + \frac{1}{4}\, \partial_{a}{\delta{A_{b}}} \partial_{b}{A_{a}} + \frac{1}{4}\, \partial_{a}{A_{b}} \partial_{b}{\delta{A_{a}}} + \frac{1}{4}\, \partial_{b}{\delta{A_{a}}} \partial_{a}{A_{b}} + \frac{1}{4}\, \partial_{b}{A_{a}} \partial_{a}{\delta{A_{b}}} - \frac{1}{4}\, \partial_{b}{\delta{A_{a}}} \partial_{b}{A_{a}} - \frac{1}{4}\, \partial_{b}{A_{a}} \partial_{b}{\delta{A_{a}}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @prodsort!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % orig % - \partial_{a}{A_{b}} \partial_{a}{\delta{A_{b}}} + \partial_{a}{A_{b}} \partial_{b}{\delta{A_{a}}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \partial_{a}{A_{b}} \partial_{a}{\delta{A_{b}}} + \partial_{a}{A_{b}} \partial_{b}{\delta{A_{a}}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \partial_{a}{\delta{A_{b}}} -> \nabla_{a}{\delta{A_{b}}} ); \end{verbatim}} % orig % - \partial_{a}{A_{b}} \nabla_{a}{\delta{A_{b}}} + \partial_{a}{A_{b}} \nabla_{b}{\delta{A_{a}}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \partial_{a}{A_{b}} \nabla_{a}{\delta{A_{b}}} + \partial_{a}{A_{b}} \nabla_{b}{\delta{A_{a}}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @pintegrate!(%)( \nabla ): @rename!(%){"\nabla"}{"\partial"}; \end{verbatim}} % orig % \partial_{a}{\partial_{a}{A_{b}}} \delta{A_{b}} - \partial_{b}{\partial_{a}{A_{b}}} \delta{A_{a}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \partial_{a}{\partial_{a}{A_{b}}} \delta{A_{b}} - \partial_{b}{\partial_{a}{A_{b}}} \delta{A_{a}}; \end{dmath*} \end{document} cadabra-0.115/examples/simple_clifford.cnb0000600000077000007700000000437110541752315020120 0ustar kantorkantor% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\large\bfseries Some simple gamma matrix algebra.} % End TeX cell {\color[named]{Blue}\begin{verbatim} ::PostDefaultRules( @@prodsort!(%), @@eliminate_kr!(%), @@canonicalise!(%), @@collect_terms!(%) ). \end{verbatim}} \begin{verbatim} Assigning property PostDefaultRules to . \end{verbatim} {\color[named]{Blue}\begin{verbatim} {s,r,l,k,m,n}::Indices(vector). {s,r,l,k,m,n}::Integer(0..d-1). \Gamma_{#}::GammaMatrix(metric=\delta). \delta_{m n}::KroneckerDelta. \end{verbatim}} \begin{verbatim} Assigning property Indices to s, r, l, k, m, n. Assigning property Integer to s, r, l, k, m, n. Assigning property GammaMatrix to \Gamma. Assigning property KroneckerDelta to \delta. \end{verbatim} % Begin TeX cell closed The expression which we want to simplify: % End TeX cell {\color[named]{Blue}\begin{verbatim} \Gamma_{s r} \Gamma_{r l} \Gamma_{k m} \Gamma_{m s}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= (-1)\, \Gamma_{m r} \Gamma_{l m} \Gamma_{k s} \Gamma_{r s}; \end{dmath*} % Begin TeX cell closed By twice joining adjacent gamma matrices, we join the first and second and third and fourth factor: % End TeX cell {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @join!(%){expand}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= (-1)\, (2\, \Gamma_{l r} - \Gamma_{l r} d + \delta_{l r} d - \delta_{l r}) (2\, \Gamma_{k r} - \Gamma_{k r} d + \delta_{k r} - \delta_{k r} d); \end{dmath*} % Begin TeX cell closed After distributing the result and joining once more, we collect factors and get the desired result: % End TeX cell {\color[named]{Blue}\begin{verbatim} @distribute!(%): @canonicalise!(%): @join!(%){expand}: @distribute!(%): @factorise!(%){d}: @collect_factors!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= \Gamma_{k l} (12 - 18\, d + 8\, d**2 - d**3) + \delta_{k l} ( - 3 + 6\, d - 4\, d**2 + d**3); \end{dmath*} \end{document} cadabra-0.115/examples/supergravity.cnb0000600000077000007700000014573410555362626017543 0ustar kantorkantor% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\large\bfseries Superinvariance of four-dimensional $N=1$ supergravity.} This notebook follows the notation and conventions of P. van Nieuwenhuizen, ``Supergravity'', Phys.~Rep.~68 (1981) 189, except for $\gamma_5$ which is always written using the product of four gamma matrices. We will use the 1.5 order formalism as described in section 1.6 and~1.7. % End TeX cell {\color[named]{Blue}\begin{verbatim} ::PostDefaultRules( @@eliminate_kr!(%), @@prodsort!(%), @@collect_terms!(%) ). \end{verbatim}} \begin{verbatim} Assigning property PostDefaultRules to . \end{verbatim} % Begin TeX cell closed Declaration of derivative operators and Dirac conjugation: % End TeX cell {\color[named]{Blue}\begin{verbatim} D{#}::Derivative. \bar{#}::DiracBar. \partial{#}::PartialDerivative. \delta{A??}::Derivative. \end{verbatim}} \begin{verbatim} Assigning property Derivative to D. Assigning property DiracBar to \bar. Assigning property PartialDerivative to \partial. Assigning property Derivative to \delta. \end{verbatim} % Begin TeX cell closed Indices for flat and curved space: % End TeX cell {\color[named]{Blue}\begin{verbatim} {m,n,p,q,r,s,t,u,m#}::Indices(flat). {m,n,p,q,r,s,t,u,m#}::Integer(0..3). {\mu,\nu,\rho,\sigma,\kappa,\lambda,\alpha,\beta,\gamma}::Indices(curved,position=fixed). {\mu,\nu,\rho,\sigma,\kappa,\lambda,\alpha,\beta,\gamma}::Integer(0..3). \end{verbatim}} \begin{verbatim} Assigning property Indices to m, n, p, q, r, s, t, u, m#. Assigning property Integer to m, n, p, q, r, s, t, u, m#. Assigning property Indices to \mu, \nu, \rho, \sigma, \kappa, \lambda, \alpha, \beta, \gamma. Assigning property Integer to \mu, \nu, \rho, \sigma, \kappa, \lambda, \alpha, \beta, \gamma. \end{verbatim} % Begin TeX cell closed Declaration of all bosonic fields: % End TeX cell {\color[named]{Blue}\begin{verbatim} e^{m \mu}::Vielbein. e_{m \mu}::InverseVielbein. g^{\mu\nu}::InverseMetric. g_{\mu\nu}::Metric. \omega_{\mu m n}::TableauSymmetry( indices={1,2}, shape={1,1} ). \delta_{\mu}^{\rho}::KroneckerDelta. \delta^{\mu}_{\rho}::KroneckerDelta. \delta^{m n}::KroneckerDelta. R_{\mu\nu m n}::TableauSymmetry( indices={0,1}, shape={1,1}, indices={2,3}, shape={1,1} ). { e^{m \mu}, e_{m \mu}, e, T^{\mu}_{\nu\rho} }::Depends(\partial, D). T^{\mu}_{\nu\rho}::TableauSymmetry( indices={1,2}, shape={1,1} ). \epsilon_{m n p q}::AntiSymmetric. \epsilon^{\mu\nu\rho\sigma}::AntiSymmetric. \end{verbatim}} \begin{verbatim} Assigning property Vielbein to e. Assigning property InverseVielbein to e. Assigning property InverseMetric to g. Assigning property Metric to g. Assigning property TableauSymmetry to \omega. Assigning property KroneckerDelta to \delta. Assigning property KroneckerDelta to \delta. Assigning property KroneckerDelta to \delta. Assigning property TableauSymmetry to R. Assigning property Depends to e, e, e, T. Assigning property TableauSymmetry to T. Assigning property AntiSymmetric to \epsilon. Assigning property AntiSymmetric to \epsilon. \end{verbatim} % Begin TeX cell closed Declaration of all fermionic fields: % End TeX cell {\color[named]{Blue}\begin{verbatim} { \epsilon,\psi_{\mu},\psi_{\mu\nu} }::Spinor(dimension=4, type=Majorana). \Gamma_{#{m}}::GammaMatrix(metric=\delta). \Gamma_{#{\mu}}::GammaMatrix(metric=g). { \psi_{\mu\nu}, \psi_{\mu}, \epsilon }::AntiCommuting. { \psi_{\mu}, \psi_{\mu\nu} }::SelfAntiCommuting. { \epsilon, \psi_{\mu}, \psi_{\mu\nu} }::SortOrder. { \epsilon, \psi_{\mu}, \psi_{\mu\nu} }::Depends(\bar,\partial,D). \Gamma_{#}::Depends(\bar). \psi_{\mu\nu}::AntiSymmetric. \end{verbatim}} \begin{verbatim} Assigning property Spinor to \epsilon, \psi, \psi. Assigning property GammaMatrix to \Gamma. Assigning property GammaMatrix to \Gamma. Assigning property AntiCommuting to \psi, \psi, \epsilon. Assigning property SelfAntiCommuting to \psi, \psi. Assigning property SortOrder to \epsilon, \psi, \psi. Assigning property Depends to \epsilon, \psi, \psi. Assigning property Depends to \Gamma. Assigning property AntiSymmetric to \psi. \end{verbatim} % Begin TeX cell closed The Lagrangian of $N=1$ four-dimensionsal supergravity, % End TeX cell {\color[named]{Blue}\begin{verbatim} L:= -1/2 e e^{n \nu} e^{m \mu} R_{\mu\nu n m} - 1/2 e \bar{\psi_\mu} \Gamma^{\mu\nu\rho} D_{\nu}{\psi_{\rho}}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, R_{\mu \nu n m} e e^{m \mu} e^{n \nu} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} D_{\nu}{\psi_{\rho}} e; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @rewrite_indices!(%){ \Gamma^{m n p} }{ e^{n \mu} }; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, R_{\mu \nu n m} e e^{m \mu} e^{n \nu} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho}; \end{dmath*} % Begin TeX cell closed This action is supposed to be invariant under the following supersymmetry transformation rules: % End TeX cell {\color[named]{Blue}\begin{verbatim} susy:= { e^{n \mu} -> -\bar{\epsilon} \Gamma^m \psi_\nu e^{m \mu} e^{n \nu}, e -> e \bar{\epsilon} \Gamma^n \psi_\mu e^{n\mu}, \psi_\mu -> D_{\mu}{\epsilon} }; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] susy\specialcolon{}= \{e^{n \mu} \rightarrow (-1)\, \bar{\epsilon} \Gamma^{m} \psi_{\nu} e^{m \mu} e^{n \nu},\quad e \rightarrow \bar{\epsilon} \Gamma^{n} \psi_{\mu} e e^{n \mu},\quad \psi_{\mu} \rightarrow D_{\mu}{\epsilon}\}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @vary!(L)( @(susy) ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{p \rho} e^{m \mu} e^{n \nu} + \frac{1}{2}\, R_{\mu \nu n m} e \bar{\epsilon} \Gamma^{p} \psi_{\rho} e^{p \mu} e^{m \rho} e^{n \nu} + \frac{1}{2}\, R_{\mu \nu n m} e e^{m \mu} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e^{p \nu} e^{n \rho} - \frac{1}{2}\, \bar{D_{\mu}{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{D_{\rho}{\epsilon}} e e^{m \mu} e^{n \nu} e^{p \rho} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{q \sigma} e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e^{q \mu} e^{m \sigma} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e^{q \nu} e^{n \sigma} e^{p \rho} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e^{q \rho} e^{p \sigma}; \end{dmath*} % Begin TeX cell closed The $D_\nu D_\rho \epsilon$ factor can be rewritten as a Riemann tensor, % End TeX cell {\color[named]{Blue}\begin{verbatim} @substitute!(%)( D_{\nu}{ D_{\rho}{ \epsilon } } -> 1/4 R_{\nu\rho m n} \Gamma^{m n} \epsilon): @prodsort!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \rho} e^{n \nu} e^{p \mu} + \frac{1}{2}\, R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \rho} e^{p \nu} - \frac{1}{2}\, \bar{D_{\mu}{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho} - \frac{1}{8}\, R_{\nu \rho q r} \bar{\psi_{\mu}} \Gamma^{m n p} \Gamma^{q r} \epsilon e e^{m \mu} e^{n \nu} e^{p \rho} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \sigma} e^{n \nu} e^{p \rho} e^{q \mu} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \sigma} e^{p \rho} e^{q \nu} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho}; \end{dmath*} % Begin TeX cell closed The $\overline{D_{\mu}{\epsilon}}$ term needs to be partially integrated. We isolate it and then take the covariant derivative apart. % End TeX cell {\color[named]{Blue}\begin{verbatim} deps:=@take_match![@(L)]( \bar{D_{\mu}{\epsilon}}*A?? ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= (\frac{-1}{2})\, \bar{D_{\mu}{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \bar{D_{\mu}{\epsilon}} -> \partial_{\mu}{\bar{\epsilon}} - 1/4 \bar{\epsilon}\omega_{\mu m n} \Gamma^{m n} ): @distribute!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= - \frac{1}{2}\, \partial_{\mu}{\bar{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{8}\, \bar{\epsilon} \Gamma^{q r} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \omega_{\mu q r} e e^{m \mu} e^{n \nu} e^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @pintegrate!(%)(\partial): @prodrule!(%): @distribute!(%): @unwrap!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} \partial_{\mu}{D_{\nu}{\psi_{\rho}}} e e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e} e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{m \mu}} e e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{n \nu}} e e^{m \mu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{p \rho}} e e^{m \mu} e^{n \nu} + \frac{1}{8}\, \bar{\epsilon} \Gamma^{q r} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \omega_{\mu q r} e e^{m \mu} e^{n \nu} e^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \Gamma^{q r}\Gamma^{m n p} -> - @join![ \Gamma^{m n p} \Gamma^{q r} - \Gamma^{q r} \Gamma^{m n p} ]{expand} ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} \partial_{\mu}{D_{\nu}{\psi_{\rho}}} e e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e} e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{m \mu}} e e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{n \nu}} e e^{m \mu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{p \rho}} e e^{m \mu} e^{n \nu} + \frac{1}{8}\, \bar{\epsilon} ( - \Gamma^{m n r} \delta^{p q} + \Gamma^{m n q} \delta^{p r} + \Gamma^{m p r} \delta^{n q} - \Gamma^{m p q} \delta^{n r} - \Gamma^{n p r} \delta^{m q} + \Gamma^{n p q} \delta^{m r} + \Gamma^{q n p} \delta^{m r} - \Gamma^{q n m} \delta^{p r} + \Gamma^{q p m} \delta^{n r} - \Gamma^{r n p} \delta^{m q} + \Gamma^{r n m} \delta^{p q} - \Gamma^{r p m} \delta^{n q}) D_{\nu}{\psi_{\rho}} \omega_{\mu q r} e e^{m \mu} e^{n \nu} e^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%): @canonicalise!(%): @rename_dummies!(%): @substitute!(%)( \partial_{\mu}{D_{\nu}{\psi_{\rho}}} -> 1/4 R_{\mu\nu m n}\Gamma^{m n} \psi_{\rho} ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, R_{\mu \nu q r} \bar{\epsilon} \Gamma^{m n p} \Gamma^{q r} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e} e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \rho}} e e^{n \mu} e^{p \nu} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \mu}} e e^{n \nu} e^{p \rho} - \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \nu}} e e^{n \mu} e^{p \rho} - \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho m q} e e^{n \mu} e^{p \rho} e^{q \nu} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho m q} e e^{n \nu} e^{p \rho} e^{q \mu} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho m q} e e^{n \mu} e^{p \nu} e^{q \rho}; \end{dmath*} % Begin TeX cell closed This now needs to be rewritten in terms of the torsion, and then the torsion is to be replaced with a fermi bilinear. % End TeX cell {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \partial_{\rho}{e} -> - e e_{n \mu} \partial_{\rho}{ e^{n \mu} } ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, R_{\mu \nu q r} \bar{\epsilon} \Gamma^{m n p} \Gamma^{q r} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} - \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{q \sigma}} e e_{q \sigma} e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \rho}} e e^{n \mu} e^{p \nu} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \mu}} e e^{n \nu} e^{p \rho} - \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \nu}} e e^{n \mu} e^{p \rho} - \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho m q} e e^{n \mu} e^{p \rho} e^{q \nu} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho m q} e e^{n \nu} e^{p \rho} e^{q \mu} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho m q} e e^{n \mu} e^{p \nu} e^{q \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \partial_{\mu}{e^{m \nu}} -> -\omega_{\mu m n} e^{n \nu} - C^{\nu}_{\mu\rho} e^{m \rho} ): @distribute!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, R_{\mu \nu q r} \bar{\epsilon} \Gamma^{m n p} \Gamma^{q r} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho q r} e e_{q \sigma} e^{m \mu} e^{n \nu} e^{p \rho} e^{r \sigma} + \frac{1}{2}\, C^{\sigma}\,_{\rho \kappa} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} e e_{q \sigma} e^{m \mu} e^{n \nu} e^{p \rho} e^{q \kappa} - \frac{1}{2}\, C^{\rho}\,_{\rho \sigma} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} e e^{m \sigma} e^{n \mu} e^{p \nu} - \frac{1}{2}\, C^{\mu}\,_{\rho \sigma} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} e e^{m \sigma} e^{n \nu} e^{p \rho} + \frac{1}{2}\, C^{\nu}\,_{\rho \sigma} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} e e^{m \sigma} e^{n \mu} e^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( e_{q \sigma} e^{q \kappa} -> \delta_{\sigma}^{\kappa}, e_{q \sigma} e^{r \sigma} -> \delta^{q r} ): @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} + \frac{1}{2}\, C^{\mu}\,_{\nu \mu} \bar{\epsilon} \Gamma^{m n p} D_{\rho}{\psi_{\sigma}} e e^{m \nu} e^{n \rho} e^{p \sigma} - \frac{1}{2}\, C^{\mu}\,_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} D_{\rho}{\psi_{\sigma}} e e^{m \nu} e^{n \rho} e^{p \sigma} - \frac{1}{2}\, C^{\mu}\,_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\sigma}} e e^{m \nu} e^{n \rho} e^{p \sigma} + \frac{1}{2}\, C^{\mu}\,_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} D_{\sigma}{\psi_{\mu}} e e^{m \nu} e^{n \rho} e^{p \sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( C^{\mu}_{\nu\kappa} -> 1/2 C^{\mu}_{\nu\kappa} + 1/2 C^{\mu}_{\kappa\nu} + T^{\mu}_{\nu\kappa} ): @distribute!(%): @canonicalise!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} T^{\rho}\,_{\rho \sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} - \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} T^{\mu}\,_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} + \frac{1}{2}\, \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} T^{\nu}\,_{\rho \sigma} e e^{m \mu} e^{n \rho} e^{p \sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( D_{\mu}{\psi_{\sigma}} -> 1/2 D_{\mu}{\psi_{\sigma}} + 1/2 D_{\sigma}{\psi_{\mu}} + \psi_{\mu\sigma} ): @distribute!(%): @canonicalise!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - T^{\mu}\,_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - T^{\mu}\,_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\mu \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma}; \end{dmath*} % Begin TeX cell closed Put this back into the main variation and continue... % End TeX cell {\color[named]{Blue}\begin{verbatim} @replace_match!(L)( \bar{D_{\mu}{\epsilon}}*A?? -> @(deps) ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} + \frac{1}{2}\, R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \rho} e^{n \nu} e^{p \mu} + \frac{1}{2}\, R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \rho} e^{p \nu} + \frac{1}{8}\, R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - T^{\mu}\,_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - T^{\mu}\,_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\mu \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - \frac{1}{8}\, R_{\nu \rho q r} \bar{\psi_{\mu}} \Gamma^{m n p} \Gamma^{q r} \epsilon e e^{m \mu} e^{n \nu} e^{p \rho} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \sigma} e^{n \nu} e^{p \rho} e^{q \mu} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \sigma} e^{p \rho} e^{q \nu} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{2}\, R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} - R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \rho} e^{p \nu} + \frac{1}{8}\, R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - T^{\mu}\,_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - T^{\mu}\,_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\mu \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - \frac{1}{8}\, R_{\mu \nu m n} \bar{\psi_{\rho}} \Gamma^{p q r} \Gamma^{m n} \epsilon e e^{p \mu} e^{q \nu} e^{r \rho} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} e^{q \mu} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} e^{q \nu} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho}; \end{dmath*} % Begin TeX cell closed Let us focus on the two terms with Riemann tensors which were obtained from the gravitino variation. We select them, and then simplify the product of gamma matrices, % End TeX cell {\color[named]{Blue}\begin{verbatim} vpsi:=@take_match[@(L)]( \Gamma^{m n p}\Gamma^{r s} A?? ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] vpsi\specialcolon{}= \frac{1}{8}\, R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - \frac{1}{8}\, R_{\mu \nu m n} \bar{\psi_{\rho}} \Gamma^{p q r} \Gamma^{m n} \epsilon e e^{p \mu} e^{q \nu} e^{r \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(vpsi){expand}: @distribute!(%): @spinorsort!(%): @canonicalise!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] vpsi\specialcolon{}= R_{\mu \nu p q} \bar{\epsilon} \Gamma^{r} \psi_{\rho} e e^{p \mu} e^{q \rho} e^{r \nu} - \frac{1}{2}\, R_{\mu \nu p q} \bar{\epsilon} \Gamma^{r} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho}; \end{dmath*} % Begin TeX cell closed That looks nice, we can now plug these terms back into the action where they came from. We then end up with only four-fermi terms, % End TeX cell {\color[named]{Blue}\begin{verbatim} @replace_match!(L)( \Gamma^{m n p}\Gamma^{r s} A?? -> @(vpsi) ): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - T^{\mu}\,_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - T^{\mu}\,_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\mu \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} e^{q \mu} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} e^{q \nu} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho}; \end{dmath*} % Begin TeX cell closed The Riemann tensor terms have cancelled completely. Inserting the torsion now leaves us with % End TeX cell {\color[named]{Blue}\begin{verbatim} @substitute!(%)( T^{\mu}_{\nu\rho} -> -1/4 \bar{\psi_{\nu}} \Gamma^{m} \psi_{\rho} e^{m\mu} ): @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{m} \psi_{\nu} e^{m \mu} \bar{\epsilon} \Gamma^{n p q} \psi_{\rho \sigma} e e^{n \nu} e^{p \rho} e^{q \sigma} + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{m} \psi_{\nu} e^{m \rho} \bar{\epsilon} \Gamma^{n p q} \psi_{\rho \sigma} e e^{n \mu} e^{p \nu} e^{q \sigma} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} e^{q \mu} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} e^{q \nu} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @eliminate_vielbein!(%){\Gamma^{m n p}, \Gamma^{m}}: @canonicalise!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{\nu \rho \sigma} \psi_{\rho \sigma} e + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{\mu \rho \sigma} \psi_{\nu \sigma} e - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{\sigma} \psi_{\sigma} e + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho \sigma} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{\mu} \psi_{\sigma} e - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} D_{\sigma}{\psi_{\nu}} \bar{\epsilon} \Gamma^{\sigma} \psi_{\rho} e + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} D_{\nu}{\psi_{\sigma}} \bar{\epsilon} \Gamma^{\sigma} \psi_{\rho} e; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \Gamma^{\sigma\nu\rho} D_{\nu}{\psi_{\rho}} ->\Gamma^{\sigma\nu\rho} \psi_{\nu\rho}); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{\nu \rho \sigma} \psi_{\rho \sigma} e + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{\mu \rho \sigma} \psi_{\nu \sigma} e - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \kappa} \psi_{\nu \kappa} \bar{\epsilon} \Gamma^{\sigma} \psi_{\sigma} e + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho \sigma} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{\mu} \psi_{\sigma} e - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} D_{\sigma}{\psi_{\nu}} \bar{\epsilon} \Gamma^{\sigma} \psi_{\rho} e + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} D_{\nu}{\psi_{\sigma}} \bar{\epsilon} \Gamma^{\sigma} \psi_{\rho} e; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( D_{\mu}{\psi_{\sigma}} -> 1/2 D_{\mu}{\psi_{\sigma}} + 1/2 D_{\sigma}{\psi_{\mu}} + \psi_{\mu\sigma} ): @distribute!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{\nu \rho \sigma} \psi_{\rho \sigma} e + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{\mu \rho \sigma} \psi_{\nu \sigma} e - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \psi_{\nu \rho} \bar{\epsilon} \Gamma^{\sigma} \psi_{\sigma} e + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho \sigma} \psi_{\nu \rho} \bar{\epsilon} \Gamma^{\mu} \psi_{\sigma} e + \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \psi_{\nu \sigma} \bar{\epsilon} \Gamma^{\sigma} \psi_{\rho} e; \end{dmath*} % Begin TeX cell closed Now we need to Fierz, indicating the preferred form of the bilinears. We will sort such that the fermion pairs appear as $\psi\psi$ and $\epsilon\psi_{(2)}$. % End TeX cell {\color[named]{Blue}\begin{verbatim} @fierz!(%)( \psi_{\mu}, \psi_{\rho}, \epsilon, \psi_{\sigma\kappa} ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{\nu \rho \sigma} \psi_{\rho \sigma} e + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{\mu \rho \sigma} \psi_{\nu \sigma} e + \frac{1}{8}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\sigma} \psi_{\sigma} \bar{\epsilon} \psi_{\nu \rho} e + \frac{1}{8}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\kappa} \Gamma^{\sigma} \psi_{\sigma} \bar{\epsilon} \Gamma_{\kappa} \psi_{\nu \rho} e + \frac{1}{16}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\kappa \lambda} \Gamma^{\sigma} \psi_{\sigma} \bar{\epsilon} \Gamma_{\lambda \kappa} \psi_{\nu \rho} e + \frac{1}{48}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\kappa \lambda \alpha} \Gamma^{\sigma} \psi_{\sigma} \bar{\epsilon} \Gamma_{\alpha \lambda \kappa} \psi_{\nu \rho} e + \frac{1}{192}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\kappa \lambda \alpha \beta} \Gamma^{\sigma} \psi_{\sigma} \bar{\epsilon} \Gamma_{\beta \alpha \lambda \kappa} \psi_{\nu \rho} e - \frac{1}{8}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho \sigma} \Gamma^{\mu} \psi_{\sigma} \bar{\epsilon} \psi_{\nu \rho} e - \frac{1}{8}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho \sigma} \Gamma^{\kappa} \Gamma^{\mu} \psi_{\sigma} \bar{\epsilon} \Gamma_{\kappa} \psi_{\nu \rho} e - \frac{1}{16}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho \sigma} \Gamma^{\kappa \lambda} \Gamma^{\mu} \psi_{\sigma} \bar{\epsilon} \Gamma_{\lambda \kappa} \psi_{\nu \rho} e - \frac{1}{48}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho \sigma} \Gamma^{\kappa \lambda \alpha} \Gamma^{\mu} \psi_{\sigma} \bar{\epsilon} \Gamma_{\alpha \lambda \kappa} \psi_{\nu \rho} e - \frac{1}{192}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho \sigma} \Gamma^{\kappa \lambda \alpha \beta} \Gamma^{\mu} \psi_{\sigma} \bar{\epsilon} \Gamma_{\beta \alpha \lambda \kappa} \psi_{\nu \rho} e - \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\sigma} \psi_{\rho} \bar{\epsilon} \psi_{\nu \sigma} e - \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\kappa} \Gamma^{\sigma} \psi_{\rho} \bar{\epsilon} \Gamma_{\kappa} \psi_{\nu \sigma} e - \frac{1}{8}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\kappa \lambda} \Gamma^{\sigma} \psi_{\rho} \bar{\epsilon} \Gamma_{\lambda \kappa} \psi_{\nu \sigma} e - \frac{1}{24}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\kappa \lambda \alpha} \Gamma^{\sigma} \psi_{\rho} \bar{\epsilon} \Gamma_{\alpha \lambda \kappa} \psi_{\nu \sigma} e - \frac{1}{96}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} \Gamma^{\kappa \lambda \alpha \beta} \Gamma^{\sigma} \psi_{\rho} \bar{\epsilon} \Gamma_{\beta \alpha \lambda \kappa} \psi_{\nu \sigma} e; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @prodsort!(%): @join!(%){expand}: @distribute!(%): @prodsort!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{\nu \rho \sigma} \psi_{\rho \sigma} e + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{\mu \rho \sigma} \psi_{\nu \sigma} e + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma_{\rho \sigma \kappa} \psi_{\lambda \alpha} e g^{\nu \rho} g^{\sigma \lambda} g^{\kappa \alpha} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma_{\sigma \kappa \lambda} \psi_{\nu \alpha} e g^{\mu \sigma} g^{\rho \kappa} g^{\lambda \alpha} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu} \psi_{\rho} \bar{\epsilon} \Gamma_{\nu \sigma \kappa \lambda} \psi_{\alpha \beta} e g^{\rho \sigma} g^{\kappa \alpha} g^{\lambda \beta} + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho} \psi_{\sigma} \bar{\epsilon} \Gamma_{\nu \kappa \lambda \alpha} \psi_{\rho \beta} e g^{\mu \kappa} g^{\sigma \lambda} g^{\alpha \beta}; \end{dmath*} % Begin TeX cell closed Finally, eliminate the metric and collect terms. % End TeX cell {\color[named]{Blue}\begin{verbatim} @eliminate_metric!(%)( \Gamma_{\sigma\kappa\lambda}, \Gamma_{\sigma\kappa\lambda\rho} ): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{3}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{\nu \rho \sigma} \psi_{\rho \sigma} e + \frac{3}{4}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{\mu \rho \sigma} \psi_{\nu \sigma} e - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu} \psi_{\rho} \bar{\epsilon} \Gamma_{\nu}\,^{\rho \sigma \kappa} \psi_{\sigma \kappa} e + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho} \psi_{\sigma} \bar{\epsilon} \Gamma_{\nu}\,^{\mu \sigma \kappa} \psi_{\rho \kappa} e; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{3}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{\nu \rho \sigma} \psi_{\rho \sigma} e + \frac{3}{4}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{\mu \rho \sigma} \psi_{\nu \sigma} e - \frac{1}{2}\, \bar{\psi_{\kappa}} \Gamma^{\kappa \mu} \psi_{\nu} \bar{\epsilon} \Gamma_{\mu}\,^{\nu \rho \sigma} \psi_{\rho \sigma} e - \frac{1}{2}\, \bar{\psi_{\kappa}} \Gamma^{\mu \nu} \psi_{\rho} \bar{\epsilon} \Gamma_{\kappa}\,^{\mu \rho \sigma} \psi_{\nu \sigma} e; \end{dmath*} % Begin TeX cell closed Since this does not quite vanish yet, we try to first verify the van Nieuwenhuizen result. See page 213. % End TeX cell {\color[named]{Blue}\begin{verbatim} tst:= -1/4 \epsilon^{\mu\nu\rho\sigma} \epsilon_{m n p q} \bar{\psi_{\mu}} \Gamma_{m n p q} \Gamma_{r} \psi_{\rho\sigma} \bar{\epsilon}\Gamma_{r}\psi_{\nu}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= (\frac{-1}{4})\, \bar{\psi_{\mu}} \Gamma_{m n p q} \Gamma_{r} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= (\frac{-1}{4})\, \bar{\psi_{\mu}} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} (\Gamma_{m n p} \delta_{q r} - \Gamma_{m n q} \delta_{p r} + \Gamma_{m p q} \delta_{n r} - \Gamma_{n p q} \delta_{m r}) \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= - \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m n p} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p r} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu} + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m n q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n r q} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu} - \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m p q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m r p q} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu} + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{n p q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{r n p q} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= (-1)\, \bar{\psi_{\mu}} \Gamma_{m n p} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu \rho} \bar{\epsilon} \Gamma_{q} \psi_{\sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @fierz!(%){ \psi_{\mu}, \psi_{\nu}, \epsilon, \psi_{\mu\nu} }; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \psi_{\nu \rho} + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{r} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu \rho} + \frac{1}{8}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{r s} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \Gamma_{s r} \psi_{\nu \rho} + \frac{1}{24}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{r s t} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \Gamma_{t s r} \psi_{\nu \rho} + \frac{1}{96}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{r s t u} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \Gamma_{u t s r} \psi_{\nu \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @join!(%){expand}: @distribute!(%): @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma_{m} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu} \bar{\epsilon} \Gamma_{n p q} \psi_{\rho \sigma} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma_{m n} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m p q r} \psi_{\nu} \bar{\epsilon} \Gamma_{n p q r} \psi_{\rho \sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} torep:=\Gamma_{m n} \epsilon_{m p q r}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] torep\specialcolon{}= \Gamma_{m n} \epsilon_{m p q r}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @decompose_product!(%): @canonicalise!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] torep\specialcolon{}= \frac{3}{4}\, \Gamma_{n m} \epsilon_{p q r m} + \frac{1}{4}\, \Gamma_{p m} \epsilon_{n q r m} - \frac{1}{4}\, \Gamma_{q m} \epsilon_{n p r m} + \frac{1}{4}\, \Gamma_{r m} \epsilon_{n p q m}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(tst)( \Gamma_{m n} \epsilon_{m p q r} -> @(torep) ): @distribute!(%): @canonicalise!(%): @collect_terms!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma_{m} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu} \bar{\epsilon} \Gamma_{n p q} \psi_{\rho \sigma}; \end{dmath*} % Begin TeX cell closed This is supposed to be proportional to % End TeX cell {\color[named]{Blue}\begin{verbatim} tst2:= 1/8 \epsilon^{\mu\nu\rho\sigma} \epsilon_{m n p q} \bar{\psi_{\mu}} \Gamma_{r} \psi_{\nu} \bar{\epsilon} \Gamma_{r}\Gamma_{m n p q}\psi_{\rho\sigma}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] tst2\specialcolon{}= \frac{1}{8}\, \bar{\psi_{\mu}} \Gamma_{r} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu} \bar{\epsilon} \Gamma_{r} \Gamma_{m n p q} \psi_{\rho \sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] tst2\specialcolon{}= \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma_{m} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu} \bar{\epsilon} \Gamma_{n p q} \psi_{\rho \sigma}; \end{dmath*} \begin{verbatim} @join: not applicable. @distribute: not applicable. \end{verbatim} {\color[named]{Blue}\begin{verbatim} @(tst)-@(tst2); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 18\specialcolon{}= 0; \end{dmath*} % Begin TeX cell closed Some random tests inspired by what happened above. % End TeX cell {\color[named]{Blue}\begin{verbatim} \epsilon_{m n p q} \Gamma_{m n p q} \Gamma_{r} \Gamma_{s t} \Gamma_{r}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \Gamma_{m n p q} \Gamma_{r} \Gamma_{s t} \Gamma_{r} \epsilon_{m n p q}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= (\Gamma_{m n p} \delta_{q r} - \Gamma_{m n q} \delta_{p r} + \Gamma_{m p q} \delta_{n r} - \Gamma_{n p q} \delta_{m r}) \Gamma_{s t} \Gamma_{r} \epsilon_{m n p q}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \Gamma_{m n p} \Gamma_{s t} \Gamma_{q} \epsilon_{m n p q} - \Gamma_{m n q} \Gamma_{s t} \Gamma_{p} \epsilon_{m n p q} + \Gamma_{m p q} \Gamma_{s t} \Gamma_{n} \epsilon_{m n p q} - \Gamma_{n p q} \Gamma_{s t} \Gamma_{m} \epsilon_{m n p q}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= (\Gamma_{m n t} \delta_{p s} - \Gamma_{m n s} \delta_{p t} - \Gamma_{m p t} \delta_{n s} + \Gamma_{m p s} \delta_{n t} + \Gamma_{n p t} \delta_{m s} - \Gamma_{n p s} \delta_{m t} + \Gamma_{m} \delta_{n t} \delta_{p s} - \Gamma_{m} \delta_{n s} \delta_{p t} - \Gamma_{p} \delta_{m s} \delta_{n t} + \Gamma_{p} \delta_{m t} \delta_{n s} + \Gamma_{n} \delta_{m s} \delta_{p t} - \Gamma_{n} \delta_{m t} \delta_{p s}) \Gamma_{q} \epsilon_{m n p q} - (\Gamma_{m n t} \delta_{q s} - \Gamma_{m n s} \delta_{q t} - \Gamma_{m q t} \delta_{n s} + \Gamma_{m q s} \delta_{n t} + \Gamma_{n q t} \delta_{m s} - \Gamma_{n q s} \delta_{m t} + \Gamma_{m} \delta_{n t} \delta_{q s} - \Gamma_{m} \delta_{n s} \delta_{q t} - \Gamma_{q} \delta_{m s} \delta_{n t} + \Gamma_{q} \delta_{m t} \delta_{n s} + \Gamma_{n} \delta_{m s} \delta_{q t} - \Gamma_{n} \delta_{m t} \delta_{q s}) \Gamma_{p} \epsilon_{m n p q} + (\Gamma_{m p t} \delta_{q s} - \Gamma_{m p s} \delta_{q t} - \Gamma_{m q t} \delta_{p s} + \Gamma_{m q s} \delta_{p t} + \Gamma_{p q t} \delta_{m s} - \Gamma_{p q s} \delta_{m t} + \Gamma_{m} \delta_{p t} \delta_{q s} - \Gamma_{m} \delta_{p s} \delta_{q t} - \Gamma_{q} \delta_{m s} \delta_{p t} + \Gamma_{q} \delta_{m t} \delta_{p s} + \Gamma_{p} \delta_{m s} \delta_{q t} - \Gamma_{p} \delta_{m t} \delta_{q s}) \Gamma_{n} \epsilon_{m n p q} - (\Gamma_{n p t} \delta_{q s} - \Gamma_{n p s} \delta_{q t} - \Gamma_{n q t} \delta_{p s} + \Gamma_{n q s} \delta_{p t} + \Gamma_{p q t} \delta_{n s} - \Gamma_{p q s} \delta_{n t} + \Gamma_{n} \delta_{p t} \delta_{q s} - \Gamma_{n} \delta_{p s} \delta_{q t} - \Gamma_{q} \delta_{n s} \delta_{p t} + \Gamma_{q} \delta_{n t} \delta_{p s} + \Gamma_{p} \delta_{n s} \delta_{q t} - \Gamma_{p} \delta_{n t} \delta_{q s}) \Gamma_{m} \epsilon_{m n p q}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \Gamma_{m n t} \Gamma_{q} \epsilon_{m n s q} - \Gamma_{m n s} \Gamma_{q} \epsilon_{m n t q} - \Gamma_{m p t} \Gamma_{q} \epsilon_{m s p q} + \Gamma_{m p s} \Gamma_{q} \epsilon_{m t p q} + \Gamma_{n p t} \Gamma_{q} \epsilon_{s n p q} - \Gamma_{n p s} \Gamma_{q} \epsilon_{t n p q} + \Gamma_{m} \Gamma_{q} \epsilon_{m t s q} - \Gamma_{m} \Gamma_{q} \epsilon_{m s t q} - \Gamma_{p} \Gamma_{q} \epsilon_{s t p q} + \Gamma_{p} \Gamma_{q} \epsilon_{t s p q} + \Gamma_{n} \Gamma_{q} \epsilon_{s n t q} - \Gamma_{n} \Gamma_{q} \epsilon_{t n s q} - \Gamma_{m n t} \Gamma_{p} \epsilon_{m n p s} + \Gamma_{m n s} \Gamma_{p} \epsilon_{m n p t} + \Gamma_{m q t} \Gamma_{p} \epsilon_{m s p q} - \Gamma_{m q s} \Gamma_{p} \epsilon_{m t p q} - \Gamma_{n q t} \Gamma_{p} \epsilon_{s n p q} + \Gamma_{n q s} \Gamma_{p} \epsilon_{t n p q} - \Gamma_{m} \Gamma_{p} \epsilon_{m t p s} + \Gamma_{m} \Gamma_{p} \epsilon_{m s p t} + \Gamma_{q} \Gamma_{p} \epsilon_{s t p q} - \Gamma_{q} \Gamma_{p} \epsilon_{t s p q} - \Gamma_{n} \Gamma_{p} \epsilon_{s n p t} + \Gamma_{n} \Gamma_{p} \epsilon_{t n p s} + \Gamma_{m p t} \Gamma_{n} \epsilon_{m n p s} - \Gamma_{m p s} \Gamma_{n} \epsilon_{m n p t} - \Gamma_{m q t} \Gamma_{n} \epsilon_{m n s q} + \Gamma_{m q s} \Gamma_{n} \epsilon_{m n t q} + \Gamma_{p q t} \Gamma_{n} \epsilon_{s n p q} - \Gamma_{p q s} \Gamma_{n} \epsilon_{t n p q} + \Gamma_{m} \Gamma_{n} \epsilon_{m n t s} - \Gamma_{m} \Gamma_{n} \epsilon_{m n s t} - \Gamma_{q} \Gamma_{n} \epsilon_{s n t q} + \Gamma_{q} \Gamma_{n} \epsilon_{t n s q} + \Gamma_{p} \Gamma_{n} \epsilon_{s n p t} - \Gamma_{p} \Gamma_{n} \epsilon_{t n p s} - \Gamma_{n p t} \Gamma_{m} \epsilon_{m n p s} + \Gamma_{n p s} \Gamma_{m} \epsilon_{m n p t} + \Gamma_{n q t} \Gamma_{m} \epsilon_{m n s q} - \Gamma_{n q s} \Gamma_{m} \epsilon_{m n t q} - \Gamma_{p q t} \Gamma_{m} \epsilon_{m s p q} + \Gamma_{p q s} \Gamma_{m} \epsilon_{m t p q} - \Gamma_{n} \Gamma_{m} \epsilon_{m n t s} + \Gamma_{n} \Gamma_{m} \epsilon_{m n s t} + \Gamma_{q} \Gamma_{m} \epsilon_{m s t q} - \Gamma_{q} \Gamma_{m} \epsilon_{m t s q} - \Gamma_{p} \Gamma_{m} \epsilon_{m s p t} + \Gamma_{p} \Gamma_{m} \epsilon_{m t p s}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \epsilon_{m n s q} (\Gamma_{m n t q} + \Gamma_{m n} \delta_{q t} - \Gamma_{m t} \delta_{n q} + \Gamma_{n t} \delta_{m q}) - \epsilon_{m n t q} (\Gamma_{m n s q} + \Gamma_{m n} \delta_{q s} - \Gamma_{m s} \delta_{n q} + \Gamma_{n s} \delta_{m q}) - \epsilon_{m s p q} (\Gamma_{m p t q} + \Gamma_{m p} \delta_{q t} - \Gamma_{m t} \delta_{p q} + \Gamma_{p t} \delta_{m q}) + \epsilon_{m t p q} (\Gamma_{m p s q} + \Gamma_{m p} \delta_{q s} - \Gamma_{m s} \delta_{p q} + \Gamma_{p s} \delta_{m q}) + \epsilon_{s n p q} (\Gamma_{n p t q} + \Gamma_{n p} \delta_{q t} - \Gamma_{n t} \delta_{p q} + \Gamma_{p t} \delta_{n q}) - \epsilon_{t n p q} (\Gamma_{n p s q} + \Gamma_{n p} \delta_{q s} - \Gamma_{n s} \delta_{p q} + \Gamma_{p s} \delta_{n q}) + \epsilon_{m t s q} (\Gamma_{m q} + \delta_{m q}) - \epsilon_{m s t q} (\Gamma_{m q} + \delta_{m q}) - \epsilon_{s t p q} (\Gamma_{p q} + \delta_{p q}) + \epsilon_{t s p q} (\Gamma_{p q} + \delta_{p q}) + \epsilon_{s n t q} (\Gamma_{n q} + \delta_{n q}) - \epsilon_{t n s q} (\Gamma_{n q} + \delta_{n q}) - \epsilon_{m n p s} (\Gamma_{m n t p} + \Gamma_{m n} \delta_{p t} - \Gamma_{m t} \delta_{n p} + \Gamma_{n t} \delta_{m p}) + \epsilon_{m n p t} (\Gamma_{m n s p} + \Gamma_{m n} \delta_{p s} - \Gamma_{m s} \delta_{n p} + \Gamma_{n s} \delta_{m p}) + \epsilon_{m s p q} (\Gamma_{m q t p} + \Gamma_{m q} \delta_{p t} - \Gamma_{m t} \delta_{p q} + \Gamma_{q t} \delta_{m p}) - \epsilon_{m t p q} (\Gamma_{m q s p} + \Gamma_{m q} \delta_{p s} - \Gamma_{m s} \delta_{p q} + \Gamma_{q s} \delta_{m p}) - \epsilon_{s n p q} (\Gamma_{n q t p} + \Gamma_{n q} \delta_{p t} - \Gamma_{n t} \delta_{p q} + \Gamma_{q t} \delta_{n p}) + \epsilon_{t n p q} (\Gamma_{n q s p} + \Gamma_{n q} \delta_{p s} - \Gamma_{n s} \delta_{p q} + \Gamma_{q s} \delta_{n p}) - \epsilon_{m t p s} (\Gamma_{m p} + \delta_{m p}) + \epsilon_{m s p t} (\Gamma_{m p} + \delta_{m p}) + \epsilon_{s t p q} (\Gamma_{q p} + \delta_{p q}) - \epsilon_{t s p q} (\Gamma_{q p} + \delta_{p q}) - \epsilon_{s n p t} (\Gamma_{n p} + \delta_{n p}) + \epsilon_{t n p s} (\Gamma_{n p} + \delta_{n p}) + \epsilon_{m n p s} (\Gamma_{m p t n} + \Gamma_{m p} \delta_{n t} - \Gamma_{m t} \delta_{n p} + \Gamma_{p t} \delta_{m n}) - \epsilon_{m n p t} (\Gamma_{m p s n} + \Gamma_{m p} \delta_{n s} - \Gamma_{m s} \delta_{n p} + \Gamma_{p s} \delta_{m n}) - \epsilon_{m n s q} (\Gamma_{m q t n} + \Gamma_{m q} \delta_{n t} - \Gamma_{m t} \delta_{n q} + \Gamma_{q t} \delta_{m n}) + \epsilon_{m n t q} (\Gamma_{m q s n} + \Gamma_{m q} \delta_{n s} - \Gamma_{m s} \delta_{n q} + \Gamma_{q s} \delta_{m n}) + \epsilon_{s n p q} (\Gamma_{p q t n} + \Gamma_{p q} \delta_{n t} - \Gamma_{p t} \delta_{n q} + \Gamma_{q t} \delta_{n p}) - \epsilon_{t n p q} (\Gamma_{p q s n} + \Gamma_{p q} \delta_{n s} - \Gamma_{p s} \delta_{n q} + \Gamma_{q s} \delta_{n p}) + \epsilon_{m n t s} (\Gamma_{m n} + \delta_{m n}) - \epsilon_{m n s t} (\Gamma_{m n} + \delta_{m n}) - \epsilon_{s n t q} (\Gamma_{q n} + \delta_{n q}) + \epsilon_{t n s q} (\Gamma_{q n} + \delta_{n q}) + \epsilon_{s n p t} (\Gamma_{p n} + \delta_{n p}) - \epsilon_{t n p s} (\Gamma_{p n} + \delta_{n p}) - \epsilon_{m n p s} (\Gamma_{n p t m} + \Gamma_{n p} \delta_{m t} - \Gamma_{n t} \delta_{m p} + \Gamma_{p t} \delta_{m n}) + \epsilon_{m n p t} (\Gamma_{n p s m} + \Gamma_{n p} \delta_{m s} - \Gamma_{n s} \delta_{m p} + \Gamma_{p s} \delta_{m n}) + \epsilon_{m n s q} (\Gamma_{n q t m} + \Gamma_{n q} \delta_{m t} - \Gamma_{n t} \delta_{m q} + \Gamma_{q t} \delta_{m n}) - \epsilon_{m n t q} (\Gamma_{n q s m} + \Gamma_{n q} \delta_{m s} - \Gamma_{n s} \delta_{m q} + \Gamma_{q s} \delta_{m n}) - \epsilon_{m s p q} (\Gamma_{p q t m} + \Gamma_{p q} \delta_{m t} - \Gamma_{p t} \delta_{m q} + \Gamma_{q t} \delta_{m p}) + \epsilon_{m t p q} (\Gamma_{p q s m} + \Gamma_{p q} \delta_{m s} - \Gamma_{p s} \delta_{m q} + \Gamma_{q s} \delta_{m p}) - \epsilon_{m n t s} (\Gamma_{n m} + \delta_{m n}) + \epsilon_{m n s t} (\Gamma_{n m} + \delta_{m n}) + \epsilon_{m s t q} (\Gamma_{q m} + \delta_{m q}) - \epsilon_{m t s q} (\Gamma_{q m} + \delta_{m q}) - \epsilon_{m s p t} (\Gamma_{p m} + \delta_{m p}) + \epsilon_{m t p s} (\Gamma_{p m} + \delta_{m p}); \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \Gamma_{m n t q} \epsilon_{m n s q} + \Gamma_{m n} \epsilon_{m n s t} - \Gamma_{m n s q} \epsilon_{m n t q} - \Gamma_{m n} \epsilon_{m n t s} - \Gamma_{m p t q} \epsilon_{m s p q} - \Gamma_{m p} \epsilon_{m s p t} + \Gamma_{m p s q} \epsilon_{m t p q} + \Gamma_{m p} \epsilon_{m t p s} + \Gamma_{n p t q} \epsilon_{s n p q} + \Gamma_{n p} \epsilon_{s n p t} - \Gamma_{n p s q} \epsilon_{t n p q} - \Gamma_{n p} \epsilon_{t n p s} - \Gamma_{m q} \epsilon_{m t s q} + \Gamma_{m q} \epsilon_{m s t q} + \Gamma_{p q} \epsilon_{s t p q} - \Gamma_{p q} \epsilon_{t s p q} - \Gamma_{n q} \epsilon_{s n t q} + \Gamma_{n q} \epsilon_{t n s q} - \Gamma_{m n t p} \epsilon_{m n p s} + \Gamma_{m n s p} \epsilon_{m n p t} + \Gamma_{m q t p} \epsilon_{m s p q} - \Gamma_{m q s p} \epsilon_{m t p q} - \Gamma_{n q t p} \epsilon_{s n p q} + \Gamma_{n q s p} \epsilon_{t n p q} + \Gamma_{q p} \epsilon_{s t p q} - \Gamma_{q p} \epsilon_{t s p q} + \Gamma_{m p t n} \epsilon_{m n p s} - \Gamma_{m p s n} \epsilon_{m n p t} - \Gamma_{m q t n} \epsilon_{m n s q} + \Gamma_{m q s n} \epsilon_{m n t q} + \Gamma_{p q t n} \epsilon_{s n p q} - \Gamma_{p q s n} \epsilon_{t n p q} - \Gamma_{q n} \epsilon_{s n t q} + \Gamma_{q n} \epsilon_{t n s q} + \Gamma_{p n} \epsilon_{s n p t} - \Gamma_{p n} \epsilon_{t n p s} - \Gamma_{n p t m} \epsilon_{m n p s} + \Gamma_{n p s m} \epsilon_{m n p t} + \Gamma_{n q t m} \epsilon_{m n s q} - \Gamma_{n q s m} \epsilon_{m n t q} - \Gamma_{p q t m} \epsilon_{m s p q} + \Gamma_{p q s m} \epsilon_{m t p q} - \Gamma_{n m} \epsilon_{m n t s} + \Gamma_{n m} \epsilon_{m n s t} + \Gamma_{q m} \epsilon_{m s t q} - \Gamma_{q m} \epsilon_{m t s q} - \Gamma_{p m} \epsilon_{m s p t} + \Gamma_{p m} \epsilon_{m t p s}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= 3\, \Gamma_{t m n q} \epsilon_{s m n q} - 3\, \Gamma_{s m n q} \epsilon_{t m n q} + 3\, \Gamma_{t m p q} \epsilon_{s m p q} - 3\, \Gamma_{s m p q} \epsilon_{t m p q} + 3\, \Gamma_{t n p q} \epsilon_{s n p q} - 3\, \Gamma_{s n p q} \epsilon_{t n p q} + 3\, \Gamma_{t m n p} \epsilon_{s m n p} - 3\, \Gamma_{s m n p} \epsilon_{t m n p}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @rename_dummies!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= 12\, \Gamma_{t m n p} \epsilon_{s m n p} - 12\, \Gamma_{s m n p} \epsilon_{t m n p}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @decompose_product!(%): @canonicalise!(%): \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= 0; \end{dmath*} \begin{verbatim} @collect_terms: not applicable. \end{verbatim} {\color[named]{Blue}\begin{verbatim} \Gamma_{r} \Gamma_{s t} \Gamma_{r}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= \Gamma_{r} \Gamma_{s t} \Gamma_{r}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= (\Gamma_{r s t} + \Gamma_{t} \delta_{r s} - \Gamma_{s} \delta_{r t}) \Gamma_{r}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= \Gamma_{r s t} \Gamma_{r} + \Gamma_{t} \Gamma_{s} - \Gamma_{s} \Gamma_{t}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= \Gamma_{r s t r} + 2\, \Gamma_{t s} + 2\, \Gamma_{s t}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= 0; \end{dmath*} \end{document} cadabra-0.115/gui/0000700000077000007700000000000010622301241013216 5ustar kantorkantorcadabra-0.115/gui/cadabra.el0000600000077000007700000000112107733546245015142 0ustar kantorkantor(defun cadabra-insertion-filter (proc string) (with-current-buffer (process-buffer proc) (let ((moving (= (point) (process-mark proc)))) (save-excursion ;; Insert the text, advancing the process marker. (goto-char (process-mark proc)) (insert string) (set-marker (process-mark proc) (point))) (if moving (goto-char (process-mark proc)))))) (setq cdbproc (start-process "cadabra" "cadabra" "cadabra")) (process-send-string cdbproc "@algorithms;\n") \begin{cdb} W_{a b c d} W_{e d e g}; @canonicalise!(%); % W_{a b c d} W_{e d e g}; \end{cdb}cadabra-0.115/gui/main.cc0000600000077000007700000001166110612672010014464 0ustar kantorkantor/* $Id: main.cc,v 1.29 2007/04/20 12:06:34 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2001-2006 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "window.hh" std::map connections; std::ofstream debugout; bool verify_breqn_presence() { char templ[10]="cdbXXXXXX"; std::ostringstream total; // First test LaTeX without any style files. int fd = mkstemp(templ); total << "\\documentclass{article}\n" << "\\begin{document}\n" << "test\n" << "\\end{document}\n"; write(fd, total.str().c_str(), total.str().size()); close(fd); std::string nf=std::string(templ)+".tex"; rename(templ, nf.c_str()); std::string cmd=std::string("latex --interaction nonstopmode ")+nf+" >/dev/null 2>&1"; int ret=system(cmd.c_str()); unlink(nf.c_str()); cmd=std::string(templ)+".aux"; unlink(cmd.c_str()); cmd=std::string(templ)+".dvi"; unlink(cmd.c_str()); cmd=std::string(templ)+".log"; unlink(cmd.c_str()); if(ret==-1) { std::cerr << "XCadabra: LaTeX not installed." << std::endl; sleep(1); return false; } if(ret!=0) { std::cerr << "XCadabra: LaTeX not installed properly." << std::endl; sleep(1); return false; } // Then test whether breqn can be included. char templ2[10]="cdbXXXXXX"; fd = mkstemp(templ2); total.str(""); total << "\\documentclass{article}\n" << "\\usepackage{breqn}\n" << "\\begin{document}\n" << "test\n" << "\\end{document}\n"; write(fd, total.str().c_str(), total.str().size()); close(fd); nf=std::string(templ2)+".tex"; rename(templ2, nf.c_str()); cmd=std::string("latex --interaction nonstopmode ")+nf+" >/dev/null 2>&1"; ret=system(cmd.c_str()); unlink(nf.c_str()); cmd=std::string(templ2)+".aux"; unlink(cmd.c_str()); cmd=std::string(templ2)+".dvi"; unlink(cmd.c_str()); cmd=std::string(templ2)+".log"; unlink(cmd.c_str()); if(ret==-1) { std::cerr << "XCadabra: LaTeX not installed." << std::endl; sleep(1); return false; } if(ret!=0) { std::cerr << "XCadabra: the breqn.sty style file is not in LaTeX's TEXINPUTS." << std::endl; sleep(1); return false; } return true; } int main (int argc, char *argv[]) { // Open the debug output file, if requested. char hostname[256]; gethostname(hostname, 255); char *pbs_job=getenv("PBS_JOBID"); std::string logname=std::string("cdb_")+hostname+(pbs_job==0?"":std::string("_")+pbs_job) +std::string(".log"); char *cdblog=getenv("CDB_LOG"); if(cdblog==0) debugout.open("/dev/null", std::ios::app); else switch(atoi(cdblog)) { case 1: debugout.open(logname.c_str(), std::ios::app); break; case 2: debugout.open("/dev/tty", std::ios::app); break; } // Ensure correct installation. if(!verify_breqn_presence()) return -1; Gtk::Main kit(&argc, &argv); modglue::main mm(argc, argv); // Set the environment for cadabra. // setenv("CDB_USE_UTF8", "1", 1); unsetenv("CDB_PRINTSTAR");//, "false", 1); // Argument parsing std::string filename; if(argc>1) filename=argv[1]; // modglue::ext_process ls_proc(std::string(DESTDIR)+std::string("/bin/cadabra")); modglue::ext_process ls_proc("cadabra"); ls_proc << "--xcadabra"; ls_proc.setup_pipes(); // FIXME: need cleaner error messages if this is forgotten mm.add(&ls_proc); XCadabra theiface(ls_proc, filename, &mm); ls_proc.input_pipe("stdout")->receiver.connect(sigc::mem_fun(theiface, &XCadabra::receive)); ls_proc.input_pipe("stderr")->receiver.connect(sigc::mem_fun(theiface, &XCadabra::receive)); mm.process_died.connect(sigc::mem_fun(theiface, &XCadabra::on_kernel_exit)); // FIXME: if we run this afterwards, the pipes are not setup yet. Note: this also // means that if we want to start a program while in the main loop, we have to // do this connecting business again. For the time being, let cadabra run forever // and don't worry too much about this. ls_proc.fork(); // FIXME: need error message upon failure *(ls_proc.output_pipe("stdin")) << "@print_status{true};\n" << std::flush; theiface.connect_io_signals(); // If done this way, we miss signals if the process exits before // the main loop is entered. Well, cadabra doesn't do that. // mm.run(0); Gtk::Main::run(); return 0; } cadabra-0.115/gui/Makefile.in0000600000077000007700000000230410622301156015271 0ustar kantorkantor .PHONY: all MACTEST= @MAC_OS_X@ all: xcadabra static: xcadabra_static OBJS = window.o main.o CFLAGS = -O2 -I. -I@top_srcdir@/include `pkg-config modglue --cflags` `pkg-config --cflags gtkmm-2.4` \ `pkg-config --cflags pango` SRCS = `find . -name "*.cc"` TIMESTAMP = -D"RELEASE=\"${RELEASE}\"" -D"DATETIME=\"`date | sed -e 's/ / /'`\"" -DHOSTNAME=\"`hostname`\" %.o: %.cc @CXX@ -Wall @CFLAGS@ -D"DESTDIR=\"@prefix@\"" ${TIMESTAMP} ${CFLAGS} -c -o $@ $< main.o: $(OBJS) Makefile xcadabra: $(OBJS) @CXX@ -o xcadabra `pkg-config modglue --libs` `pkg-config --libs gtkmm-2.4` $+ xcadabra_static: $(OBJS) @CXX@ -o xcadabra -static $+ -L@prefix@/lib `pkg-config modglue --libs` \ `pkg-config --libs gtkmm-2.4` `pkg-config libxml++-2.6` \ -lpthread -lexpat install: install -d ${DESTDIR}@prefix@/bin install -m 0755 xcadabra ${DESTDIR}@prefix@/bin uninstall: rm -f ${DESTDIR}@prefix@/bin/xcadabra clean: rm -f *~ *.o xcadabra spawner multi distclean: clean rm -f Makefile .depend .depend: rm -f .depend for i in ${SRCS}; \ do g++ -E -MM -MT `echo $$i | sed -e 's/\.\///' -e 's/\.cc/\.o/'` ${CFLAGS} $$i >> .depend; \ done include .depend cadabra-0.115/gui/tutorial3.cnb0000600000077000007700000001246710534772740015666 0ustar kantorkantor% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\Large\bfseries Superinvariance of super QED} This notebook shows how to deal with spinors and gamma matrix algebra. % End TeX cell {\color[named]{Blue}\begin{verbatim} { a,b,c,d,e }::Indices(vector). \bar{#}::DiracBar. { \partial{#}, \ppartial{#} }::PartialDerivative. { A_{a}, f_{a b} }::Depends(\partial, \ppartial). { \epsilon, \gamma_{#} }::Depends(\bar). \lambda::Depends(\bar, \partial). { \lambda, \gamma_{#} }::NonCommuting. { \lambda, \epsilon }::Spinor(dimension=4, type=Majorana). { \epsilon, \lambda }::SortOrder. { \epsilon, \lambda }::AntiCommuting. \lambda::SelfAntiCommuting. \gamma_{#}::GammaMatrix(metric=\delta). \delta{#}::Accent. f_{a b}::AntiSymmetric. \delta_{a b}::KroneckerDelta. \end{verbatim}} \begin{verbatim} Assigning property Indices to a, b, c, d, e. Assigning property DiracBar to \bar. Assigning property PartialDerivative to \partial, \ppartial. Assigning property Depends to A, f. Assigning property Depends to \epsilon, \gamma. Assigning property Depends to \lambda. Assigning property NonCommuting to \lambda, \gamma. Assigning property Spinor to \lambda, \epsilon. Assigning property SortOrder to \epsilon, \lambda. Assigning property AntiCommuting to \epsilon, \lambda. Assigning property SelfAntiCommuting to \lambda. Assigning property GammaMatrix to \gamma. Assigning property Accent to \delta. Assigning property AntiSymmetric to f. Assigning property KroneckerDelta to \delta. \end{verbatim} {\color[named]{Blue}\begin{verbatim} ::PostDefaultRules(@@prodsort!(%), @@rename_dummies!(%), @@canonicalise!(%), @@collect_terms!(%) ). \end{verbatim}} \begin{verbatim} Assigning property PostDefaultRules to . \end{verbatim} {\color[named]{Blue}\begin{verbatim} susy:= { \delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = -(1/2) \gamma_{a b} \epsilon f_{a b} }; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] susy\specialcolon{}= \{\delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = (\frac{-1}{2})\, \gamma_{a b} \epsilon f_{a b}\}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} S:= -(1/4) f_{a b} f_{a b} - (1/2) \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{4}\, f_{a b} f_{a b} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @vary!(%)( f_{a b} -> \partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}, \lambda -> \delta{\lambda} ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{2}\, ((\partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}) f_{a b}) - \frac{1}{2}\, \bar{\delta{\lambda}} \gamma_{a} \partial_{a}{\lambda} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}{\delta{\lambda}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); @substitute!(%)( @(susy) ): @prodrule!(%): @distribute!(%): @unwrap!(%); @rewrite_diracbar!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \partial_{a}{\delta{A_{b}}} f_{a b} - \frac{1}{2}\, \bar{\delta{\lambda}} \gamma_{a} \partial_{a}{\lambda} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}{\delta{\lambda}}; \end{dmath*} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} + \frac{1}{4}\, \bar{\gamma_{a b} \epsilon} \gamma_{c} \partial_{c}{\lambda} f_{a b} + \frac{1}{4}\, \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; \end{dmath*} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} + \frac{1}{4}\, \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; \end{dmath*} \begin{verbatim} Warning: assuming Minkowski signature. \end{verbatim} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \partial_{c}{f_{a b}} -> \ppartial_{c}{f_{a b}} ): @pintegrate!(%){\ppartial}: @rename!(%){"\ppartial"}{"\partial"}: @prodrule!(%): @unwrap!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} - \frac{1}{4}\, \partial_{a}{\bar{\lambda}} \gamma_{a} \gamma_{b c} \epsilon f_{b c}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @substitute!(%)( \partial_{a}{\bar{\lambda}} -> \bar{\partial_{a}{\lambda}} ); @spinorsort!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \frac{1}{2}\, \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c} - \frac{1}{4}\, \bar{\partial_{a}{\lambda}} \gamma_{a b c} \epsilon f_{b c} - \frac{1}{2}\, \bar{\partial_{a}{\lambda}} \gamma_{b} \epsilon f_{a b}; \end{dmath*} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= (\frac{-1}{2})\, \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c}; \end{dmath*} \end{document} cadabra-0.115/gui/window.cc0000600000077000007700000020366510622301156015057 0ustar kantorkantor/* $Id: window.cc,v 1.88 2007/05/08 09:11:04 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2001-2006 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "window.hh" #include #include #include #include #include #include #include // #define DEBUG 1 #define LINE_SPACING 3 extern std::ofstream debugout; #define THEFONT "cmtt12" // General tool to strip spaces from both ends inline std::string trim(const std::string& s) { if(s.length() == 0) return s; int b = s.find_first_not_of(" \t\n"); int e = s.find_last_not_of(" \t\n"); if(b == -1) // No non-spaces return ""; return std::string(s, b, e - b + 1); } TeXBuffer::TeXBuffer(Glib::RefPtr tb, int fs) : tex_source(tb), foreground_colour("black"), font_size(fs) { } void TeXBuffer::generate(const std::string& startwrap, const std::string& endwrap, int horizontal_pixels) { start_wrap_=startwrap; end_wrap_=endwrap; horizontal_pixels_=horizontal_pixels; regenerate(); } void TeXBuffer::regenerate() { char templ[10]="cdbXXXXXX"; // The size in mm or inches which we use will in the end determine how large // the font will come out. // // For given horizontal size, we stretch this up to the full window // width using horizontal_pixels/(horizontal_size/millimeter_per_inch) dots per inch. // The appropriate horizontal size in mm is determined by trial and error, // and of course scales with the number of horizontal pixels. const double horizontal_mm=horizontal_pixels_*(12.0/font_size)/3.94; //(int)(millimeter_per_inch*horizontal_pixels/100.0); //140; const double vertical_mm=10*horizontal_mm; // Write to .tex file and run latex. std::ostringstream total; int fd = mkstemp(templ); total << "\\documentclass[12pt]{article}\n" << "\\usepackage[dvips,voffset=0pt,hoffset=0pt,textwidth=" << horizontal_mm << "mm,textheight=" << vertical_mm << "mm]{geometry}\n" << "\\usepackage{color}\n" << "\\usepackage[parfill]{parskip}\n\\usepackage{breqn}\n" << "\\def\\specialcolon{\\mathrel{\\mathop{:}}\\hspace{-.5em}}\n" << "\\renewcommand{\\bar}[1]{\\overline{#1}}\n" << "\\begin{document}\n\\pagestyle{empty}\n"; if(tex_source->get_text().size()>100000) total << "Expression too long, output suppressed.\n"; else { if(start_wrap_.size()>0) total << start_wrap_; total << tex_source->get_text(); if(end_wrap_.size()>0) total << "\n" << end_wrap_; else total << "\n"; } total << "\\end{document}\n"; write(fd, total.str().c_str(), total.str().size()); debugout << templ << std::endl; close(fd); debugout << "---\n" << total.str() << "\n---" << std::endl; std::string nf=std::string(templ)+".tex"; rename(templ, nf.c_str()); modglue::child_process latex_proc("latex"); latex_proc << "--interaction" << "nonstopmode" << nf; std::string result; try { latex_proc.call("", result); debugout << result << std::endl; } catch(std::logic_error& err) { unlink(nf.c_str()); throw std::logic_error("Cannot start LaTeX, is it installed?"); } // if(ret!=0 && errno!=10) { // unlink(nf.c_str()); // throw std::logic_error("LaTeX failed, incorrect source?"); // } // Convert to png. std::ostringstream cmdstr; cmdstr << "dvipng -v "; #ifndef DEBUG cmdstr << "-q* 1>/dev/null 2>&1 "; #endif cmdstr << "-T tight -bg Transparent -fg \"rgb " << foreground_colour.get_red()/65536.0 << " " << foreground_colour.get_green()/65536.0 << " " << foreground_colour.get_blue()/65536.0 << "\" -D "; cmdstr << horizontal_pixels_/(1.0*horizontal_mm)*millimeter_per_inch; cmdstr << " " << std::string(templ) << ".dvi" << std::ends; #ifdef DEBUG std::cerr << cmdstr.str() << std::endl; #endif int ret=system(cmdstr.str().c_str()); if(ret==-1 && errno!=10) throw std::logic_error("Cannot start dvipng, is it installed?"); if(ret!=0 && errno!=10) throw std::logic_error("The dvipng failed, ignoring output."); std::string cmd=std::string(templ)+"1.png"; pixbuf = Gdk::Pixbuf::create_from_file(cmd); #ifdef DEBUG std::cerr << "image created, cleaning up" << std::endl; #endif // Remove all temporaries. unlink(cmd.c_str()); cmd=std::string(templ)+".tex"; unlink(cmd.c_str()); cmd=std::string(templ)+".aux"; unlink(cmd.c_str()); cmd=std::string(templ)+".dvi"; unlink(cmd.c_str()); cmd=std::string(templ)+".log"; unlink(cmd.c_str()); #ifdef DEBUG std::cerr << "generating done" << std::endl; #endif } TeXView::TeXView(Glib::RefPtr texb, int hmargin) : texbuf(texb), vbox(false, 10), hbox(false, hmargin) { add(vbox); vbox.pack_start(hbox, Gtk::PACK_SHRINK, 10); hbox.pack_start(image, Gtk::PACK_SHRINK, hmargin); image.set(texb->pixbuf); // set_state(Gtk::STATE_PRELIGHT); modify_bg(Gtk::STATE_NORMAL, Gdk::Color("white")); } //PropertyList::PropertyList() // { // set_size_request(200,900); // pack_start(scroll, true, true); // scroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); // scroll.set_border_width(1); // tv.set_editable(false); // tv.set_wrap_mode(Gtk::WRAP_WORD); // textbuf=tv.get_buffer(); // scroll.add(tv); // show_all(); // } NotebookCanvas::NotebookCanvas(XCadabra& doc_) : doc(doc_), font_size(12) { pack1(scroll, true, true); scroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); scroll.set_border_width(1); scroll.add(ebox); ebox.add(scrollbox); ebox.modify_bg(Gtk::STATE_NORMAL, Gdk::Color("white")); scrollbox.pack_start(bottomline, Gtk::PACK_SHRINK); } NotebookCanvas::~NotebookCanvas() { VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { delete (*it); ++it; } } void NotebookCanvas::redraw_cells() { VisualCells_t::iterator it=visualcells.begin(); std::ostringstream fstr; fstr << THEFONT << " " << font_size; while(it!=visualcells.end()) { switch((*it)->datacell->cell_type) { case DataCell::c_input: (*it)->inbox->edit.modify_font(Pango::FontDescription(fstr.str())); break; case DataCell::c_comment: case DataCell::c_error: case DataCell::c_output: (*it)->outbox->image.set((*it)->datacell->texbuf->pixbuf); break; case DataCell::c_tex: (*it)->texbox->edit.modify_font(Pango::FontDescription(fstr.str())); (*it)->texbox->texview.image.set((*it)->datacell->texbuf->pixbuf); break; } ++it; } } VisualCell *NotebookCanvas::add_cell(DataCell *dc, DataCell *ref, bool before) { VisualCell *newcell=new VisualCell; newcell->datacell=dc; // Temporarily remove bottom line marker. scrollbox.remove(bottomline); // Find the correct place to insert the new cell in visualcells, and keep // track of the number so we can insert the widget at the right spot in the Gtk // container later. int cellnum=0; if(ref==0) visualcells.push_back(newcell); else { VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { if((*it)->datacell==ref) { if(!before) { // skip to the next input cell do { ++it; ++cellnum; } while(it!=visualcells.end() && ( (*it)->datacell->cell_type==DataCell::c_comment || (*it)->datacell->cell_type==DataCell::c_output || (*it)->datacell->cell_type==DataCell::c_error) ); } visualcells.insert(it, newcell); break; } ++it; ++cellnum; } } #ifdef DEBUG std::cerr << "gtk logic" << std::endl; #endif Gtk::VBox::BoxList bl=scrollbox.children(); Gtk::VBox::BoxList::iterator gtkit; if(ref==0) gtkit=bl.end(); else { gtkit=bl.begin(); while(cellnum!=0) { ++gtkit; --cellnum; } } // Insert the widget in the Gtk container and connect signals. #ifdef DEBUG std::cerr << "inserting" << std::endl; #endif switch(dc->cell_type) { case DataCell::c_input: { #ifdef DEBUG std::cerr << "incell" << std::endl; #endif std::ostringstream fstr; fstr << THEFONT << " " << font_size; newcell->inbox=manage( new ExpressionInput(dc->textbuf, fstr.str()) ); Gtk::VBox::BoxList::iterator newit=bl.insert(gtkit, *newcell->inbox); gtk_box_set_child_packing(((Gtk::Box *)(&scrollbox))->gobj(), ((Gtk::Widget *)(newcell->inbox))->gobj(), false, false, 0, GTK_PACK_START); // (*newit).set_options(Gtk::PACK_SHRINK); newcell->inbox->edit.emitter.connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_editbox_output), this, newcell)); newcell->inbox->edit.signal_grab_focus().connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_on_grab_focus), this, newcell)); newcell->inbox->edit.content_changed.connect( sigc::bind( sigc::mem_fun(this, &NotebookCanvas::handle_key_press), newcell)); newcell->inbox->show_all(); break; } case DataCell::c_error: case DataCell::c_output: case DataCell::c_comment: { newcell->outbox=manage( new TeXView(dc->texbuf) ); Gtk::VBox::BoxList::iterator newit=bl.insert(gtkit, *newcell->outbox); // REPORT BUG: this sometimes segfaults // (*newit).set_options(Gtk::PACK_SHRINK); gtk_box_set_child_packing(((Gtk::Box *)(&scrollbox))->gobj(), ((Gtk::Widget *)(newcell->outbox))->gobj(), false, false, 0, GTK_PACK_START); newcell->outbox->show_all(); newcell->outbox->signal_button_release_event().connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_outbox_select), this, newcell)); break; } case DataCell::c_tex: { std::ostringstream fstr; fstr << THEFONT << " " << font_size; newcell->texbox=manage( new TeXInput(dc->textbuf, dc->texbuf, fstr.str()) ); newcell->texbox->texview.signal_button_release_event().connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_visibility_toggle), this, newcell)); newcell->texbox->edit.emitter.connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_tex_update_request), this, newcell)); Gtk::VBox::BoxList::iterator newit=bl.insert(gtkit, *newcell->texbox); gtk_box_set_child_packing(((Gtk::Box *)(&scrollbox))->gobj(), ((Gtk::Widget *)(newcell->texbox))->gobj(), false, false, 0, GTK_PACK_START); // (*newit).set_options(Gtk::PACK_SHRINK); newcell->texbox->edit.signal_grab_focus().connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_on_grab_focus), this, newcell)); // Hide source depending on setting in the datacell. newcell->texbox->texview.show_all(); if(newcell->datacell->tex_hidden) newcell->texbox->edit.hide_all(); else newcell->texbox->edit.show_all(); break; } } // Restore bottom line marker scrollbox.pack_start(bottomline, Gtk::PACK_SHRINK); bottomline.show(); return newcell; //visualcells.back(); } void NotebookCanvas::remove_cell(DataCell *dc) { int cellnum=0; VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { if((*it)->datacell==dc) break; ++it; ++cellnum; } assert(it!=visualcells.end()); switch((*it)->datacell->cell_type) { case DataCell::c_input: scrollbox.remove(*((*it)->inbox)); break; case DataCell::c_error: case DataCell::c_comment: case DataCell::c_output: scrollbox.remove(*((*it)->outbox)); break; case DataCell::c_tex: scrollbox.remove(*((*it)->texbox)); break; } visualcells.remove(*it); } void NotebookCanvas::cell_grab_focus(DataCell *dc) { VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { if((*it)->datacell==dc) { #ifdef DEBUG std::cerr << "grabbing " << dc << " " << *it << std::endl; #endif cell_grab_focus(*it); break; } ++it; } } // void NotebookCanvas::adjust_scroll(Gtk::Allocation& al) // { // Gtk::Adjustment *va=scroll.get_vadjustment(); // #ifdef DEBUG // std::cerr << va->get_value() << " vs " << al.get_y() << " + " << al.get_height() << std::endl; // std::cerr << va->get_lower() << " - " << va->get_upper() << " - " << va->get_page_size() << std::endl; // #endif // if(al.get_y()+al.get_height() < va->get_value() || // al.get_y()+al.get_height() > va->get_value() + va->get_page_size()) { // #ifdef DEBUG // std::cerr << "adjusting scrollbar to"; // // va->set_value(std::min((double)(al.get_y()), va->get_upper()-va->get_page_size())); // std::cerr << al.get_y()-va->get_page_size()+al.get_height() << std::endl; // #endif // va->set_value(std::max(0.0, // std::min((double)(al.get_y()-va->get_page_size()+al.get_height()), // va->get_upper()-va->get_page_size()))); // } // adjust_scroll_connection.disconnect(); // } void NotebookCanvas::cell_grab_focus(VisualCell *vis) { VisualCells_t::iterator it=std::find(visualcells.begin(), visualcells.end(), vis); if(it!=visualcells.end()) { switch(vis->datacell->cell_type) { case DataCell::c_input: { vis->inbox->edit.grab_focus(); // make sure the display is updated while (gtk_events_pending ()) gtk_main_iteration (); // and scroll to the right location scroll_to(vis->inbox->get_allocation()); break; } case DataCell::c_error: case DataCell::c_output: case DataCell::c_comment: break; case DataCell::c_tex: break; } } } void NotebookCanvas::scroll_to(Gtk::Allocation al) { Gtk::Adjustment *va=scroll.get_vadjustment(); if(al.get_y()+al.get_height() < va->get_value() || al.get_y()+al.get_height() > va->get_value() + va->get_page_size()) { va->set_value(std::max(0.0, std::min((double)(al.get_y()-va->get_page_size()+al.get_height()+40), va->get_upper()-va->get_page_size()))); } } bool NotebookCanvas::handle_key_press(VisualCell *vc) { Gdk::Rectangle rect; vc->inbox->edit.get_iter_location(vc->inbox->edit.get_buffer()->get_iter_at_mark( vc->inbox->edit.get_buffer()->get_insert()), rect); Gtk::Allocation al=vc->inbox->get_allocation(); Gtk::Adjustment *va=scroll.get_vadjustment(); double upper_visible=va->get_value(); double lower_visible=va->get_value()+va->get_page_size(); if(al.get_y() + rect.get_y() < upper_visible) va->set_value(std::max(0.0, (double)(al.get_y() + rect.get_y() - LINE_SPACING))); else if(al.get_y() + rect.get_y() + rect.get_height() > lower_visible) va->set_value(al.get_y() + rect.get_y() + rect.get_height() - va->get_page_size()); return false; } void NotebookCanvas::select_first_input_cell() { #ifdef DEBUG std::cerr << "select first input" << std::endl; #endif VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { #ifdef DEBUG std::cerr << "inspect" << std::endl; #endif if((*it)->datacell->cell_type==DataCell::c_input) break; ++it; } if(it!=visualcells.end()) { #ifdef DEBUG std::cerr << "notebook going to grab focus" << std::endl; #endif cell_grab_focus(*it); } } void NotebookCanvas::show() { ebox.show(); scroll.show(); scrollbox.show(); bottomline.show(); VPaned::show(); } ExpressionInput::exp_input_tv::exp_input_tv(Glib::RefPtr tb) : Gtk::TextView(tb) { } ExpressionInput::ExpressionInput(Glib::RefPtr tb, const std::string& fontname, int hmargin) : edit(tb) { // scroll_.set_size_request(-1,200); // scroll_.set_border_width(1); // scroll_.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); edit.modify_font(Pango::FontDescription(fontname)); edit.set_wrap_mode(Gtk::WRAP_WORD); edit.modify_text(Gtk::STATE_NORMAL, Gdk::Color("blue")); edit.set_pixels_above_lines(LINE_SPACING); edit.set_pixels_below_lines(LINE_SPACING); edit.set_pixels_inside_wrap(2*LINE_SPACING); edit.set_left_margin(hmargin); edit.set_accepts_tab(false); edit.signal_button_press_event().connect(sigc::mem_fun(this, &ExpressionInput::handle_button_press), false); // edit.get_buffer()->signal_changed().connect(sigc::mem_fun(this, &ExpressionInput::handle_changed)); // add(hbox); // hbox.add(vsep); // hbox.add(edit); add(edit); // set_border_width(3); show(); } bool ExpressionInput::exp_input_tv::on_key_press_event(GdkEventKey* event) { // std::cerr << event.keyval() << ", " << event.state() << " pressed" << std::endl; if(get_editable() && event->keyval==GDK_Return && (event->state&Gdk::SHIFT_MASK)) {// shift-return // std::cerr << "activate!!" << std::endl; Glib::RefPtr textbuf=get_buffer(); // std::cerr << textbuf->get_text(textbuf->get_start_iter(), textbuf->get_end_iter()) << std::endl; std::string tmp(trim(textbuf->get_text(get_buffer()->begin(), get_buffer()->end()))); if(tmp[0]!='#' && tmp[tmp.size()-1]!=';' && tmp[tmp.size()-1]!=':' && tmp[tmp.size()-1]!='.' ) { Gtk::MessageDialog md("Input error"); md.set_secondary_text("This cell does not end with a delimiter (a \":\", \";\" or \".\")"); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } else { #ifdef DEBUG std::cerr << "sending: " << tmp << std::endl; #endif content_changed(); emitter(tmp); } // set_editable(false); // textbuf->set_text(""); return true; } else { bool retval=Gtk::TextView::on_key_press_event(event); while (gtk_events_pending ()) gtk_main_iteration (); content_changed(); return retval; } } bool ExpressionInput::handle_button_press(GdkEventButton* button) { if(button->button!=2) return false; Glib::RefPtr refClipboard = Gtk::Clipboard::get(GDK_SELECTION_PRIMARY); std::vector sah=refClipboard->wait_for_targets(); for(unsigned int i=0; iwait_for_contents("cadabra"); edit.get_buffer()->insert_at_cursor(sd.get_data_as_string()); return true; } } Gtk::SelectionData sd=refClipboard->wait_for_contents("TEXT"); edit.get_buffer()->insert_at_cursor(sd.get_data_as_string()); return true; } // gdouble page_inc, step_inc, upper, lower, pos; // // GtkAdjustment* vadj = gtk_scrolled_window_get_vadjustment( // GTK_SCROLLED_WINDOW(scrolled_window)); // // page_inc = vadj->page_increment; // step_inc = vadj->step_increment; // lower = vadj->lower; // // /* Otherwise we sometimes scroll down into a page of black. */ // upper = vadj->upper - page_inc - step_inc; // // /* Center on the widget. */ // pos = (gdouble)widget->allocation.y - page_inc/2; // // gtk_adjustment_set_value(vadj, CLAMP(pos, lower, upper)); // TeXInput::exp_input_tv::exp_input_tv(Glib::RefPtr tb) : Gtk::TextView(tb) { } TeXInput::TeXInput(Glib::RefPtr tb, Glib::RefPtr texb, const std::string& fontname) : edit(tb), texview(texb, 10) { // scroll_.set_size_request(-1,200); // scroll_.set_border_width(1); // scroll_.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); edit.modify_font(Pango::FontDescription(fontname)); edit.set_wrap_mode(Gtk::WRAP_WORD); edit.modify_text(Gtk::STATE_NORMAL, Gdk::Color("darkgray")); edit.set_pixels_above_lines(3); edit.set_pixels_below_lines(3); edit.set_left_margin(10); // add(expander); // expander.set_label_widget(texview); // expander.add(edit); // expander.set_expanded(); pack_start(edit); pack_start(texview); show(); } bool TeXInput::toggle_visibility() { if(edit.is_visible()) edit.hide_all(); else edit.show_all(); return true; } bool TeXInput::exp_input_tv::on_key_press_event(GdkEventKey* event) { // std::cerr << event.keyval() << ", " << event.state() << " pressed" << std::endl; if(get_editable() && event->keyval==GDK_Return && (event->state&Gdk::SHIFT_MASK)) {// shift-return // std::cerr << "activate!!" << std::endl; Glib::RefPtr textbuf=get_buffer(); // std::cerr << textbuf->get_text(textbuf->get_start_iter(), textbuf->get_end_iter()) << std::endl; std::string tmp(textbuf->get_text(get_buffer()->begin(), get_buffer()->end())); #ifdef DEBUG std::cerr << "running: " << tmp << std::endl; #endif emitter(tmp); // set_editable(false); // textbuf->set_text(""); return true; } else { bool retval=Gtk::TextView::on_key_press_event(event); return retval; } } Glib::RefPtr TeXBuffer::create(Glib::RefPtr tb) { return Glib::RefPtr(new TeXBuffer(tb)); } DataCell::DataCell(cell_t ct, const std::string& str, bool texhidden) : cell_type(ct), tex_hidden(texhidden), sensitive(true), sectioning(0), running(false) { textbuf=Gtk::TextBuffer::create(); textbuf->set_text(trim(str)); switch(cell_type) { case c_error: case c_output: case c_comment: case c_tex: texbuf=TeXBuffer::create(textbuf); break; case c_input: break; } } XCadabra::XCadabra(modglue::ext_process& cdbproc, const std::string& filename, modglue::main *mm) : hglass(Gdk::WATCH), load_file(false), have_received(false), cmm(mm), name(filename), modified(false), running(false), running_last(0), restarting_kernel(false), b_cdbstatus(" Status: Kernel idle."), b_kernelversion("Kernel version: not running"), b_stop(Gtk::Stock::STOP), cdb(cdbproc), font_step(0), selected(0) { b_run.set_label("Run all"); b_run_to.set_label("Run to cursor"); b_run_from.set_label("Run from cursor"); b_kill.set_label("Restart kernel"); parse_mode.push_back(m_discard); b_cdbstatus.set_alignment( 0.0, 0.5 ); b_kernelversion.set_alignment( 0.0, 0.5 ); b_cdbstatus.set_size_request(200,-1); if(filename.size()>0) load_file=true; update_title(); set_default_size(std::min(Gdk::Screen::get_default()->get_width()-20, 800), std::min(Gdk::Screen::get_default()->get_height()-20, 900)); add(topbox); actiongroup=Gtk::ActionGroup::create(); actiongroup->add( Gtk::Action::create("MenuFile", "_File") ); actiongroup->add( Gtk::Action::create("MenuEdit", "_Edit") ); actiongroup->add( Gtk::Action::create("MenuView", "_View") ); actiongroup->add( Gtk::Action::create("MenuSettings", "_Settings") ); actiongroup->add( Gtk::Action::create("MenuTutorial", "_Tutorial") ); actiongroup->add( Gtk::Action::create("MenuFontSize", "Font size") ); actiongroup->add( Gtk::Action::create("MenuHelp", "_Help") ); actiongroup->add( Gtk::Action::create("New", Gtk::Stock::NEW), sigc::mem_fun(*this, &XCadabra::on_file_new) ); actiongroup->add( Gtk::Action::create("Open", "_Open"), Gtk::AccelKey("O"), sigc::mem_fun(*this, &XCadabra::on_file_open) ); actiongroup->add( Gtk::Action::create("Save", Gtk::Stock::SAVE), Gtk::AccelKey("S"), sigc::mem_fun(*this, &XCadabra::on_file_save) ); actiongroup->add( Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS), sigc::mem_fun(*this, &XCadabra::on_file_save_as) ); actiongroup->add( Gtk::Action::create("Print", Gtk::Stock::PRINT), sigc::mem_fun(*this, &XCadabra::on_file_print) ); actiongroup->add( Gtk::Action::create("ExportTxt", "Export as text..."), sigc::mem_fun(*this, &XCadabra::on_file_export_text) ); actiongroup->add( Gtk::Action::create("Quit", Gtk::Stock::QUIT), sigc::mem_fun(*this, &XCadabra::on_file_quit) ); actiongroup->add( Gtk::Action::create("InsertTeXAbove", "Insert TeX cell above"), Gtk::AccelKey("Up"), sigc::mem_fun(*this, &XCadabra::on_edit_insert_tex_above) ); actiongroup->add( Gtk::Action::create("InsertTeXBelow", "Insert TeX cell below"), Gtk::AccelKey("Down"), sigc::mem_fun(*this, &XCadabra::on_edit_insert_tex_below)); actiongroup->add( Gtk::Action::create("InsertInputAbove", "Insert input cell above"), Gtk::AccelKey("Up"), sigc::mem_fun(*this, &XCadabra::on_edit_insert_input_above) ); actiongroup->add( Gtk::Action::create("InsertInputBelow", "Insert input cell below"), Gtk::AccelKey("Down"), sigc::mem_fun(*this, &XCadabra::on_edit_insert_input_below) ); actiongroup->add( Gtk::Action::create("RemoveActive", "Remove active cell"), Gtk::AccelKey("Delete"), sigc::mem_fun(*this, &XCadabra::on_edit_remove_cell) ); actiongroup->add( Gtk::Action::create("DivideCell", "Divide active cell"), Gtk::AccelKey("D"), sigc::mem_fun(*this, &XCadabra::on_edit_divide_cell) ); actiongroup->add( Gtk::Action::create("SplitView", "Split view"), sigc::mem_fun(*this, &XCadabra::on_view_split) ); actiongroup->add( Gtk::Action::create("CloseView", "Close view"), sigc::mem_fun(*this, &XCadabra::on_view_close) ); actiongroup->add( Gtk::Action::create("FontSmall", "Small"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_font_size),-1) ); actiongroup->add( Gtk::Action::create("FontMedium", "Medium (default)"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_font_size),0) ); actiongroup->add( Gtk::Action::create("FontLarge", "Large"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_font_size),2) ); actiongroup->add( Gtk::Action::create("FontExtraLarge", "Extra large"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_font_size),4) ); actiongroup->add( Gtk::Action::create("Basics", "Basics"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_tutorial_open),0) ); actiongroup->add( Gtk::Action::create("Derivatives", "Derivatives"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_tutorial_open),1) ); actiongroup->add( Gtk::Action::create("Relativity", "Relativity"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_tutorial_open),2) ); actiongroup->add( Gtk::Action::create("Spinors", "Spinors"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_tutorial_open),3) ); actiongroup->add( Gtk::Action::create("About", Gtk::Stock::ABOUT), sigc::mem_fun(*this, &XCadabra::on_help_about) ); actiongroup->add( Gtk::Action::create("CitingInfo", "Citing cadabra"), sigc::mem_fun(*this, &XCadabra::on_help_citing) ); uimanager = Gtk::UIManager::create(); uimanager->insert_action_group(actiongroup); add_accel_group(uimanager->get_accel_group()); Glib::ustring ui_info = "" " " "

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; // " " // " " // " " // " " // " " // " " uimanager->add_ui_from_string(ui_info); Gtk::Widget *menubar = uimanager->get_widget("/MenuBar"); topbox.pack_start(*menubar, Gtk::PACK_SHRINK); // // add the lot to the window // topbox.pack_start(menubar, Gtk::PACK_SHRINK); topbox.pack_start(supermainbox, true, true); topbox.pack_start(statusbarbox, false, false); supermainbox.pack_start(mainbox, true, true); // The three main widgets mainbox.pack_start(buttonbox, Gtk::PACK_SHRINK, 0); buttonbox.pack_start(statusbox, Gtk::PACK_EXPAND_WIDGET, 0); b_cdbstatus.set_justify(Gtk::JUSTIFY_LEFT); statusbarbox.pack_start(b_cdbstatus); b_kernelversion.set_justify(Gtk::JUSTIFY_LEFT); statusbarbox.pack_start(b_kernelversion); // statusbarbox.pack_start(progressbarvbox); statusbarbox.pack_start(progressbar1); statusbarbox.pack_start(progressbar2); progressbar1.set_size_request(200,-1); progressbar2.set_size_request(200,-1); buttonbox.pack_start(b_run, Gtk::PACK_SHRINK); buttonbox.pack_start(b_run_to, Gtk::PACK_SHRINK); buttonbox.pack_start(b_run_from, Gtk::PACK_SHRINK); buttonbox.pack_start(b_stop, Gtk::PACK_SHRINK); buttonbox.pack_start(b_kill, Gtk::PACK_SHRINK); b_stop.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_stop)); b_kill.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_kill)); b_run.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_run)); b_run_to.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_run_to)); b_run_from.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_run_from)); // We always have at least one canvas: this one canvasses.push_back(manage( new NotebookCanvas(*this) )); mainbox.pack_start(*canvasses.back(), Gtk::PACK_EXPAND_WIDGET, 0); // canvasses[0]->to_cdb.connect(sigc::mem_fun(*this, &XCadabra::handle_editbox_output)); active_canvas=canvasses[0]; show_all(); // Setup an empty notebook and add a single empty input cell. DataCell *newcell=new DataCell(DataCell::c_input); add_cell(newcell); active_canvas->cell_grab_focus(newcell); modified=false; update_title(); } bool XCadabra::callmm(Glib::IOCondition, int fd) { if(!(cmm->select_callback(fd))) { connections[fd].disconnect(); connections.erase(fd); } return true; } void XCadabra::add_canvas() { canvasses.push_back(manage( new NotebookCanvas(*this) )); canvasses[canvasses.size()-2]->pack2(*canvasses.back()); // canvasses.back()->to_cdb.connect(sigc::mem_fun(*this, &XCadabra::handle_editbox_output)); // Make it display all DataCells DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { canvasses.back()->add_cell(*it); ++it; } canvasses.back()->show(); // Set up selection mechanisms. For Maple, it seems that we need LENGTH. // Also, we will put normal, non-utf8-dressed text in TEXT, instead of the // \x{...} stuff that the TextView widget normally spits out. // selection_add_target(GDK_SELECTION_PRIMARY, Gtk::TargetEntry("LENGTH", 1)); // selection_add_target(GDK_SELECTION_PRIMARY, Gtk::TargetEntry("TEXT", 2)); } void XCadabra::on_stop() { kill(cdb.get_pid(), SIGINT); } void XCadabra::on_kill() { restarting_kernel=true; *(cdb.output_pipe("stdin")) << "@quit;\n" << std::flush; b_cdbstatus.set_text(" Status: Restarting kernel..."); b_kernelversion.set_text("Kernel: not running"); // We now wait for the process to terminate properly and // modglue to send us a signal about that. // cdb.terminate(); // cdb.fork(); // *(cdb.output_pipe("stdin")) << "@print_status{true};\n" << std::flush; // b_cdbstatus.set_text("Status: Kernel restarted, idle."); } void XCadabra::on_run() { get_window()->set_cursor(hglass); running=true; running_last=0; b_cdbstatus.set_text(" Status: Executing notebook."); active_canvas->select_first_input_cell(); } void XCadabra::on_run_to() { get_window()->set_cursor(hglass); running=true; running_last=active_cell->datacell; b_cdbstatus.set_text(" Status: Executing until cursor."); active_canvas->select_first_input_cell(); } void XCadabra::on_run_from() { if(active_cell!=0) { get_window()->set_cursor(hglass); running=true; running_last=0; b_cdbstatus.set_text(" Status: Executing from cursor."); active_canvas->cell_grab_focus(active_cell); } } void XCadabra::on_help_about() { std::ostringstream str; str << "XCadabra release " << RELEASE <<"\n" << "Copyright (C) 2006-2007 by Kasper Peeters\n\n" << "Available under the GNU General Public License"; Gtk::MessageDialog md(str.str()); md.set_secondary_text("For more information consult the web site at http://www.aei.mpg.de/~peekas/cadabra/\n\nUsing kernel: "+cdb.name()); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } void XCadabra::on_help_citing() { std::ostringstream str; str << "Cadabra citing information"; Gtk::MessageDialog md(str.str()); md.set_secondary_text("If you use Cadabra to write a paper, please cite both\n\nKasper Peeters\n\"A field-theory motivated approach to computer algebra\"\ncs.sc/0608005\nComput. Phys. Commun 176 (2007) 550\n\nKasper Peeters\n\"Introducing Cadabra: a symbolic computer algebra system for field theory problems\"\nhep-th/0701238\n\nThank you!"); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } bool XCadabra::on_kernel_exit(modglue::ext_process& pr) { #ifdef DEBUG std::cerr << pr.name() << " has ended, restarting..." << std::endl; #endif disconnect_io_signals(); if(!restarting_kernel) { running=false; Gtk::MessageDialog md("The kernel has disconnected unexpectedly."); md.set_secondary_text("If you can reproduce this, please file a bug report."); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } cdb.fork(); *(cdb.output_pipe("stdin")) << "@print_status{true};\n" << std::flush; b_cdbstatus.set_text(" Status: Kernel restarted, idle."); connect_io_signals(); // return 'false' to keep the main loop running. return false; } void XCadabra::disconnect_io_signals() { std::map::iterator it=connections.begin(); while(it!=connections.end()) { it->second.disconnect(); ++it; } connections.clear(); } void XCadabra::connect_io_signals() { assert(connections.size()==0); std::vector fds; cmm->fds_to_watch(fds); for(unsigned int i=0; icell_type) { case DataCell::c_output: newcell->texbuf->font_size=12+(font_step*2); newcell->texbuf->generate("\\begin{dmath*}[compact,spread=2pt]\n","\\end{dmath*}\n", horizontal_pixels); break; case DataCell::c_comment: newcell->texbuf->font_size=12+(font_step*2); newcell->texbuf->generate("\\begin{verbatim}\n","\\end{verbatim}\n", horizontal_pixels); break; case DataCell::c_input: newcell->textbuf->signal_changed().connect(sigc::mem_fun(this, &XCadabra::input_cell_modified)); break; case DataCell::c_error: newcell->texbuf->font_size=12+(font_step*2); newcell->texbuf->generate("{\\color[named]{Red}", "}", horizontal_pixels); break; case DataCell::c_tex: newcell->texbuf->font_size=12+(font_step*2); newcell->texbuf->generate("","", horizontal_pixels); newcell->textbuf->signal_changed().connect(sigc::mem_fun(this, &XCadabra::tex_cell_modified)); break; } } catch(std::exception& ex) { Gtk::MessageDialog md(ex.what()); // md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } // Now we have to tell all NotebookCanvas objects to create a // view on the just created DataCell. for(unsigned int i=0; iadd_cell(newcell, ref, before); if(canvasses[i]==active_canvas) { #ifdef DEBUG std::cerr << "found active canvas" << std::endl; #endif // active_canvas->cell_grab_focus(vis); active_cell=vis; } } return newcell; } bool XCadabra::handle_editbox_output(std::string str, NotebookCanvas *can, VisualCell *vis) { // Disable this cell until output has been received, so we // don't get it twice. if(vis->datacell->running==false) { vis->datacell->running=true; // Remove any old error boxes until the next // Now run the input through cadabra. #ifdef DEBUG std::cerr << "sending to cdb " << str << std::endl; #endif b_cdbstatus.set_text(" Status: Kernel busy."); get_window()->set_cursor(hglass); *(cdb.output_pipe("stdin")) << "#cellstart " << vis->datacell << "\n" << str << "\n" << "#cellend\n" << std::flush; } return true; } void XCadabra::handle_on_grab_focus(NotebookCanvas *can, VisualCell *vis) { #ifdef DEBUG std::cerr << "focus grabbed" << std::endl; #endif active_canvas=can; active_cell=vis; if(selected) { selected->outbox->set_state(Gtk::STATE_NORMAL); selected=0; } if(running && vis) { if(running_last==active_cell->datacell) { running=false; #ifdef DEBUG std::cerr << "end cell reached" << std::endl; #endif get_window()->set_cursor(); b_cdbstatus.set_text(" Status: Kernel idle."); } else { Glib::RefPtr textbuf=active_cell->datacell->textbuf; std::string tmp(trim(textbuf->get_text(textbuf->begin(), textbuf->end()))); if(tmp[0]!='#' && tmp[tmp.size()-1]!=';' && tmp[tmp.size()-1]!=':' && tmp[tmp.size()-1]!='.' ) { #ifdef DEBUG std::cerr << "cell does not end with delimiter" << std::endl; #endif running=false; get_window()->set_cursor(); b_cdbstatus.set_text(" Status: Kernel idle."); } else { #ifdef DEBUG std::cerr << "executing cell\n" << tmp << std::endl; #endif *(cdb.output_pipe("stdin")) << "#cellstart " << active_cell->datacell << "\n" << tmp << "\n" << "#cellend\n" << std::flush; } } } } bool XCadabra::handle_visibility_toggle(GdkEventButton *, NotebookCanvas *can, VisualCell *vis) { vis->datacell->tex_hidden = !vis->datacell->tex_hidden; for(unsigned int i=0; ivisualcells.begin(); while(it!=canvasses[i]->visualcells.end()) { if((*it)->datacell==vis->datacell) { if(vis->datacell->tex_hidden) (*it)->texbox->edit.hide_all(); else (*it)->texbox->edit.show_all(); break; } ++it; } } return true; } bool XCadabra::handle_outbox_select(GdkEventButton *, NotebookCanvas *can, VisualCell *vis) { Glib::RefPtr refClipboard = Gtk::Clipboard::get(GDK_SELECTION_PRIMARY); if(selected) { selected->outbox->set_state(Gtk::STATE_NORMAL); if(selected==vis) { refClipboard->set_text(""); selected=0; return true; } } selected=vis; vis->outbox->set_state(Gtk::STATE_PRELIGHT); std::string cpystring=vis->datacell->texbuf->tex_source->get_text(); size_t pos=cpystring.find("\\specialcolon{}"); if(pos!=std::string::npos) cpystring.replace(pos, 15, " :"); // Setup clipboard handling clipboard_txt = cpystring; clipboard_cdb = vis->datacell->cdbbuf; std::list listTargets; if(clipboard_cdb.size()>0) listTargets.push_back( Gtk::TargetEntry("cadabra") ); listTargets.push_back( Gtk::TargetEntry("UTF8_STRING") ); listTargets.push_back( Gtk::TargetEntry("TEXT") ); refClipboard->set( listTargets, sigc::mem_fun(this, &XCadabra::on_clipboard_get), sigc::mem_fun(this, &XCadabra::on_clipboard_clear) ); return true; } bool XCadabra::handle_tex_update_request(std::string, NotebookCanvas *can, VisualCell *vis) { // First re-generate the image. Gtk::Allocation al=get_allocation(); const int horizontal_pixels=al.get_width()-20; vis->texbox->texview.texbuf->generate("","",horizontal_pixels); // Now walk through all TeXInput cells and update the Image widget. for(unsigned int i=0; ivisualcells.begin(); while(it!=canvasses[i]->visualcells.end()) { if((*it)->datacell==vis->datacell) { (*it)->texbox->texview.image.set(vis->texbox->texview.texbuf->pixbuf); break; } ++it; } } return true; } XCadabra::~XCadabra() { DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { delete *it; ++it; } } bool XCadabra::on_delete_event(GdkEventAny* event) { if(quit_safeguard()) { cdb.terminate(); Gtk::Window::on_delete_event(event); Gtk::Main::quit(); return false; } else return true; } void XCadabra::input_cell_modified() { if(!modified) { modified=true; update_title(); } } void XCadabra::tex_cell_modified() { if(!modified) { modified=true; update_title(); } } void XCadabra::remove_noninput_below(DataCell *dc) { if(selected) { selected->outbox->set_state(Gtk::STATE_NORMAL); selected=0; } DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { if((*it)==dc) { ++it; while(it!=datacells.end() && ( (*it)->cell_type==DataCell::c_output || (*it)->cell_type==DataCell::c_comment || (*it)->cell_type==DataCell::c_error) ) { for(unsigned int i=0; iremove_cell(*it); it=datacells.erase(it); } return; } ++it; } } bool XCadabra::receive(modglue::ipipe& p) { static std::string str; static std::string comment; static std::string error; static bool error_occurred=false; static bool last_was_prompt=true; // avoid repeated empty cells static bool in_cell=false; // prompts only get honored outside cells static DataCell *cp=0, *origcell=0; have_received=true; while(std::getline(p,str)) { #ifdef DEBUG std::cerr << "rec: " << str << std::endl; #endif if(str.substr(0,10)=="#cellstart") { std::istringstream ss(str.substr(11)); int help; ss >> std::hex >> help; cp=reinterpret_cast(help); remove_noninput_below(cp); origcell=cp; in_cell=true; comment=""; continue; } else if(str=="#cellend") { in_cell=false; if(trim(comment).size()!=0 && trim(comment)!=">") { DataCell *newcell=new DataCell(DataCell::c_comment, trim(comment)); cp=add_cell(newcell, cp, false); } comment=""; continue; } else if(str.substr(0,7)=="Cadabra") { b_kernelversion.set_label("Kernel: "+str.substr(8,5)+"."); } else if(str=="") { parse_mode.push_back(m_comment); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); last_was_prompt=false; continue; } else if(str=="") { parse_mode.push_back(m_status); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); continue; } else if(str=="") { parse_mode.push_back(m_plain); plain=""; last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); last_was_prompt=false; continue; } else if(str=="") { progress=""; progress_todo=-1; progress_done=-1; progress_count=-1; parse_mode.push_back(m_progress); continue; } else if(str=="") { std::ostringstream ss; if(progress_todo>0) ss << progress << "..." << " (" << progress_done << " of " << progress_todo << ")"; else ss << progress << "..."; if(progress_count==1) { progressbar1.set_text(ss.str()); if(progress_todo==0) progressbar1.set_fraction(0); else progressbar1.set_fraction(progress_done/(1.0*progress_todo)); } else { progressbar2.set_text(ss.str()); if(progress_todo==0) progressbar2.set_fraction(0); else progressbar2.set_fraction(progress_done/(1.0*progress_todo)); } parse_mode.pop_back(); continue; } else if(str=="") { parse_mode.push_back(m_error); last_was_prompt=false; error_occurred=true; continue; } else if(str=="") { parse_mode.pop_back(); if(trim(error).size()!=0) { DataCell *newcell=new DataCell(DataCell::c_error, trim(error)); running=false; // halt automatic notebook execution, if any get_window()->set_cursor(); cp=add_cell(newcell, cp, false); } error=""; last_was_prompt=false; continue; } else if(str=="") { parse_mode.push_back(m_eqno); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); continue; } else if(str=="") { parse_mode.push_back(m_eq); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); if(eq.size()!=0) { DataCell *newcell=new DataCell(DataCell::c_output, eqno+"\\specialcolon{}= "+eq); newcell->cdbbuf=plain; cp=add_cell(newcell, cp, false); } eq=""; eqno=""; plain=""; last_was_prompt=false; continue; } else if(str=="") { parse_mode.push_back(m_property); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); continue; } else if(trim(str).substr(0,1)==">") { progressbar2.set_fraction(0); progressbar1.set_fraction(0); progressbar2.set_text(" "); progressbar1.set_text(" "); if(!last_was_prompt && !in_cell) { if(!running) { b_cdbstatus.set_text(" Status: Kernel idle."); get_window()->set_cursor(); } last_was_prompt=true; if(error_occurred) { error_occurred=false; // re-enable original cell if(origcell!=0) { origcell->running=false; origcell=0; } } else { // everything hunky dorey if(datacells.back()==cp || cp==0 ) { // no input cell below if(datacells.size()>0 && datacells.back()->cell_type==DataCell::c_input && trim(datacells.back()->textbuf->get_text()).size()==0 ) { #ifdef DEBUG std::cerr << "no cell needed" << std::endl; #endif if(restarting_kernel) { restarting_kernel=false; active_canvas->cell_grab_focus(active_cell); } else active_canvas->cell_grab_focus(datacells.back()); } else { #ifdef DEBUG std::cerr << "adding empty input cell" << std::endl; #endif DataCell *newcell=new DataCell(DataCell::c_input, ""); cp=add_cell(newcell, cp, false); active_canvas->cell_grab_focus(cp); } // re-enable original cell if(origcell!=0) { origcell->running=false; origcell=0; } } else { if(restarting_kernel) { restarting_kernel=false; } else { DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { if(*it==cp) { ++it; while(it!=datacells.end() && (*it)->cell_type!=DataCell::c_input) ++it; if(it==datacells.end()) { DataCell *newcell=new DataCell(DataCell::c_input, ""); cp=add_cell(newcell, cp, false); active_canvas->cell_grab_focus(cp); } else active_canvas->cell_grab_focus(*it); // re-enable original cell if(origcell!=0) { origcell->running=false; origcell=0; } break; } ++it; } } } } } else str="\n"; } switch(parse_mode.back()) { case m_eq: eq+=str; break; case m_eqno: eqno+=str; break; case m_status: case m_discard: break; case m_property: break; case m_comment: if(trim(str).size()>0) comment+=str+"\n"; break; case m_error: error+=str+"\n"; break; case m_plain: plain+=str; break; case m_progress: if(progress=="") progress=str; else if(progress_todo==-1) progress_todo=atoi(str.c_str()); else if(progress_done==-1) progress_done=atoi(str.c_str()); else progress_count=atoi(str.c_str()); break; } } p.clear(); if(load_file) { load_file=false; #ifdef DEBUG std::cerr << "Loading file..." << std::endl; #endif std::string tmp=name; std::string res=load(tmp); name=tmp; if(res.size()>0) { Gtk::MessageDialog md("Error loading document "+name); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } else { modified=false; update_title(); } } return true; } void XCadabra::on_file_new() { if(quit_safeguard(false)) { clear(); DataCell *newcell=new DataCell(DataCell::c_input); add_cell(newcell); active_canvas->cell_grab_focus(newcell); modified=false; update_title(); on_kill(); } } void XCadabra::on_file_open() { if(quit_safeguard(false)) { Gtk::FileChooserDialog fd("Open notebook...", Gtk::FILE_CHOOSER_ACTION_OPEN); fd.add_button(Gtk::Stock::OPEN,1); fd.add_button(Gtk::Stock::CANCEL,2); fd.set_default_response(1); int action=fd.run(); if(action==1) { fd.hide_all(); std::string res=load(fd.get_filename()); if(res.size()>0) { Gtk::MessageDialog md("Error loading document "+fd.get_filename()); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } else { name=fd.get_filename(); DataCell *newcell=new DataCell(DataCell::c_input); add_cell(newcell); active_canvas->select_first_input_cell(); modified=false; update_title(); } } } } void XCadabra::on_file_save() { // check if name known, otherwise call save_as if(name.size()>0) { std::string res=save(name); if(res.size()>0) { Gtk::MessageDialog md("Error saving document "+name); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } else { modified=false; update_title(); } } else on_file_save_as(); } void XCadabra::on_file_export_text() { Gtk::FileChooserDialog fd("Export to text...", Gtk::FILE_CHOOSER_ACTION_SAVE); fd.add_button(Gtk::Stock::SAVE,1); fd.add_button(Gtk::Stock::CANCEL,2); int action=fd.run(); if(action==1) { fd.hide_all(); #ifdef DEBUG std::cerr << "going to export as " << fd.get_filename() << std::endl; #endif std::string res=expo(fd.get_filename()); if(res.size()>0) { Gtk::MessageDialog md("Error exporting document "+fd.get_filename()); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } } } void XCadabra::update_title() { if(name.size()>0) { if(modified) set_title("XCadabra: "+name+"*"); else set_title("XCadabra: "+name); } else { if(modified) set_title("XCadabra*"); else set_title("XCadabra"); } } void XCadabra::on_file_save_as() { Gtk::FileChooserDialog fd("Save notebook as...", Gtk::FILE_CHOOSER_ACTION_SAVE); fd.add_button(Gtk::Stock::SAVE,1); fd.add_button(Gtk::Stock::CANCEL,2); fd.set_default_response(1); int action=fd.run(); if(action==1) { fd.hide_all(); #ifdef DEBUG std::cerr << "going to save as " << fd.get_filename() << std::endl; #endif std::string res=save(fd.get_filename()); if(res.size()>0) { Gtk::MessageDialog md("Error saving document "+fd.get_filename()); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } else { name=fd.get_filename(); modified=false; update_title(); } } } void XCadabra::on_file_print() { Gtk::MessageDialog md("Printing information"); md.set_secondary_text("In order to print a notebook file, simply save it and then run LaTeX on it.\n\nCadabra notebook files are at the same time also valid LaTeX files, ready to be processed in any way you would normally process LaTeX files."); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } void XCadabra::clear() { // Remove all NotebookCanvas objects by removing the // outer-most one. mainbox.remove(*canvasses[0]); canvasses.clear(); // Remove all DataCells. DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { delete *it; ++it; } datacells.clear(); // Add in a new NotebookCanvas canvasses.push_back(manage( new NotebookCanvas(*this) )); mainbox.pack_start(*canvasses.back(), Gtk::PACK_EXPAND_WIDGET, 0); active_canvas=canvasses.back(); active_cell=0; selected=0; // canvasses.back()->to_cdb.connect(sigc::mem_fun(*this, &XCadabra::handle_editbox_output)); show_all(); name=""; modified=false; update_title(); } // Returns false if backup could not be made. // Returns true if original file not present or backup ok. bool XCadabra::make_backup(const std::string& nm) const { std::ifstream old(nm.c_str()); std::ofstream temp(std::string(nm+"~").c_str()); if(!old) return true; if(temp) { std::string ln; while(std::getline(old, ln)) { temp << ln << "\n"; if(!temp) return false; } return true; } return false; } std::string XCadabra::save(const std::string& fn) const { if(!make_backup(fn)) return "Cannot create backup file."; std::ofstream str(fn.c_str()); if(!str) { return "Cannot open file for writing."; } else { str << "% Cadabra notebook version 1.0\n" << "\\documentclass[11pt]{article}\n" << "\\usepackage[textwidth=460pt, textheight=660pt]{geometry}\n" << "\\usepackage[usenames]{color}\n" << "\\usepackage[parfill]{parskip}\n" << "\\usepackage{breqn}\n" << "\\def\\specialcolon{\\mathrel{\\mathop{:}}\\hspace{-.5em}}\n" << "\\renewcommand{\\bar}[1]{\\overline{#1}}\n" << "\\begin{document}\n"; DataCells_t::const_iterator it=datacells.begin(); while(it!=datacells.end()) { if((*it)->textbuf->size()>0) { switch((*it)->cell_type) { case DataCell::c_input: str << "{\\color[named]{Blue}\\begin{verbatim}\n" << trim( (*it)->textbuf->get_text() ) << "\n\\end{verbatim}}\n"; break; case DataCell::c_output: str << "% orig\n"; str << "% " << (*it)->cdbbuf << "\n"; str << "% end_orig\n"; str << "\\begin{dmath*}[compact, spread=2pt]\n" << trim( (*it)->textbuf->get_text() ) << "\n\\end{dmath*}\n"; break; case DataCell::c_comment: str << "\\begin{verbatim}\n" << trim( (*it)->textbuf->get_text() ) << "\n\\end{verbatim}\n"; break; case DataCell::c_tex: str << "% Begin TeX cell " << ( (*it)->tex_hidden==true ? "closed\n":"open\n" ); if((*it)->sectioning>0) str << "\\section{" << trim( (*it)->textbuf->get_text() ) << "}"; else str << trim( (*it)->textbuf->get_text() ); str << "\n% End TeX cell\n"; break; case DataCell::c_error: str << "{\\color[named]{Red}%\n" << trim( (*it)->textbuf->get_text() ) << "%\n" << "} % error\n"; break; } } ++it; } str << "\\end{document}\n"; } return ""; } std::string XCadabra::expo(const std::string& fn) const { if(!make_backup(fn)) return "Cannot create backup file."; std::ofstream str(fn.c_str()); if(!str) { return "Cannot open file for writing."; } else { str << "# Exported Cadabra notebook\n"; DataCells_t::const_iterator it=datacells.begin(); while(it!=datacells.end()) { if((*it)->textbuf->size()>0) { switch((*it)->cell_type) { case DataCell::c_input: str << trim( (*it)->textbuf->get_text() ) << "\n\n"; break; case DataCell::c_tex: // str << "% Begin TeX cell " // << ( (*it)->tex_hidden==true ? "closed\n":"open\n" ); // if((*it)->sectioning>0) // str << "\\section{" << trim( (*it)->textbuf->get_text() ) << "}"; // else str << trim( (*it)->textbuf->get_text() ); // str << "\n% End TeX cell\n"; break; case DataCell::c_error: case DataCell::c_output: case DataCell::c_comment: break; break; } } ++it; } str << "\n"; } return ""; } std::string XCadabra::load(const std::string& fn) { std::ifstream str(fn.c_str()); std::ostringstream err; if(str.is_open()==false) { return "Cannot open file for reading."; } else { std::string ln; std::getline(str,ln); if(ln!="% Cadabra notebook version 1.0") { return "Not in Cadabra notebook version 1.0 format."; } clear(); enum state_t { s_top, s_input, s_output, s_comment, s_tex, s_error, s_output_as_cdb }; state_t curstat=s_top; std::string buffer, cdb_buffer; int line_num=2; bool tex_hidden=false; while(std::getline(str,ln)) { #ifdef DEBUG std::cerr << "read: " << ln << std::endl; #endif if(ln=="{\\color[named]{Blue}\\begin{verbatim}") { if(curstat!=s_top) { err << "Illegal location of input cell at line " << line_num << "."; return err.str(); } curstat=s_input; buffer=""; } else if(ln=="\\end{verbatim}}") { if(curstat!=s_input) { err << "Unmatched input cell closing at line " << line_num << "."; return err.str(); } DataCell *newcell=new DataCell(DataCell::c_input, buffer); add_cell(newcell); curstat=s_top; } else if(ln=="{\\color[named]{Red}%") { if(curstat!=s_top) { err << "Illegal location of error cell at line " << line_num << "."; return err.str(); } curstat=s_error; buffer=""; } else if(ln=="} % error") { if(curstat!=s_error) { err << "Unmatched error cell closing at line " << line_num << "."; return err.str(); } DataCell *newcell=new DataCell(DataCell::c_error, buffer); add_cell(newcell); curstat=s_top; } else if(ln.substr(0,6)=="% orig") { if(curstat!=s_top) { err << "Illegal location of output cell in Cadabra input format at line " << line_num << "."; return err.str(); } curstat=s_output_as_cdb; buffer=""; cdb_buffer=""; } else if(ln.substr(0,10)=="% end_orig") { if(curstat!=s_output_as_cdb) { err << "Unmatched output cell in Cadabra input format closing at line " << line_num << "."; return err.str(); } curstat=s_top; cdb_buffer=buffer; buffer=""; } else if(ln.substr(0,14)=="\\begin{dmath*}") { if(curstat!=s_top) { err << "Illegal location of output cell at line " << line_num << "."; return err.str(); } curstat=s_output; buffer=""; } else if(ln=="\\end{dmath*}") { if(curstat!=s_output) { err << "Unmatched output cell closing at line " << line_num << "."; return err.str(); } #ifdef DEBUG std::cerr << buffer << std::endl; #endif DataCell *newcell=new DataCell(DataCell::c_output, buffer); if(cdb_buffer.size()>2) newcell->cdbbuf=cdb_buffer.substr(2); cdb_buffer=""; add_cell(newcell); curstat=s_top; } else if(ln=="\\begin{verbatim}") { if(curstat!=s_top) { err << "Illegal location of comment cell at line " << line_num << "."; return err.str(); } curstat=s_comment; buffer=""; } else if(ln=="\\end{verbatim}") { if(curstat!=s_comment) { err << "Unmatched comment cell closing at line " << line_num << "."; return err.str(); } DataCell *newcell=new DataCell(DataCell::c_comment, buffer); add_cell(newcell); curstat=s_top; } else if(ln=="% Begin TeX cell open") { if(curstat!=s_top) { err << "Illegal location of TeX cell at line " << line_num << "."; return err.str(); } curstat=s_tex; tex_hidden=false; buffer=""; } else if(ln=="% Begin TeX cell closed") { if(curstat!=s_top) { err << "Illegal location of TeX cell at line " << line_num << "."; return err.str(); } curstat=s_tex; tex_hidden=true; buffer=""; } else if(ln=="% End TeX cell") { if(curstat!=s_tex) { err << "Unmatched TeX cell closing at line " << line_num << "."; return err.str(); } DataCell *newcell=new DataCell(DataCell::c_tex, trim(buffer)); newcell->tex_hidden=tex_hidden; add_cell(newcell); curstat=s_top; } else buffer+=ln+"\n"; ++line_num; while (gtk_events_pending ()) gtk_main_iteration (); } } return ""; } void XCadabra::on_file_quit() { if(quit_safeguard()) { cdb.terminate(); Gtk::Main::quit(); } } bool XCadabra::quit_safeguard(bool quit) { if(modified) { std::string mes; if(quit) { if(name.size()>0) mes="Save changes to "+name+" before closing?"; else mes="Save changes before closing?"; } else { if(name.size()>0) mes="Save changes to "+name+" before continuing?"; else mes="Save changes before continuing?"; } Gtk::MessageDialog md(mes, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE, true); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.add_button(Gtk::Stock::SAVE,1); md.add_button(Gtk::Stock::CANCEL,2); if(quit) md.add_button(Gtk::Stock::QUIT,3); else md.add_button(Gtk::Stock::NO, 3); int action=md.run(); switch(action) { case 1: on_file_save(); return true; case 2: break; case 3: return true; } } else return true; return false; } void XCadabra::on_edit_copy() { } void XCadabra::on_edit_paste() { } void XCadabra::on_edit_insert_tex_above() { DataCell *newcell=new DataCell(DataCell::c_tex, "[empty TeX cell]"); active_canvas->cell_grab_focus( add_cell(newcell, active_cell->datacell) ); } void XCadabra::on_edit_insert_tex_below() { DataCell *newcell=new DataCell(DataCell::c_tex, "[empty TeX cell]"); active_canvas->cell_grab_focus( add_cell(newcell, active_cell->datacell, false) ); } void XCadabra::on_edit_insert_input_above() { DataCell *newcell=new DataCell(DataCell::c_input, ""); active_canvas->cell_grab_focus( add_cell(newcell, active_cell->datacell) ); } void XCadabra::on_edit_insert_input_below() { DataCell *newcell=new DataCell(DataCell::c_input, ""); active_canvas->cell_grab_focus( add_cell(newcell, active_cell->datacell, false) ); } void XCadabra::on_edit_insert_section_above() { DataCell *newcell=new DataCell(DataCell::c_tex, "[insert section header]"); newcell->sectioning=1; active_canvas->cell_grab_focus( add_cell(newcell, active_cell->datacell) ); } void XCadabra::on_edit_remove_cell() { DataCell *dc=active_cell->datacell; if(dc->cell_type!=DataCell::c_input && dc->cell_type!=DataCell::c_tex) return; selected=0; DataCells_t::iterator fnd=std::find(datacells.begin(), datacells.end(), dc); if(fnd==datacells.end()) return; // Remove cells until an input or tex cell is found. while(fnd!=datacells.end()) { for(unsigned int i=0; iremove_cell(*fnd); fnd=datacells.erase(fnd); if((*fnd)->cell_type==DataCell::c_input || (*fnd)->cell_type==DataCell::c_tex) break; } #ifdef DEBUG std::cerr << "all widgets removed" << std::endl; #endif if(fnd!=datacells.end()) { #ifdef DEBUG std::cerr << "grabbing focus" << std::endl; #endif active_canvas->cell_grab_focus(*fnd); } else { #ifdef DEBUG std::cerr << "adding new cell" << std::endl; #endif DataCell *newcell=new DataCell(DataCell::c_input); active_canvas->cell_grab_focus( add_cell(newcell, active_cell->datacell) ); } } void XCadabra::on_edit_divide_cell() { DataCell *dc=active_cell->datacell; if(dc->cell_type!=DataCell::c_input) return; selected=0; DataCells_t::iterator fnd=std::find(datacells.begin(), datacells.end(), dc); if(fnd==datacells.end()) return; #ifdef DEBUG std::cerr << "dividing cell" << std::endl; #endif // Find the position of the cursor. std::string segment1= trim( dc->textbuf->get_slice(dc->textbuf->begin(), dc->textbuf->get_iter_at_mark(dc->textbuf->get_insert()))); std::string segment2= trim( dc->textbuf->get_slice(dc->textbuf->get_iter_at_mark(dc->textbuf->get_insert()), dc->textbuf->end())); if(segment1.size()==0 || segment2.size()==0) return; remove_noninput_below(dc); dc->textbuf->erase(dc->textbuf->get_iter_at_mark(dc->textbuf->get_insert()), dc->textbuf->end()); DataCell *newcell=new DataCell(DataCell::c_input, segment2); add_cell(newcell, dc, false); } void XCadabra::on_view_split() { add_canvas(); } void XCadabra::on_view_close() { if(canvasses.size()>1) { canvasses[canvasses.size()-2]->remove(*canvasses.back()); canvasses.pop_back(); } } void XCadabra::on_settings_font_size(int num) { font_step=num; // Update all TeXBuffers, i.e. rerun tex & dvipng on them. DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { if((*it)->cell_type==DataCell::c_output || (*it)->cell_type==DataCell::c_tex || (*it)->cell_type==DataCell::c_error || (*it)->cell_type==DataCell::c_comment) { (*it)->texbuf->font_size=12+(num*2); (*it)->texbuf->regenerate(); } ++it; } // Update all VisualCells. for(unsigned int i=0; ifont_size=12+(num*2); canvasses[i]->redraw_cells(); } } void XCadabra::on_tutorial_open(unsigned int num) { Gtk::MessageDialog md("Tutorial information"); md.set_secondary_text("Tutorials are not yet available, sorry."); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } void XCadabra::on_clipboard_get(Gtk::SelectionData& selection_data, guint info) { const Glib::ustring target = selection_data.get_target(); if(target == "cadabra") selection_data.set("cadabra", clipboard_cdb); else if(target == "UTF8_STRING" || target=="TEXT") { selection_data.set_text(clipboard_txt); } } void XCadabra::on_clipboard_clear() { } cadabra-0.115/gui/window.hh0000600000077000007700000002721210622301156015061 0ustar kantorkantor/* $Id: window.hh,v 1.62 2007/05/07 16:38:43 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2001-2006 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class XCadabra; const double millimeter_per_inch = 25.4; /// TeXBuffer is like a TextBuffer, but now for images /// generated by TeX+dvipng. That is, for each cell in the /// document, there is one TeXBuffer (and one TextBuffer); /// the TeXView and TextView classes use these buffers to /// get their content. class TeXBuffer : public Glib::Object { public: TeXBuffer(Glib::RefPtr, int fs=12); void generate(const std::string& startwrap, const std::string& endwrap, int horizontal_pixels); void regenerate(); static Glib::RefPtr create(Glib::RefPtr); Glib::RefPtr tex_source; Glib::RefPtr pixbuf; Gdk::Color foreground_colour; int font_size; private: std::string start_wrap_, end_wrap_; int horizontal_pixels_; }; /// TeXView is an image widget with some additional Gtk /// structure; we use it to display images generated by TeX. /// The actual pixbuf is generated by a TeXBuffer. class TeXView : public Gtk::EventBox { public: TeXView(Glib::RefPtr, int hmargin=25); Glib::RefPtr texbuf; Gtk::VBox vbox; Gtk::HBox hbox; // Gtk::Button button; Gtk::Image image; }; /// ExpressionInput is essentially a TextView with some /// additional i/o logic. class ExpressionInput : public Gtk::VBox { public: ExpressionInput(Glib::RefPtr, const std::string& fontname, int hmargin=25); class exp_input_tv : public Gtk::TextView { public: exp_input_tv(Glib::RefPtr); virtual bool on_key_press_event(GdkEventKey*); sigc::signal1 emitter; sigc::signal0 content_changed; }; bool handle_button_press(GdkEventButton *); exp_input_tv edit; Gtk::HBox hbox; Gtk::VSeparator vsep; }; /// TeXInput is a widget which can be used to edit and display /// TeX input. Double-clicking on the graphical TeX version /// toggles visibility of the edit box. class TeXInput : public Gtk::VBox { public: TeXInput(Glib::RefPtr, Glib::RefPtr, const std::string& fontname); class exp_input_tv : public Gtk::TextView { public: exp_input_tv(Glib::RefPtr); virtual bool on_key_press_event(GdkEventKey*); sigc::signal1 emitter; }; exp_input_tv edit; bool toggle_visibility(); TeXView texview; }; /// A DataCell contains the information required to display a /// cell, but not the actual widget. Therefore, multiple widgets /// can read from the data stored in this cell; multiple notebook /// canvasses can therefore display the same notebook data. class DataCell { public: enum cell_t { c_input, c_output, c_comment, c_tex, c_error }; DataCell(cell_t, const std::string& str="", bool texhidden=false); cell_t cell_type; Glib::RefPtr textbuf; Glib::RefPtr texbuf; std::string cdbbuf; // c_output only: the output in cadabra input format bool tex_hidden; // c_tex only bool sensitive; int sectioning; // >0 for section header cells bool running; }; /// A VisualCell contains pointers to the various cell widgets, /// which in turn contain pointers to DataCell objects. class VisualCell { public: union { ExpressionInput *inbox; TeXView *outbox; TeXInput *texbox; }; DataCell *datacell; }; /// NotebookCanvas is a view on notebook data. Any number of these /// may be instantiated, and they all reflect the current status /// of the document stored in the master XCadabra class. class NotebookCanvas : public Gtk::VPaned { public: NotebookCanvas(XCadabra& doc); ~NotebookCanvas(); // bool handle_expression_input(std::string str); // bool handle_tex_update(const std::string&); // bool receive_output(std::string eqno, std::string eq); // bool receive_comment(std::string comment); /// Add a VisualCell corresponding to the given DataCell. /// The second and third element determine the position relative /// to another DataCell (or, by default, relative to the end marker). VisualCell* add_cell(DataCell *, DataCell *ref=0, bool before=true); /// Remove a VisualCell corresponding to the given DataCell. void remove_cell(DataCell *); void cell_grab_focus(VisualCell *); void cell_grab_focus(DataCell *); void select_first_input_cell(); virtual void show(); void scroll_to(Gtk::Allocation al); void redraw_cells(); bool handle_key_press(VisualCell *); XCadabra& doc; typedef std::list VisualCells_t; VisualCells_t visualcells; // managed here Gtk::EventBox ebox; Gtk::ScrolledWindow scroll; Gtk::VBox scrollbox; Gtk::HSeparator bottomline; unsigned int font_size; }; /// Each notebook has one cadabra process associated to it, and one /// main window to control it. class XCadabra : public Gtk::Window { public: XCadabra(modglue::ext_process&, const std::string& filename, modglue::main *); virtual ~XCadabra(); /// Data coming from cadabra arrives here. This handles /// adding boxes to the document and propagating this to the /// notebooks. bool receive(modglue::ipipe& p); /// Data from the NotebookCanvas objects arrives here. bool handle_editbox_output(std::string str, NotebookCanvas *, VisualCell *); /// Events from the notebook cells arrive here. void handle_on_grab_focus(NotebookCanvas *, VisualCell *); bool handle_visibility_toggle(GdkEventButton *, NotebookCanvas *, VisualCell *); bool handle_outbox_select(GdkEventButton *, NotebookCanvas *, VisualCell *); bool handle_tex_update_request(std::string, NotebookCanvas *, VisualCell *); /// All the menu routines. void on_file_new(); void on_file_open(); void on_file_save(); void on_file_save_as(); void on_file_print(); void on_file_export_text(); void on_file_quit(); bool quit_safeguard(bool quit=true); void on_edit_copy(); void on_edit_paste(); void on_edit_insert_tex_above(); void on_edit_insert_tex_below(); void on_edit_insert_input_above(); void on_edit_insert_input_below(); void on_edit_insert_section_above(); void on_edit_remove_cell(); void on_edit_divide_cell(); void on_view_split(); void on_view_close(); void on_settings_font_size(int); void on_tutorial_open(unsigned int); void on_help_about(); void on_help_citing(); void on_stop(); void on_kill(); void on_run(); void on_run_to(); void on_run_from(); /// Saving and loading to disk. If the return string is non-empty, it contains /// an error message. void clear(); std::string save(const std::string&) const; std::string load(const std::string&); std::string expo(const std::string&) const; /// Handling starting/restarting of the kernel. bool on_kernel_exit(modglue::ext_process&); /// Clipboard handling void on_clipboard_get(Gtk::SelectionData&, guint info); void on_clipboard_clear(); std::string clipboard_txt, clipboard_cdb; /// Adding and removing cells from the current document. /// These routines also update all NotebookCanvas objects /// so that they reflect the current structure of the document. /// The DataCell ownership is handled by the XCadabra class once /// it has been added here. DataCell *add_cell(DataCell *, DataCell *ref=0, bool before=true); //DataCell::cell_t, const std::string&, bool tex_hidden=false, void add_canvas(); /// Signals from Gtk, such as closing windows or changing the text /// of an input cell. virtual bool on_delete_event(GdkEventAny*); void input_cell_modified(); void tex_cell_modified(); void connect_io_signals(); void disconnect_io_signals(); private: Gdk::Cursor hglass; bool load_file; // used by main to indicate a load should occur after start bool have_received; modglue::main *cmm; std::map connections; bool callmm(Glib::IOCondition, int fd); std::string name; bool modified; bool running; DataCell *running_last; bool restarting_kernel; void update_title(); bool make_backup(const std::string&) const; void remove_noninput_below(DataCell *); std::vector canvasses; // managed by gtk NotebookCanvas *active_canvas; VisualCell *active_cell; // Gtk::VPaned paned; Gtk::VBox topbox; Gtk::HBox supermainbox; Gtk::VBox mainbox; Gtk::HBox buttonbox; Gtk::HBox statusbarbox; Gtk::VBox progressbarvbox; Gtk::ProgressBar progressbar1,progressbar2; Glib::RefPtr actiongroup; Glib::RefPtr uimanager; // Gtk::MenuBar menubar; // Gtk::MenuItem menu_file_top, menu_edit_top, menu_view_top, menu_help_top; // Gtk::Menu menu_file, menu_edit, menu_view, menu_help; Gtk::HBox statusbox; Gtk::Label b_cdbstatus, b_kernelversion; Gtk::Button b_kill, b_run, b_run_to, b_run_from, b_stop; /// All data of the document is stored here. Data is not /// managed and should be deleted by the XCadabra destructor. typedef std::list DataCells_t; DataCells_t datacells; /// Data concerning the interaction with the externally started /// cadabra process. modglue::ext_process& cdb; enum parse_mode_t { m_status, m_eqno, m_eq, m_property, m_discard, m_comment, m_error, m_progress, m_plain }; std::vector parse_mode; std::string eqno, eq, status, progress, plain; int progress_todo, progress_done, progress_count; int font_step; /// Cut-n-paste data VisualCell *selected; }; cadabra-0.115/history0000600000077000007700000000060710453676776014121 0ustar kantorkantorAbandoned ideas: - Patterns: a?VectorIndex labelled name with property a??VectorIndex labelled object with property ?VectorIndex unlabelled name with property a? | @@type(a?,VectorIndex) a? | @@regex(a?,"B[0-9]*") But for the time being we could do with a? | \type{a?}{VectorIndex} and catch it just like we catch \regex. cadabra-0.115/INSTALL0000600000077000007700000000026607262617042013510 0ustar kantorkantor To install `cadabra', do ./configure make make install as usual. If you want it installed in a different directory than /usr/local, use the --prefix option to configure. cadabra-0.115/Makefile.in0000600000077000007700000000455310622301155014514 0ustar kantorkantor export RELEASE=0.115 .PHONY: static program_static test fasttest gui gui_static doc ifeq (@enable_gui@,no) all: program install: install_program else all: program gui install: install_program install_gui endif static: program_static program: ( cd src && $(MAKE) ); program_static: ( cd src && $(MAKE) static ); profile: ( export CFLAGS=-pg && export LDFLAGS=-pg && cd src && $(MAKE) ); doc: ( cd doc && $(MAKE) ); gui: ( cd gui && $(MAKE) ); gui_static: ( cd gui && $(MAKE) static ); test: program @echo "==== Running tests ====" ( export CDB_PARANOID=1 && export CDB_ERRORS_ARE_FATAL=1 \ && export CDB_PRINTSTAR=1 && cd tests && $(MAKE) clean && $(MAKE) all); @echo "==== Tests passed =====" @echo "**** Do not forget to run the advanced tests with 'make advtest' ****" fasttest: program @echo "==== Running tests without consistency checks ====" ( export CDB_PRINTSTAR=1 && export CDB_ERRORS_ARE_FATAL=1 && cd tests && $(MAKE) clean && $(MAKE) all); @echo "==== Tests passed =====" @echo "**** Do not forget to run the advanced tests with 'make advtest' ****" advtest: program @echo "==== Running advanced tests (this may take a while) ====" ( export CDB_PARANOID=1 && export CDB_PRINTSTAR=1 && cd tests && $(MAKE) clean && $(MAKE) advanced); @echo "==== Advanced tests passed =====" install_program: program ( cd src && $(MAKE) install ); install -d ${DESTDIR}@prefix@/share/man/man1 install man/man1/cadabra.1 ${DESTDIR}@prefix@/share/man/man1 install -d ${DESTDIR}@prefix@/bin install -d ${DESTDIR}@prefix@/share/TeXmacs/plugins/cadabra/progs install -m 644 texmacs/init-cadabra.scm ${DESTDIR}@prefix@/share/TeXmacs/plugins/cadabra/progs install_gui: gui ( cd gui && $(MAKE) install ); install man/man1/xcadabra.1 ${DESTDIR}@prefix@/share/man/man1 uninstall: ( cd src && $(MAKE) uninstall ); clean: ( cd src && $(MAKE) clean ); ( cd tests && $(MAKE) clean ); ( cd gui && $(MAKE) clean ); ( cd doc && $(MAKE) clean ); # ( cd deb && rm -Rf usr ); rm -f cadabra*.deb rm -f doc/*~ rm -f *~ rm -f man/man1/*~ distclean: ( cd src && $(MAKE) distclean ); ( cd tests && $(MAKE) distclean ); ( cd gui && $(MAKE) distclean ); ( cd doc && $(MAKE) distclean ); rm -f Makefile config.cache config.log config.status cdb.log aclocal.m4 rm -f cdb*.log tst rm -Rf autom4te.cache depend: ( cd src && $(MAKE) .depend ); ( cd gui && $(MAKE) .depend ); cadabra-0.115/man/0000700000077000007700000000000007634307736013235 5ustar kantorkantorcadabra-0.115/man/man1/0000700000077000007700000000000010540215056014050 5ustar kantorkantorcadabra-0.115/man/man1/cadabra.10000600000077000007700000000472210540215056015516 0ustar kantorkantor.TH CADABRA 1 "Dec 14, 2006" "" "" .\" .\" Man page written by Kasper Peeters .\" .\" 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 2 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, write to the Free Software .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. .\" .\" .SH NAME cadabra \- field-theory motivated computer algebra system .SH SYNOPSIS .BR "cadabra" .SH DESCRIPTION .B Cadabra is a computer algebra system for the manipulation of tensorial expressions. The output of cadabra is either plain text or UTF8 encoded Unicode (see the environment variables described below). The line-breaking properties of the latter are used to wrap large expressions are reasonable points. In addition to the standard output, cadabra can print status information, which is wrapped in special ... blocks. .SH OPTIONS .TP \fB --silent\fR Disables all output, except for output generated by the @print algorithm. .TP \fB --loginput\fR Copy the input into the log file. .TP \fB --input filename\fR Read the indicated file as input before switching to console input. .TP \fB --prompt string\fR Set the prompt of the interactive session to the indicated string. .SH ENVIRONMENT VARIABLES The following variables toggle various features on or off, depending on whether the variable is set or not: .TP \fB CDB_PRINTSTAR\fR Display a star to indicate products. Without this setting, a space is used. .TP \fB CDB_USE_UTF8\fR Use UTF8 encoding for output. This in particular will introduce non-breakable spaces to group objects together, as well as zero-width non-breakable spaces to prevent line-breaks after brackets, underscore and caret symbols. When this variable is not set, the output will be plain ASCII without any special symbols. .SH SEE ALSO .BR xcadabra (1). See the web page at .BR "http://www.aei.mpg.de/~peekas/cadabra/" for binaries, example calculations and the full manual. .SH AUTHORS Kasper Peeters cadabra-0.115/man/man1/xcadabra.10000600000077000007700000000227110540215056015703 0ustar kantorkantor.TH XCADABRA 1 "Dec 14, 2006" "" "" .\" .\" Man page written by Kasper Peeters .\" .\" 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 2 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, write to the Free Software .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. .\" .\" .SH NAME xcadabra \- gtk front-end for cadabra .SH SYNOPSIS .BR "xcadabra" .SH DESCRIPTION .B Xcadabra is a graphical front-end for the computer algebra system .B cadabra. .SH SEE ALSO .BR cadabra (1). See the web page at .BR "http://www.aei.mpg.de/~peekas/cadabra/" for more information and up-to-date sample notebooks. .SH AUTHORS Kasper Peeters cadabra-0.115/rpm/0000700000077000007700000000000010622301156013235 5ustar kantorkantorcadabra-0.115/rpm/cadabra.spec0000600000077000007700000000204210622301156015466 0ustar kantorkantorSummary: field-theory motivated computer algebra system Name: cadabra Version: 0.115 Release: 1 License: GPL Group: Application/Math Source: http://www.aei.mpg.de/~peekas/cadabra/cadabra-0.115.tar.gz URL: http://www.aei.mpg.de/~peekas/cadabra Packager: Kasper Peeters BuildRoot: /tmp/cadabra-0.115 Prefix: /usr Requires: tetex, lie, breqn %description Cadabra is a computer algebra system designed specifically for the solution of problems encountered in field theory. It has extensive functionality for tensor polynomial simplification including multi-term symmetries, fermions and anti-commuting variables, Clifford algebras and Fierz transformations, implicit coordinate dependence, multiple index types and many more. The input format is a subset of TeX. %prep %setup ./configure --prefix=/usr %build make %files /usr/bin/cadabra /usr/bin/xcadabra /usr/share/TeXmacs/plugins/cadabra/progs/init-cadabra.scm /usr/share/man/man1/cadabra.1.gz /usr/share/man/man1/xcadabra.1.gz %install make DESTDIR="$RPM_BUILD_ROOT" install cadabra-0.115/spkg-install0000644000077000007700000000021610623024243015003 0ustar kantorkantor#!/bin/sh ./configure --prefix="$SAGE_LOCAL" --disable-gui CPPFLAGS=-I"$SAGE_LOCAL/include" LDFLAGS=-L"SAGE_LOCAL/lib" make make install cadabra-0.115/src/0000700000077000007700000000000010622301241013221 5ustar kantorkantorcadabra-0.115/src/algorithm.cc0000600000077000007700000014172310612672010015534 0ustar kantorkantor/* $Id: algorithm.cc,v 1.161 2007/04/19 16:22:29 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2002 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "algorithm.hh" #include "display.hh" #include "storage.hh" #include "props.hh" #include "modules/dummies.hh" #include "modules/algebra.hh" #include "modules/field_theory.hh" #include #include stopwatch algorithm::index_sw; stopwatch algorithm::get_dummy_sw; consistency_error::consistency_error(const std::string& str) : logic_error(str) { } algorithm_interrupted::algorithm_interrupted() : logic_error("Ctrl-C pressed") { } algorithm_interrupted::algorithm_interrupted(const std::string& str) : logic_error("Ctrl-C pressed while executing "+str) { } active_node::active_node(exptree& tr_, iterator it_) : this_command(it_), tr(tr_), args_begin_(tr_.end()), args_end_(tr_.end()) { } exptree::sibling_iterator active_node::args_begin() const { if(args_begin_==tr.end() && this_command!=tr.end()) { args_begin_=tr.begin(this_command); args_end_ =tr.end(this_command); if(args_begin_!=args_end_) { if(args_begin_->fl.bracket==str_node::b_round || args_begin_->fl.bracket==str_node::b_square) ++args_begin_; } } return args_begin_; } exptree::sibling_iterator active_node::args_end() const { args_begin(); return args_end_; } unsigned int active_node::number_of_args() const { sibling_iterator it=args_begin(); unsigned int ret=0; while(it!=args_end()) { ++ret; ++it; } return ret; } bool active_node::has_argument(const std::string& arg) const { sibling_iterator sit=args_begin(); while(sit!=args_end()) { if(*sit->name==arg) return true; ++sit; } return false; } algorithm::constructor_error::constructor_error() { } algorithm::algorithm(exptree& tr_, iterator it_) : active_node(tr_, it_), equation_number(0), global_success(g_not_yet_started), number_of_calls(0), number_of_modifications(0), suppress_normal_output(false), discard_command_node(false) { } algorithm::~algorithm() { } bool algorithm::can_apply(iterator it) { if(tr.begin(it)!=tr.end(it)) return can_apply(tr.begin(it), tr.end(it)); else return false; } bool algorithm::can_apply(sibling_iterator st, sibling_iterator nd) { txtout << "calling algorithm::can_apply?!?" << std::endl; while(st!=nd) { if(can_apply(st)) return true; ++st; } return false; } algorithm::result_t algorithm::apply(iterator& it) { // This will be called when acting recursively or pointwise, yet the // algorithm only implements range operations. sibling_iterator st=tr.begin(it); sibling_iterator nd=tr.end(it); return apply(st, nd); } algorithm::result_t algorithm::apply(sibling_iterator& st, sibling_iterator& nd) { // This will be called when acting on a mark but the algorithms // implements only node-wise operations. // FIXME: fix this, does not work yet (handle error conditions). result_t retval=l_error; sibling_iterator sbb=st; while(sbb!=nd) { iterator backup=sbb; retval=apply(backup); if(sbb==st) st=backup; sbb=backup; ++sbb; } return retval; } // The entry point called by manipulator.cc void algorithm::apply(unsigned int lue, bool multiple, bool make_copy, int act_at_level, bool called_by_manipulator) { if(called_by_manipulator) { report_progress_stopwatch.stop(); report_progress_stopwatch.reset(); } last_used_equation_number=lue; expression_modified=false; iterator actold=tr.end(); iterator acton=tr.end(); subtree=tr.end(); // Figure out on which subtree the algorithm is supposed to act. if(tr.number_of_children(this_command)>=1) { iterator chld=tr.begin(this_command); if(chld->fl.bracket==str_node::b_round && *this_command->name!="@") { // exception for '@(1)' actold=tr.equation_by_number_or_name(chld, last_used_equation_number, equation_number); global_success=g_arguments_accepted; if(actold==tr.end()) { throw consistency_error("Expression (" +tr.equation_number_or_name(chld, last_used_equation_number) +") does not exist."); return; } else global_success=g_operand_determined; } else if(chld->fl.bracket==str_node::b_square || *this_command->name=="@") { global_success=g_operand_determined; acton=chld; // if(chld->fl.bracket==str_node::b_square) // chld->fl.bracket=str_node::b_none; // otherwise the square brackets stay forever } else { txtout << "applying algorithm on marks (if any)." << std::endl; } } // Depending on the outcome, different actions should be taken to copy the // original tree and store the result. bool is_output_module=dynamic_cast(this); if(actold!=tr.end()) { // act on an existing expression previous_expression=tr.named_parent(tr.active_expression(actold), "\\expression"); if(!is_output_module && make_copy) copy_expression(previous_expression); actold=tr.active_expression(actold); if(multiple) { subtree=actold; apply_recursive(subtree, true, act_at_level, called_by_manipulator); } else { subtree=tr.begin(actold); if(can_apply(subtree)) { ++number_of_calls; report_progress((*this_command->name).substr(1, (*this_command->name).size()-2), 0,0,1); result_t res=apply(subtree); if(expression_modified) { ++number_of_modifications; global_success=g_applied; if(getenv("CDB_PARANOID")) check_consistency(tr.named_parent(subtree,"\\expression")); } else if(is_output_module && res==l_applied) global_success=g_applied; if(res==l_error) global_success=g_apply_failed; } } if(!is_output_module) { if(global_success==g_apply_failed) { if(make_copy) { txtout << "cancelling modification" << std::endl; cancel_modification(); txtout << "cancelling modification done" << std::endl; } subtree=previous_expression; } } discard_command_node=true; } else if(acton!=tr.end()) { // act on argument subtree=acton; if(multiple) { apply_recursive(subtree, true, act_at_level, called_by_manipulator); } else { if(can_apply(subtree)) { global_success=g_operand_determined; ++number_of_calls; report_progress((*this_command->name).substr(1, (*this_command->name).size()-2), 0,0,1); apply(subtree); } } if(is_output_module) global_success=g_applied; // txtout << *this_command->name << " completed, " << (subtree!=tr.end()) << " " // << expression_modified << std::endl; if(/* expression_modified && */ subtree!=tr.end()) { // even if expr. not modified, keep original global_success=g_applied; check_consistency(tr.named_parent(subtree,"\\expression")); multiply(subtree->multiplier, *this_command->multiplier); subtree->fl.bracket=this_command->fl.bracket; subtree->fl.parent_rel=this_command->fl.parent_rel; // Rename dummy indices in the replacement to avoid clashes rename_replacement_dummies(subtree, true); // Then safely replace. First remove all children of the command // node which are not the replacement subtree. sibling_iterator sibrem=tr.begin(this_command); while(sibrem!=tr.end(this_command)) { if(sibrem!=subtree) sibrem=tr.erase(sibrem); else ++sibrem; } // Now flatten the tree at the node. tr.flatten(this_command); tr.erase(this_command); // SOMETHING IS WRONG WITH ARGUMENT STUFF. // subtree=tr.replace(this_command,thiscp,subtree,citp); if(*subtree->name=="\\prod") { if(*tr.parent(subtree)->name=="\\prod") { multiply(tr.parent(subtree)->multiplier, *subtree->multiplier); tr.flatten(subtree); subtree=tr.erase(subtree); } } else { if(*tr.parent(subtree)->name=="\\prod") { if(*subtree->multiplier!=1) { multiply(tr.parent(subtree)->multiplier, *subtree->multiplier); subtree->multiplier=rat_set.insert(1).first; } } else if(*subtree->name=="\\sum") { if(*subtree->multiplier!=1) { sibling_iterator sib=tr.begin(subtree); while(sib!=tr.end(subtree)) { multiply(sib->multiplier, *subtree->multiplier); ++sib; } ::one(subtree->multiplier); } if(*tr.parent(subtree)->name=="\\sum") { tr.flatten(subtree); subtree=tr.erase(subtree); } } } discard_command_node=false; } else { txtout << "* no change" << std::endl; discard_command_node=true; subtree=tr.end(); } } else { // act on marked nodes if(prepare_for_modification(make_copy)) { // there are marks sibling_iterator start=marks[0].first; sibling_iterator end =marks[0].second; result_t res; if(can_apply(start, end)) { ++number_of_calls; res=apply(start,end); if(res==l_error) { cancel_modification(); subtree=previous_expression; } else if(getenv("CDB_PARANOID")) check_consistency(tr.named_parent(subtree,"\\expression")); } else { cancel_modification(); subtree=previous_expression; } } else { // no marks // debugout << "no marks" << std::endl; iterator dummy=tr.end(); ++number_of_calls; result_t res=apply(dummy); if(is_output_module || res!=l_error) global_success=g_applied; } discard_command_node=true; } if(is_output_module) { suppress_normal_output=true; } // txtout << *subtree->name << std::endl; // bughunt: there does not seem to be any slowdown anymore in apply. // ww.stop(); // txtout << " apply took " << ww << std::endl; } // Returns whether the algorithm has applied at least once. // bool algorithm::apply_recursive(exptree::iterator& st, bool check_cons, int act_at_level, bool called_by_manipulator) { assert(tr.is_valid(st)); assert(st!=tr.end()); // bughunt: this one remains constant in time unsigned long count=0; // debugout << "apply_recursive" << std::endl; bool atleastone=false; bool atleastoneglobal=false; post_order_iterator cit=st; post_order_iterator wit; int worked=0; int failed=0; long total_number_of_nodes=0; long processed_number_of_nodes=0; do { // loop which keeps iterating until the expression no longer changes post_order_iterator end; if(act_at_level!=-1) { wit=tr.begin_fixed(st, act_at_level); end=tr.end(); } else { total_number_of_nodes=tr.size(cit); wit=cit; end=wit; wit.descend_all(); ++end; } atleastone=false; int num=1; int applied=0; while(tr.is_valid(wit) && wit!=end) { bool change_st=false; iterator start=wit; // If we are at the top node and the algorithm changes the iterator 'start', // we have to propagate that change into 'st'. if(start==st) change_st=true; if(can_apply(start)) { if(global_successname).substr(1, (*this_command->name).size()-2), total_number_of_nodes, processed_number_of_nodes, 1); ++nextone; // txtout << "applying at " << *wit->name << " next is " << *nextone->name << std::endl; } else { nextone=tr.next_at_same_depth(wit); // txtout << "applying at " << *wit->name << " next is " << *nextone->name << std::endl; } count++; ++number_of_calls; std::string www=*wit->name; result_t res=apply(start); wit=start; // this copying back and forth is needed because wit has different type switch(res) { case l_no_action: ++failed; wit=nextone; break; case l_applied: global_success=g_applied; ++applied; if(change_st) st=start; if(expression_modified) { ++worked; ++number_of_modifications; atleastone=true; atleastoneglobal=true; } if(wit!=tr.end() && *wit->multiplier==0) { // txtout << "propagating..." << std::endl; // THIS IS THE CULPRIT propagate_zeroes(wit,st); // txtout << "Oops? " << *st->name << std::endl; if(*wit->multiplier==0) ++wit; // a top-level zero else if(act_at_level!=-1) wit=nextone; // do not follow post_order sequence } else wit=nextone; break; case l_error: global_success=g_apply_failed; return atleastoneglobal; break; } } else { if(act_at_level==-1) ++wit; else { // txtout << "no luck at " << *wit->name; wit=tr.next_at_same_depth(wit); // txtout << " continuing at " << *wit->name << std::endl; } } if(interrupted) throw algorithm_interrupted("apply_recursive"); ++num; } } while(1==0); //atleastone); enable this again at some point for repeatall type apply if(getenv("CDB_PARANOID")) if(global_success==g_applied && check_cons) check_consistency(tr.named_parent(cit,"\\expression")); // txtout << "algorithm " << (this_command==tr.end()?"?":*this_command->name) << " worked " << worked // << " failed " << failed << std::endl; return atleastoneglobal; } bool algorithm::prepare_for_modification(bool make_copy) { // Collect iterators pointing to all selected nodes and copy the // expression into a new \\expression node where the modifications // can be made. marks.clear(); // tr.marked_nodes(marks); if(marks.size()==0) return false; // previous_expression=tr.named_parent(marks[0], "\\expression"); if(make_copy) copy_expression(previous_expression); // for(unsigned int i=0; imultiplier==0); if(it==topnode) return; iterator walk=tr.parent(it); // debugout << *walk->name << std::endl; if(!tr.is_valid(walk)) return; const Derivative *der=properties::get(walk); if(*walk->name=="\\prod" || der) { if(der && it->is_index()) return; walk->multiplier=rat_set.insert(0).first; it=walk; propagate_zeroes(it, topnode); } else if(*walk->name=="\\pow") { if(tr.index(it)==0) { // the argument walk->multiplier=rat_set.insert(0).first; it=walk; propagate_zeroes(it, topnode); } else { // the exponent rset_t::iterator rem=walk->multiplier; tr.erase(it); tr.flatten(walk); it=tr.erase(walk); node_one(it); it->multiplier=rem; } } else if(*walk->name=="\\sum") { if(tr.number_of_children(walk)>2) { if(tr.is_valid(tr.next_sibling(it))) { it=tr.erase(it); it.descend_all(); } else { iterator ret=tr.parent(it); tr.erase(it); it=ret; } } else { // If the sum is the top node, we cannot flatten it because // we are not allowed to invalidate the topnode iterator if(walk==topnode) return; tr.erase(it); iterator singlearg=tr.begin(walk); if(singlearg!=tr.end(walk)) { singlearg->fl.bracket=walk->fl.bracket; // to remove brackets of the sum if(*tr.parent(walk)->name=="\\prod") { multiply(tr.parent(walk)->multiplier, *singlearg->multiplier); ::one(singlearg->multiplier); } } tr.flatten(walk); it=tr.erase(walk); if(*it->name=="\\prod" && *tr.parent(it)->name=="\\prod") { tr.flatten(it); it=tr.erase(it); } } } else { iterator nn=tr.insert_after(it, str_node("1")); nn->fl.parent_rel=it->fl.parent_rel; nn->fl.bracket=it->fl.bracket; it=tr.erase(it); zero(it->multiplier); } return; } void algorithm::pushup_multiplier(iterator it) { if(!tr.is_valid(it)) return; if(*it->multiplier!=1) { if(*it->name=="\\sum") { sibling_iterator sib=tr.begin(it); while(sib!=tr.end(it)) { multiply(sib->multiplier, *it->multiplier); pushup_multiplier(sib); ++sib; } ::one(it->multiplier); } else { if(tr.is_valid(tr.parent(it))) { const PropertyInherit *pin=properties::get(tr.parent(it)); if(pin || *(tr.parent(it)->name)=="\\prod") { multiply(tr.parent(it)->multiplier, *it->multiplier); pushup_multiplier(tr.parent(it)); ::one(it->multiplier); } } } } } void algorithm::node_zero(iterator it) { ::zero(it->multiplier); tr.erase_children(it); it->name=name_set.insert("1").first; } void algorithm::node_one(iterator it) { ::one(it->multiplier); tr.erase_children(it); it->name=name_set.insert("1").first; } void algorithm::node_integer(iterator it, int num) { ::one(it->multiplier); tr.erase_children(it); it->name=name_set.insert("1").first; ::multiply(it->multiplier, num); } int algorithm::index_parity(iterator it) const { sibling_iterator frst=tr.begin(tr.parent(it)); sibling_iterator fnd(it); int sgn=1; while(frst!=fnd) { sgn=-sgn; ++frst; } return sgn; } bool algorithm::less_without_numbers(nset_t::iterator it1, nset_t::iterator it2) { std::string::const_iterator ch1=(*it1).begin(); std::string::const_iterator ch2=(*it2).begin(); while(ch1!=(*it1).end() && ch2!=(*it2).end()) { if(isdigit(*ch1)) return true; // bla1 < blaq if(isdigit(*ch2)) return false; // blaa !< bla1 if(*ch1>=*ch2) return false; ++ch1; ++ch2; } if(ch1==(*it1).end()) { if(ch2==(*it2).end()) return false; else return true; } return false; } bool algorithm::equal_without_numbers(nset_t::iterator it1, nset_t::iterator it2) { std::string::const_iterator ch1=(*it1).begin(); std::string::const_iterator ch2=(*it2).begin(); while(ch1!=(*it1).end() && ch2!=(*it2).end()) { if(isdigit(*ch1)) { if(isdigit(*ch2)) return true; else return false; } if(*ch1!=*ch2) return false; ++ch1; ++ch2; } if(ch1==(*it1).end()) { if(ch2==(*it2).end()) return true; else return false; } return false; } bool algorithm::check_index_consistency(iterator it) const { index_map_t ind_free, ind_dummy; classify_indices(it,ind_free,ind_dummy); return true; } bool algorithm::check_consistency(iterator it) const { stopwatch w1; w1.start(); debugout << "checking consistency ... " << std::flush; assert(*it->name=="\\expression"); iterator end=it; end.skip_children(); ++end; while(it!=end) { if(interrupted) throw algorithm_interrupted("check_consistency"); if(*it->name=="\\sum") { if(*it->multiplier!=1) throw consistency_error("Found \\sum not with non-unit multiplier."); else if(exptree::number_of_children(it)<2) throw consistency_error("Found a \\sum node with 0 or 1 child nodes."); else { sibling_iterator sumch=it.begin(); str_node::bracket_t firstbracket=sumch->fl.bracket; while(*sumch->name=="\\sum" || *sumch->name=="\\prod") { ++sumch; if(sumch==it.end()) break; else firstbracket=sumch->fl.bracket; } sumch=it.begin(); while(sumch!=it.end()) { if(*sumch->name!="\\sum" && *sumch->name!="\\prod") { if(sumch->fl.bracket!=firstbracket) throw consistency_error("Found a \\sum node with different brackets on its children."); } else if(*sumch->name=="\\sum") { sibling_iterator sumchch=sumch.begin(); while(sumchch!=sumch.end()) { if(sumchch->fl.bracket==str_node::b_none) { tr.print_recursive_treeform(txtout, it); throw consistency_error("Found a sum node with \\sum child without bracketed children."); } ++sumchch; } } ++sumch; } } } else if(*it->name=="\\prod") { if(exptree::number_of_children(it)<=1) throw consistency_error("Found \\prod node with only 0 or 1 children."); sibling_iterator ch=it.begin(); str_node::bracket_t firstbracket=ch->fl.bracket; while(*ch->name=="\\sum" || *ch->name=="\\prod") { ++ch; if(ch==it.end()) break; else firstbracket=ch->fl.bracket; } ch=it.begin(); while(ch!=it.end()) { if(*ch->name!="\\prod" && *ch->name!="\\sum") { if(ch->fl.bracket!=firstbracket) throw consistency_error("Found \\prod node with different brackets on its children."); } if(*ch->multiplier!=1) { throw consistency_error("Found \\prod child with non-unit multiplier."); // debugout << "node name " << *ch->name << ", multiplier " << *ch->multiplier << std::endl; // inconsistent=true; // break; } ++ch; } } else if(*it->name=="\\sequence") { if(exptree::number_of_children(it)!=2) throw consistency_error("Found \\sequence node with incorrect (non-2) number of children."); } ++it; } w1.stop(); debugout << "checking done..." << w1 << std::endl; return true; } void algorithm::report_progress(const std::string& str, int todo, int done, int count) { bool display=false; if(count==2) display=true; else { if(report_progress_stopwatch.stopped()) { display=true; report_progress_stopwatch.start(); } else { if(report_progress_stopwatch.seconds()>0 || report_progress_stopwatch.useconds()>300000L) { display=true; report_progress_stopwatch.reset(); } } } if(display) { // prevents updates at a rate of more than one per second if(output_format==exptree_output::out_xcadabra) { txtout << "" << std::endl << str << std::endl << todo << std::endl << done << std::endl << count << std::endl << "" << std::endl; } else { if(count==2) txtout << str << " (" << done << " of " << todo << " completed)" << std::endl; } } } bool algorithm::rename_replacement_dummies(iterator two, bool still_inside_algo) { // txtout << "full story " << *two->name << std::endl; // print_classify_indices(tr.named_parent(one, "\\expression")); // txtout << "replacement" << std::endl; // print_classify_indices(two); index_map_t ind_free, ind_dummy; index_map_t ind_free_full, ind_dummy_full; if(still_inside_algo) { classify_indices_up(tr.parent(two), ind_free_full, ind_dummy_full); // print_classify_indices(tr.parent(two)); } else { // txtout << "classify indices up" << *(tr.parent(two)->name) << std::endl; classify_indices_up(two, ind_free_full, ind_dummy_full); // the indices in everything except the replacement } classify_indices(two, ind_free, ind_dummy); // the indices in the replacement subtree index_map_t must_be_empty; index_map_t newly_generated; // Catch double index pairs determine_intersection(ind_dummy_full, ind_dummy, must_be_empty); index_map_t::iterator it=must_be_empty.begin(); while(it!=must_be_empty.end()) { // txtout << "double index pair " << *((*it).first.begin()->name) // << " (index appears " << must_be_empty.count((*it).first) // << " times); renaming..." << std::endl; exptree the_key=(*it).first; const Indices *dums=properties::get(it->second); if(!dums) throw consistency_error("Failed to find dummy property for "+*it->second->name+" while renaming dummies"); // txtout << "failed to find dummy property for " << *it->second->name << std::endl; assert(dums); exptree relabel =get_dummy(dums, &ind_dummy_full, &ind_dummy, &ind_free_full, &ind_free, &newly_generated); newly_generated.insert(index_map_t::value_type(exptree(relabel),(*it).second)); // txtout << " renamed to " << *relabel << std::endl; do { tr.replace_index((*it).second, relabel.begin()); // (*it).second->name=relabel; ++it; } while(it!=must_be_empty.end() && tree_exact_equal((*it).first,the_key, 1, true, -2, true)); } // Catch triple indices (two cases: dummy pair in replacement, free index elsewhere and // dummy elsewhere, free index in replacement) must_be_empty.clear(); // newly_generated.clear(); // DO NOT ERASE, IDIOT! determine_intersection(ind_free_full, ind_dummy, must_be_empty); it=must_be_empty.begin(); while(it!=must_be_empty.end()) { // txtout << "triple index " << *((*it).first) // << " (index appears " << must_be_empty.count((*it).first) // << " times); renaming..." << std::endl; exptree the_key=(*it).first; const Indices *dums=properties::get(it->second); assert(dums); exptree relabel =get_dummy(dums, &ind_dummy_full, &ind_dummy, &ind_free_full, &ind_free, &newly_generated); newly_generated.insert(index_map_t::value_type(relabel,(*it).second)); do { tr.replace_index((*it).second, relabel.begin()); // (*it).second->name=relabel; ++it; } while(it!=must_be_empty.end() && tree_exact_equal((*it).first,the_key, 1, true, -2, true)); } must_be_empty.clear(); // newly_generated.clear(); determine_intersection(ind_free, ind_dummy_full, must_be_empty); it=must_be_empty.begin(); while(it!=must_be_empty.end()) { // txtout << "triple index " << *((*it).first) // << " (index appears " << must_be_empty.count((*it).first) // << " times); renaming..." << std::endl; exptree the_key=(*it).first; const Indices *dums=properties::get(it->second); assert(dums); exptree relabel =get_dummy(dums, &ind_dummy_full, &ind_dummy, &ind_free_full, &ind_free, &newly_generated); newly_generated.insert(index_map_t::value_type(relabel,(*it).second)); do { tr.replace_index((*it).second, relabel.begin()); ++it; } while(it!=must_be_empty.end() && tree_exact_equal((*it).first,the_key, 1, true, -2, true)); } return true; } int algorithm::max_numbered_name_one(const std::string& nm, const index_map_t * one) const { assert(one); int themax=0; index_map_t::const_iterator it=one->begin(); while(it!=one->end()) { size_t pos=(*it->first.begin()->name).find_first_of("0123456789"); if(pos!=std::string::npos) { // txtout << (*it->first).substr(0,pos) << std::endl; if((*it->first.begin()->name).substr(0,pos) == nm) { int thenum=atoi((*it->first.begin()->name).substr(pos).c_str()); // txtout << "num = " << thenum << std::endl; themax=std::max(themax, thenum); } } ++it; } return themax; } int algorithm::max_numbered_name(const std::string& nm, const index_map_t * one, const index_map_t * two, const index_map_t * three, const index_map_t * four, const index_map_t * five) const { int themax=0; if(one) { themax=std::max(themax, max_numbered_name_one(nm, one)); if(two) { themax=std::max(themax, max_numbered_name_one(nm, two)); if(three) { themax=std::max(themax, max_numbered_name_one(nm, three)); if(four) { themax=std::max(themax, max_numbered_name_one(nm, four)); if(five) { themax=std::max(themax, max_numbered_name_one(nm, five)); } } } } } return themax; } exptree algorithm::get_dummy(const list_property *dums, const index_map_t * one, const index_map_t * two, const index_map_t * three, const index_map_t * four, const index_map_t * five) const { std::pair pr=properties::pats.equal_range(dums); while(pr.first!=pr.second) { // txtout << "trying " << std::endl; // tr.print_recursive_treeform(txtout, (*pr.first).second->obj.begin()); if(pr.first->second->obj.begin()->is_range_wildcard()) { std::string base=*pr.first->second->obj.begin()->name_only(); int used=max_numbered_name(base, one, two, three, four, five); std::ostringstream str; str << base << used+1; // txtout << "going to use " << str.str() << std::endl; nset_t::iterator newnm=name_set.insert(str.str()).first; exptree ret; ret.set_head(str_node(newnm)); return ret; } else { const exptree& inm=(*pr.first).second->obj; if(!one || one->count(inm)==0) if(!two || two->count(inm)==0) if(!three || three->count(inm)==0) if(!four || four->count(inm)==0) if(!five || five->count(inm)==0) { return inm; } } ++pr.first; } const Indices *dd=dynamic_cast(dums); assert(dd); throw consistency_error("Ran out of dummy indices for type \""+dd->set_name+"\"."); } exptree algorithm::get_dummy(const list_property *dums, iterator it) const { index_map_t one, two, three, four, five; classify_indices_up(it, one, two); classify_indices(it, three, four); return get_dummy(dums, &one, &two, &three, &four, 0); } // Find a dummy index of the type given in "nm", making sure that this index // name does not class with the object in it1 nor it2. exptree algorithm::get_dummy(const list_property *dums, iterator it1, iterator it2) const { index_map_t one, two, three, four, five; classify_indices_up(it1, one, two); classify_indices_up(it2, one, two); classify_indices(it1, three, four); classify_indices(it2, three, four); return get_dummy(dums, &one, &two, &three, &four, 0); } void algorithm::print_classify_indices(iterator st) const { index_map_t ind_free, ind_dummy; classify_indices(st, ind_free, ind_dummy); index_map_t::iterator it=ind_free.begin(); index_map_t::iterator prev=ind_free.end(); txtout << "free indices: " << std::endl; while(it!=ind_free.end()) { if(prev==ind_free.end() || tree_exact_equal((*it).first,(*prev).first,1,true,-2,true)==false) txtout << *(*it).first.begin()->name << " (" << ind_free.count((*it).first) << ") "; prev=it; ++it; } txtout << std::endl; it=ind_dummy.begin(); prev=ind_dummy.end(); txtout << "dummy indices: "; while(it!=ind_dummy.end()) { if(prev==ind_dummy.end() || tree_exact_equal((*it).first,(*prev).first,1,true,-2,true)==false) txtout << *(*it).first.begin()->name << " (" << ind_dummy.count((*it).first) << ") "; prev=it; ++it; } txtout << std::endl; } // For each iterator in the original map, find the sequential position of the index. // That is, the index 'd' has position '3' in A_{a b} C_{c} D_{d}. // WARNING: expensive operation. // void algorithm::fill_index_position_map(iterator prodnode, const index_map_t& im, index_position_map_t& ipm) const { ipm.clear(); index_map_t::const_iterator imit=im.begin(); while(imit!=im.end()) { int current_pos=0; bool found=false; exptree::index_iterator indexit=tr.begin_index(prodnode); while(indexit!=tr.end_index(prodnode)) { if(imit->second==(iterator)(indexit)) { ipm.insert(index_position_map_t::value_type(imit->second, current_pos)); found=true; break; } ++current_pos; ++indexit; } ++imit; } } void algorithm::fill_map(index_map_t& mp, sibling_iterator st, sibling_iterator nd) const { while(st!=nd) { mp.insert(index_map_t::value_type(exptree(st), iterator(st))); ++st; } } // Determine those indices in 'two' which have a name which is identical to // an index name occurring in 'one'. Store these indices of 'two' in target. // If 'move_out' is true, instead move both the indices in 'one' and 'two' // (i.e. move instead of copy, and also store the 'one' index). // // One exception: numerical, coordinate and symbol indices are always kept in 'one'. // void algorithm::determine_intersection(index_map_t& one, index_map_t& two, index_map_t& target, bool move_out) const { index_map_t::iterator it1=one.begin(); while(it1!=one.end()) { const Coordinate *cdn=properties::get(it1->second); const Symbol *smb=properties::get(it1->second); if(it1->second->is_integer()==false && !cdn && !smb) { bool move_this_one=false; index_map_t::iterator it2=two.begin(); while(it2!=two.end()) { if(tree_exact_equal((*it1).first,(*it2).first,1,true,-2,true)) { target.insert((*it2)); if(move_out) { index_map_t::iterator nxt=it2; ++nxt; two.erase(it2); it2=nxt; move_this_one=true; } else ++it2; } else ++it2; } exptree the_key=(*it1).first; if(move_this_one && move_out) { index_map_t::iterator nxt=it1; ++nxt; target.insert(*it1); one.erase(it1); it1=nxt; } else ++it1; // skip all indices in two with the same name while(it1!=one.end() && tree_exact_equal((*it1).first,the_key,1,true,-2,true)) { if(move_this_one && move_out) { index_map_t::iterator nxt=it1; ++nxt; target.insert(*it1); one.erase(it1); it1=nxt; } else ++it1; } } else ++it1; } } // Directly add an index to the free/dummy sets, as appropriate (only add if this really is an // index!) void algorithm::classify_add_index(iterator it, index_map_t& ind_free, index_map_t& ind_dummy) const { if((it->fl.parent_rel==str_node::p_sub || it->fl.parent_rel==str_node::p_super) && it->fl.bracket==str_node::b_none /* && it->is_integer()==false */) { if(it->is_integer()) ind_free.insert(index_map_t::value_type(exptree(it), it)); else { index_map_t::iterator fnd=ind_free.find(it); if(fnd!=ind_free.end()) { if(ind_dummy.count(it)>0) { txtout << "triple index occurred." << std::endl; } ind_dummy.insert(*fnd); ind_dummy.insert(index_map_t::value_type(exptree(it), it)); ind_free.erase(fnd); } else { ind_free.insert(index_map_t::value_type(exptree(it), it)); } } } } // This classifies indices bottom-up, that is, given a node, it goes up the tree to find // all free and dummy indices in the product in which this node would end up if a full // distribute would be done on the entire expression. void algorithm::classify_indices_up(iterator it, index_map_t& ind_free, index_map_t& ind_dummy) const { loopie: iterator par=exptree::parent(it); if(tr.is_valid(par)==false || par==tr.end() || *par->name=="\\expression" || *par->name=="\\history") { // reached the top return; } const IndexInherit *inh=properties::get(par); // txtout << "class: " << *par->name << std::endl; if(*par->name=="\\sum" || *par->name=="\\equals") { // sums or equal signs are no problem since the other terms do not end up in our // factor; therefore, just go up. it=par; goto loopie; } else if(*par->name=="\\commutator" || *par->name=="\\anticommutator" || *par->name=="\\indexbracket" || *par->name=="\\fermibilinear" || inh) { // For each _other_ child in this product, do a top-down classify for all non-sub/super // children; add the indices thus found to the maps since they will end up in our factor. sibling_iterator sit=par.begin(); while(sit!=par.end()) { if(sit!=sibling_iterator(it)) { if(sit->is_index()==false) { index_map_t factor_free, factor_dummy; classify_indices(sit, factor_free, factor_dummy); // Test for absence of triple or quadruple indices index_map_t must_be_empty; determine_intersection(factor_free, ind_dummy, must_be_empty); if(must_be_empty.size()>0) txtout << "triple index occurred." << std::endl; // Test for absence of double index pairs must_be_empty.clear(); determine_intersection(factor_dummy, ind_dummy, must_be_empty); if(must_be_empty.size()>0) txtout << "double index pair occurred." << std::endl; ind_dummy.insert(factor_dummy.begin(), factor_dummy.end()); index_map_t new_dummy; determine_intersection(factor_free, ind_free, new_dummy, true); ind_free.insert(factor_free.begin(), factor_free.end()); ind_dummy.insert(new_dummy.begin(), new_dummy.end()); } else { // ind_free.insert(free_so_far.begin(), free_so_far.end()); // free_so_far.clear(); classify_add_index(sit, ind_free, ind_dummy); } } ++sit; } it=par; goto loopie; } else if(*par->name=="\\expression") { // reached the top index_sw.stop(); return; } else if((*par->name).size()>0 && (*par->name)[0]=='@') { // command nodes swallow everything index_sw.stop(); return; } else if(*par->name=="\\tie") { // tie lists do not care about indices ind_free.clear(); ind_dummy.clear(); it=par; goto loopie; } else if(*par->name=="\\arrow") { // rules can have different indices on lhs and rhs // ind_free.clear(); // ind_dummy.clear(); it=par; goto loopie; } // else if(*par->name=="\\indexbracket") { // it's really just a bracket, so go up // sibling_iterator sit=tr.begin(par); // ++sit; // while(sit!=tr.end(par)) { // ++sit; // } // it=par; // goto loopie; // } else if(*par->name=="\\comma") { // comma lists can contain anything NO: [a_{mu}, b_{nu}] // reaching a comma node is like reaching the top of an expression. return; } // FIXME: do something with these warnings!! // txtout << "Index classification for this expression failed because of " // << *par->name << " node, disabling index checking." << std::endl; // assert(1==0); ind_free.clear(); ind_dummy.clear(); } void algorithm::dumpmap(std::ostream& str, const index_map_t& mp) const { index_map_t::const_iterator dpr=mp.begin(); while(dpr!=mp.end()) { str << *(dpr->first.begin()->name) << " "; ++dpr; } str << std::endl; } // This classifies indices top-down, that is, finds the free indices and all dummy // index pairs used in the full subtree below a given node. void algorithm::classify_indices(iterator it, index_map_t& ind_free, index_map_t& ind_dummy) const { index_sw.start(); // txtout << " " << *it->name << std::endl; const IndexInherit *inh=properties::get(it); if(*it->name=="\\sum" || *it->name=="\\equals") { index_map_t first_free; sibling_iterator sit=it.begin(); bool is_first_term=true; while(sit!=it.end()) { if(*sit->multiplier!=0) { // zeroes are always ok index_map_t term_free, term_dummy; classify_indices(sit, term_free, term_dummy); if(!is_first_term) { index_map_t::iterator fri=first_free.begin(); while(fri!=first_free.end()) { const Coordinate *cdn=properties::get(fri->second); const Symbol *smb=properties::get(fri->second); // integer, coordinate or symbol indices always ok if(fri->second->is_integer()==false && !cdn && !smb) { if(term_free.count((*fri).first)==0) { debugout << "free indices elsewhere: "; dumpmap(debugout, first_free); debugout << "free indices here : "; dumpmap(debugout, term_free); if(*it->name=="\\sum") throw consistency_error("Free indices in different terms in a sum do not match."); else throw consistency_error("Free indices on lhs and rhs do not match."); } } ++fri; } fri=term_free.begin(); while(fri!=term_free.end()) { const Coordinate *cdn=properties::get(fri->second); const Symbol *smb=properties::get(fri->second); // integer, coordinate or symbol indices always ok if(fri->second->is_integer()==false && !cdn && !smb) { if(first_free.count((*fri).first)==0) { debugout << "free indices elsewhere: "; dumpmap(debugout, first_free); debugout << "free indices here : "; dumpmap(debugout, term_free); if(*it->name=="\\sum") throw consistency_error("Free indices in different terms in a sum do not match."); else throw consistency_error("Free indices on lhs and rhs do not match."); } } ++fri; } } else { first_free=term_free; is_first_term=false; } ind_dummy.insert(term_dummy.begin(), term_dummy.end()); ind_free.insert(term_free.begin(), term_free.end()); } ++sit; } } else if(*it->name=="\\commutator" || *it->name=="\\anticommutator" || inh) { index_map_t free_so_far; sibling_iterator sit=it.begin(); while(sit!=it.end()) { if(sit->is_index()==false) { index_map_t factor_free, factor_dummy; classify_indices(sit, factor_free, factor_dummy); // Test for absence of triple or quadruple indices index_map_t must_be_empty; determine_intersection(factor_free, ind_dummy, must_be_empty); if(must_be_empty.size()>0) throw consistency_error("Triple index " + *sit->name + " inside a single factor found."); // Test for absence of double index pairs must_be_empty.clear(); determine_intersection(factor_dummy, ind_dummy, must_be_empty); if(must_be_empty.size()>0) throw consistency_error("Double index pair " + *sit->name + " inside a single factor found."); ind_dummy.insert(factor_dummy.begin(), factor_dummy.end()); index_map_t new_dummy; determine_intersection(factor_free, free_so_far, new_dummy, true); free_so_far.insert(factor_free.begin(), factor_free.end()); // txtout << "free_so_far: " << free_so_far.size() << std::endl; ind_dummy.insert(new_dummy.begin(), new_dummy.end()); } else { // ind_free.insert(free_so_far.begin(), free_so_far.end()); // free_so_far.clear(); classify_add_index(sit, free_so_far, ind_dummy); } ++sit; // const Derivative *der=properties::get(it); // if(*it->name=="\\indexbracket" || der) { // the other children are indices themselves // ind_free.insert(free_so_far.begin(), free_so_far.end()); // free_so_far.clear(); // while(sit!=it.end()) { // classify_add_index(sit, ind_free, ind_dummy); // ++sit; // } // break; // } } ind_free.insert(free_so_far.begin(), free_so_far.end()); } else if(*it->name=="\\expression") { classify_indices(it.begin(), ind_free, ind_dummy); } else if(*it->name=="\\tie") { ind_free.clear(); ind_dummy.clear(); } else if((*it->name).size()>0 && (*it->name)[0]=='@') { // This is an active node that has not been replaced yet; since // we do not know anything about what this will become, do not return // any index information (clashes will be resolved when the active // node gets replaced). } else { // txtout << "classifying " << *it->name << std::endl; sibling_iterator sit=it.begin(); index_map_t item_free; index_map_t item_dummy; while(sit!=it.end()) { // txtout << *sit->name << std::endl; if((sit->fl.parent_rel==str_node::p_sub || sit->fl.parent_rel==str_node::p_super) && sit->fl.bracket==str_node::b_none /* && sit->is_integer()==false */) { if(*sit->name!="??") { const Coordinate *cdn=properties::get(sit); const Symbol *smb=properties::get(sit); // integer, coordinate or symbol indices always ok if(sit->is_integer() || cdn || smb) { item_free.insert(index_map_t::value_type(exptree(sit), iterator(sit))); } else { index_map_t::iterator fnd=item_free.find(exptree(sit)); if(fnd!=item_free.end()) { if(item_dummy.find(exptree(sit))!=item_dummy.end()) throw consistency_error("Triple index " + *sit->name + " inside a single factor found."); item_dummy.insert(*fnd); item_free.erase(fnd); item_dummy.insert(index_map_t::value_type(exptree(sit), iterator(sit))); } else { item_free.insert(index_map_t::value_type(exptree(sit), iterator(sit))); } } } } // else { // item_free.insert(index_map_t::value_type(sit->name, iterator(sit))); // } ++sit; } ind_free.insert(item_free.begin(), item_free.end()); ind_dummy.insert(item_dummy.begin(), item_dummy.end()); } // txtout << "ind_free: " << ind_free.size() << std::endl; // txtout << "ind_dummy: " << ind_dummy.size() << std::endl; index_sw.stop(); } bool algorithm::contains(sibling_iterator from, sibling_iterator to, sibling_iterator arg) { while(from!=to) { if(from->name==arg->name) return true; ++from; } return false; } algorithm::range_vector_t::iterator algorithm::find_arg_superset(range_vector_t& ran, sibling_iterator it) { sibling_iterator nxt=it; ++nxt; return find_arg_superset(ran, it, nxt); } void algorithm::find_argument_lists(range_vector_t& ran, bool only_comma_lists) const { sibling_iterator argit=args_begin(); while(argit!=args_end()) { if(*argit->name=="\\comma") { ran.push_back(range_t(tr.begin(argit), tr.end(argit))); } else if(!only_comma_lists) { sibling_iterator argnxt=argit; ++argnxt; ran.push_back(range_t(argit, argnxt)); } ++argit; } } template algorithm::range_vector_t::iterator algorithm::find_arg_superset(range_vector_t& ran, Iter st, Iter nd) { range_vector_t::iterator ranit=ran.begin(); while(ranit!=ran.end()) { sibling_iterator findthese=st; bool contained=true; while(findthese!=nd) { if(contains((*ranit).first, (*ranit).second, findthese)) { ++findthese; } else { contained=false; break; } } if(contained) return ranit; ++ranit; } return ran.end(); } bool algorithm::is_single_term(iterator it) { if(*it->name!="\\prod" && *it->name!="\\sum" && *it->name!="\\asymimplicit" && *it->name!="\\comma") { if(tr.is_valid(tr.parent(it))) { if(*tr.parent(it)->name=="\\sum" || *tr.parent(it)->name=="\\expression" || tr.parent(it)->is_command()) return true; } else return true; } return false; } bool algorithm::prod_wrap_single_term(iterator& it) { if(is_single_term(it)) { iterator prodnode=tr.insert(it, str_node("\\prod")); sibling_iterator fr=it, to=it; ++to; tr.reparent(prodnode, fr, to); prodnode->fl.bracket=it->fl.bracket; it->fl.bracket=str_node::b_none; prodnode->multiplier=it->multiplier; one(it->multiplier); it=prodnode; return true; } return false; } bool algorithm::prod_unwrap_single_term(iterator& it) { if((*it->name)=="\\prod") { if(tr.number_of_children(it)==1) { multiply(tr.begin(it)->multiplier, *it->multiplier); tr.begin(it)->fl.bracket=it->fl.bracket; tr.begin(it)->multiplier=it->multiplier; tr.flatten(it); it=tr.erase(it); return true; } } return false; } void cleanup_expression(exptree& tr) { exptree::iterator it=tr.begin(); cleanup_expression(tr,it); } void cleanup_expression(exptree& tr, exptree::iterator& it) { // txtout << "cleanup called on " << *it->name << std::endl; ratrewrite rr(tr, tr.end()); rr.apply_recursive(it,false); reduce_sub rsub(tr, tr.end()); rsub.apply_recursive(it, false); reduce_div rdiv(tr, tr.end()); rdiv.apply_recursive(it, false); cleanup_sums_products(tr,it); } void cleanup_sums_products(exptree& tr, exptree::iterator& it) { sumflatten sf(tr, tr.end()); sf.make_consistent_only=true; sf.apply_recursive(it, false); prodflatten pf(tr, tr.end()); pf.make_consistent_only=true; pf.apply_recursive(it, false); // collect_terms ct(tr, tr.end()); // This collect_terms makes A+A input become 2*A automatically // ct.apply_recursive(it,false); // which goes against the spirit of cdb; now disabled. prodcollectnum pc(tr, tr.end()); pc.apply_recursive(it,false); // ct.apply_recursive(it,false); } void cleanup_nests(exptree&tr, exptree::iterator &it) { // txtout << "** " << *it->name << std::endl; if(!tr.is_valid(tr.parent(it))) return; if(*(it->name)=="\\prod") { assert(tr.parent(it)!=tr.end()); // txtout << "*** " << *tr.parent(it)->name << std::endl; if(*(tr.parent(it)->name)=="\\prod") { multiplier_t fac=*(tr.parent(it)->multiplier)*(*it->multiplier); tr.parent(it)->multiplier=rat_set.insert(fac).first; tr.flatten(it); it=tr.erase(it); } // else if(*(tr.parent(it)->name)=="\\diff") { // multiply(tr.parent(it)->multiplier, *it->multiplier); // one(it->multiplier); // } return; } if(*(it->name)=="\\sum") { assert(tr.parent(it)!=tr.end()); // txtout << "*** " << *tr.parent(it)->name << std::endl; if(*(tr.parent(it)->name)=="\\sum") { // WARNING, this is a copy of code in sumflatten! exptree::sibling_iterator facs=tr.begin(tr.parent(it)); str_node::bracket_t btype_par=facs->fl.bracket; exptree::sibling_iterator terms=tr.begin(it); while(terms!=tr.end(it)) { multiplier_t tfac=(*terms->multiplier)*(*it->multiplier); terms->multiplier=rat_set.insert(tfac).first; terms->fl.bracket=btype_par; ++terms; } tr.flatten(it); it=tr.parent(tr.erase(it)); } return; } const Derivative *der=properties::get(it); if(der) { // take constants outside multiply(it->multiplier, *(tr.begin()->multiplier)); one(tr.begin()->multiplier); // flatten nested diffs assert(tr.parent(it)!=tr.end()); der=properties::get(tr.parent(it)); if(der && tr.parent(it)->name==it->name) { multiplier_t fac=*(tr.parent(it)->multiplier)*(*it->multiplier); tr.parent(it)->multiplier=rat_set.insert(fac).first; tr.flatten(it); it=tr.erase(it); } return; } } cadabra-0.115/src/algorithm.hh0000600000077000007700000002351010606501476015551 0ustar kantorkantor/* $Id: algorithm.hh,v 1.79 2007/04/07 21:43:13 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2002 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef algorithm_hh_ #define algorithm_hh_ #include #include "stopwatch.hh" #include "storage.hh" #include "props.hh" #include "display.hh" #include // These are initiated in main.cc #include extern std::ostream *fake_txtout; #define txtout (*fake_txtout) extern std::ostream *fake_forcedout; #define forcedout (*fake_forcedout) extern modglue::opipe texout; extern std::ofstream debugout; extern bool interrupted; extern stopwatch globaltime; /// An error class which can be thrown if there is no local way to recover /// from an error. Will be handled at the top level and will lead to /// the current expression being removed from the tree. class consistency_error : public std::logic_error { public: consistency_error(const std::string&); }; /// An error class which should be thrown by any algorithm as soon as it /// detects that the "interrupted" flag has been set by the sigint signal /// handler. class algorithm_interrupted : public std::logic_error { public: algorithm_interrupted(); algorithm_interrupted(const std::string&); }; /// Base class for objects which represent algorithms, i.e. which get /// expanded by the manipulator when they are encountered in the tree. class active_node { public: typedef exptree::iterator iterator; typedef exptree::post_order_iterator post_order_iterator; typedef exptree::sibling_iterator sibling_iterator; active_node(exptree&, iterator); virtual ~active_node() {}; // Helpers for iterating over or inspecting argument lists. sibling_iterator args_begin() const; sibling_iterator args_end() const; unsigned int number_of_args() const; bool has_argument(const std::string&) const; virtual void description() const=0; iterator this_command; protected: exptree& tr; mutable sibling_iterator args_begin_; mutable sibling_iterator args_end_; // Return the number of elements in the first range for which an identical element // is present in the second range. template unsigned int intersection_number(sibling_iterator, sibling_iterator, sibling_iterator, sibling_iterator, BinaryPredicate) const; }; class algorithm : public active_node { public: algorithm(exptree&, iterator); virtual ~algorithm(); class constructor_error { public: constructor_error(); }; enum result_t { l_no_action, l_applied, l_error }; enum global_success_t { g_not_yet_started=0, g_arguments_accepted=1, g_operand_determined=2, g_applied=4, g_apply_failed=6 }; virtual bool can_apply(iterator); virtual bool can_apply(sibling_iterator, sibling_iterator); // These return their result in the return value virtual result_t apply(iterator&); virtual result_t apply(sibling_iterator&, sibling_iterator&); // These give result in global_success. bool apply_recursive(iterator&, bool check_consistency=true, int act_at_level=-1, bool called_by_manipulator=false); void apply(unsigned int last_used_equation_number, bool multiple, bool make_copy, int act_at_level=-1, bool called_by_manipulator=false); // Per-call information bool expression_modified; iterator subtree; // subtree to be displayed unsigned int equation_number; // Global information global_success_t global_success; unsigned int number_of_calls; unsigned int number_of_modifications; bool suppress_normal_output; bool discard_command_node; // Any output will follow the settings of this flag. exptree_output::output_format_t output_format; // Given an \expression node, check consistency bool check_consistency(iterator) const; bool check_index_consistency(iterator) const; static stopwatch index_sw; static stopwatch get_dummy_sw; void report_progress(const std::string&, int todo, int done, int count=2); stopwatch report_progress_stopwatch; protected: unsigned int last_used_equation_number; // FIXME: this is a hack, just to see this in 'eqn'. std::vector > marks; iterator previous_expression; bool dont_iterate; // Index stuff int index_parity(iterator) const; static bool less_without_numbers(nset_t::iterator, nset_t::iterator); static bool equal_without_numbers(nset_t::iterator, nset_t::iterator); /// Finding objects in sets. typedef std::pair range_t; typedef std::vector range_vector_t; bool contains(sibling_iterator from, sibling_iterator to, sibling_iterator arg); void find_argument_lists(range_vector_t&, bool only_comma_lists=true) const; template range_vector_t::iterator find_arg_superset(range_vector_t&, Iter st, Iter nd); range_vector_t::iterator find_arg_superset(range_vector_t&, sibling_iterator it); /// Take a single non-product node in a sum and wrap it in a /// product node, so it can be handled on the same footing as a proper product. bool is_single_term(iterator); bool prod_wrap_single_term(iterator&); bool prod_unwrap_single_term(iterator&); // Given a node with non-zero multiplier, distribute this // multiplier up the tree when the node is a \sum node, or push it into the // \prod node if that is the parent. Do this recursively // in case a child is a sum as well. void pushup_multiplier(iterator); // Turn a node into a '1' or '0' node. void node_zero(iterator); void node_one(iterator); void node_integer(iterator, int); // Find all dummy index pairs in an expression. This takes into account // products and sums. // Note: dummy indices do not always come in pairs, for instance // a_{m n} ( b^{n p} + q^{n p} ) // /// A map from a pattern to the position where it occurs in the tree. typedef std::multimap index_map_t; /// A map from the position of each index to the sequential index. typedef std::map index_position_map_t; void fill_index_position_map(iterator, const index_map_t&, index_position_map_t&) const; void fill_map(index_map_t&, sibling_iterator, sibling_iterator) const; bool rename_replacement_dummies(iterator, bool still_inside_algo=false); void print_classify_indices(iterator) const; void determine_intersection(index_map_t& one, index_map_t& two, index_map_t& target, bool move_out=false) const; void classify_add_index(iterator it, index_map_t& ind_free, index_map_t& ind_dummy) const; void classify_indices_up(iterator, index_map_t& ind_free, index_map_t& ind_dummy) const; void classify_indices(iterator, index_map_t& ind_free, index_map_t& ind_dummy) const; int max_numbered_name_one(const std::string& nm, const index_map_t * one) const; int max_numbered_name(const std::string&, const index_map_t *m1, const index_map_t *m2=0, const index_map_t *m3=0, const index_map_t *m4=0, const index_map_t *m5=0) const; exptree get_dummy(const list_property *, const index_map_t *m1, const index_map_t *m2=0, const index_map_t *m3=0, const index_map_t *m4=0, const index_map_t *m5=0) const; exptree get_dummy(const list_property *, iterator) const; exptree get_dummy(const list_property *, iterator, iterator) const; private: void cancel_modification(); void copy_expression(exptree::iterator) const; bool prepare_for_modification(bool make_copy); /// Given a node with zero multiplier, propagate this zero /// upwards in the tree. Changes the iterator so that it points /// to the next node in a post_order traversal (post_order: /// children first, then node). The second node is the topmost /// node, beyond which this routine is not allowed to touch the /// tree (i.e. the 2nd iterator will always remain valid). void propagate_zeroes(post_order_iterator&, const iterator&); void dumpmap(std::ostream&, const index_map_t&) const; }; void cleanup_expression(exptree&); void cleanup_expression(exptree&, exptree::iterator&); // may change the pointer! void cleanup_sums_products(exptree&, exptree::iterator&); void cleanup_nests(exptree&tr, exptree::iterator &it); template std::auto_ptr create(exptree& tr, exptree::iterator it) { return std::auto_ptr(new T(tr, it)); } /// Determine the number of elements in the first range which also occur in the /// second range. template unsigned int active_node::intersection_number(sibling_iterator from1, sibling_iterator to1, sibling_iterator from2, sibling_iterator to2, BinaryPredicate fun) const { unsigned int ret=0; sibling_iterator it1=from1; while(it1!=to1) { sibling_iterator it2=from2; while(it2!=to2) { if(fun(*it1,*it2)) ++ret; ++it2; } ++it1; } return ret; } #endif cadabra-0.115/src/ChangeLog0000600000077000007700000000000007465771503015012 0ustar kantorkantorcadabra-0.115/src/combinatorics.cc0000600000077000007700000000324610555362626016416 0ustar kantorkantor #include "combinatorics.hh" unsigned long combin::factorial(unsigned int x) { unsigned long ret=1; while(x) { ret*=x--; } return ret; } int combin::determine_intersection_ranges(const combin::range_vector_t& prod, const combin::range_vector_t& indv, combin::range_vector_t& target) { int ret=1; for(unsigned int i=0; i=2) { ret*=factorial(newrange.size()); target.push_back(newrange); } } } return ret; } long combin::vector_sum(const std::vector& v) { long ret=0; for(unsigned int i=0; i& v) { unsigned long ret=1; for(unsigned int i=0; i& v) { unsigned long ret=1; for(unsigned int i=0; i& one, const std::vector& two) { if(one.size()!=two.size()) return false; for(unsigned int k=0; k& one) { long ret=1; for(unsigned int k=0; k #include #include #include #include #include namespace combin { typedef std::vector range_t; typedef std::vector range_vector_t; typedef std::vector weights_t; unsigned long factorial(unsigned int x); /// sum of elements long vector_sum(const std::vector&); /// product of elements unsigned long vector_prod(const std::vector&); /// product of factorials of elements unsigned long vector_prod_fact(const std::vector&); bool operator==(const std::vector&, const std::vector&); /// compute a hash value for a vector of unsigned ints long hash(const std::vector&); template class combinations_base { public: combinations_base(); combinations_base(const std::vector&); virtual ~combinations_base(); void permute(long start=-1, long end=-1); virtual void clear(); virtual void clear_results(); unsigned int sum_of_sublengths() const; void set_unit_sublengths(); unsigned int multiplier(const std::vector&) const; unsigned int total_permutations() const; // including the ones not stored enum weight_cond { weight_equals, weight_less, weight_greater }; unsigned int block_length; std::vector sublengths; range_vector_t input_asym; std::vector original; bool multiple_pick; std::vector weights; std::vector max_weights; std::vector weight_conditions; unsigned int sub_problem_blocksize; // when non-zero, do permutations within protected: virtual void vector_generated(const std::vector&)=0; virtual bool entry_accepted(unsigned int current) const; std::vector temparr; long start_, end_, vector_generated_called_; std::vector current_weight; private: bool is_allowed_by_weight_constraints(unsigned int i); bool final_weight_constraints_check() const; void update_weights(unsigned int i); void restore_weights(unsigned int i); void nextstep(unsigned int current, unsigned int fromalgehad, unsigned int groupindex, std::vector algehad); }; template class combinations : public combinations_base { public: typedef typename std::vector > permuted_sets_t; typedef typename permuted_sets_t::const_iterator const_iterator; combinations(); combinations(const std::vector&); virtual ~combinations(); virtual void clear(); virtual void clear_results(); const std::vector& operator[](unsigned int) const; int ordersign(unsigned int) const; unsigned int size() const; unsigned int multiplier(unsigned int) const; protected: virtual void vector_generated(const std::vector&); private: permuted_sets_t storage; }; template class symmetriser; template class symm_helper : public combinations_base { public: symm_helper(symmetriser&); virtual void clear(); int current_multiplicity; protected: bool first_one; symmetriser& owner_; virtual void vector_generated(const std::vector&); }; template class symm_val_helper : public combinations_base { public: symm_val_helper(symmetriser&); virtual void clear(); int current_multiplicity; protected: bool first_one; symmetriser& owner_; virtual void vector_generated(const std::vector&); }; template class symmetriser { public: symmetriser(); void apply_symmetry(long start=-1, long end=-1); std::vector original; unsigned int block_length; std::vector permute_blocks; // offset in unit elements! (not in blocks) std::vector value_permute; int permutation_sign; std::vector sublengths; // refers to position within permute_blocks range_vector_t input_asym; // as in combinations_base range_vector_t sublengths_scattered; // sublengths, in original, but not connected. /// Convert vectors of values to vectors of locations in the original /// (mainly useful to create input_asym for permutation by value). range_t values_to_locations(const std::vector& values) const; const std::vector& operator[](unsigned int) const; int signature(unsigned int) const; void set_multiplicity(unsigned int pos, int val); unsigned int size() const; void clear(); /// Collect equal entries, and adjust the multiplier field accordingly. void collect(); void remove_multiplicity_zero(); friend class symm_helper; friend class symm_val_helper; private: symm_helper sh_; symm_val_helper svh_; unsigned int current_; std::vector > originals; std::vector multiplicity; }; int determine_intersection_ranges(const range_vector_t& prod, const range_vector_t& indv, range_vector_t& target); template int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, int stepsize=1); template int ordersign(iterator1 b1, iterator1 e1); template T fact(T x); template std::ostream& operator<<(std::ostream& str, const symmetriser& sym); /* I assume PI consists of the integers 1 to N. It can be done with O(N) comparisons and transpositions of integers in the list. sign:= 1; for i from 1 to N do while PI[i] <> i do interchange PI[i] and PI[PI[i]]; sign:= -sign od od */ template int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, int stepsize) { int sign=1; std::vector crossedoff(std::distance(b1,e1),false); while(b1!=e1) { int otherpos=0; iterator2 it=b2; while(it!=e2) { if((*it)==(*b1) && crossedoff[otherpos]==false) { crossedoff[otherpos]=true; break; } else { if(!crossedoff[otherpos]) sign=-sign; } it+=stepsize; ++otherpos; } b1+=stepsize; } return sign; } //template //int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, comparator cmp, int stepsize) // { // int sign=1; // std::vector crossedoff(std::distance(b1,e1),false); // while(b1!=e1) { // int otherpos=0; // iterator2 it=b2; // while(it!=e2) { // if(cmp((*it), (*b1)) && crossedoff[otherpos]==false) { // crossedoff[otherpos]=true; // break; // } // else { // if(!crossedoff[otherpos]) // sign=-sign; // } // it+=stepsize; // ++otherpos; // } // b1+=stepsize; // } // return sign; // } template int ordersign(iterator1 b1, iterator1 e1) { std::vector fil; for(int k=0; k T fact(T x) { T ret=1; assert(x>=0); while(x!=0) { ret*=x--; } return ret; } // Implementations template combinations_base::combinations_base() : block_length(1), multiple_pick(false), sub_problem_blocksize(0) { } template combinations_base::combinations_base(const std::vector& oa) : block_length(1), original(oa), multiple_pick(false), sub_problem_blocksize(0) { } template combinations::combinations() : combinations_base() { } template combinations::combinations(const std::vector& oa) : combinations_base(oa) { } template combinations_base::~combinations_base() { } template combinations::~combinations() { } template void combinations::vector_generated(const std::vector& toadd) { ++this->vector_generated_called_; if((this->start_==-1 || this->vector_generated_called_ >= this->start_) && (this->end_==-1 || this->vector_generated_called_ < this->end_)) { std::vector newone(toadd.size()*this->block_length); for(unsigned int i=0; iblock_length; ++bl) newone[i*this->block_length+bl]=this->original[toadd[i]*this->block_length+bl]; storage.push_back(newone); } } template bool combinations_base::entry_accepted(unsigned int) const { return true; } template void combinations_base::permute(long start, long end) { start_=start; end_=end; vector_generated_called_=-1; // Initialise weight handling. current_weight.clear(); current_weight.resize(weights.size(), 0); for(unsigned int i=0; i0) { if(weight_conditions.size()==0) weight_conditions.resize(weights.size(), weight_equals); else assert(weight_conditions.size()==weights.size()); } else assert(weight_conditions.size()==0); // Sublength handling. assert(sublengths.size()!=0); unsigned int len=sum_of_sublengths(); // Consistency checks. assert(original.size()%block_length==0); if(!multiple_pick) assert(len*block_length<=original.size()); for(unsigned int i=0; iinput_asym.size(); ++i) std::sort(this->input_asym[i].begin(), this->input_asym[i].end()); temparr=std::vector(len/* *block_length*/); std::vector algehad(original.size()/block_length,false); nextstep(0,0,0,algehad); } template void combinations_base::clear() { block_length=1; sublengths.clear(); this->input_asym.clear(); original.clear(); weights.clear(); max_weights.clear(); weight_conditions.clear(); sub_problem_blocksize=0; temparr.clear(); current_weight.clear(); } template void combinations_base::clear_results() { temparr.clear(); } template void combinations::clear() { storage.clear(); combinations_base::clear(); } template void combinations::clear_results() { storage.clear(); combinations_base::clear_results(); } template const std::vector& combinations::operator[](unsigned int i) const { assert(i unsigned int combinations::size() const { return storage.size(); } template unsigned int combinations_base::sum_of_sublengths() const { unsigned int ret=0; for(unsigned int i=0; i unsigned int combinations_base::total_permutations() const { return vector_generated_called_+1; } template void combinations_base::set_unit_sublengths() { sublengths.clear(); for(unsigned int i=0; i int combinations::ordersign(unsigned int num) const { assert(numblock_length); } template unsigned int combinations::multiplier(unsigned int num) const { return combinations_base::multiplier(this->storage[num]); } template unsigned int combinations_base::multiplier(const std::vector& stor) const { unsigned long numerator=1; for(unsigned int i=0; iinput_asym.size(); ++i) numerator*=fact(this->input_asym[i].size()); unsigned long denominator=1; for(unsigned int i=0; iinput_asym.size(); ++i) { // for each input asym, and for each output asym, count // the number of overlap elements. unsigned int current=0; for(unsigned int k=0; ksublengths.size(); ++k) { if(this->sublengths[k]>1) { unsigned int overlap=0; for(unsigned int slc=0; slcsublengths[k]; ++slc) { for(unsigned int j=0; jinput_asym[i].size(); ++j) { unsigned int index=0; while(!(stor[current]==this->original[index])) ++index; if(index==this->input_asym[i][j]) ++overlap; } ++current; } if(overlap>0) denominator*=fact(overlap); // FIXME: for each overlap thus found, divide out by a factor // due to the fact that output asym ranges can overlap. // well, that's not right either. } else ++current; } } return numerator/denominator; } template bool combinations_base::is_allowed_by_weight_constraints(unsigned int i) { if(weights.size()==0) return true; for(unsigned int cn=0; cn= max_weights[cn]) return false; } return true; } template bool combinations_base::final_weight_constraints_check() const { for(unsigned int cn=0; cn void combinations_base::update_weights(unsigned int i) { if(weights.size()==0) return; for(unsigned int cn=0; cn void combinations_base::restore_weights(unsigned int i) { if(weights.size()==0) return; for(unsigned int cn=0; cn void combinations_base::nextstep(unsigned int current, unsigned int lowest_in_group, unsigned int groupindex, std::vector algehad) { unsigned int grouplen=0; for(unsigned int i=0; i<=groupindex; ++i) grouplen+=sublengths[i]; if(current==grouplen) { // group is filled ++groupindex; if(groupindex==sublengths.size()) { if(final_weight_constraints_check()) vector_generated(temparr); return; } lowest_in_group=0; } unsigned int starti=0, endi=original.size()/block_length; if(sub_problem_blocksize>0) { starti=current-current%sub_problem_blocksize; endi=starti+sub_problem_blocksize; } for(unsigned int i=starti; iinput_asym.size(); ++k) { for(unsigned int kk=0; kkinput_asym[k].size(); ++kk) { if(i==this->input_asym[k][kk]) { unsigned int k2=kk; while(k2!=0) { --k2; if(!algehad[this->input_asym[k][k2]]) { // std::cout << "discarding " << std::endl; discard=true; break; } } } } if(discard) break; } } else discard=true; if(!discard) if(i+1>lowest_in_group) { algehad[i]=true; update_weights(i); temparr[current]=i; // for(unsigned bl=0; bl symmetriser::symmetriser() : block_length(1), permutation_sign(1), sh_(*this), svh_(*this) { } template void symmetriser::clear() { original.clear(); block_length=1; permute_blocks.clear(); value_permute.clear(); permutation_sign=1; sublengths.clear(); input_asym.clear(); sublengths_scattered.clear(); originals.clear(); multiplicity.clear(); } template void symmetriser::collect() { std::cout << "collecting" << std::endl; // Fill the hash map: entries which are equal have to sit in the same // bin, but there may be other entries in that bin which still have to // be separated. std::multimap hashmap; for(unsigned int i=0; i(hash(originals[i]), i)); // Collect equal vectors. std::multimap::iterator it=hashmap.begin(), thisbin1, thisbin2, tmpit; while(it!=hashmap.end()) { long current_hash=it->first; thisbin1=it; while(thisbin1!=hashmap.end() && thisbin1->first==current_hash) { thisbin2=thisbin1; ++thisbin2; while(thisbin2!=hashmap.end() && thisbin2->first==current_hash) { if(originals[(*thisbin1).second]==originals[(*thisbin2).second]) { multiplicity[(*thisbin1).second]+=multiplicity[(*thisbin2).second]; multiplicity[(*thisbin2).second]=0; tmpit=thisbin2; ++tmpit; hashmap.erase(thisbin2); thisbin2=tmpit; } else ++thisbin2; } ++thisbin1; } it=thisbin1; } remove_multiplicity_zero(); } template void symmetriser::remove_multiplicity_zero() { std::vector > new_originals; std::vector new_multiplicity; for(unsigned int k=0; k void symmetriser::apply_symmetry(long start, long end) { unsigned int current_length=originals.size(); if(current_length==0) { originals.push_back(original); multiplicity.push_back(1); current_length=1; } // Some options are mutually exclusive. assert(permute_blocks.size()>0 || value_permute.size()>0); assert(sublengths.size()==0 || sublengths_scattered.size()==0); if(permute_blocks.size()==0) { // permute by value assert(value_permute.size()!=0); if(input_asym.size()==0 && sublengths_scattered.size()==0) { // When permuting by value, we can do the permutation once, // and then figure out (see vector_generated of symm_val_helper), // for each permutation which is already stored in the symmetriser, // how the objects are moved. current_=current_length; svh_.clear(); svh_.original=value_permute; svh_.input_asym.clear(); svh_.sublengths=sublengths; svh_.current_multiplicity=combin::vector_prod_fact(sublengths); if(svh_.sublengths.size()==0) svh_.set_unit_sublengths(); svh_.permute(start, end); // Since we do not divide by the number of permutations, we need // to adjust the multiplicity of all the originals. // for(unsigned int i=0; i my_permute_blocks; // Determine the location of the values. for(unsigned int k=0; k0) { // Re-order my_permute_blocks in such a way that the objects which sit // in one sublength_scattered range are consecutive. This does not make // any difference for the sign. sh_.sublengths.clear(); std::vector reordered_permute_blocks; for(unsigned int m=0; m::iterator it=my_permute_blocks.begin(); while(it!=my_permute_blocks.end()) { if((*it)==sublengths_scattered[m][mm]) { // std::cout << " found " << std::endl; reordered_permute_blocks.push_back(*it); my_permute_blocks.erase(it); ++overlap; break; } ++it; } // std::cout << std::endl; } if(overlap>0) sh_.sublengths.push_back(overlap); } std::vector::iterator it=my_permute_blocks.begin(); while(it!=my_permute_blocks.end()) { reordered_permute_blocks.push_back(*it); // std::cout << "adding one" << std::endl; sh_.sublengths.push_back(1); ++it; } my_permute_blocks=reordered_permute_blocks; // std::cout << "handled sublengths" << std::endl; } // Put to-be-permuted data in originals. for(unsigned int k=0; k0) { // Make a proper input_asym which refers to object locations // in the permute blocks array, rather than in the original // array. for(unsigned int k=0; k1) { subprob_input_asym.push_back(newrange); sh_.current_multiplicity*=fact(newrange.size()); } } } if(sh_.sublengths.size()==0) sh_.set_unit_sublengths(); sh_.current_multiplicity*=combin::vector_prod_fact(sh_.sublengths); // debugging // std::cout << "my_permute_blocks: "; // for(unsigned int ii=0; ii0) { // for(unsigned int k=0; k0); // When permuting by location, we have to apply the permutation // algorithm separately to each and every permutation which is // already stored in the symmetriser. for(unsigned int i=0; i const std::vector& symmetriser::operator[](unsigned int i) const { assert(i unsigned int symmetriser::size() const { return originals.size(); } template range_t symmetriser::values_to_locations(const std::vector& values) const { range_t ret; for(unsigned int i=0; i symm_val_helper::symm_val_helper(symmetriser& tt) : current_multiplicity(1), first_one(true), owner_(tt) { } template void symm_val_helper::clear() { first_one=true; combinations_base::clear(); } template void symm_val_helper::vector_generated(const std::vector& vec) { ++this->vector_generated_called_; if(first_one) { first_one=false; } else { if((this->start_==-1 || this->vector_generated_called_ >= this->start_) && (this->end_==-1 || this->vector_generated_called_ < this->end_)) { // Since we permuted by value, we can do this permutation in one // shot on all previously generated sets. for(unsigned int i=0; ioriginal[j]) { owner_.originals[loc][k]=this->original[vec[j]]; break; } } } } } } } template symm_helper::symm_helper(symmetriser& tt) : current_multiplicity(1), first_one(true), owner_(tt) { } template void symm_helper::clear() { first_one=true; combinations_base::clear(); } template int symmetriser::signature(unsigned int i) const { assert(i void symmetriser::set_multiplicity(unsigned int i, int val) { assert(i void symm_helper::vector_generated(const std::vector& vec) { ++this->vector_generated_called_; if(first_one) { first_one=false; } else { if((this->start_==-1 || this->vector_generated_called_ >= this->start_) && (this->end_==-1 || this->vector_generated_called_ < this->end_)) { // std::cout << "produced "; // for(unsigned int m=0; m std::ostream& operator<<(std::ostream& str, const symmetriser& sym) { for(unsigned int i=0; i #define HAVE_GLIB cadabra-0.115/src/config.h.in0000600000077000007700000000006610471350770015265 0ustar kantorkantor#define EXPECTPATH #define HAVE_GLIB cadabra-0.115/src/defaults.cc0000600000077000007700000000067410556146713015371 0ustar kantorkantor#include std::string defaults="\\prod{#}::Distributable.\n\ \\prod{#}::IndexInherit.\n\ \\prod{#}::CommutingAsProduct.\n\ \\prod{#}::DependsInherit.\n\ \\prod{#}::WeightInherit(label=all, type=Multiplicative).\n\ \n\ \\sum{#}::CommutingAsSum.\n\ \\sum{#}::DependsInherit.\n\ \\sum{#}::IndexInherit.\n\ \\sum{#}::WeightInherit(label=all, type=Additive).\n\ \n\ \\indexbracket{#}::Distributable.\n\ \\indexbracket{#}::IndexInherit.\n\ "; cadabra-0.115/src/display.cc0000600000077000007700000010666410622301157015222 0ustar kantorkantor/* $Id: display.cc,v 1.70 2007/05/04 12:14:40 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2001-2006 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "display.hh" #include "manipulator.hh" #include "props.hh" #include "modules/algebra.hh" #include "modules/relativity.hh" #include "modules/gamma.hh" #include #include #define nbsp (( parent.utf8_output?(unichar(0x00a0)):" ")) #define zwnbsp (( parent.utf8_output?(unichar(0xfeff)):"")) exptree_output::exptree_output(const exptree& tr_, std::ostream& str_, output_format_t of) : tight_star(getenv("CDB_TIGHTSTAR")), tight_plus(getenv("CDB_TIGHTPLUS")), tight_brackets(getenv("CDB_TIGHTBRACKETS")), print_star(getenv("CDB_PRINTSTAR")), output_format(of), xml_structured(false), utf8_output(false), print_expression_number(true), str(str_), tr(tr_), bracket_level(0), print_default_(&create) { setup_handlers(); } void exptree_output::setup_handlers(bool infix) { printers_.clear(); if(infix) { switch(output_format) { case out_mathml: printers_["\\expression"] =&create; printers_["\\prod"] =&create; printers_["\\div"] =&create; printers_["\\sum"] =&create; printers_["\\pow"] =&create; printers_["\\indexbracket"] =&create; printers_["\\factorial"] =&create; printers_["\\equals"] =&create; printers_["\\unequals"] =&create; printers_["\\sequence"] =&create; printers_["\\comma"] =&create; // FIXME: these two are not yet declared reserved? printers_["\\wedge"] =&create; // printers_["\\commutator"] =&create; break; default: printers_["\\expression"] =&create; printers_["\\div"] =&create; printers_["\\wedge"] =&create; printers_["\\prod"] =&create; printers_["\\sum"] =&create; printers_["\\equals"] =&create; printers_["\\unequals"] =&create; printers_["\\arrow"] =&create; printers_["\\comma"] =&create; printers_["\\factorial"] =&create; printers_["\\sequence"] =&create; printers_["\\commutator"] =&create; printers_["\\indexbracket"] =&create; printers_["\\pow"] =&create; break; } } } display_error::display_error() { } display_interrupted::display_interrupted() { } std::auto_ptr exptree_output::get_printer(exptree::iterator it) { if(interrupted) { interrupted=false; throw display_interrupted(); } printmap_t::const_iterator prit=printers_.find(*it->name); if(prit!=printers_.end()) return (*prit).second(*this); else return print_default_(*this); } void exptree_output::print_infix(exptree::iterator start) { setup_handlers(true); if(output_format==out_texmacs) str << DATA_BEGIN << "latex:$"; get_printer(start)->print_infix(str, start); if(output_format==out_texmacs) str << "$" << DATA_END << std::flush; } void exptree_output::print_prefix(exptree::iterator start) { setup_handlers(false); get_printer(start)->print_infix(str, start); } print_expression::print_expression(exptree_output& eo) : node_printer(eo) { } void print_expression::print_infix(std::ostream& str, exptree::iterator it) { // We print only the subtree starting at the first sibling node. // All other subtrees are supposed to contain other information, // like the externally (anti)symmetrised indices, which should // be displayed in a different way. parent.get_printer(tr.begin(it))->print_infix(str, tr.begin(it)); str << ";"; } /* --------------------------------------------------------------------- */ print_wedge::print_wedge(exptree_output& eo) : print_productlike(eo) { } void print_wedge::print_infix(std::ostream& str, exptree::iterator it) { doprint(str, it, "^"); } print_prod::print_prod(exptree_output& eo) : print_productlike(eo) { } void print_prod::print_infix(std::ostream& str, exptree::iterator it) { doprint(str, it, "*"); } print_productlike::print_productlike(exptree_output& eo) : node_printer(eo) { } void print_productlike::doprint(std::ostream& str, exptree::iterator it, const std::string& inbetween) { // bool close_bracket=false; if(*it->multiplier!=1) { print_multiplier(str, it); sibling_iterator st=tr.begin(it); // while(st!=tr.end(it)) { // if(*st->name=="\\sum") { // str << "("; // close_bracket=true; // break; // } // ++st; // } } // To print \prod{\sum{a}{b}}{\sum{c}{d}} correctly: // If there is any sum as child, and if the sum children do not // all have the same bracket type (different from b_none or b_no), // then print brackets. str_node::bracket_t previous_bracket_=str_node::b_invalid; bool beginning_of_group=true; sibling_iterator ch=tr.begin(it); while(ch!=tr.end(it)) { str_node::bracket_t current_bracket_=(*ch).fl.bracket; if(previous_bracket_!=current_bracket_) { if(current_bracket_!=str_node::b_none) { print_opening_bracket(str, current_bracket_, str_node::p_none); beginning_of_group=true; } } // bool wrapping_bracket=false; // if(*ch->name=="\\sum") { // wrapping_bracket=!children_have_brackets(ch); // if(wrapping_bracket) // str << "("; // } parent.get_printer(ch)->print_infix(str, ch); // if(wrapping_bracket) // str << ")"; ++ch; if(ch==tr.end(it)) { if(current_bracket_!=str_node::b_none) print_closing_bracket(str, current_bracket_, str_node::p_none); } // else assert(current_bracket_==(*ch).fl.bracket); if(ch!=tr.end(it)) { if(parent.print_star && parent.output_format != exptree_output::out_texmacs) { if(parent.tight_star) str << inbetween; else if(parent.utf8_output) { str << unichar(0x00a0) << inbetween << unichar(0x00a0); } else str << " " << inbetween << " "; } else { if(parent.output_format==exptree_output::out_texmacs) str << "\\,"; else str << " "; } } previous_bracket_=current_bracket_; } // if(close_bracket) str << ")"; } print_arrow::print_arrow(exptree_output& eo) : node_printer(eo) { } void print_arrow::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator lhs=tr.begin(it), rhs=lhs; ++rhs; parent.get_printer(lhs)->print_infix(str, lhs); if(parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_texmacs ) str << " \\rightarrow "; else str << " -> "; parent.get_printer(rhs)->print_infix(str, rhs); } print_pow::print_pow(exptree_output& eo) : node_printer(eo) { } void print_pow::print_infix(std::ostream& str, exptree::iterator it) { if(*it->multiplier!=1) print_multiplier(str, it); bool close_bracket=false; sibling_iterator st=tr.begin(it); while(st!=tr.end(it)) { if(*st->name=="\\sum") { str << "("; close_bracket=true; break; } ++st; } sibling_iterator ch=tr.begin(it); parent.get_printer(ch)->print_infix(str, ch); if(close_bracket) str << ")"; if(parent.output_format==exptree_output::out_xcadabra) { str << "{}^{"; ++ch; parent.get_printer(ch)->print_infix(str, ch); str << "}"; } else { str << "**"; ++ch; parent.get_printer(ch)->print_infix(str, ch); } } print_div::print_div(exptree_output& eo) : node_printer(eo) { } void print_div::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator num=tr.begin(it), den=num; ++den; bool close_bracket=false; if(*it->multiplier!=1) { print_multiplier(str, it); str << "("; close_bracket=true; } parent.get_printer(num)->print_infix(str, num); str << "/"; parent.get_printer(den)->print_infix(str, den); if(close_bracket) str << ")"; } print_sum::print_sum(exptree_output& eo) : node_printer(eo) { } void print_sum::print_infix(std::ostream& str, exptree::iterator it) { std::ostringstream lstr; // txtout << "length of sum=" << lstr.str().size() << std::endl; // do_actual_print(lstr, it); do_actual_print(str, it); } void print_sum::do_actual_print(std::ostream& str, exptree::iterator it) { bool close_bracket=false; if(*it->multiplier!=1) print_multiplier(str, it); iterator par=tr.parent(it); if(*it->multiplier!=1 || (tr.is_valid(par) && *par->name!="\\expression")) { // test whether we need extra brackets close_bracket=!children_have_brackets(it); if(close_bracket) str << "("; } unsigned int steps=0; str_node::bracket_t previous_bracket_=str_node::b_invalid; sibling_iterator ch=tr.begin(it); bool beginning_of_group=true; bool mathematica_postponed_endl=false; while(ch!=tr.end(it)) { if(++steps==100) { str << std::flush; steps=0; } str_node::bracket_t current_bracket_=(*ch).fl.bracket; if(previous_bracket_!=current_bracket_) if(current_bracket_!=str_node::b_none) { if(ch!=tr.begin(it)) { if(parent.tight_plus) str << "+"; else if(parent.utf8_output) str << " +" << unichar(0x00a0); else str << " + "; } print_opening_bracket(str, current_bracket_, str_node::p_none); beginning_of_group=true; } if(beginning_of_group) { beginning_of_group=false; if(*ch->multiplier<0) { if(parent.tight_plus) str << "-"; else if(parent.utf8_output) str << " -" << unichar(0x00a0); else str << " - "; } } else { if(*ch->multiplier<0) { if(parent.tight_plus) str << "-"; else if(parent.utf8_output) str << " -" << unichar(0x00a0); else str << " - "; } else { if(parent.tight_plus) str << "+"; else if(parent.utf8_output) str << " +" << unichar(0x00a0); else str << " + "; } } if(mathematica_postponed_endl) { str << std::endl; mathematica_postponed_endl=false; } if(*ch->name=="1" && (*ch->multiplier==1 || *ch->multiplier==-1)) str << "1"; // special case numerical constant else parent.get_printer(ch)->print_infix(str, ch); ++ch; if(ch==tr.end(it)) { if(current_bracket_!=str_node::b_none) print_closing_bracket(str, current_bracket_, str_node::p_none); } else { // if(current_bracket_!=(*ch).fl.bracket) // throw display_error(); // assert(current_bracket_==(*ch).fl.bracket); if(parent.bracket_level==0) { if(parent.output_format==exptree_output::out_mathematica) mathematica_postponed_endl=true; // FIXME: this endl should be re-inserted for nodes having line_per_node true // else // str << std::endl; } } previous_bracket_=current_bracket_; } if(close_bracket) str << ")"; str << std::flush; } print_equals::print_equals(exptree_output& eo) : node_printer(eo) { } void print_equals::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator lhs=tr.begin(it), rhs=lhs; ++rhs; parent.get_printer(lhs)->print_infix(str, lhs); if(parent.tight_plus) str << "="; else str << " = "; parent.get_printer(rhs)->print_infix(str, rhs); } print_unequals::print_unequals(exptree_output& eo) : node_printer(eo) { } void print_unequals::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator lhs=tr.begin(it), rhs=lhs; ++rhs; parent.get_printer(lhs)->print_infix(str, lhs); if(parent.tight_plus) str << "!="; else str << " != "; parent.get_printer(rhs)->print_infix(str, rhs); } print_factorial::print_factorial(exptree_output& eo) : node_printer(eo) { } void print_factorial::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator arg=tr.begin(it); parent.get_printer(arg)->print_infix(str, arg); str << "!"; } print_comma::print_comma(exptree_output& eo) : node_printer(eo) { } void print_comma::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator ch=tr.begin(it); if(! (tr.begin(it)->fl.bracket==str_node::b_none && it->fl.bracket!=str_node::b_none) ) { str << "\\"; print_opening_bracket(str, tr.begin(it)->fl.bracket, tr.begin(it)->fl.parent_rel); } while(ch!=tr.end(it)) { parent.get_printer(ch)->print_infix(str, ch); ++ch; if(ch!=tr.end(it)) { str << ","; if(!parent.tight_plus) { if(parent.output_format==exptree_output::out_xcadabra) str << "\\quad "; else str << " "; // FIXME: print extra endl depending on line_per_node // if(parent.bracket_level==1) // str << std::endl; } } } if(! (tr.begin(it)->fl.bracket==str_node::b_none && it->fl.bracket!=str_node::b_none) ) { str << "\\"; print_closing_bracket(str, tr.begin(it)->fl.bracket, tr.begin(it)->fl.parent_rel); } } print_sequence::print_sequence(exptree_output& eo) : node_printer(eo) { } void print_sequence::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator ch=tr.begin(it); parent.get_printer(ch)->print_infix(str, ch); str << ".."; ++ch; parent.get_printer(ch)->print_infix(str, ch); } print_commutator::print_commutator(exptree_output& eo) : node_printer(eo) { } void print_commutator::print_infix(std::ostream& str, exptree::iterator it) { if(*it->multiplier!=1) print_multiplier(str, it); sibling_iterator ch=tr.begin(it); str << "["; parent.get_printer(ch)->print_infix(str, ch); str << ", "; ++ch; parent.get_printer(ch)->print_infix(str, ch); str << "]"; } print_indexbracket::print_indexbracket(exptree_output& eo) : node_printer(eo) { } void print_indexbracket::print_infix(std::ostream& str, exptree::iterator it) { iterator arg=tr.begin(it); // if(*arg->name!="\\sum" && *arg->name!="\\prod") { // if(children_have_brackets(it)) // print_opening_bracket(str,arg->fl.bracket); // } // else { // if(!children_have_brackets(tr.begin(it))) str << "("; // } parent.get_printer(tr.begin(it))->print_infix(str, tr.begin(it)); // if(*arg->name!="\\sum" && *arg->name!="\\prod") { // if(children_have_brackets(it)) // print_closing_bracket(str,arg->fl.bracket); // } // else { // if(!children_have_brackets(tr.begin(it))) str << ")"; // } print_children(str, it, 1); } /* --------------------------------------------------------------------- */ print_mathml_expression::print_mathml_expression(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_expression::print_infix(std::ostream& str, iterator it) { str << "" << std::endl; parent.get_printer(tr.begin(it))->print_infix(str, tr.begin(it)); str << ""; } print_mathml_productlike::print_mathml_productlike(exptree_output& eo) : mathml_node_printer(eo) { } print_mathml_wedge::print_mathml_wedge(exptree_output& eo) : print_mathml_productlike(eo) { } void print_mathml_wedge::print_infix(std::ostream&, iterator) { } print_mathml_prod::print_mathml_prod(exptree_output& eo) : print_mathml_productlike(eo) { } void print_mathml_prod::print_infix(std::ostream&, iterator) { } print_mathml_indexbracket::print_mathml_indexbracket(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_indexbracket::print_infix(std::ostream&, iterator) { } print_mathml_pow::print_mathml_pow(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_pow::print_infix(std::ostream&, iterator) { } print_mathml_div::print_mathml_div(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_div::print_infix(std::ostream&, iterator) { } print_mathml_sum::print_mathml_sum(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_sum::print_infix(std::ostream&, iterator) { } print_mathml_sequence::print_mathml_sequence(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_sequence::print_infix(std::ostream&, iterator) { } print_mathml_equals::print_mathml_equals(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_equals::print_infix(std::ostream&, iterator) { } print_mathml_unequals::print_mathml_unequals(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_unequals::print_infix(std::ostream&, iterator) { } print_mathml_factorial::print_mathml_factorial(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_factorial::print_infix(std::ostream&, iterator) { } print_mathml_comma::print_mathml_comma(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_comma::print_infix(std::ostream&, iterator) { } /* --------------------------------------------------------------------- */ node_base_printer::node_base_printer(exptree_output& eo) : parent(eo), tr(eo.tr) { } bool node_base_printer::children_have_brackets(iterator ch) const { sibling_iterator chlds=tr.begin(ch); str_node::bracket_t childbr=chlds->fl.bracket; if(childbr==str_node::b_none || childbr==str_node::b_no) return false; else return true; } /* --------------------------------------------------------------------- */ node_printer::node_printer(exptree_output& eo) : node_base_printer(eo), isdelta(false), isweyl(false) { } void node_printer::print_infix(std::ostream& str, exptree::iterator it) { // if((*it).fl.mark && parent.highlight) str << "\033[1m"; // print multiplier and object name if(*it->multiplier!=1) print_multiplier(str, it); if(*it->name=="1") { if(*it->multiplier==1) // this would print nothing altogether. str << "1"; return; } if(parent.output_format==exptree_output::out_mathematica && it->fl.parent_rel==str_node::p_none) { const GammaMatrix *g=properties::get(it); const KroneckerDelta *k=properties::get(it); const WeylTensor *wt=properties::get(it); if(g) str << "GammaProd" << zwnbsp << "["; else if(k) { str << "Delta" << zwnbsp << "["; isdelta=true; } else if(wt) { str << "Weyl" << zwnbsp << "["; isweyl=true; } else if(tr.number_of_children(it)>0) { if(getenv("CDB_MATH_COMPACT")) str << *it->name << "["; else str << "Tensor" << zwnbsp << "[" << *it->name << "," << nbsp; } else str << *it->name; } else if(parent.output_format==exptree_output::out_maple && it->fl.parent_rel==str_node::p_none) { const WeylTensor *wt=properties::get(it); if(wt) { isweyl=true; str << *it->name << "["; } else str << *it->name; } else { str << *it->name; } print_children(str, it); } void node_printer::print_children(std::ostream& str, exptree::iterator it, int skip) { previous_bracket_ =str_node::b_invalid; previous_parent_rel_=str_node::p_none; if(parent.output_format==exptree_output::out_mathematica && isdelta) { // Mathematica str << "{"; exptree::sibling_iterator ch=tr.begin(it); while(ch!=tr.end(it)) { if(ch!=tr.begin(it)) str << "," << nbsp; parent.get_printer(ch)->print_infix(str, ch); ++ch; ++ch; } str << "}," << nbsp << "{"; ch=tr.begin(it); while(ch!=tr.end(it)) { if(ch!=tr.begin(it)) str << "," << nbsp; ++ch; parent.get_printer(ch)->print_infix(str, ch); ++ch; } str << "}"; } else if(parent.output_format==exptree_output::out_maple && isweyl) { // Maple exptree::sibling_iterator ch=tr.begin(it); while(ch!=tr.end(it)) { if(ch!=tr.begin(it)) str << "," << nbsp; if(ch->fl.parent_rel==str_node::p_sub) str << "-"; parent.get_printer(ch)->print_infix(str, ch); ++ch; } } else { // Normal (non-maple, non-mathematica) output int number_of_nonindex_children=0; int number_of_index_children=0; exptree::sibling_iterator ch=tr.begin(it); while(ch!=tr.end(it)) { if(ch->is_index()==false) { ++number_of_nonindex_children; if(*ch->name=="\\prod") ++number_of_nonindex_children; } else ++number_of_index_children; ++ch; } ch=tr.begin(it); ch+=skip; unsigned int chnum=0; while(ch!=tr.end(it)) { current_bracket_ =(*ch).fl.bracket; current_parent_rel_=(*ch).fl.parent_rel; if(current_bracket_!=str_node::b_none || previous_bracket_!=current_bracket_ || previous_parent_rel_!=current_parent_rel_) { if(parent.output_format==exptree_output::out_plain || parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_texmacs ) print_parent_rel(str, current_parent_rel_, ch==tr.begin(it)); if(parent.output_format!=exptree_output::out_reduce) print_opening_bracket(str, (number_of_nonindex_children>1 && number_of_index_children>0 && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << zwnbsp << "(" << zwnbsp; } if(parent.output_format==exptree_output::out_mathematica && getenv("CDB_MATH_COMPAC")==0) { if(ch!=tr.begin(it)) { if(chnum==2 && isweyl) str << "}," << nbsp << "{"; else str << "," << nbsp; } } else if(parent.output_format==exptree_output::out_reduce) { if(ch!=tr.begin(it)) str << "," << zwnbsp; } parent.get_printer(ch)->print_infix(str, ch); // if((*it).fl.mark && parent.highlight) str << "\033[1m"; ++ch; if(ch==tr.end(it) || current_bracket_!=str_node::b_none || current_bracket_!=(*ch).fl.bracket || current_parent_rel_!=(*ch).fl.parent_rel) { if(parent.output_format!=exptree_output::out_reduce) print_closing_bracket(str, (number_of_nonindex_children>1 && number_of_index_children>0 && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << ")"; } else if(parent.output_format==exptree_output::out_plain || parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_maple || parent.output_format==exptree_output::out_texmacs) str << nbsp; previous_bracket_=current_bracket_; previous_parent_rel_=current_parent_rel_; ++chnum; } } if(parent.output_format==exptree_output::out_mathematica && it->fl.parent_rel==str_node::p_none && tr.number_of_children(it)>0) str << "]"; if(parent.output_format==exptree_output::out_maple && isweyl) str << "]"; // if((*it).fl.mark && parent.highlight) str << "\033[0m"; } void node_printer::print_multiplier(std::ostream& str, exptree::iterator it) { bool turned_one=false; mpz_class denom=it->multiplier->get_den(); if(*it->multiplier<0) { if(*tr.parent(it)->name=="\\sum") { // sum takes care of minus sign if(*it->multiplier!=-1) { if(denom!=1 && ( parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "\\frac{" << -(it->multiplier->get_num()) << "}{" << it->multiplier->get_den() << "}"; } else { str << -(*it->multiplier); } } else turned_one=true; } else { if(denom!=1 && ( parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "(\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "})"; } else { str << "(" << *it->multiplier << ")"; } } } else { if(denom!=1 && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "}"; } else str << *it->multiplier; } if(!turned_one && !(*it->name=="1")) { if(parent.print_star && !(parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { if(parent.tight_star) str << "*"; else if(parent.utf8_output) str << unichar(0x00a0) << "*" << unichar(0x00a0); else str << " * "; } else { if(!parent.tight_star) { if(parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra ) str << "\\, "; else str << " "; } } } } void node_printer::print_opening_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: str << "{"; break; case str_node::b_pointy: str << "\\<"; break; case str_node::b_curly: str << "\\{"; break; case str_node::b_round: str << "("; break; case str_node::b_square: str << "["; break; default : return; } ++(parent.bracket_level); } void node_printer::print_closing_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: str << "}"; break; case str_node::b_pointy: str << "\\>"; break; case str_node::b_curly: str << "\\}"; break; case str_node::b_round: str << ")"; break; case str_node::b_square: str << "]"; break; default : return; } --(parent.bracket_level); } void node_printer::print_parent_rel(std::ostream& str, str_node::parent_rel_t pr, bool first) { switch(pr) { case str_node::p_super: if(!first && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) str << "\\,"; str << "^"; break; case str_node::p_sub: if(!first && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra)) str << "\\,"; str << "_"; break; case str_node::p_property: str << "$"; break; case str_node::p_exponent: str << "**"; break; case str_node::p_none: break; } // Prevent line break after this character. str << zwnbsp; } void exptree_output::print_full_standardform(exptree::iterator it, bool eqno) { if(eqno) { nset_t::iterator name=tr.equation_label(it); if(xml_structured) str << "" << std::endl; if(name!=name_set.end()) str << *name; else str << tr.equation_number(it); if(!xml_structured) str << ":= "; else str << std::endl << "" << std::endl; } if(output_format==exptree_output::out_xcadabra) { // first output plain output_format=exptree_output::out_plain; str << "" << std::endl; print_infix(tr.active_expression(it)); str << std::endl << "" << std::endl; output_format=exptree_output::out_xcadabra; } if(xml_structured) str << "" << std::endl; print_infix(tr.active_expression(it)); if(xml_structured) str << std::endl << "" << std::endl; } /* ----------------------------------------------------------------------- */ mathml_node_printer::mathml_node_printer(exptree_output& eo) : node_base_printer(eo) { } void mathml_node_printer::print_infix(std::ostream& str, exptree::iterator it) { // if((*it).fl.mark && parent.highlight) str << "\033[1m"; // print multiplier and object name if(*it->multiplier!=1) print_multiplier(str, it); if(*it->name=="1") { if(*it->multiplier==1) // this would print nothing altogether. str << "1"; return; } str << *it->name; print_children(str, it); } void mathml_node_printer::print_children(std::ostream& str, exptree::iterator it, int skip) { previous_bracket_ =str_node::b_invalid; previous_parent_rel_=str_node::p_none; int number_of_nonindex_children=0; int number_of_index_children=0; exptree::sibling_iterator ch=tr.begin(it); while(ch!=tr.end(it)) { if(ch->is_index()==false) { ++number_of_nonindex_children; if(*ch->name=="\\prod") ++number_of_nonindex_children; } else ++number_of_index_children; ++ch; } ch=tr.begin(it); ch+=skip; unsigned int chnum=0; while(ch!=tr.end(it)) { current_bracket_ =(*ch).fl.bracket; current_parent_rel_=(*ch).fl.parent_rel; if(current_bracket_!=str_node::b_none || previous_bracket_!=current_bracket_ || previous_parent_rel_!=current_parent_rel_) { if(parent.output_format==exptree_output::out_plain || parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_texmacs) print_parent_rel(str, current_parent_rel_, ch==tr.begin(it)); if(parent.output_format!=exptree_output::out_reduce) print_opening_bracket(str, (number_of_nonindex_children>1 && number_of_index_children>0 && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << zwnbsp << "(" << zwnbsp; } if(parent.output_format==exptree_output::out_mathematica && getenv("CDB_MATH_COMPAC")==0) { if(ch!=tr.begin(it)) { str << "," << nbsp; } } else if(parent.output_format==exptree_output::out_reduce) { if(ch!=tr.begin(it)) str << "," << zwnbsp; } parent.get_printer(ch)->print_infix(str, ch); // if((*it).fl.mark && parent.highlight) str << "\033[1m"; ++ch; if(ch==tr.end(it) || current_bracket_!=str_node::b_none || current_bracket_!=(*ch).fl.bracket || current_parent_rel_!=(*ch).fl.parent_rel) { if(parent.output_format!=exptree_output::out_reduce) print_closing_bracket(str, (number_of_nonindex_children>1 && number_of_index_children>0 && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << ")"; } else if(parent.output_format==exptree_output::out_plain || parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_maple || parent.output_format==exptree_output::out_texmacs) str << nbsp; previous_bracket_=current_bracket_; previous_parent_rel_=current_parent_rel_; ++chnum; } if(parent.output_format==exptree_output::out_mathematica && it->fl.parent_rel==str_node::p_none && tr.number_of_children(it)>0) str << "]"; // if((*it).fl.mark && parent.highlight) str << "\033[0m"; } void mathml_node_printer::print_multiplier(std::ostream& str, exptree::iterator it) { bool turned_one=false; mpz_class denom=it->multiplier->get_den(); if(*it->multiplier<0) { if(*tr.parent(it)->name=="\\sum") { // sum takes care of minus sign if(*it->multiplier!=-1) { if(denom!=1 && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "\\frac{" << -(it->multiplier->get_num()) << "}{" << it->multiplier->get_den() << "}"; } else { str << -(*it->multiplier); } } else turned_one=true; } else { if(denom!=1 && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "(\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "})"; } else { str << "(" << *it->multiplier << ")"; } } } else { if(denom!=1 && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "}"; } else str << *it->multiplier; } if(!turned_one && !(*it->name=="1")) { if(parent.print_star && !parent.output_format==exptree_output::out_texmacs && !parent.output_format==exptree_output::out_xcadabra ) { if(parent.tight_star) str << "*"; else if(parent.utf8_output) str << unichar(0x00a0) << "*" << unichar(0x00a0); else str << " * "; } else { if(!parent.tight_star) { if(parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra ) str << "\\, "; else str << " "; } } } } void mathml_node_printer::print_opening_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: str << "{"; break; case str_node::b_pointy: str << "\\<"; break; case str_node::b_curly: str << "\\{"; break; case str_node::b_round: str << "("; break; case str_node::b_square: str << "["; break; default : return; } ++(parent.bracket_level); } void mathml_node_printer::print_closing_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: str << "}"; break; case str_node::b_pointy: str << "\\>"; break; case str_node::b_curly: str << "\\}"; break; case str_node::b_round: str << ")"; break; case str_node::b_square: str << "]"; break; default : return; } --(parent.bracket_level); } void mathml_node_printer::print_parent_rel(std::ostream& str, str_node::parent_rel_t pr, bool first) { switch(pr) { case str_node::p_super: if(!first && ( parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) str << "\\,"; str << "^"; break; case str_node::p_sub: if(!first && ( parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) str << "\\,"; str << "_"; break; case str_node::p_property: str << "$"; break; case str_node::p_exponent: str << "**"; break; case str_node::p_none: break; } // Prevent line break after this character. str << zwnbsp; } /* ----------------------------------------------------------------------- */ // Thanks to Behdad Esfahbod int k_unichar_to_utf8(kunichar c, char *buf) { buf[0]=(c) < 0x00000080 ? (c) : (c) < 0x00000800 ? ((c) >> 6) | 0xC0 : (c) < 0x00010000 ? ((c) >> 12) | 0xE0 : (c) < 0x00200000 ? ((c) >> 18) | 0xF0 : (c) < 0x04000000 ? ((c) >> 24) | 0xF8 : ((c) >> 30) | 0xFC; buf[1]=(c) < 0x00000080 ? 0 /* null-terminator */ : (c) < 0x00000800 ? ((c) & 0x3F) | 0x80 : (c) < 0x00010000 ? (((c) >> 6) & 0x3F) | 0x80 : (c) < 0x00200000 ? (((c) >> 12) & 0x3F) | 0x80 : (c) < 0x04000000 ? (((c) >> 18) & 0x3F) | 0x80 : (((c) >> 24) & 0x3F) | 0x80; buf[2]=(c) < 0x00000800 ? 0 /* null-terminator */ : (c) < 0x00010000 ? ((c) & 0x3F) | 0x80 : (c) < 0x00200000 ? (((c) >> 6) & 0x3F) | 0x80 : (c) < 0x04000000 ? (((c) >> 12) & 0x3F) | 0x80 : (((c) >> 18) & 0x3F) | 0x80; buf[3]=(c) < 0x00010000 ? 0 /* null-terminator */ : (c) < 0x00200000 ? ((c) & 0x3F) | 0x80 : (c) < 0x04000000 ? (((c) >> 6) & 0x3F) | 0x80 : (((c) >> 12) & 0x3F) | 0x80; buf[4]=(c) < 0x00200000 ? 0 /* null-terminator */ : (c) < 0x04000000 ? ((c) & 0x3F) | 0x80 : (((c) >> 6) & 0x3F) | 0x80; buf[5]=(c) < 0x04000000 ? 0 /* null-terminator */ : ((c) & 0x3F) | 0x80; buf[6]=0; return 6; } const char *unichar(kunichar c) { static char buffer[7]; int pos=k_unichar_to_utf8(c, buffer); buffer[pos]=0; return buffer; } cadabra-0.115/src/display.hh0000600000077000007700000002455410612672011015230 0ustar kantorkantor/* $Id: display.hh,v 1.40 2007/04/13 12:10:08 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2001-2006 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef display_hh_ #define display_hh_ #include "storage.hh" //#include "modules/properties.hh" #include typedef uint32_t kunichar; // TeXmacs markers #define DATA_BEGIN ((char) 2) #define DATA_END ((char) 5) #define DATA_COMMAND ((char) 16) #define DATA_ESCAPE ((char) 27) class exptree_output; class display_error { public: display_error(); }; class display_interrupted { public: display_interrupted(); }; /// The base class for displaying/printing nodes in the expression /// tree. class node_base_printer { public: typedef exptree::iterator iterator; typedef exptree::sibling_iterator sibling_iterator; node_base_printer(exptree_output&); virtual ~node_base_printer() {}; virtual void print_infix(std::ostream&, iterator) = 0; protected: exptree_output& parent; const exptree& tr; str_node::parent_rel_t previous_parent_rel_, current_parent_rel_; str_node::bracket_t previous_bracket_, current_bracket_; // Determine whether the children of the indicated node all have // the same, non-empty bracket type (i.e. determines whether, when // the indicated node is a \\sum, the children will automatically // be wrapped in a bracket). bool children_have_brackets(iterator) const; }; /// The default printing class for standard text output to the console. /// Also contains logic for printing in Mathematica and Maple format, /// to be split off in a separate class hierarchy later. class node_printer : public node_base_printer { public: node_printer(exptree_output&); virtual ~node_printer() {}; virtual void print_infix(std::ostream&, iterator); protected: void print_multiplier(std::ostream&, exptree::iterator); void print_opening_bracket(std::ostream&, str_node::bracket_t, str_node::parent_rel_t); void print_closing_bracket(std::ostream&, str_node::bracket_t, str_node::parent_rel_t); void print_parent_rel(std::ostream&, str_node::parent_rel_t, bool first); void print_children(std::ostream&, exptree::iterator, int skip=0); // some random junk variables bool isdelta; bool isweyl; }; /// The default node printing class for MathML output. class mathml_node_printer : public node_base_printer { public: mathml_node_printer(exptree_output&); virtual ~mathml_node_printer() {}; virtual void print_infix(std::ostream&, iterator); protected: void print_multiplier(std::ostream&, exptree::iterator); void print_opening_bracket(std::ostream&, str_node::bracket_t, str_node::parent_rel_t); void print_closing_bracket(std::ostream&, str_node::bracket_t, str_node::parent_rel_t); void print_parent_rel(std::ostream&, str_node::parent_rel_t, bool first); void print_children(std::ostream&, exptree::iterator, int skip=0); }; /* ------------------------------------------------------------------------------- */ class print_expression : public node_printer { public: print_expression(exptree_output&); virtual ~print_expression() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_productlike : public node_printer { public: print_productlike(exptree_output&); virtual ~print_productlike() {}; protected: void doprint(std::ostream&, exptree::iterator, const std::string&); }; class print_wedge : public print_productlike { public: print_wedge(exptree_output&); virtual ~print_wedge() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_prod : public print_productlike { public: print_prod(exptree_output&); virtual ~print_prod() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_arrow : public node_printer { public: print_arrow(exptree_output&); virtual ~print_arrow() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_commutator : public node_printer { public: print_commutator(exptree_output&); virtual ~print_commutator() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_indexbracket : public node_printer { public: print_indexbracket(exptree_output&); virtual ~print_indexbracket() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_pow : public node_printer { public: print_pow(exptree_output&); virtual ~print_pow() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_div : public node_printer { public: print_div(exptree_output&); virtual ~print_div() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_sum : public node_printer { public: print_sum(exptree_output&); virtual ~print_sum() {}; virtual void print_infix(std::ostream&, iterator ); private: void do_actual_print(std::ostream&, iterator); }; class print_sequence : public node_printer { public: print_sequence(exptree_output&); virtual ~print_sequence() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_equals : public node_printer { public: print_equals(exptree_output&); virtual ~print_equals() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_unequals : public node_printer { public: print_unequals(exptree_output&); virtual ~print_unequals() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_factorial : public node_printer { public: print_factorial(exptree_output&); virtual ~print_factorial() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_comma : public node_printer { public: print_comma(exptree_output&); virtual ~print_comma() {}; virtual void print_infix(std::ostream&, iterator ); }; /* ------------------------------------------------------------------------------- */ class print_mathml_expression : public mathml_node_printer { public: print_mathml_expression(exptree_output&); virtual ~print_mathml_expression() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_productlike : public mathml_node_printer { public: print_mathml_productlike(exptree_output&); virtual ~print_mathml_productlike() {}; protected: void doprint(std::ostream&, exptree::iterator, const std::string&); }; class print_mathml_wedge : public print_mathml_productlike { public: print_mathml_wedge(exptree_output&); virtual ~print_mathml_wedge() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_prod : public print_mathml_productlike { public: print_mathml_prod(exptree_output&); virtual ~print_mathml_prod() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_indexbracket : public mathml_node_printer { public: print_mathml_indexbracket(exptree_output&); virtual ~print_mathml_indexbracket() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_pow : public mathml_node_printer { public: print_mathml_pow(exptree_output&); virtual ~print_mathml_pow() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_div : public mathml_node_printer { public: print_mathml_div(exptree_output&); virtual ~print_mathml_div() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_sum : public mathml_node_printer { public: print_mathml_sum(exptree_output&); virtual ~print_mathml_sum() {}; virtual void print_infix(std::ostream&, iterator ); private: void do_actual_print(std::ostream&, iterator); }; class print_mathml_sequence : public mathml_node_printer { public: print_mathml_sequence(exptree_output&); virtual ~print_mathml_sequence() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_equals : public mathml_node_printer { public: print_mathml_equals(exptree_output&); virtual ~print_mathml_equals() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_unequals : public mathml_node_printer { public: print_mathml_unequals(exptree_output&); virtual ~print_mathml_unequals() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_factorial : public mathml_node_printer { public: print_mathml_factorial(exptree_output&); virtual ~print_mathml_factorial() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_comma : public mathml_node_printer { public: print_mathml_comma(exptree_output&); virtual ~print_mathml_comma() {}; virtual void print_infix(std::ostream&, iterator ); }; /* ------------------------------------------------------------------------------- */ class exptree_output { public: enum output_format_t { out_plain, out_mathematica, out_reduce, out_maple, out_texmacs, out_mathml, out_xcadabra }; exptree_output(const exptree&, std::ostream&, output_format_t of=out_plain); bool highlight; const bool tight_star; const bool tight_plus; const bool tight_brackets; const bool print_star; output_format_t output_format; bool xml_structured; bool utf8_output; bool print_expression_number; std::ostream& str; const exptree& tr; void print_full_standardform(exptree::iterator, bool eqno); void print_infix(exptree::iterator); void print_prefix(exptree::iterator); void setup_handlers(bool infix=true); std::auto_ptr get_printer(exptree::iterator); unsigned int bracket_level; // FIXME: perhaps a stack? private: typedef std::map (*)(exptree_output&)> printmap_t; printmap_t printers_; std::auto_ptr (*print_default_)(exptree_output&); }; template std::auto_ptr create(exptree_output& eo) { return std::auto_ptr(new T(eo)); } const char *unichar(kunichar c); #endif cadabra-0.115/src/exchange.cc0000600000077000007700000002337010600576021015327 0ustar kantorkantor #include "exchange.hh" #include "modules/algebra.hh" #include "modules/gamma.hh" #include "modules/lie.hh" #include "modules/numerical.hh" #include // Find groups of identical tensors. // int exchange::collect_identical_tensors(exptree& tr, exptree::iterator it, std::vector& idts) { assert(*it->name=="\\prod"); int total_number_of_indices=0; exptree::sibling_iterator sib=it.begin(); while(sib!=it.end()) { unsigned int i=0; if(exptree::number_of_indices(sib)==0) { ++sib; continue; } if(properties::get_composite(sib)) { total_number_of_indices+=tr.number_of_indices(sib); ++sib; continue; } // In case of spinors, the name may be hidden inside a Dirac bar. exptree::sibling_iterator truetensor=sib; const DiracBar *db=properties::get_composite(truetensor); if(db) truetensor=tr.begin(truetensor); // Compare the current tensor with all other tensors encountered so far. for(; i(truetensor2); if(db2) truetensor2=tr.begin(truetensor2); if(subtree_equal(truetensor2, truetensor)) { // If this is a spinor, check that it's connected to the one already stored // by a Gamma matrix, or that it is connected directly. if(idts[i].spino) { exptree::sibling_iterator tmpit=idts[i].tensors[0]; const GammaMatrix *gmnxt=0; const Spinor *spnxt=0; // skip objects without spinor line do { ++tmpit; gmnxt=properties::get_composite(tmpit); spnxt=properties::get_composite(tmpit); } while(gmnxt==0 && spnxt==0); if(tmpit==sib) { // txtout << "using fermi exchange" << std::endl; idts[i].extra_sign++; break; } if(gmnxt) { // txtout << "gamma next " << std::endl; int numind=exptree::number_of_indices(tmpit); // skip objects without spinor line do { ++tmpit; gmnxt=properties::get_composite(tmpit); spnxt=properties::get_composite(tmpit); } while(gmnxt==0 && spnxt==0); if(tmpit==sib) { // yes, it's a proper Majorana spinor pair. // txtout << "using fermi exchange with gamma " << numind << std::endl; if( ((numind*(numind+1))/2)%2 == 0 ) idts[i].extra_sign++; break; } } } else break; } } if(i==idts.size()) { identical_tensors_t ngr; ngr.comm=properties::get_composite(sib); ngr.spino=properties::get_composite(sib); ngr.tab=properties::get_composite(sib); ngr.traceless=properties::get_composite(sib); ngr.gammatraceless=properties::get_composite(sib); ngr.extra_sign=0; ngr.number_of_indices=exptree::number_of_indices(truetensor); ngr.tensors.push_back(sib); ngr.seq_numbers_of_first_indices.push_back(total_number_of_indices); total_number_of_indices+=ngr.number_of_indices; if(ngr.spino==false || ngr.spino->majorana==true) idts.push_back(ngr); } else { idts[i].tensors.push_back(sib); idts[i].seq_numbers_of_first_indices.push_back(total_number_of_indices); total_number_of_indices+=idts[i].number_of_indices; } ++sib; } return total_number_of_indices; } unsigned int exchange::possible_singlets(exptree& tr, exptree::iterator it) { std::vector idts; collect_identical_tensors(tr, it, idts); if(idts.size()==0) return 1; // no indices, so this is a singlet already LiE::LiE_t lie; // Figure out the algebra from one of the indices. exptree::index_iterator indit=tr.begin_index(idts[0].tensors[0]); const Integer *iprop=properties::get(indit); if(!iprop) throw consistency_error("Need to know about the range of the " + *indit->name + " index."); // iprop->difference.print_recursive_treeform(txtout, iprop->difference.begin()); unsigned int dims=to_long(*iprop->difference.begin()->multiplier); // std::cout << "*** " << dims << std::endl; if(dims%2==0) lie.algebra_type=LiE::LiE_t::alg_D; else lie.algebra_type=LiE::LiE_t::alg_B; lie.algebra_dim=dims/2; lie.start(); // Find the representation for each group of tensors, taking into // account their exchange symmetries. std::vector groupreps; for(unsigned int i=0; i1) { assert(idts[i].tab); // Every tensor with 2+ indices needs a TableauSymmetry. TableauBase::tab_t thetab=idts[i].tab->get_tab(tr, idts[i].tensors[0], 0); std::vector topleth; for(unsigned int rws=0; rwssign()==-1) ++sign; lie.alt_sym_tensor(idts[i].tensors.size(), single_tensor_rep, multi_tensor_rep, sign%2==0); groupreps.push_back(multi_tensor_rep); } } // Now tensor the whole lot together. LiE::LiE_t::reps_t result=groupreps[0], tmpstore; for(unsigned int i=0; i >& gs) { std::vector idts; int total_number_of_indices=collect_identical_tensors(tr, it, idts); if(idts.size()==0) return 1; // no indices, so nothing to permute // Make a strong generating set for the permutation of identical tensors. for(unsigned int i=0; i1) { std::vector gsel(total_number_of_indices+2); for(unsigned int sobj=0; sobj sobj. for(unsigned int obj=sobj; objsign()==-1) std::swap(gsel[total_number_of_indices], gsel[total_number_of_indices+1]); else if(idts[i].comm->sign()==0) return false; } if(idts[i].spino && idts[i].number_of_indices==0) { if(gsel[total_number_of_indices+1]==total_number_of_indices+1) return false; } else gs.push_back(gsel); } } } } // for(unsigned int i=0; i1) { // for(int t1=0; t1 gsel(total_number_of_indices+2); // for(int kk=0; kksign()==-1) { // // txtout << "anticommuting" << std::endl; // std::swap(gsel[total_number_of_indices], gsel[total_number_of_indices+1]); // } // else if(idts[i].comm->sign()==0) // return false; // } // // if(idts[i].spino && idts[i].number_of_indices==0) { // if(gsel[total_number_of_indices+1]==total_number_of_indices+1) // return false; // } // else gs.push_back(gsel); // } // } // } // } return true; } bool operator<(const exchange::tensor_type_t& one, const exchange::tensor_type_t& two) { if(*one.name < *two.name) return true; if(one.name == two.name) if(one.number_of_indices < two.number_of_indices) return true; return false; } cadabra-0.115/src/exchange.hh0000600000077000007700000000471110541333720015340 0ustar kantorkantor/* $Id: exchange.hh,v 1.13 2006/12/17 21:33:38 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2001-2006 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** Functions to handle the exchange properties of two or more symbols in a product. This module is only concerned with the exchange properties of tensors as a whole, not with index permutation symmetries (which are handled in the canonicalise class of algebra.cc). */ #ifndef exchange_hh_ #define exchange_hh_ #include "storage.hh" #include #include "modules/algebra.hh" #include "modules/gamma.hh" class exchange { public: struct identical_tensors_t { unsigned int number_of_indices; std::vector tensors; std::vector seq_numbers_of_first_indices; const SelfCommutingBehaviour *comm; const Spinor *spino; const TableauBase *tab; const Traceless *traceless; const GammaTraceless *gammatraceless; int extra_sign; }; // Obtain index exchange symmetries under tensor permutation. Returns 'false' if // an identically zero expression is encountered. static int collect_identical_tensors(exptree& tr, exptree::iterator it, std::vector& idts); static unsigned int possible_singlets(exptree&, exptree::iterator); static bool get_node_gs(exptree&, exptree::iterator, std::vector >& ); // static void get_index_gs(exptree::iterator, std::vector >& ); struct tensor_type_t { nset_t::iterator name; unsigned int number_of_indices; }; }; bool operator<(const exchange::tensor_type_t& one, const exchange::tensor_type_t& two); #endif cadabra-0.115/src/main.cc0000600000077000007700000002437110612672011014472 0ustar kantorkantor/* $Id: main.cc,v 1.86 2007/04/19 16:22:29 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2001-2006 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** \mainpage Cadabra \author Kasper Peeters \version development \date latest \see http://www.aei.mpg.de/~peekas/cadabra/ Cadabra: an extendable open-source symbolic tensor algebra system. The core of the manipulator is stored in the following files - main.cc - manipulator.hh and manipulator.cc - algorithm.hh and algorithm.cc - display.hh and display.cc - settings.hh and settings.cc - preprocessor.hh and preprocessor.cc - parser.hh and parser.cc - props.hh and props.cc - exchange.hh and exchange.cc - storage.hh and storage.cc Further code is in the src/modules directory. */ #include "storage.hh" #include "props.hh" #include "manipulator.hh" #include #include #include "stopwatch.hh" #include #include #include #include //#include #include #include #include #include #include #include // prompt does not do non-standard pipe names yet, so therefore the hack: modglue::ipipe commands("stdin"); modglue::opipe raw_txtout("stdout"); modglue::opipe texout("stderr"); std::ofstream debugout; std::ofstream nullout("/dev/null",std::ios::app); std::ostream *real_txtout; std::ostream *fake_txtout; std::ostream *real_forcedout; std::ostream *fake_forcedout; #define txtout (*fake_txtout) #define forcedout (*fake_forcedout) // global flag to indicate a control-C interrupt. bool interrupted=false; stopwatch globaltime; unsigned int size_x, size_y; bool loginput=false; bool nowarnings=false; bool silentfail=false; std::vector cmdline_arguments; extern std::string defaults; void sigc_handler(int num) { interrupted=true; signal(SIGINT,sigc_handler); } void determine_window_size() { struct winsize tmp; if (ioctl( 0, TIOCGWINSZ, &tmp)==-1) { // debugout << "cannot determine window size" << std::endl; size_x=80; size_y=24; } else { size_x=tmp.ws_col; size_y=tmp.ws_row; } // debugout << "window size now " << size_x << "x" << size_y << std::endl; } void winch_handler(int num) { debugout << "window size changed" << std::endl; determine_window_size(); } bool verify_tool_presence() { return true; } int main(int argc, char **argv) { std::string inputfile; char hostname[256]; gethostname(hostname, 255); char *pbs_job=getenv("PBS_JOBID"); std::string logname=std::string("cdb_")+hostname+(pbs_job==0?"":std::string("_")+pbs_job) +std::string(".log"); char *cdblog=getenv("CDB_LOG"); if(cdblog==0) debugout.open("/dev/null", std::ios::app); else switch(atoi(cdblog)) { case 1: debugout.open(logname.c_str(), std::ios::app); break; case 2: debugout.open("/dev/tty", std::ios::app); break; } signal(SIGINT,sigc_handler); signal(SIGWINCH, winch_handler); real_txtout=&raw_txtout; real_forcedout=&raw_txtout; modglue::main mm(argc, argv); manipulator mnp; bool disable_defaults=false; bool disable_dot_cadabra=false; bool continue_interactive=false; for(int i=1; i 0.8>" << std::endl; txtout << DATA_BEGIN << "latex:"; txtout << "\\rm {\\Large Cadabra " << RELEASE << "} ("; #ifdef STATICBUILD txtout << "static, "; #endif txtout << "built on " << DATETIME << ")\\\\" << std::endl; txtout << "Copyright (c) 2001-2007 Kasper Peeters \\\\" << std::endl; txtout << "Available under the terms of the GNU General Public License.\\\\" << std::endl; } else { txtout << "Cadabra " << RELEASE << " ("; #ifdef STATICBUILD txtout << "static, "; #endif txtout << "built on " << DATETIME /* << " on " << HOSTNAME */ << ")" << std::endl << "Copyright (C) 2001-2007 Kasper Peeters " << std::endl << "Info at http://www.aei.mpg.de/~peekas/cadabra/" << std::endl << "Available under the terms of the GNU General Public License." << std::endl << std::endl; } debugout << "-----" << std::endl << "Cadabra (compiled " << DATETIME << " on " << HOSTNAME << ")" << std::endl; // Process default startup file (included in the binary). if(!disable_defaults) { std::istringstream tst(defaults); real_txtout=&nullout; fake_txtout=real_txtout; mnp.open_stream(&tst); mnp.handle_input(); (*real_txtout) << std::flush; real_txtout=&raw_txtout; fake_txtout=real_txtout; } // Process user startup file, if any. if(!disable_dot_cadabra) { std::string defname=getenv("HOME"); defname+="/.cadabra"; std::ifstream tst(defname.c_str()); if(tst.is_open()) { tst.close(); mnp.open_stream(defname); mnp.handle_input(); } else debugout << "Default startup file ~/.cadabra not present." << std::endl << std::endl; } if(mnp.output_format==exptree_output::out_texmacs) txtout << DATA_END << std::flush; // Process input file, if any. if(inputfile.size()>0) { int orig_fd=open(inputfile.c_str(), O_RDONLY); if(orig_fd!=1) { // make a temporary copy char temp_name[]="cdbtmp_XXXXXX"; int temp_fd=mkstemp(temp_name); if(temp_fd!=1) { char buffer[8192]; ssize_t read_len; while((read_len=read(orig_fd, buffer, 8192))!=0) { write(temp_fd, buffer, read_len); } close(orig_fd); close(temp_fd); mnp.open_stream(temp_name); unlink(temp_name); // immediately unlink, so that the tmp file goes away in case of crash/abort } } else txtout << "Input file " << inputfile << " not found." << std::endl; } // int oldin; // if(isatty(0)==0) { // oldin=dup(0); // txtout << oldin << std::endl; // } // Run main loop. mainloop: if(inputfile.size()==0) mnp.print_prompt(); bool reading_input_file=false; try { if(inputfile.size()==0) mm.run(1); else { reading_input_file=true; inputfile=""; mnp.handle_input(); } } catch(stream_end_error& se) { txtout << "Normal stream ended" << std::endl; if(continue_interactive) { commands.clear(); assert(reading_input_file==false); // We were reading a redirected stdin, we have to reopen the tty. freopen("/dev/tty","r",stdin); goto mainloop; } else return_value=-2; } catch(std::exception& ex) { txtout << std::endl; txtout << "FATAL: " << ex.what() << std::endl; if(getenv("CDB_LOG")) txtout << " See the log file \"" << logname << "\" for more details." << std::endl; else txtout << " Rerun with the CDB_LOG environment variable set, to generate a log." << std::endl; txtout << std::endl; // FIXME: output is still screwed up, perhaps we should set fcntl stuff back. // Although it seems that this output only arrives when using prompt. return_value=-1; } catch(exit_exception& ex) { txtout << "Cadabra exiting"; if(getenv("CDB_LOG")) txtout << "; log written on \"" << logname << "\"." << std::endl; else txtout << "." << std::endl; return_value=0; } if(reading_input_file) { txtout << "Input file ended" << std::endl; reading_input_file=""; if(continue_interactive) { txtout << "Continuing interactively" << std::endl; commands.clear(); // freopen("/dev/tty","r",stdin); goto mainloop; } } else if(isatty(0)==0) { txtout << "Redirected input ended." << std::endl; if(continue_interactive) { txtout << "Continuing interactively" << std::endl; commands.clear(); assert(reading_input_file==false); // We were reading a redirected stdin, we have to reopen the tty. // FIXME: this fails, though it used to work. if(freopen("/dev/tty","r",stdin)==0) txtout << "Failed to re-open stdin."; goto mainloop; } } debugout << "-----" << std::endl; } // Funny things appear on the output if we do not flush here... std::cout << std::flush; std::cerr << std::flush; raw_txtout << std::flush; texout << std::flush; return return_value; } cadabra-0.115/src/Makefile.in0000600000077000007700000001173610622301156015305 0ustar kantorkantor MACTEST= @MAC_OS_X@ .PHONY: all tests modules all: cadabra modules tests static: cadabra_static tests: test_gmp test_preprocessor test_tree tree_example test_combinatorics test_young \ tree_regression_tests test_xperm test_lie #test_parser OBJS =preprocessor.o storage.o display.o parser.o main.o algorithm.o manipulator.o \ youngtab.o combinatorics.o props.o settings.o exchange.o defaults.o stopwatch.o MOBJS=modules/algebra.o modules/pertstring.o modules/convert.o modules/gamma.o \ modules/field_theory.o modules/select.o modules/dummies.o modules/output.o \ modules/properties.o modules/relativity.o modules/substitute.o \ modules/tableaux.o modules/diff_geometry.o modules/numerical.o \ modules/linear.o modules/combinat.o modules/xperm.o modules/lie.o modules/lists.o SRCS = `find . -name "*.cc"` MCFLAGS = -O2 ${CFLAGS} -I. -I@top_srcdir@/src `pkg-config modglue --cflags` TIMESTAMP = -D"RELEASE=\"${RELEASE}\"" -D"DATETIME=\"`date | sed -e 's/ / /'`\"" -DHOSTNAME=\"`hostname`\" %.o: %.cc ${CXX} -Wall -g ${MCFLAGS} ${TIMESTAMP} -c -o $@ $< modules/xperm.o: modules/xperm.c ${CC} -Wall -g @NESTED@ ${MCFLAGS} ${TIMESTAMP} -c -o $@ $< modules: $(MOBJS) cadabra: $(OBJS) $(MOBJS) ${CXX} -o cadabra ${LDFLAGS} `pkg-config modglue --libs` $+ -lgmpxx -lpcre -lpcrecpp -lgmp #`pkg-config glib-2.0 --libs` # Static linking now works! cadabra_static: $(OBJS) $(MOBJS) rm -f main.o ${CXX} -Wall -g ${MCFLAGS} ${TIMESTAMP} -DSTATICBUILD -c -o main.o main.cc ifeq ($(strip $(MACTEST)),) g++ -o cadabra -static $+ ${LDFLAGS} `pkg-config modglue --libs` -lmodglue \ -lgmpxx -lgmp -lpcrecpp -lpcre \ `pkg-config sigc++-2.0 --libs` -lsigc-2.0 -lutil else export MACOSX_DEPLOYMENT_TARGET=10.3 g++ -o cadabra $+ ${LDFLAGS} `pkg-config modglue --libs` \ -lgmp -lgmpxx -lpcre++ -lpcre -lexpect endif # In order to get the build date linked in. # main.o: ${MOBJS} Makefile # defaults.o: defaults # echo "#include" > defaults.cc # echo -n "std::string defaults=\"" >> defaults.cc # cat defaults | tr '\n' '<' | sed -e 's/\\/\\\\/g' | sed -e 's/> defaults.cc # echo "\";" >> defaults.cc # ${CXX} -c -o defaults.o defaults.cc test_tree: test_tree.o ${CXX} -o test_tree test_tree.o test_lie: test_lie.o modules/lie.o ifeq ($(strip $(MACTEST)),) ${CXX} -o test_lie test_lie.o modules/lie.o `pkg-config --libs modglue` else ${CXX} -o test_lie test_lie.o modules/lie.o `pkg-config --libs modglue` endif tree_regression_tests: tree_regression_tests.o ${CXX} -o tree_regression_tests tree_regression_tests.o test_xperm: test_xperm.o modules/xperm.o ${CXX} -o test_xperm test_xperm.o modules/xperm.o tree_example: tree_example.o tree.hh ${CXX} -o tree_example tree_example.o test_combinatorics: test_combinatorics.o combinatorics.o ${CXX} -o test_combinatorics test_combinatorics.o combinatorics.o test_young: test_young.o youngtab.o combinatorics.o ${CXX} -o test_young test_young.o youngtab.o combinatorics.o ${LDFLAGS} -lgmpxx -lgmp test_preprocessor: test_preprocessor.o preprocessor.o ${CXX} -o test_preprocessor test_preprocessor.o preprocessor.o ${LDFLAGS} -lgmpxx -lgmp mpi_pass_tree: mpi_pass_tree.o ${CXX} -o mpi_pass_tree mpi_pass_tree.o -L/usr/lib/mpich/lib -lmpich++ -lpmpich -lmpich mpi_remote_run.o: mpi_remote_run.cc mpiCC -c -o mpi_remote_run.o mpi_remote_run.cc mpi_remote_run: mpi_remote_run.o mpiCC -o mpi_remote_run mpi_remote_run.o #test_parser: test_parser.o storage.o parser.o preprocessor.o display.o # ${CXX} -o test_parser test_parser.o storage.o parser.o preprocessor.o display.o modules/properties.o algorithm.o -lgmpxx test_gmp: test_gmp.o ${CXX} -o test_gmp test_gmp.o ${LDFLAGS} -lgmpxx -lgmp # The 2nd generation parser. # First the lexx/yacc bit. parser2.tab.h parser2.tab.c: parser2.y bison -v -d parser2.y lex.yy.c: parser2.l parser2.tab.h flex -o lex.yy.c parser2.l # Then the actual compilation. lex.yy.o: lex.yy.c parser2.tab.h ${CXX} -c -o lex.yy.o lex.yy.c parser2.tab.o: parser2.tab.c ${CXX} -c -o parser2.tab.o parser2.tab.c parser2: parser2.tab.o lex.yy.o storage.o props.o ${CXX} -o parser2 parser2.tab.o lex.yy.o storage.o props.o -ll -ly -lgmpxx -lgmp # Installation and cleanup. install: strip cadabra install -m 0755 -d ${DESTDIR}@prefix@/bin install -m 0755 cadabra ${DESTDIR}@prefix@/bin uninstall: rm -f @prefix@/bin/cadabra # rm -f @prefix@/include/tree.hh clean: rm -f *.o *~ cadabra cadabra_static test_tree test_combinatorics test_preprocessor test_parser test_gmp tree_example test_young tree_regression_tests test_lie test_xperm rm -f parser2.output parser2.tab.c parser2.tab.h lex.yy.cc lex.yy.c ( cd modules; $(MAKE) clean ) distclean: clean rm -f Makefile out cdb.log result .depend gprof.out ( cd modules; $(MAKE) distclean ) .depend: rm -f .depend for i in ${SRCS}; \ do g++ ${MCFLAGS} -E -MM -MT `echo $$i | sed -e 's/\.\///' -e 's/\.cc/\.o/'` ${CFLAGS} $$i >> .depend; \ done include .depend cadabra-0.115/src/manipulator.cc0000600000077000007700000012500610615347065016111 0ustar kantorkantor/* $Id: manipulator.cc,v 1.213 2007/04/30 11:04:00 peekas Exp $ Cadabra: an extendable open-source symbolic tensor algebra system. Copyright (C) 2002 Kasper Peeters 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, version 2. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "modules/modules.hh" #include "manipulator.hh" #include "preprocessor.hh" #include "settings.hh" #include "parser.hh" #include extern std::string defaults; stream_end_error::stream_end_error() { } exit_exception::exit_exception() { } manipulator::algo_info::algo_info(std::auto_ptr (*cr)(exptree&, iterator)) : create(cr), calls(0) { } manipulator::manipulator() : output_format(exptree_output::out_plain), editing_equation(0), last_used_equation_number(0), utf8_output(getenv("CDB_USE_UTF8")), status_output(false), prompt_string(">") { properties::register_properties(); settings::register_properties(); // pertstring algorithms["@aticksen"] =new algo_info(&create); algorithms["@riemannid"] =new algo_info(&create); // tableaux tableaux::register_properties(); algorithms["@lr_tensor"] =new algo_info(&create); algorithms["@decompose_product"] =new algo_info(&create); // algebra algebra::register_properties(); algorithms["@distribute"] =new algo_info(&create); algorithms["@expand_power"] =new algo_info(&create); algorithms["@prodrule"] =new algo_info(&create); algorithms["@prodflatten"] =new algo_info(&create); algorithms["@sumflatten"] =new algo_info(&create); algorithms["@listflatten"] =new algo_info(&create); algorithms["@remove_indexbracket"] =new algo_info(&create); algorithms["@prodcollectnum"] =new algo_info(&create); algorithms["@collect_terms"] =new algo_info(&create); algorithms["@collect_factors"]=new algo_info(&create); algorithms["@factorise"] =new algo_info(&create); algorithms["@canonicalise"] =new algo_info(&create); algorithms["@reduce"] =new algo_info(&create); algorithms["@ratrewrite"] =new algo_info(&create); algorithms["@canonicalorder"] =new algo_info(&create); algorithms["@acanonicalorder"]=new algo_info(&create); algorithms["@prodsort"] =new algo_info(&create); algorithms["@sumsort"] =new algo_info(&create); algorithms["@spinorsort"] =new algo_info(&create); // algorithms["@subseq"] =new algo_info(&create); algorithms["@drop"] =new algo_info(&create); algorithms["@drop_weight"] =new algo_info(&create); algorithms["@keep_weight"] =new algo_info(&create); algorithms["@sym"] =new algo_info(&create); algorithms["@asym"] =new algo_info(&create); algorithms["@"] =new algo_info(&create); algorithms["@indexsort"] =new algo_info(&create); algorithms["@asymprop"] =new algo_info(&create); algorithms["@impose_asym"] =new algo_info(&create); algorithms["@young_project"] =new algo_info(&create); algorithms["@young_project_tensor"] =new algo_info(&create); algorithms["@keep_terms"] =new algo_info(&create); // linear algorithms["@lsolve"] =new algo_info(&create); algorithms["@decompose"] =new algo_info(&create); // combinat algorithms["@permute"] =new algo_info(&create); // convert algorithms["@from_math"] =new algo_info(&create); algorithms["@from_maple"] =new algo_info(&create); algorithms["@run"] =new algo_info(&create); // differential geometry diff_geometry::register_properties(); // gamma gamma_algebra::register_properties(); algorithms["@join"] =new algo_info(&create); algorithms["@projweyl"] =new algo_info(&create); algorithms["@remove_gamma_trace"]=new algo_info(&create); algorithms["@gammasplit"] = new algo_info(&create); algorithms["@rewrite_diracbar"] = new algo_info(&create); algorithms["@fierz"] = new algo_info(&create); // field_theory field_theory::register_properties(); algorithms["@eliminate_kr"] =new algo_info(&create); algorithms["@einsteinify"] =new algo_info(&create); algorithms["@combine"] =new algo_info(&create); algorithms["@expand"] =new algo_info(&create); algorithms["@debracket"] =new algo_info(&create); algorithms["@reduce_gendelta"] =new algo_info(&create); algorithms["@breakgendelta"] =new algo_info(&create); algorithms["@eliminateeps"] =new algo_info(&create); algorithms["@dualise_tensor"] =new algo_info(&create); algorithms["@epsprod2gendelta"]=new algo_info(&create); algorithms["@product_shorthand"]=new algo_info(&create); algorithms["@expand_product_shorthand"]=new algo_info(&create); algorithms["@remove_eoms"] =new algo_info(&create); algorithms["@pintegrate"] =new algo_info(&create); algorithms["@impose_bianchi"] =new algo_info(&create); algorithms["@all_contractions"]=new algo_info(&create); algorithms["@unique_indices"] =new algo_info(&create); algorithms["@remove_vanishing_derivatives"] =new algo_info(&create); algorithms["@unwrap"] =new algo_info(&create); // dummies dummy::register_properties(); algorithms["@rename_dummies"] =new algo_info(&create); // select // algorithms["@select"] =&create