Richard Kreckel [Sun, 22 Sep 2019 11:19:00 +0000 (13:19 +0200)]
Remove exhashmap<T> class.
Class exhashmap<T> was a workaround for missing std::hash_map<Key, T>
in the original C++98 standard. It was put in GiNaC because map<Key, T>
was deemed too slow. Since C++11 there is std::unorderd_map<Key, T>,
which is hash-based. To be able to use it, add specializations of
std::hash<ex> and std:equal_to<ex>.
Richard Kreckel [Fri, 3 May 2019 19:14:20 +0000 (21:14 +0200)]
[DOC] Change library order in tutorial example.
Some systems care about library ordering: Dependent libraries must be
linked last. Let's link with -lginac before -lcln in the example so it
will work on any system, even on Windows.
Richard Kreckel [Sat, 9 Mar 2019 17:40:32 +0000 (18:40 +0100)]
Refactor matrix::determinant_minor() a bit.
Remove special cases for small matrices and for for last column
minor computation. Add early return for the case that all minors
relevant for one column turn out to be zero. Improve some comments.
Richard Kreckel [Sat, 16 Feb 2019 11:58:38 +0000 (12:58 +0100)]
Fix elusive bug in expairseq ctor.
When an expair turns out to represent a number, that should go into
the expairseq's overall_coeff. This was accomplished by class mul,
thanks to the override of expair_needs_further_processing(), but not
always for class add.
This patch fixes the base class' expair_needs_further_processing()
with similar logic as that already in place for class mul.
Vitaly Magerya [Fri, 12 Oct 2018 18:45:27 +0000 (20:45 +0200)]
Handle un-normal zeros properly in the division-free elimination.
Call .normal() instead of just .expand(), such that matrix::pivot() finds
the pivot.
Note that this problem also affects matrix::solve() with 'algo'
set to solve_algo::automatic.
Of course, using .normal() makes division_free_elimination only
truly "division-free" if the input matrix didn't have fractions.
In other cases, GCDs will be computed.
Vitaly Magerya [Wed, 13 Jun 2018 21:07:45 +0000 (23:07 +0200)]
Add optional matrix::rank() algorighm selection.
Before, matrix::rank() was hardcoded to use Bareiss elimination,
which for some matrices is way too slow (and I had to work around
this limitation in my own code). I propose adding an argument that
will allow users to select which elimination scheme to use. The
argument is the same as matrix::solve() takes (so, solve_algo::*).
I've tried to mimic how a similar argument was added to
matrix::inverse() by keeping the current set of rank() functions
and defining separate ones with the 'algo' argument, with the
old ones calling the new ones with solve_algo::automatic. This
is instead of using default argument values.
I've also put the code that makes the automatic selection of
the elimination method into a separate function so that both
matrix::solve() and matrix::rank() could share it. There's a bit
of similar code in matrix::determinant(), but since the self
of determinant algorithms is different from the elimination
algorithms, it's not clear if these two could be unified.
This algorithm avoids the 'fill-in' problem of Gaussian elimination
and significantly improves the times for solving large sparse systems.
See: <https://www.ginac.de/pipermail/ginac-list/2018-May/002202.html>.
Richard Kreckel [Wed, 31 Jan 2018 09:04:25 +0000 (10:04 +0100)]
Improve gcd(a, b) where one argument is a power of a symbol.
The already implemented recursion
gcd(x^n, x*p(x)) -> x*gcd(x^(n-1), p(x))
is not ambitious enough: If p(x) has a factor of x, it just goes through
the same step again, and if p(x) has a factor which is a power of x, this
is reapeted many times.
Example:
gcd(x^n, expand(x^n*(1+x)))
used to go recurse through the gcd routine n times, which could
easily lead to a stack overflow for n about 10^5.
To improve the situation, introduce a special case for gcd where one
argument is a power of a symbol and just cancel the common factor.
This turned out to be the root cause of segfaults in matrix elimination
algorithms, as reported by Patrick Schulz and Vitaly Magerya:
Cf. <https://www.ginac.de/pipermail/ginac-list/2018-January/thread.html>
Richard Kreckel [Sun, 28 Jan 2018 18:59:54 +0000 (19:59 +0100)]
[CHECK] Add some more factorization exams.
Add the 15 multivariate polynomials from P. S. Wang's paper "An
Improved Multivariate Polynomial Factoring Algorithm" as exams.
Don't add them as benchmarks since timings vary considerably
depending on internal choice of variables. In any case, this should
never take hours. (But before 630db9a0b0 it did, occasionally.)
Richard Kreckel [Sun, 28 Jan 2018 18:23:50 +0000 (19:23 +0100)]
Add optional algorithm selection to matrix::inverse().
Following a proposal by Vitaly Magerya, a signature with a solve_algo
is added to class matrix. (Not using a default argument in order to
not break the ABI.)
Richard Kreckel [Wed, 24 Jan 2018 21:37:24 +0000 (22:37 +0100)]
Speed up special cases of square-free factorization.
Square-free factorization of polynomials containing a factor which is
a high power P of a symbol x did scale like O(P) in space and time.
This patch introduces a shortcut in Yun's algorithm, such that the
computation is only O(1) in space and time.
This makes it possible to compute, say sqrfree(x^P + x^(P+1)) =>
(1+x)*x^P with P=123456789.
Found this to be a bottleneck while debugging one of Vitaly Magerya's
examples.
Richard Kreckel [Wed, 15 Feb 2017 11:58:48 +0000 (12:58 +0100)]
Clean up combinatorial helpers.
* Convert all signatures from int to unsiged.
* Renamed partition_generator to partition_with_zero_parts_generator...
* ...and add class partition_generator which does not include zero parts.
* Rename ::current() to ::get() and make them compute vectors on first use.
Richard Kreckel [Sun, 6 Nov 2016 18:35:46 +0000 (19:35 +0100)]
Clean up some header files and fix compilation with MSC.
On MSC there is no <unistd.h>. It turns out that we need to #include <io.h>
in order to use close(3). This fixes the build failure introduced in 8305ec38.
Richard Kreckel [Sat, 1 Oct 2016 22:45:11 +0000 (00:45 +0200)]
Suppress compiler warnings about inconsistent override.
The introduction of the 'override' keyword in GiNaC in d5b86dd10 was
deliberately incomplete: Duplication of code in macros was avoided.
It turns out that some compilers (e.g. g++ -Wsuggest-override or clang++
-Wall) complain if the 'override' keyword is used inconsistently. Let's
make this consistent now, even if it leads to the introduction of two
more macros.
Vladimir Kisil [Thu, 11 Aug 2016 18:47:08 +0000 (20:47 +0200)]
Add proper functions to make clifford_bar() and clifford_star().
Previously operations clifford_bar() and clifford_star() called
conjugate() method. This results in reversion of all non-commutative
entries (not only Clifford units) and produced complex conjugation
of all non-real items. The new routine operates on Clifford units only.
Richard Kreckel [Thu, 21 Jul 2016 06:55:44 +0000 (08:55 +0200)]
[bugfix] Fix crash in basic::subs().
A regression in 1.7.0 was introduced with 1b8bcb06 in function
basic::subs_one_level(): implicitly casting *this to an ex first for
finding *this in m and later in the function's return statement caused
a crash in the second cast because *this was deleted in the first one.
After all, *this was dynamically allocated in basic::subs().
This bug was reported and hunted down by Mario Prausa.
Richard Kreckel [Mon, 4 Apr 2016 07:05:50 +0000 (09:05 +0200)]
Install ginac-excompiler in $LIBEXECDIR, not in $BINDIR.
...and make the GiNaC library aware of where it is installed.
The ginac-excompiler script is only invoked by GiNaC::compile_ex(...)
and serves no purpose on its own. In compliance with the FHS, it should
be installed in $LIBEXECDIR, not in $BINDIR. This also disburdens
distribution packagers from having to provide a manpage (which may be
required for all programs in $BINDIR).
The location for $LIBEXECDIR defaults to ${prefix}/libexec/. It may be
overwritten at configuration time. (Many distributions want to set it to
${prefix}/lib/ginac/.)
Richard Kreckel [Fri, 5 Feb 2016 23:47:08 +0000 (00:47 +0100)]
[bugfix] fix elusive bug in quo, rem,...
The power of two rational numeric objects needs not be rational. As a
result, some care is required when transforming (b^e)*l -> (b*l^(1/e))^e
for some rational e and l. This is a common transformation in order to
convert a polynomial over Q into a polynomial over Z when computing
their quotient, remainder, etc. Failure to be careful can potentially
introduce spurious non-rational numbers into rational polynomials and
make those operations fail. This patch avoids this transformation when
l^(1/e) is not a rational number.
Richard Kreckel [Fri, 5 Feb 2016 23:47:08 +0000 (00:47 +0100)]
[bugfix] fix elusive bug in quo, rem,...
The power of two rational numeric objects needs not be rational. As a
result, some care is required when transforming (b^e)*l -> (b*l^(1/e))^e
for some rational e and l. This is a common transformation in order to
convert a polynomial over Q into a polynomial over Z when computing
their quotient, remainder, etc. Failure to be careful can potentially
introduce spurious non-rational numbers into rational polynomials and
make those operations fail. This patch avoids this transformation when
l^(1/e) is not a rational number.