A GlobalManager
object does some very simple management of (certain)
global values used by CoCoALib (in particular controlled
destruction). So that the operations in CoCoALib can work properly you
should create an object of type GlobalManager
before using any other
feature of CoCoALib. Conversely, the GlobalManager
object should be
destroyed only after you have finished using CoCoALib features. An easy
way to achieve this is to create a local variable of type GlobalManager
at the start of a top level procedure (e.g. main
). See for instance
the CoCoALib example programs.
Once the GlobalManager
has been created you can use the following functions:
DefaultResiduesAreSymm
returns true
iff residues in quotients of Z
are to be printed out as values in the range -m/2 to m/2;
GlobalRandomSource
a global randomness source; see RandomSource
for
a description of the permitted operations on random source objects.
The ctor for a GlobalManager
has one (optional) argument. This
argument is used to specify the global settings. Currently the
settings which can be specified are the type of memory manager to use
for GMP values (viz. big integers and rationals), and whether
elements of rings of the form ZZ/n should be printed as least
non-negative residues or as (symmetric) least magnitude residues. The
current defaults are to use the system memory mananger and to print
symmetric residues.
There are three possibilities for specifying the memory manager for GMP:
UseSystemAllocatorForGMP
to use the GMP default memory manager
UseGMPAllocator
to use the CoCoALib custom memory manager
UseGMPAllocator(
sz )
to use the CoCoALib custom memory manager with slice size of sz bytes
WARNING if you store GMP values in global variables, it is safest to use only the GMP default memory manager!
There are two possibilities for specifying the printing convention for elements of rings of the form ZZ/n:
UseSymmResidues
symmetric residues (if n is even, the residue n/2 is printed as positive)
UseNonNegResidues
least non-negative residues
To specify more than one global setting the individual specifiers should be
combined using operator+
. Combining incompatible or redundant
specifiers will produce a run-time error. We recommend using the CoCoALib
custom allocator (with default slice size) if possible; it may not be
possible if you use CoCoALib with another library which uses GMP values.
The custom allocator offers slightly better performance, and can be
helpful when debugging or fine-tuning code.
An exception will be thrown if you attempt to create more than one
GlobalManager
object (without having destroyed all earlier
GlobalManager
s). The exception is of type CoCoA::ErrorInfo
and has error
code ERR::GlobalManager2
. At the moment the
ctor for GlobalManager
is not threadsafe; it is the user's
responsibility to avoid trying to create several instances simultaneously.
The concept of GlobalManager
was created to handle in a clean and
coherent manner (almost) all global values used by CoCoALib; in particular
it was prompted by the decision to make the ring of integers a global value
(and also the field of rationals). The tricky part was ensuring the
orderly destruction of RingZZ
and RingQQ
before main
exits.
Recall that C++ normally destroys globals after main
has completed, and
that the order of destruction of globals cannot easily be governed;
destroying values in the wrong order can cause to the program to crash just
before it terminates. Another advantage of forcing destruction before
main
exits is that it makes debugging very much simpler (e.g. the
MemPool
object inside RingZZImpl
will be destroyed while the input
and output streams are still functioning, thus allowing the MemPool
destructor to report any anomalies). And of course, it is simply good
manners to clean up properly at the end of the program.
To implement the restriction that only one GlobalManager
may exist
at any one time, the first instruction in the ctor checks that the
global variable GlobalManager::ourGlobalDataPtr
is null. If it is
null, it is immediately set to point the object being constructed.
The ctor for GlobalManager
is fairly delicate: e.g. the functions
it calls cannot use the functions RingZZ()
and RingQQ()
since
they will not work before the GlobalManager
is registered.
The two functions MakeUniqueCopyOfRingZZ
and MakeUniqueCopyOfRingQQ
are supposed to be accessible only to the ctor of GlobalManager
; they
create the unique copies of those two rings which will be stored in the
global data. The functions are defined in RingZZ.C
and RingQQ.C
respectively but do not appear in the corresponding header files (thus
making them "invisible" to other users).
The dtor for GlobalManager
checks that RingZZ
and RingQQ
are not
referred to by any other values (e.g. ring elements which have been
stored in global variables). A rude message is printed on cerr
if
the reference counts are too high, and a program crash is likely once
the GlobalManager
has been destroyed.
The GMPMemMgr
class performs the necessary steps for setting the
memory manager for GMP values. At the moment there are essentially
two choices: use the system memory manager, or use a MemPool to handle
the memory for small values. The first parameter to the ctor for
GMPMemMgr
says which sort of memory manager to use. If the system
allocator is chosen, then the ctor does nothing (since the GMP default
is the system manager); similarly nothing is done when the GMPMemMgr
object is destroyed. The second argument is completely ignored when
the system allocator is chosen.
The situation is more complicated if CoCoALib's custom allocator is to
be used. The second argument specifies the "slice size" (in bytes)
which is to be used -- the implementation may automatically increase
this value to the next "convenient" value (see also the documentation
for MemPool
). The slice size defines what a GMP small value is:
it is a value whose GMP internal representation fits into a single slice.
The memory for small values is managed by a (global) MemPool
, while
the memory for larger values is managed by the standard malloc
family
of functions.
Since the only place a GMPMemMgr
object appears is as a data field in a
GlobalManager
, we have an automatic guarantee that there will be at
most one GMPMemMgr
object in existence -- this fact is exploited
(implicitly) in the ctor and dtor for GMPMemMgr
when calling the GMP
functions for setting the memory management functions.
Of the alloc/free/realloc functions which are handed to GMP, only
CoCoA_GMP_realloc
displays any complication. GMP limbs can be stored
either in memory supplied by the MemPool
belonging to a GMPAllocator
object or in system allocated memory; a reallocation could cause the limbs
to be moved from one sort of memory to the other.
The GlobalSettings
class serves only to allow a convenient syntax
for specifying the parameters to the GlobalManager
ctor. The only
mild complication is the operator+
for combining the ctor
parameters, where we must check that nonsensical combinations are not
built.
2010-09-30 The private copies of RingZZ
and RingQQ
are now direct
members, previously they were owned via auto_ptr
s. The new
implementation feels cleaner, but has to include the definitions of
ring
and FractionField
.
You cannot print out a GlobalManager
object; is this really a bug?
Ctor for GlobalManager
is NOT THREADSAFE.
Should the ctor for GlobalManager
set the globals which control
debugging and verbosity in MemPool
s?