A FractionField
is an abstract class (inheriting from ring
)
representing a fraction field of an effective GCD domain.
See RingElem
FractionField for operations on its elements.
NewFractionField(R)
-- creates a new ring
, more precisely a
FractionField
, whose elements are formal fractions of elements of
R
(where R
is a true GCD domain, see IsTrueGCDDomain
in ring
).
RingQQ()
-- produces the CoCoA ring
which represents QQ, the
field of rational numbers, fraction field of RingZZ
.
Calling RingQQ()
several times will always produce the same unique
ring in CoCoALib.
FractionField(R)
-- sort of downcast the ring R
to a fraction field;
will throw an ErrorInfo
object with code ERR::NotFracField
if needed.
Let S
be a ring
IsFractionField(S)
-- true
iff S
is actually a FractionField
FractionFieldPtr(S)
-- pointer to the fraction field impl (for calling mem fns);
will throw an ErrorInfo
object with code ERR::NotFracField
if needed.
In addition to the standard ring
operations, a FractionField
may be used in other functions.
Let FrF
be a FractionField
built as NewFractionField(R)
with R
a ring
BaseRing(FrF)
-- the ring
it is the FractionField
of --
an identical copy of R
, not merely an isomorphic
ring
.
EmbeddingHom(FrF)
-- BaseRing(FrF)
--> FrF
InducedHom(FrF, phi)
-- phi: BaseRing(K)
--> codomain(phi)
The class FractionField
is wholly analogous to the class ring
,
i.e. a reference counting smart pointer. The only difference is that
FractionField
knows that the myRingPtr
data member actually points to
an instance of a class derived from FractionFieldBase
(and so can
safely apply a static_cast
when the pointer value is accessed).
FractionFieldBase
is an abstract class derived from RingBase
.
It adds a few pure virtual functions to those contained in RingBase
:
virtual const ring& myBaseRing() const; virtual ConstRawPtr myRawNum(ConstRawPtr rawq) const; // NB result belongs to BaseRing!! virtual ConstRawPtr myRawDen(ConstRawPtr rawq) const; // NB result belongs to BaseRing!! virtual const RingHom& myEmbeddingHom() const; virtual RingHom myInducedHomCtor(const RingHom& phi) const;
myBaseRing
returns a reference to the ring
(guaranteed to be an effective GCD
domain) supplied to the constructor.
myRawNum
(resp. myRawDen
) produces a raw pointer to a value belonging to
BaseRing
( and *NOT* to the FractionField
!); these two functions *practically*
*oblige* the implementation of FractionField
to represent a value as a pair of
raw values "belonging" to the BaseRing
. Note that, while the value belongs to
BaseRing
, the resources are owned by the FractionField
!!
EmbeddingHom
returns the embedding homomorphism from the BaseRing
into
the FractionField
; it actually returns a reference to a fixed homomorpism
held internally.
InducedHom
creates a new homomorpism from the FractionField
to another
ring
S given a homomorpism from the BaseRing
to S.
FractionFieldImpl
implements a general fraction field. Its
elements are just pairs of RawValue
s belonging to the BaseRing
(see the struct FractionFieldElem
). For this implementation the
emphasis was clearly on simplicity over speed (at least partly because
we do not expect FractionFieldImpl
to be used much). For polynomials
whose coefficients lie in a FractionField
we plan to implement a
specific ring
which uses a common denominator representation for
the whole polynomial. If you want to make this code faster, see some
of the comments in the bugs section.
Important: while fractions are guaranteed to be reduced (i.e. no common factor exists between numerator and denominator), it is rather hard to ensure that they are canonical since in general we can multiply numerator and denominator by any unit. See a bug comment about normalizing units.
The functions myNew
are not exception safe: memory would be leaked if
space for the numerator were successfully allocated while allocation for
the denominator failed -- nobody would clean up the resources consumed
by the numerator. Probably need a sort of auto_ptr
for holding
temporary bits of a value.
Should partial homomorphisms be allowed: e.g. from QQ to ZZ/(3)? Mathematically it is a bit dodgy, but in practice all works out fine provided you don't divide by zero. I think it would be too useful (e.g. for chinese remaindering methods) to be banned. Given phi:ZZ->ZZ[x] it might be risky to induce QQ->ZZ[x]; note that ker(phi)=0, so this is not a sufficient criterion!
Currently you can make a FractionField
only from a ring satisfying
IsTrueGCDDomain
; in principle one could create a FractionFieldImpl
of any integral domain (it just wouldn't be possible to cancel factors
without a GCD -- so probably not terribly practical). I'll wait until
someone really needs it before allowing it.
It is not clear how to make the denominator positive when the GCD domain is ZZ (so the fraction field is QQ). In general we would need the GCD domain to supply a normalizing unit: such a function could return 1 unless we have some special desire to normalize the denominator in a particular way. HERE'S A CONUNDRUM: FractionField(Q[x]) -- all rationals are units, and so we could end up with horrible representations like (22/7)/(22/7) instead of just 1. MUST FIX THIS!!
The printing function is TERRIBLE!
myIsRational
is incomplete: it will fail to recognise rationals whose
numerator and denominator have been multiplied by non-trivial units. BAD BUG!
Ironically myIsInteger
does work correctly.