axiom-developer
[Top][All Lists]

## [Axiom-developer] Re: conditionally defined functions

 From: William Sit Subject: [Axiom-developer] Re: conditionally defined functions Date: Fri, 17 Sep 2004 23:56:12 -0400

```Martin Rubey wrote:
>
> Dear Manuel, Ralf, Tim, William, *,
>
> I'm struggling with something, maybe you are able to help. If not please tell
> me so.
Ok, can't help :-).

> As you might know, I'm experimenting with fixes of the following,
> superficially
> strange behaviour:
>
> (1) -> (1/x)::UP(x, FRAC POLY INT)
>
>         1
>    (1)  -
>         x
>                     Type: UnivariatePolynomial(x,Fraction Polynomial Integer)
>
> Well, I think that this is calling for trouble. So, one way to fix this is to
> make coerce(coef:R)-> % of UP, MPOLY and the like (in fact, are there others?)
> check whether or not coef contains one of the variables -- in this case x. In
> fact, I believe this is the "right" approach.

Axiom was designed to accommodate this, that is, some polynomial domains (like
POLY, ODPOLY) are constructed with Symbol as the set of indeterminates while
others like UP, MPOLY, DMP, HDMP, GDMP, SMP, DSMP, etc specify a particular set
of named indeterminates. If you want to construct towers of polynomial rings,
then you should be using the second kind. Any time you mix one kind with the
other in a tower, you are calling for trouble (your words). If indeed a domain
of the first kind has to mixed with one of the other kind in a tower, it is
imperative that the first kind domain be converted (coerced, lifted, whatever)
to the second kind by finding the set of indeterminates involved IN THE
COMPUTATION (that is, "locally" for a finite set of polynomials involved only,
not the entire domain)  using the spad function [variables] ([ ] just to say
this is a spad function, not used as an English mathematical word). This is
routinely done in radical ideal membership testing using grobner basis, where
the user supplies polynomials from POLY INT and an auxilliary indeterminate is
needed. The computation is done in for example a tower of DMP's. The auxilliary
indeterminate can be generated by the compiler which does not conflict of any
existing names. The result is then converted back to POLY, if needed.

Note that the suggestion you made above, when carried out locally, amounts to
the same thing. The "local" solution works, though it is not very efficient
because of all the coercions. For example, see source for qalgsetp.spad (see
construction of newPoly. The "global" solution, on the other hand, does not make
sense because Symbol includes everything.

In previous messages, we already discussed and agreed that the x in UP(x, FRAC
POLY INT) will be internally different than the x in FRAC POLY INT. The compiler
keeps track of them as different. However, to use the same output symbol for two
different indeterminates is simply wrong from the user interface viewpoint.

>
> In principle, this is not too difficult. However, there is a slight subtlety:
> Currently not all domains that contain variables provide such a function, in
> particular, FRAC does not. Instead, there is a package RF that provides this
> functionality. Well, no problem:
>
> * move the operation variables from RF and POLYCATQ to QFCAT :
>
>     if S has variables: S -> List Symbol then
>       variables: % -> List Symbol
>       variables f ==
>          mymerge(variables(numer(f)), variables(denom(f)))
>
> and add the following to UP and MPOLY :
>
>     if R has variables: R -> List Symbol then
>       coerce(r:R):% ==
>         if member?(x, variables(r)) then
>           error "coefficient contains variable"
>         else coerce(r)\$Rep
>
> "fix":

If this works, it works wrongly, because this confuses the x in the inner domain
of a tower with the x in the outer domain of the tower. Remember that the
compiler distinguishes these already. So the condition
member?(x, variables(r))
would always return false. The identifier x (NOT a symbol) is bound to an
internal symbol, which would NOT appear in variables(r) (a "local"
construct).Unless you change UP fundamentally to consider the parameter x in its
call to bind to an existing identifier x. But this would probably break a lot of
code and defeat the r'aison d'ete of UP.

> * the function "variables" thus (conditionally) provided in QFCAT is only one
>   of many. I don't know of an example, but POLYCAT (which defines variables
>   originally) defines variables : % -> VarSet (which is a member of the
>   Category OrderedSet). So, for example, since SUP specialises VarSet to be
>   SingletonAsOrderedSet, FRAC UP won't have a function variables.
>
> * philosophically, this is not very beautiful. But I don't see another way to
>   overcome the problem.

If you are only dealing with a finite set of polynomials or fraction of these
and want to find its variables, you can always write such a routine even if the
domain does not have one (as in FRAC).

> Now a mail of William comes in. He wrote, quite some time ago:
>  > Actually, there is a more general request for ages: that is, each
>  > CONSTRUCTOR in Axiom should provide the means to return ALL the
> parameters. This
>  > would have to be built like OutputForm form the bottom up because of
> nesting.
>  > Lots of editing and a total rebuilt. Currently, when writing a constructor,
>  > there is no way one can "descend" inside its parameters other than finding
> their
>  > categorical property or attributes.
>
> However, I don't really see how this could be used. I modified POLYCAT to
> contain a function
>
> varset: () -> OrderedSet
> varset () == VarSet
>
> but I was not able to do anything useful with this. Of course, what I'd like
> to
> say in QFCAT would be
>
> I'd like to be able to say in QFCAT something like:
>
>     if S has varset: () -> OrderedSet then
>       variables: % -> List varset()
>       variables f ==
>          mymerge(variables(numer(f)), variables(denom(f)))
>
> But this looks fishy.

I don't know what you meant by "fishy". The code would not work at present
because I don't think you can consider a function as an attribute. You have to
register it in the AttributeRegistry first. However, since the signature is not
"constant", I wonder if this can be done at all.  Note also you must package
call varset(), which thus requires you to know the parameters, a catch-22
situation.

The problem you raised is one of what might be called dynamic signature, that is
the codomain depends on the input value. The Axiom compiler can handle this
partly, in a category/domain constructor's signature, but not on the function
level. For an example, see the signature of domain constructor DMP, where #vl is
used in the codomain.
>
> So, in more general terms, here's my question:
>
> Suppose you have a category A, taking as parameter a domain P and providing an
> operation f: % -> P. Furthermore, you have a category (or a domain, a package)
> B, taking as parameter a domain Q. Now you want to achieve the following:
>
> If Q is a domain in A, provide a function g: % -> P, using f.
>
> Of course, it is not possible to provide P as a parameter of B, since B should
> also be defined for Q's that are not domains in A...

The way to handle this is to create a special version of B, which takes a domain
in A as parameter, together with parameters needed for A and construct the
special version using the general one. This is ok because the compiler can
handle dynamic signature on the category/domain constructor level.

BforA(P:Cat1, Q: A(P)): Cat2 == B(Q) with { g:%->P }

You can then add the function g without a problem. The moral is: Don't Ask, Just
Tell.

William
--
William Sit