Jens Vollinga [Thu, 13 Nov 2008 10:13:05 +0000 (11:13 +0100)]
Fixed lots of bugs in factor_multivariate().
factor_univariate() takes now the content of the polynomial into accout when
choosing a prime. It also returns the chosen prime. This supports the
factor_multivariate() code.
Polynomials are expanded before calling factor_sqrfree(). This avoids problems
with some input polynomials.
Jens Vollinga [Mon, 10 Nov 2008 12:38:11 +0000 (13:38 +0100)]
Added modular square free factorization.
Completed distinct degree factorization.
Univariate polynomial factorization uses now upoly.
Merged class Partition and function split into class factor_partition.
Jens Vollinga [Wed, 5 Nov 2008 10:22:19 +0000 (11:22 +0100)]
Changed code from using cl_UP_MI to using umodpoly. The cl_UP_MI interface was
inconvenient to use and caused several very difficult bugs (some were still
unresolved before changing to umodpoly!).
Fixed severe bug in multivariate factorization. The condition that all modular
factors should be relatively prime in the base ring was violated. This caused
the factorization sometimes to go into an infinite loop.
symbol: remove return_type_tinfo() and return_type() (shrink symbol by 8 bytes)
Bloating symbol to the state sizeof(symbol) == 64 is not appreciated at all.
If someone needs/wants non-commutative symbols or other fancy stuff, please
derive from class symbol and do whatever you want.
return_type_tinfo() is used in order to distingish between non-commutative
objects of different type. However, often it's necessary to distingish
between non-commutative objects of the same type, for example, between
gamma matrices with different representation label. return_type_tinfo()
does not provide any clean way to do that. Hence, introduce return_type_t
type which holds representation label along with type information, and
use it for return_type_tinfo().
calchash(): use type_info::name() instead of tinfo().
Custom RTTI considered harmful, part 4.
The hash value of the object of different types should be different whenever
possible. Hence calcash() needs a unique per type number. Previously we used
tinfo_key for this. typeinfo::name() (a *pointer* to implementation dependent
string) is also unique for each class, so it's just as good as tinfo() is.
basic, expairseq: use standard C++ RTTI in compare(), is_equal(), match(), etc.
Custom RTTI considered harmful, part 2.
* basic.cpp: use standard C++ RTTI in compare(), is_equal(), operator=(),
match().
* expairseq.cpp: use standard C++ RTTI in match(), make_flat(),
construct_from_2_ex().
is_exactly_a: use typeid() to check the type of expression.
Custom RTTI considered harmful, part 1.
Custom run time type information (RTTI) system implemented in GiNaC have
several serious drawbacks, such as
1. It makes writing GiNaC classes unnecessary cumbersome.
2. It wastes sizeof(void *) bytes per object, for small objects like
symbol, numeric, etc. this overhead is considerable.
It turns out that GiNaC's RTTI is not any faster than the standard one
(at least on GNU/Linux and Solaris with GNU C++ library and compiler).
So, GiNaC RTTI have no reasons to exit any more.
ptr.h: use unsigned int to store reference counts (in order to save memory).
We'll hardly ever get more than 2^32 references to the same object. So using
size_t to store reference count only wastes 4 bytes per object (on 64-bit
architecture). Use unsigned int instead.
1. Bad performance. Parsing a sum seems to be O(N^{2 + a}) (a > 0).
For example, parsing a sum (actually, a univariate polynomial) of 32768
terms takes about 90 sec. on my box, parsing a sum of 10^6 terms takes
"eternity".
2. The user is expected to provide list of all symbols in the expression.
Often this is very annoying (and useless), sometimes it is not possible
at all.
3. Parser is not reentrant (bison *can* produce reentrant parsers, but that
won't solve other problems).
4. Parser is difficult to extend.
Since the new parser handles almost everything (useful) as the old one, let's
remove the latter.
check: time_parser.cpp: don't run the same benchmark twice.
Since ex(const string&, lst&) ctor uses the new parser now comparing its
performance (and result) with one of direct invocation of the parser is
pointless.
parser: add necessary checks to operator() to stop accepting nonsense.
Since the parser is recursive parse_* methods (in particular,
parse_binop_rhs()) does NOT check if the last unparsed token is valid.
Thus parse_expression() stops if it encounters an unknown token. That's
why parser::operator() needs to make sure nothing is left in the input
stream.
parser: change order of the constructor optional arguments.
Functions/methods having multiple optional arguments are not very convenient
to use in C++ (to put it mildly). Shuffle parser ctor arguments so not so
frequently used argument is the last one.
parser: allow read/write access to symbol table and strictness.
Intended usage:
parser reader;
ifstream input_file1, input_file2;
// read the first file...
ex e1 = reader(input_file1);
// ... add extra entry into the symbol table used by parser
symbol x;
parser.get_syms()["x"] = x;
// Disable the parser to introduce new symbols, e.g. to ensure the expression
// in input_file2 contains the same symbols as e1 (read from input_file1).
parser.strict = true;
ex e2;
try {
e2 = reader(input_file2);
} catch (...) {
abort();
}
G_numeric: use cl_N and int to manipulate numbers (instead of ex).
Convert helper functions G_do_hoelder and G_do_trafo in the same manner,
update all call sites. This should speed up numerical calculation of
multiple polylogarithms a little bit, and reduce the memory usage.
G_numeric: put convergence/acceleration transofrmations into helper functions.
This is simple code move, everything else should be considered a bug.
The helper functions (as well as G_numeric itself) will be improved by
subsequent patches.
expairseq::match(): remove the code which works around basic::match bug.
basic::match() used to have side effects in a case of a failed match. As
a result of that bug exparsed::match did not work correctly in some cases,
see [1] for more details. These false negatives were worked around by [2].
Now that match() has no unwanted side effects [3] we don't need any work
arounds any more.
Allow user to disable GiNaC::compile_ex (e.g. for security reasons).
configure takes --{disable,enable}-excompiler argument now. It can be
used to disable GiNaC::compile_ex (default is to enable it).
acinclude.m4:
GINAC_EXCOMPILER: new macro. Checks for libdl, allows user to disable
GiNaC::compile_ex. Also it doesn't bother to check for libdl on MinGW.
configure.ac: use GINAC_EXCOMPILER to check for libdl.
utils.h: use <stdint.h> (if available) instead of reinventing it.
The argument of golden_ratio_hash() is as an integer of the same size as
a void* pointer. Unfortunately ISO C++ 98 does not provide suitable typedef.
Hence
* use <stdint.h> if available and define p_int to uintptr_t. Note: AC_PROG_CC
already checks for this header, so no extra checks are necessary.
* as a fallback define p_int to be unsigned long, this works on most systems
I know of (the only exception is woe64).
While at it, stop including "config.h" unconditionally.
match: don't modify subexpression list if expression doesn't match the pattern.
As of now the match() method modifies the list of matched subexpressions
(its second argument) even if the expression in question does not match
the pattern. Thus, this simple program
#include <ginac/ginac.h>
#include <iostream>
using namespace GiNaC;
int main(int argc, char** argv)
{
symbol x;
ex e = pow(x, 5);
ex pattern = pow(wild(), -1);
lst repl;
bool test = e.match(pattern, repl);
std::cout << "repl = " << repl << std::endl;
}
prints
repl = {x}
Such behaviour is a bit unexpected. Sometimes it confuses even GiNaC
developers, see e.g.
http://www.ginac.de/pipermail/ginac-devel/2006-April/000942.html
[BUGFIX] Reclaiming the memory allocated for static objects *is* necessary.
GiNaC allocates memory for static objects (i.e. flyweights, remember tables,
etc), but doesn't free it. This is OK if the program lifetime matches libginac
lifetime, since the OS will reclaim that memory anyway.
However, if the program lifetime is different from that of libginac, this
turns into a memory leak. This happens if someone dlopen's libginac.so, and
dlclose's it later on (read: if someone uses GiNaC via scripting language
bindings).
symbol::autoname_prefix(): there's no need for dynamical memory allocation.
remember_table::remember_tables(): likewise.
function::registered_functions(): likewise.
lib_init::~lib_init(): if library usage count drops to 0, reclaim the memory
allocated for flyweights.
symbol: get rid of assign/unassign (for performance and other reasons).
* symbol::eval() is trivial now, so compiler can inline it in some cases.
* symbol takes less memory.
* no functionality is lost (as C++ has associative arrays).
multiple zeta values: make crandall_Y_loop helper function reentrant.
* Move crB and crG variables into initcX function (the only user of these
variables).
* Pass crX coefficients to crandall_Y_loop instead of using a global variable.
* While at it make crandall_Y_loop and initcX functions static.
gcd(): allow user to override (some of) heuristics.
GiNaC tries to avoid expanding expressions while computing GCDs and applies
a number of heuristics. Usually this improves performance, but in some cases
it doesn't. Allow user to switch off heuristics.
Part 5:
* gcd(): don't use heuristic GCD algorithm if gcd_options::no_heur_gcd
flag is set.
* gcd(): don't handle partially factored expressions in a special way
if gcd_options::no_part_factored flag is set.
refactor gcd() a little bit (no functional changes).
GiNaC tries to avoid expanding expressions while computing GCDs and applies
a number of heuristics. Usually this improves performance, but in some cases
it doesn't. Allow user to switch off heuristics.
Part 4:
refactor gcd() a little bit, so subsequent patch(es) won't be so big and ugly.
introduce gcd_pf_mul: gcd helper to handle partially factored expressions.
GiNaC tries to avoid expanding expressions while computing GCDs and applies
a number of heuristics. Usually this improves performance, but in some cases
it doesn't. Allow user to switch off heuristics.
Part 3:
Move the code handling products from gcd() into a separate function. This
is *really* only code move, everything else should be considered a bug.
introduce gcd_pf_pow: gcd helper to handle partially factored expressions.
GiNaC tries to avoid expanding expressions while computing GCDs and applies
a number of heuristics. Usually this improves performance, but in some cases
it doesn't. Allow user to switch off heuristics.
Part 2:
Move the code handling powers from gcd() into a separate function. This
is *really* only code move, everything else should be considered a bug.
GiNaC tries to avoid expanding expressions while computing GCDs and applies
a number of heuristics. Usually this improves performance, but in some cases
it doesn't. Allow user to switch off heuristics.
Part 1:
* add new (optional) argument to gcd() to control its behaviour.
* introduce gcd_options structure.
N.B. No actual code changes so far, the actual handling of newly introduced
options is the subject of further patches.
inifscn_nstdsums: make functions handling Li/G transformations reentrant.
Explicitly pass the dummy symbols instead of using a global variable.
As a side effect, the code is more clear now (that's a bit subjective, but
anyway).
1. Bad performance. Parsing a sum seems to be O(N^{2 + a}) (a > 0) [1].
For example, parsing a sum (actually, a univariate polynomial) of 32768
terms takes about 90 sec. on my box, parsing a sum of 10^6 terms takes
"eternity".
2. The user is expected to provide list of all symbols in the expression.
Often this is very annoying (and useless).
3. Parser is not reentrant (bison *can* produce reentrant parsers, but that
won't solve other problems).
4. Parser is difficult to extend.
Hence the new parser.
Features:
1. Parsing large sums and products is O(N).
2. Parser is reentrant (well, almost).
3. It's possible to insert (shell style) comments inside the expressions.
4. matrices, lists, FAIL are NOT handled. Yes, this *is* a feature :-)
Limitations:
1. Error handling is a bit terse: on error exception is thrown, and that's it.
2. Binary, octal, and hexadecimal numbers can not be parsed (yet).
3. Tensors, noncommutative products, etc. can not be parsed.
Other notes:
1. ex ctor still uses the old parser.
2. ginsh still uses the old parser.
[1] Mesured by this script (requires gnuplot):
make_expression_string ()
{
printf "1 + x"
local n=2
while test $n -le $1; do
printf " + %s*x^%s" $n $n
n=$(expr $n + 1)
done
}