axiom-developer
[Top][All Lists]

## [Axiom-developer] Re: Mixing up variables: (was Re: conditionally define

 From: William Sit Subject: [Axiom-developer] Re: Mixing up variables: (was Re: conditionally defined functions) Date: Sat, 25 Sep 2004 20:45:08 -0400

```Hi Martin:

Martin Rubey wrote:
>
> Dear William,
>
> hope I'm not annoying you...
Not at all. When I said "I am pressed for time", I simply meant that at that
time, I would not be able to answer or test code as thoroughly as I would like
and it was an apologetic remark.

>  > This result is wrong since I can change x to another symbol and the result
>  > would be the same:
>
> I'm not so sure about "wrong". One (not me...) could argue that the two
> univariate polynomials 3*x+1 and 3*t+1 are the same. On the other hand, I (!)
> would say that this behaviour should be reserved for SUPs.

Yes, when univariate polynomials are interpreted as functions in the
mathematical sense, 3*x+1 and 3*t+1 are the same (x, t are dummy variables or
placeholders for the functions). But this is seldom the interpretation in
symbolic computation.  Here, we are getting closer to a discussion on what
"equality" means, a well-understood problem with many possibilities but no clear
choice that would work for all situations. I am not sure what "this behaviour"
refers to, or why SUPs are more appropriate.

> And indeed, axiom
> does say that
>
> ((x::UP(x, INT))=(t::UP(t, INT)))::Boolean
>
> is false.

Again, at the risk of being repetitve, be careful here. Your axiom line above
means first defining an equation x=t (in the domain Equation UP(x, UP(t, INT))
after automatic coercion) and then coercing to Boolean in that same domain,
which then gives false. The action Axiom takes is NOT the same as in the case

g:Boolean:= ((x::UP(x, INT))=(t::UP(t, INT)))

even though the results are the same. The subtle difference lies in side-effects
while getting to the result. In the first instance, it looks for a domain T:
Type and a signature for [equation:(T,T)->Equation(T)], while in the latter, a
domain S:SetCategory and a signature for ["=": (S,S)-> Boolean].

>  > So I think this is a bug in the interpreter. Instead of trying to be
>  > to search for an "=" that returns Boolean for the types given on the lhs
> and
>  > rhs, it should simply first check whether the two sides have the same type
>  > and then whether equality testing "=" exist for that type. No automatic
>  > coercion should be done.
>
> types (if you do not coerce to Boolean), everything looks sane. I do
> understand
> that the domain EQ is not involved when you do ask for a boolean immediately,
> but I wouldn't hurry here.

Equation(T) only needs T:Type. Equation(T) has CoercibleTo(Boolean) if
T:SetCategory.  I wish Axiom had not overloaded the operator "=" but say used
"=?" for boolean (indeed, I like it to always use an identifier ending with ?
for all functions with codomain Boolean). There is really no good reason to
coerce lhs and rhs to a common S:SetCategory if lhs and rhs are not already in
the same domain, then they are not equal, period, even if a test for equality
has not been implemented. Note that lhs and rhs are always evaluated (and
presumably simplified to \$Rep form) before the test. If they do not belong to
the same domain, why should they be equal in a super-domain? Of course, if they
do not belong to the same domain (without coercion), no ["="] will be found and
so no result will be output; but in that case, an error message is the correct
response (and the error should be trapped via a throw/catch mechanism) -- it is
like someone writes an *equality* where the lhs and rhs does not have the same
fundamental dimensions of time, length, mass -- it is an error that should be
caught. Note that to coerce the lhs and rhs to a common domain T to use
[equation] would make sense in some cases, because after all, we could have
written the equation as lhs-rhs=0 if the domain T has AbelianGroup and we may
want to solve the equation.

> It seems that there is a fundamental misunderstanding concerning my intention
> with regards to the semantics of UP(x, POLY INT). You wrote
>
>  > There is one problem with the
>  >
>  >     member?(x, variables(r))
>  >
>  > condition. If R is EXPR INT, and if x occurs in r say as 1/x or as sin(x),
> I
>  > would think that variables(r) would have x as a member, and so you would
>  > the error message when coerce is called. But according to your intention,
> you
>  > may still want to coerce r (that is, in my terminology, reformat r) to
> look like
>  > UP(x, EXPR INT).
>
> In fact, an error message is exactly what I'd like to see for
> (1/x)::UP(x, EXPR INT).

Sorry, Martin, I probably misunderstood it when you wrote on
Wed, 22 Sep 2004 17:08:07 +0000:

> On the other hand, it is easy to clarify the semantics of types like
> UP(x, EXPR INT): x belongs to UP, and 1/x, 2^x, sin x are not members of this
> domain.

I took that to mean it is easy to view (reformat) an expression such as
x^2 sin(x) - cos(x)/x as a polynomial in x and so UP(x, EXPR INT) makes sense
even when x wears two hats.

> I try to get it right now: (It may be that my current position differs from
> that I had some months ago, but it was constant in the last few weeks. Save I
>
> For any polynomial (or series) domain that has a specified list of variables,
> I
> want that axiom ensures that any coefficient of a member does not contain one
> of these variables. Examples:
>
> (1/x)::UP(x, EXPR INT) produces an error
> x*2^x::UP(x, EXPR INT) produces an error
> (1/x)::UP(x, FRAC POLY INT) produces an error
> (1/x)::UTS(FRAC POLY INT,x,0) produces an error

I am not sure. If UP(x, EXPR INT) is a valid domain (which it is at present),
then all the above can be regarded as in the ground ring EXPR INT.
>
> however, for example
>
> x*2^y::UP(x, EXPR INT) is ok.
>
> More generally, the "outermost" domain "takes" all the variables:

In that case, you would forbid expressions like x^2 sin(x) - cos(x)/x in UP(x,
EXPR INT), where the expression can either be considered as in the ground ring
EXPR INT, or as a polynomial of degree 2. I don't think the second view is
necessarily "wrong," just that Axiom at present does not do this conversion
consistently. I gave some examples where the built-in coercions led to
inconsistencies in [degree].

> POLY EXPR INT would be the domain of polynomials with coefficients that do not
> contain any variables. For example,
>
> (x*sin(2))::POLY EXPR INT would be ok
> (x*sin(y))::POLY EXPR INT would produce an error.

Again, I am not sure why the second one should be an error and the first is not,
if POLY EXPR INT is allowed at all. In both cases, the element may be
interpreted either as in EXPR INT, or a linear polynomial with coefficient in
EXPR INT. Neither is mathematically wrong and each is useful. The problem is
each element may have two different data representations, and the[:: POLY EXPR
INT] does not say specifically what data representation should be used. We need
a clearer way to make the choice. Using a hidden and probably unjustified
convention that the "outer domain takes all the variables" is questionable.

> The domain EXPR POLY INT would be strictly the same as EXPR INT, I think.

No, we are not talking about mathematics, but data structure. I think we agree
that the current semantics allowed is ambiguous and for this reason, any
reformating should be done with specific variables.

>
> On the other hand, there is a completely different solution to the original
> problem, i.e., providing a domain like UP(x, EXPR INT) with good semantics:
>
> > > Yes. I'm inclined to think that this is the best way to go: create a
> > > domain
> > > EXPR(VarSet, CoeffSet) and forbid all of the above constructions: UP(x,
> > > POLY
> > > ?), UP(x, FRAC POLY ?), UP(x, EXPR ?) and so on...
> >
> > Good. I am glad we are beginning to agree. However, your point of creating
> > something like sin(2) x somewhere should be considered carefully.
>
> sin(2)*x would be in UP(x, EXPR([], INT)). Did you mean that?

Yes. For the sake of completeness, let me quote what I wrote on
Wed, 22 Sep 2004 15:20:14 -0400:
------- quote
> Well, I think that EXPR POLY INT (and similarly POLY EXPR INT) should be
> forbidden, since it is not clear where the variables belong.

AGREED!

> On the other hand, it is easy to clarify the semantics of types like
> UP(x, EXPR INT): x belongs to UP, and 1/x, 2^x, sin x are not members of this
> domain. I don't think that there is another way to make sense of such a
> domain. That's the reason for the question I started with, in fact.

But so should UP(x, EXPR INT). You are inconsistent in the application of your
logic: according to the above, POLY EXPR INT is equally fine (just that there
may be more variables). But back to UP. EXPR INT can also contain polynomials in
x in addition to 1/x, 2^x, sin x. In fact:

(15) sin(x)*x + sin(x)*x^2
(x^2 + x)sin(x)            Type Expression Integer

This regrouping is automatic. If you rather prefer the input form, which
separates the powers of x, I think you should use a package to provide the
conversion WITHIN EXPR INT and where you also change the outputform. In Axiom,
the domains correspond to mathematical objects, and to have x in BOTH EXPR INT
and UP(x, EXPR INT) is not right since mathematically, the two are the same, as
underlying set and all operations on it. Indeed, any operation in UP(x, EXPR
INT), say multiplication by sin(x) or 1/x, or even by x, will immediately need
to reconvert UP(x, EXPR INT) back to EXPR INT --- a difficult dilemma because
you now have to consider UP(x,EXPR INT) elements as ground elements (ground? may
fail, in general, though not here), perform the operation, and reformating back
to UP(x, EXPR INT). This really shows that the only thing you can achieve is
reformatting output and so it should be done that way.

If you are not mixing x in both places, then something like UP(y,
EXPR([a,b],INT)) may make sense where a new EXPR with specified variables is
constructed.
----- end quote

Actually, I think it is possible to implement something like EXPR([a,b], INT).
The current discussion arose all because EXPR (and by dependencies, also FS and
perhaps more like ES) uses Symbol as default variable set (same as POLY).
Whereas POLYCAT is parametrically constructed with good control for the
variables set AND its ordering, EXPR and FS do not provide such control. So we
need to study how to add such control without breaking any established code.

As a preliminary suggestion, I propose to generalize the FS category
constructors analogous to POLYCAT:
FunctionSpaceCategory(V:OrderedSet, R: OrderedSet):Category
with abbreviation FSCAT.

This will be done by suitably modifying the existing FunctionSpace(R) code. Then
we can "capture" back FunctionSpace(R) by:
FunctionSpace(R:OrderedSet):Category == FSCAT(Symbol, R)

In a similar way, we can generalize Expression. (I was thinking about a category
constructor ExpressionCategory, but I think this would be the same as
FunctionSpaceCategory).

MultivariateExpression(V:OrderedSet, R: OrderedSet):FSCAT(V,R)

to be abbreviated as MEXPR, and recapture Expression as:

Expression(R:OrderedSet):FS(R)== MEXPR(Symbol, R)

We can also have SparseMultivariateExpression if someone can think of a suitable
data structure.

The next thing would be to put in controls to disallow towers to ensure that no
intermediate extensions involve Symbol as the variable set.

> ------------------------------------------------------------------------
>
> However, currently this seems unachievable. At least I don't know how to do
> it. Your suggestion to extend axiom to allow
>
>  > Ideally, perhaps we can try:
>  >
>  >      if S has variables: S -> List V where V:OrderedSet then
>  >        variables: % -> List V
>  >        variables f ==
>  >           mymerge(variables(numer(f)), variables(denom(f)))
>
> seems most appealing to me, although I don't think this could be done in the
> near future. I read a bit about the "post-facto" extensions provided by aldor,
> maybe they adress this problem too. I'm not sure that I've understood them
> well
> enough, though.
>
> PS: In fact, I can think of a way to do it: provide a function
> variables2: % -> List Any in POLYCAT that simply wraps up the function
> variables:% -> List VarSet.
>
> Then I can provide a function variables2 in QFCAT. The only tricky part is
> that
> I need the operation "<" from VarSet in QFCAT (for mymerge) and I don't know
> of
> a *good* way to get it. I do know an ugly way: provide a function
> (Any, Any)->Boolean in POLYCAT that wraps "<" from VarSet.
>
> Maybe there is a better way, but I'm tired now.

Take a rest! Yes, someone who is experienced with Aldor may tell us whether to
move there or it is still possible to patch Axiom.  However, I think using Any
should be a last resort, even though this may be the only way under Axiom to
treat functions as first class. The trouble with this type of construct is that
the interpreter cannot handle dynamic signature as nicely as the compiler, but
the interpreter can step through code whereas the compiler cannot.

> -------------------------------------------------------------------------
>
> just for the record:
>
> > > I agree, if there remains a clear design. For example, I find the wealth
> > > of
> > > polynomial domains and packages a little confusing:
> > >
>     ...
>
Wait till we get all the varieties of EXPR (and dare I mention DPOLYCAT or
DEXPR?)

William

```