Scope markers

5 views
Skip to first unread message

Waldek Hebisch

unread,
Apr 16, 2023, 8:09:55 PM4/16/23
to fricas...@googlegroups.com
Some time I wrote about scope markers. Now I have trial
implementation (attached patch).

With the patch one can do:

P1 := SUP(INT)
P2 := SUP(P1)
p1 := monomial(monomial(1, 1)$P1, 0)$P2
p2 := monomial(1$P1, 1)$P2
rl := [message(a)$OutputForm for a in ["p", "q", "r", "s", "t"]]
set_replacements(rl)$OutputFormTools

Then:

(7) -> p1

(7) q
Type: SparseUnivariatePolynomial(SparseUnivariatePolynomial(Integer))
(8) -> p2

(8) p
Type: SparseUnivariatePolynomial(SparseUnivariatePolynomial(Integer))

That is "?" gets replaced by names from 'rl' depending on nesting
level.

The patch only handles SUP. There is regression: 'precodition'
replaces scope markers as needed, but when outputting type we
do not call 'precodition', so scope markers appear in output of
types. I am working on this, will write a separate message.



--
Waldek Hebisch
sum_sc.diff

Waldek Hebisch

unread,
Apr 27, 2023, 9:06:21 AM4/27/23
to fricas...@googlegroups.com
This is part of public disscusion, so back to the list.
On Sun, Apr 23, 2023 at 01:03:59AM +0200, Ralf Hemmecke wrote:
> On 17.04.23 02:52, Waldek Hebisch wrote:
> > Some time I wrote about scope markers. Now I have trial
> > implementation (attached patch).
>
> > With the patch one can do:
> >
> > P1 := SUP(INT)
> > P2 := SUP(P1)
> > p1 := monomial(monomial(1, 1)$P1, 0)$P2
> > p2 := monomial(1$P1, 1)$P2
> > rl := [message(a)$OutputForm for a in ["p", "q", "r", "s", "t"]]
> > set_replacements(rl)$OutputFormTools
> >
> > Then:
> >
> > (7) -> p1
> >
> > (7) q
> > Type: SparseUnivariatePolynomial(SparseUnivariatePolynomial(Integer))
> > (8) -> p2
> >
> > (8) p
> > Type: SparseUnivariatePolynomial(SparseUnivariatePolynomial(Integer))
> >
> > That is "?" gets replaced by names from 'rl' depending on nesting
> > level.
>
> Oh, I was a bit surprised that the first name in rl is given to P2 and not
> P1, I find that a bit strange, because then we get something like this:
>
> (9) -> P3 := SUP P2
>
> (14) -> p1 :: P3
>
> (14) q
> Type: SUP(SUP(SUP(INT)))
> (15) -> p1
>
> (15) q
> Type: SUP(SUP(INT))
> (16) -> p2
>
> (16) p
> Type: SUP(SUP(INT))
> (17) -> p1::P3
>
> (17) q
> Type: SUP(SUP(SUP(INT)))
> (18) -> p2::P3
>
> (18) p
> Type: SUP(SUP(SUP(INT)))
>
> Well, if it is just for debugging, then this is still an improvement, but a
> confusing one, I would say.

The above is confusing because polynomial coercions are confusing
(they "move" variables up and down).

> I would rather like an implementation where the innermost SUP gets the first
> variable.

Well, there are limitations. One my goal is that given single polynomial
its type and output form should be enough to reconstruct the polynomial.
I think that the approach above allows it.

Concerning limitations, we can depend on presence of outer scope,
but there is no warranty that inner scope will be there. So
in single pass approach to 'precondition' we must start from
outer variables. Of course, if one really want to start from
inner variables, then two pass approach is possible: in first
pass collect info about scopes, in second pass do actual renaming.
OTOH, I an not sure if making innermost variable first is better.
If you have two towers of SUP-s thare are many possible ways
to embed them in common type, the user will have to cope with
this regardless how we choose variable names.

> > The patch only handles SUP. There is regression: 'precodition'
> > replaces scope markers as needed, but when outputting type we
> > do not call 'precodition', so scope markers appear in output of
> > types. I am working on this, will write a separate message.
>
> Oh, while you are looking at this... I actually wanted to write a mail about
> it two days ago, In order not to spoil this thread it will go separate, but
> is related to the problem of printing types.
>
> I somehow do not like the terse documentation of scope:
>
> scope : (%, %) -> %
> ++ scope(v, a) delimits scope of v to a.
>
> Honestly, if I didn't know the history in the mailinglist, I would not know
> why someone introduced this function and what its purpose actually is. You
> may see this generic description as an advantage, but if nowhere else in the
> source one can learn about it, then it's pretty hard (and time consuming) to
> find out.

If that goes in, it will go together with test which can serve as
example. Also, 'scope' is part of internal machinery which should
be ignorable except for folks that implement things like SUP.

Rather, user visible functionality is accessed via 'set_replacements'.
Concerning documentation, if this is deemed useful enough we
could add a paragraph to FriCAS book to explain the problem
and solution.

For people curious why we have some function generic way is to
try break things. Remove the function or redefine it. Then
run tests. If no test breaks, then maybe function has no
purpose. Or, more likely, there is deficiency in our tests.

> Wouldn't it make sense that if someone use set_replacements and the provided
> list is too short that one could continue with using "?1", "?2" etc. for the
> next names?

It makes sense. Simply, it is not clear how far we want to go.
I expect the user to know how many variables are there, fallback
is to avoid gross breakage of output form in case when user makes
an error.

> Anyway, my biggest problem is with the order of the variables connected to
> the depth of SCOPE.

--
Waldek Hebisch

Ralf Hemmecke

unread,
Apr 27, 2023, 10:34:51 AM4/27/23
to fricas...@googlegroups.com
On 27.04.23 15:49, Waldek Hebisch wrote:
> This is part of public disscusion, so back to the list.

I'm sorry. I must have hit the wrong botton on my mailer.

> The above is confusing because polynomial coercions are confusing
> (they "move" variables up and down).

Hmmm... Let me say something general. I already said that I find your
patch an improvement. When I wrote the mail, I was already thinking
about how difficult it is to implement what I would prefer.
SUP comes without variable name. Period. If one wants names then one
should use UP.

> OTOH, I an not sure if making innermost variable first is better.

Well, it wouldn't confuse me in the most common cases when I embed a
SUP(R) into another SUP, but whether naming the variables inside out or
outside in is not really much different. The whole stuff is for
debugging only. And there it helps even if the name of the variable
changes when I coerce from SUP(R) to SUP(SUP(R)) or back. One must be
very careful anyway at debugging time. In fact, having this, I would
even be bold and claiming that changing the default to ?, ?2, ?3, etc.
where ? is outermost ?2 is second level etc. would actually be fully
enough for debugging. I think that setting variable names is a
nice-to-have, but wouldn't be vital if the question mark variable names
come with numbers that specify the depth of the scope.

> If that goes in, it will go together with test which can serve as
> example. Also, 'scope' is part of internal machinery which should be
> ignorable except for folks that implement things like SUP.

Yes, yes. I usually do not much distiguish between user and developer
documentation, but anyway, I very much like that code is documented for
developer explaining the reason why something was introduced. There
should be a link to the mailing list or even a short explanation (i.e.
"--" comments near the place where scope is implemented. And if it is
not for the general user, then the ++ docstring should mention that
scope is intended for internal purpose.

> Rather, user visible functionality is accessed via
> 'set_replacements'. Concerning documentation, if this is deemed
> useful enough we could add a paragraph to FriCAS book to explain the
> problem and solution.

Yes. But it's pretty uninteresting and should go into a developer section.

> For people curious why we have some function generic way is to try
> break things. Remove the function or redefine it. Then run tests.
> If no test breaks, then maybe function has no purpose. Or, more
> likely, there is deficiency in our tests.

We certainly have enough deficiencies in our tests (not every part of
FriCAS is covered), but if you patch breaks one test, then the test is
also bad, because relying on the output of SUP is not a good test.

>> Wouldn't it make sense that if someone use set_replacements and the
>> provided list is too short that one could continue with using "?1",
>> "?2" etc. for the next names?
>
> It makes sense. Simply, it is not clear how far we want to go.

Oh, infinity. Just count the scopes and whenever you need a variable,
then generate one with prepending ? to the number of scopes and use that
variable, if there is none left in the user provided variable names
list. That should be pretty easy to implement.

Ralf

Waldek Hebisch

unread,
Apr 27, 2023, 7:21:29 PM4/27/23
to fricas...@googlegroups.com
On Thu, Apr 27, 2023 at 04:34:48PM +0200, Ralf Hemmecke wrote:
> On 27.04.23 15:49, Waldek Hebisch wrote:
>
> > If that goes in, it will go together with test which can serve as
> > example. Also, 'scope' is part of internal machinery which should be
> > ignorable except for folks that implement things like SUP.
>
> Yes, yes. I usually do not much distiguish between user and developer
> documentation, but anyway, I very much like that code is documented for
> developer explaining the reason why something was introduced. There
> should be a link to the mailing list or even a short explanation (i.e.
> "--" comments near the place where scope is implemented. And if it is
> not for the general user, then the ++ docstring should mention that
> scope is intended for internal purpose.

FriCAS constructors export a lot of things that users are unlikely
to find useful, but are needed for internal purposes. In particular
naive users should be able to ignore OutputForm, for such users
it is just part of magic to get output on the screen. And
description of OutputForm: "It is intended to provide an insulating
layer between ..." sould make clear that this is internal functionality.

> > Rather, user visible functionality is accessed via
> > 'set_replacements'. Concerning documentation, if this is deemed
> > useful enough we could add a paragraph to FriCAS book to explain the
> > problem and solution.
>
> Yes. But it's pretty uninteresting and should go into a developer section.
>
> > For people curious why we have some function generic way is to try
> > break things. Remove the function or redefine it. Then run tests.
> > If no test breaks, then maybe function has no purpose. Or, more
> > likely, there is deficiency in our tests.
>
> We certainly have enough deficiencies in our tests (not every part of
> FriCAS is covered), but if you patch breaks one test, then the test is
> also bad, because relying on the output of SUP is not a good test.

In principle every thing implemented in FriCAS should have a test.
Test testing that output of SUP is as intended is a good test, otherwise
output could get broken and breakage could be detected only after
release.

Granted, other test should not depend on specific form of output, but
there should be at least one test that breaks if you remove functionality.

> > > Wouldn't it make sense that if someone use set_replacements and the
> > > provided list is too short that one could continue with using "?1",
> > > "?2" etc. for the next names?
> >
> > It makes sense. Simply, it is not clear how far we want to go.
>
> Oh, infinity.

I meant how much functionality we want to implement. So you say that
we should fill all available storage with FriCAS sources and binaries
and we should use all available RAM. Well, we are working on this...

> Just count the scopes and whenever you need a variable, then
> generate one with prepending ? to the number of scopes and use that
> variable, if there is none left in the user provided variable names list.
> That should be pretty easy to implement.

Yes, that would be easy.

--
Waldek Hebisch
Reply all
Reply to author
Forward
0 new messages