Adding new functions for specific tasks related (logarithm, rational functions, ....)

8 views
Skip to first unread message

ma...@mendelu.cz

unread,
Nov 12, 2009, 8:04:59 AM11/12/09
to sage-devel
Dear readers of sage-devel

This is related to Ticket #7334 http://trac.sagemath.org/sage_trac/ticket/7334
which introduces new function for contracting logarithms, expanding
logarithms, reducing powers of trigonometric functions and simplifying
rational expressions.


------------------------------
Burcin wrote:
I really dislike the idea of adding a new function for each
functionality of this kind. This makes it very hard for users to
figure out the function name they need for a specific task.

We should be able to provide an interface to all these "rewriting"
tasks through a few conceptually defined methods like rewrite(), expand
() and combine()( or contract()?).

Francois Maltey had a proposal for a possible interface to all this.
Maybe he can comment here, or we can discuss his proposal on sage-
devel.
------------------------------


It would be great to find some simple and clean solution which gives
access to many posibilities included in Maxima or/and other CAS. I
think that if we take into account the many possibilities how to
simplify expressions, it will be difficult to do this job.

I think that it is better to have small functions which do their small
job - they do what the user wants. I think that this is Maxima
approach. I do not like the approach in Maple and Mathematica, where
user has one big command for many simplifications and it is not easy
to find out, what to do, if we do not want to use some of
simplifications and rewriting rules included in this big command.

If such a complete solution for rewriting tasks appears, it would be
great to give to the users enough power for fine tunning, like current
expand_trig()

Thanks.
Robert

Francois Maltey

unread,
Nov 12, 2009, 9:17:44 AM11/12/09
to sage-...@googlegroups.com
Dear Marik,

> Burcin wrote:
> I really dislike the idea of adding a new function for each
> functionality of this kind. This makes it very hard for users to
> figure out the function name they need for a specific task.
>
> We should be able to provide an interface to all these "rewriting"
> tasks through a few conceptually defined methods like rewrite(), expand
> () and combine()( or contract()?).
>
> Francois Maltey had a proposal for a possible interface to all this.
> Maybe he can comment here, or we can discuss his proposal on sage-
> devel.
> ------------------------------
>
>
> It would be great to find some simple and clean solution which gives
> access to many posibilities included in Maxima or/and other CAS. I
> think that if we take into account the many possibilities how to
> simplify expressions, it will be difficult to do this job.
>
I dislike simplify word.

Look at theses 2 examples : what is the simplified formula .

2*cos(x)^2-1 : you wait the combined formula cos(2*x)
cos(2*x)+1 : you wait the expanded formula 2*cos(x)^2

a simplify function must have a purpose.
This purpose is only in the user mind, not in any computer algebra
algorithms.

But expand has a clean description :
An expand formula has more transcendent function calls with smaller
arguments.
sin (x+y) == sin(x)*cos(y)+cos(x)*sin(y)

The opposite way may be a combine or a contract function :
less transcendent call but larger arguments :
combine(exp(a)^3/exp(b))=exp(3*a-b).


> I do not like the approach in Maple and Mathematica, where
> user has one big command for many simplifications and it is not easy
> to find out, what to do, if we do not want to use some of
> simplifications and rewriting rules included in this big command.
>

Please, let me have the opposite taste.
I can only record a very small number of functions in my mind.
I also can explain a little number of theory to my students.
So I prefer choose a complete theory or a large transform and then
refine it by options or examples.

In your case, it may be possible to add optional parameters to expand
functions.
By example you may choose a target : only logarithms or trigonometric
functions.

Burcin proposed a target parameter.

So imagine a Sage 4.xyz with

y = log(2)+log(3)+exp(2)*exp(3)
contract (y) # log(6)+exp(5)
contract(y, target=log) # log(6)+exp(2)*exp(3)
contract(y, target=exp) # log(2)+log(3)+exp(5)

An other option may be a predicate select in order to restrain the
tested subexpression.

contract (exp(x+1)*exp(x-1)*exp(y), target=exp, select=lambda subexpr :
has(subexpr, x))
# the answer will be exp(2*x)*exp(y)

And the last option may add a mainBranchCut option.
In a normal (complex) calculus it's impossible to simplify log(x)+log(y)
to log(x*y). Try with x=y=-1.
But a mainBranchCut option overwrite the general rule and suppose the
right hypothesis to get
log(x*y), and 1/2*log(x) give log(sqrt(x)).

> I think that it is better to have small functions which do their small
> job - they do what the user wants. I think that this is Maxima
> approach.
>

It's very difficult to have an complete view of maxima rules. There are
too many functions.
With only one function, the help docstring can explains all the
refinement options.
And options in a main functions can make the (only one) little
transforms you want to apply.
You don't like maple way because I don't think that maple has this
ability to restrain the convert transform.

> If such a complete solution for rewriting tasks appears, it would be
> great to give to the users enough power for fine tunning, like current

> expand_trig().
>
An other question :

How theses rewriting rules may be coded :

1/ With maxima kernel call ?
2/ In Ginac library ?
3/ By a sage interpreter call ?

My vote goes to the number-3/. I don't like maxima method with its
numerous flags.
Look at the previous mail in sage-support about integrate
(sqrt(sin(x)^2+cos(x)^2), x, 0, 2*pi) = only pi
because there was a little change to an inner flag of maxima.

The 2/ way is the longer method. If I want to code it I must learn sage
and also the ginac code. This method looks like to the axiom(s)
language. A function can be right for the interpreter language, but it
takes hours and hours to code it in the axiom kernel with other compiled
rules.(1)

The 3/ is the easiest way to read and to understand the code. When you
read sage files then you understand its functions. It's almost the maple
way with "the verbose option and print the function" and it was the
mupad way. Bug are easiest to find. Interpreted code isn't so slow, you
may wait 1 second more, and there is less wasted time than in (1).


ma...@mendelu.cz

unread,
Nov 12, 2009, 9:42:49 AM11/12/09
to sage-devel
On 12 lis, 15:17, Francois Maltey <fmal...@nerim.fr> wrote:
> So imagine a Sage 4.xyz with
>
> y = log(2)+log(3)+exp(2)*exp(3)
> contract (y) # log(6)+exp(5)
> contract(y, target=log) # log(6)+exp(2)*exp(3)
> contract(y, target=exp) # log(2)+log(3)+exp(5)
>
> An other option may be a predicate select in order to restrain the
> tested subexpression.
>
> contract (exp(x+1)*exp(x-1)*exp(y), target=exp, select=lambda subexpr :
> has(subexpr, x))
> # the answer will be exp(2*x)*exp(y)

Sound good, thanks. I look forward to Sage 4.xyz :)
Thank you for your long and detailed answer.

Robert

Burcin Erocal

unread,
Nov 12, 2009, 10:24:48 AM11/12/09
to sage-...@googlegroups.com
Dear Francois,

Thank you for your detailed explanation.

On Thu, 12 Nov 2009 15:17:44 +0100
Francois Maltey <fma...@nerim.fr> wrote:

> An other question :
>
> How theses rewriting rules may be coded :
>
> 1/ With maxima kernel call ?
> 2/ In Ginac library ?
> 3/ By a sage interpreter call ?

The main motivation behind switching to pynac for symbolics was to make
it possible to develop this functionality in Sage, using python/cython.
We were always aiming for the 3rd option.

Hopefully a future 4.xyz release of Sage will allow you to implement all
this using only python. In order to get there, we should just start and
see what functionality needs to be exposed. :)

I know you already have some suggestions. Maybe you can post them here,
or open trac tickets so others can help implement them.


Burcin

Burcin Erocal

unread,
Nov 12, 2009, 10:38:45 AM11/12/09
to sage-...@googlegroups.com

Care to help?

Francois has a fairly detailed proposal about a possible interface to
expand, contract, and rewrite. I was planning to implement a prototype
to this for a while, but couldn't find the time.

We could start by putting the draft proposal on the wiki, and work on a
prototype implementation.


Cheers,
Burcin

ma...@mendelu.cz

unread,
Nov 12, 2009, 3:30:01 PM11/12/09
to sage-devel
On 12 lis, 16:38, Burcin Erocal <bur...@erocal.org> wrote:
> Care to help?

Many thanks but .... I do not know anything about programming. I can
write simple artless scripts and thats all. I also do not know enough
from complex analysis, know nothing about computer algorithms and so
on. I think that nobody would be interested in CAS with code from
complete beginner.

I like opensource software and math, but have not enough knowledges to
bring significant contribution in this topic.


Could the conclusion be the following?
"If you want (and if the realease manager includes corresponding
patches), add support for Maxima commands which you need. When python
of ginac will be able to replace these commands, these interfaces to
Maxima commands will be removed."


Robert

Robert Bradshaw

unread,
Nov 12, 2009, 3:41:47 PM11/12/09
to sage-...@googlegroups.com
On Nov 12, 2009, at 12:30 PM, ma...@mendelu.cz wrote:

> On 12 lis, 16:38, Burcin Erocal <bur...@erocal.org> wrote:
>> Care to help?
>
> Many thanks but .... I do not know anything about programming. I can
> write simple artless scripts and thats all. I also do not know enough
> from complex analysis, know nothing about computer algorithms and so
> on. I think that nobody would be interested in CAS with code from
> complete beginner.
>
> I like opensource software and math, but have not enough knowledges to
> bring significant contribution in this topic.

Everyone has something they can contribute: bug reports,
documentation, and even feature requests like you've been doing.

> Could the conclusion be the following?
> "If you want (and if the realease manager includes corresponding
> patches), add support for Maxima commands which you need. When python
> of ginac will be able to replace these commands, these interfaces to
> Maxima commands will be removed."


No, I don't see any reason why we would remove the Maxima interface.
What we might do is change our internal routines to call the a non-
maxima version if available (though when more than one system can do
an operation it is customary to take an optional flag to make it easy
to choose).

For something like simplification, I don't see either as completely
subsuming the other. There will probably be cases that maxima can
handle that nothing else can, and vice-versa, so it'd be very useful
to have both.

- Robert

kcrisman

unread,
Nov 12, 2009, 5:03:14 PM11/12/09
to sage-devel

> > I like opensource software and math, but have not enough knowledges to
> > bring significant contribution in this topic.
>
> Everyone has something they can contribute: bug reports,  
> documentation, and even feature requests like you've been doing.
>

And Robert is perhaps a little too modest; he has already contributed
several non-trivial patches either awaiting review or with positive
review, and he actually understands Maxima (which many of us do not).
I am sure there is much he can contribute in the way of code.

- kcrisman

Burcin Erocal

unread,
Nov 13, 2009, 8:07:17 AM11/13/09
to sage-...@googlegroups.com

This is also what I thought when I asked for help. :)

You don't need to be an expert programmer to contribute code to Sage. I
thought the biggest hassle is the initial steps of preparing a patch,
submitting to trac and going through review.

I will try to put a proposal on the wiki and provide an initial patch
this weekend. Maybe that future 4.xyz version Francois mentioned will be
4.3, who knows?


Cheers,
Burcin

Burcin Erocal

unread,
Nov 13, 2009, 8:30:56 AM11/13/09
to sage-...@googlegroups.com
On Thu, 12 Nov 2009 12:30:01 -0800 (PST)
"ma...@mendelu.cz" <ma...@mendelu.cz> wrote:

> Could the conclusion be the following?
> "If you want (and if the realease manager includes corresponding
> patches), add support for Maxima commands which you need. When python
> of ginac will be able to replace these commands, these interfaces to
> Maxima commands will be removed."

I am really reluctant to keep adding functions, since they would have
to be maintained for a long time because of the deprecation policy.

Let's see if we can quickly come up with a "clean" solution in the
next couple of days. Then you can add the functionality you need (still
using maxima if necessary), using the interface that we will maintain
long term.


If this process takes too long, or if you still want to use only maxima
for this functionality even when we have Sage equivalents, we could
add a .maxima_methods() function to symbolic expressions which returns
a class that hosts wrappers to maxima methods. This would prevent
polluting the namespace of the class Expression, and provide a better
location to search for this functionality.


Thanks.

Burcin

ma...@mendelu.cz

unread,
Nov 13, 2009, 9:13:19 AM11/13/09
to sage-devel
On 13 lis, 14:30, Burcin Erocal <bur...@erocal.org> wrote:
> On Thu, 12 Nov 2009 12:30:01 -0800 (PST)
>
> "ma...@mendelu.cz" <ma...@mendelu.cz> wrote:
> > Could the conclusion be the following?
> > "If you want (and if the realease manager includes corresponding
> > patches), add support for Maxima commands which you need. When python
> > of ginac will be able to replace these commands, these interfaces to
> > Maxima commands will be removed."
>
> I am really reluctant to keep adding functions, since they would have
> to be maintained for a long time because of the deprecation policy.
>
> Let's see if we can quickly come up with a "clean" solution in the
> next couple of days.

Seems as a very good suggestion.

My techaer of english told me once, that "couple of days" means
"exactly two days" :). Is it true? If yes, then I think that a couple
of weeks or couple of months are also convenient and perhaps better,
since we have to introduce new general concept. If I will be able to
work on the problem (despite very limited knowledge of programming), I
will be happy to help with this task. At least with testing and
reporting bugs.

Thank you.
Robert

Robert Bradshaw

unread,
Nov 13, 2009, 1:12:37 PM11/13/09
to sage-...@googlegroups.com

How is this not just

sage: mf = maxima(f)
sage: mf.[tab]

which can already be done?

- Robert

William Stein

unread,
Nov 13, 2009, 5:12:31 PM11/13/09
to sage-...@googlegroups.com

I think the idea is that it should be more transparent to the user,
i.e., the result should be a *Sage* symbolic expression, not a maxima
object. Also, the default maxima interface has the default Maxima
conventions and settings, which don't agree with Sage's internal
maxima interface's conventions (e.g., assumptions, default complex
powers, etc.). Finally, one could imagine the implementation of the
maxima_methods() function being moved to Nils Bruin's new ecl lisp
library interface (is that refereed yet?!), and the maxima_methods
would retain *exactly* the same API, but be faster.

So I think there is a lot of value in Burcin's suggestion. I really like it.

William

kcrisman

unread,
Nov 13, 2009, 8:17:02 PM11/13/09
to sage-devel
> Finally, one could imagine the implementation of the
> maxima_methods() function being moved to Nils Bruin's new ecl lisp
> library interface (is that refereed yet?!),

No! Please, please, someone who knows more about Lisp than I do
referee it! It would be a great addition to 4.3. There is real
potential here for bit-by-bit moving to using Maxima-as-ECL down the
line (Nils and I have been discussing some of the details), but we
need more people who know Lisp (and Pynac internals) to do it.

- kcrisman

William Stein

unread,
Nov 13, 2009, 10:45:49 PM11/13/09
to sage-...@googlegroups.com
There are several core Sage developers who are also very familiar with
lisp. However, the first two few that come to my mind are presently
very busy with their theses right now.

But yes, it would be nice to move forward with that.

William

>
> - kcrisman
> >
>



--
William Stein
Associate Professor of Mathematics
University of Washington
http://wstein.org

Francois Maltey

unread,
Nov 14, 2009, 12:30:41 PM11/14/09
to sage-...@googlegroups.com
Hello,

This purpose about expression has 3 differents aspects.

A/ The first aspect we discover is the user interface. This interface
must be coherent.
This means that 1/ it's possible to describe it with "few word" 2/ The
most common calculus has no option 3/ This system will be able to be
refined for more difficult computations.

B/ Theses mathematic rules are well known and this coding aspect is a
visit inside the expressions, its branchs, its leaves, its operands and
its operators. I feel that this point is not so difficult when A/ is
well described.

C/ I can't test my ideas about A/ by B/ in sage/python because I need
some primitives I don't find.

a- expr.operator() and expr.operands() are already right.
a'-Extract and test sin in sin(x) is easy, but recognize the + in x+y is
heavy.

b- Burcin is working about an very fine automatic retract.
If the result is an (defined) integer as in 0*x, its type becomes
integer, and doesn't remain expression.
b'- test for rational numbers, real numbers, positive ones will also be
used.

c- I don't find the test "this expression is an atomic variable" True
for x, False for sqrt(2)

d- For a later Sage tests around assume will be integrate in theses
predicates.
After assume (n, Integer), (-1)^(2*n) computes 1, sin(n*pi) answers 0
and cos(n*pi) remains.
But this mail isn't the right place for the test x>0 or x<0 !

One time theses methods exist, code B/ becomes easy.
With some tips, the d- improvement may be partially predict.

From my point of view, the hardest aspect is the B-point.

I used Maple, Mupad and Axiom... and I see what way is nice to use, and
what way is disagreable.
And I don't love Maxima manner with its numerous flags and numerous
functions.

The C-point is a play I'll done one day or an other because I make tipo
every time I type
expr.subs_expr(cos(x)==(exp(i*x)+exp(-i*x))/2), sin(x)==...)

Francois.

William Stein

unread,
Nov 14, 2009, 12:54:18 PM11/14/09
to sage-...@googlegroups.com
On Sat, Nov 14, 2009 at 9:30 AM, Francois Maltey <fma...@nerim.fr> wrote:
>
> Hello,
>
> This purpose about expression has 3 differents aspects.
>
> A/ The first aspect we discover is the user interface. This interface
> must be coherent.
> This means that 1/ it's possible to describe it with "few word" 2/ The
> most common calculus has no option 3/ This system will be able to be
> refined for more difficult computations.
>
> B/ Theses mathematic rules are well known and this coding aspect is a
> visit inside the expressions, its branchs, its leaves, its operands and
> its operators. I feel that this point is not so difficult when A/ is
> well described.
>
> C/ I can't test my ideas about A/ by B/ in sage/python because I need
> some primitives I don't find.
>
> a- expr.operator() and expr.operands() are already right.
> a'-Extract and test sin in sin(x) is easy, but recognize the + in x+y is
> heavy.

But isn't it just operator()???

sage: var('x,y'); a = x+y
(x, y)
sage: a.operator()
<built-in function add>


>
> b- Burcin is working about an very fine automatic retract.
> If the result is an (defined) integer as in 0*x, its type becomes
> integer, and doesn't remain expression.
> b'- test for rational numbers, real numbers, positive ones will also be
> used.
>
> c- I don't find the test "this expression is an atomic variable"   True
> for x, False for sqrt(2)

Burcin -- does this needs to be added? I can't figure out how to do
it either? It used to be easy with the old symbolics, but not with
the new ones.

> d- For a later Sage tests around assume will be integrate in theses
> predicates.
> After assume (n, Integer), (-1)^(2*n) computes 1, sin(n*pi) answers 0
> and cos(n*pi) remains.
> But this mail isn't the right place for the test x>0 or x<0 !

Assume in Sage is 100% implemented by Maxima... Inevitably we will
have to implement our own assume system eventually in pynac.

> One time theses methods exist, code B/  becomes easy.
> With some tips, the d- improvement may be partially predict.
>
>  From my point of view, the hardest  aspect is the B-point.

I personally didn't understand what you meant by B above, actually.

> I used Maple, Mupad and Axiom... and I see what way is nice to use, and
> what way is disagreable.
> And I don't love Maxima manner with its numerous flags and numerous
> functions.
>
> The C-point is a play I'll done one day or an other because I make tipo
> every time I type
> expr.subs_expr(cos(x)==(exp(i*x)+exp(-i*x))/2), sin(x)==...)
>

Thanks for sharing your thoughts and experience!

William

Jason Grout

unread,
Nov 14, 2009, 1:03:58 PM11/14/09
to sage-...@googlegroups.com
William Stein wrote:
> Burcin -- does this needs to be added? I can't figure out how to do
> it either? It used to be easy with the old symbolics, but not with
> the new ones.


Here's a round-about (and probably failure-prone) way:

a=sqrt(2)

t=a.variables()
if len(t)==1:
print bool(t[0]==a)
else:
print "False"

--
Jason Grout

Francois Maltey

unread,
Nov 14, 2009, 1:12:19 PM11/14/09
to sage-...@googlegroups.com
William wrote :

> But isn't it just operator()???
>
> sage: var('x,y'); a = x+y
> (x, y)
> sage: a.operator()
> <built-in function add>
>
Sage also need tests over theses operators :
In an expression we test

op = expr.operator

if op == sin : ... # is right
elif op == + : ... # doesn't work (or add or _plus...)

The way I find is to add a dummy variable opplus = (x+y).operator() and
then test

elif op == opplus : ...

I don't find it's a pretty code.


>> From my point of view, the hardest aspect is the B-point.
>>
>
> I personally didn't understand what you meant by B above, actually.
>

This point is about missing ginac primitives in sage :

test if an expression is an atomic variable, if an expression is a
(defined) integer, and so.
Very few primitives are missing (and some are present in ginac, but not
in sage), but it's impossible to climb in an expression by Sage if one
of theses functions are missing.

F. (I hope I'm more expressive in this message)

William Stein

unread,
Nov 14, 2009, 1:16:15 PM11/14/09
to sage-...@googlegroups.com
On Sat, Nov 14, 2009 at 10:12 AM, Francois Maltey <fma...@nerim.fr> wrote:
>
> William wrote :
>> But isn't it just operator()???
>>
>> sage: var('x,y'); a = x+y
>> (x, y)
>> sage: a.operator()
>> <built-in function add>
>>
> Sage also need tests over theses operators :
> In an expression we test
>
> op = expr.operator
>
> if op == sin : ... # is right
> elif op == + : ... # doesn't work (or add or _plus...)

You should use

sage: import operator
sage: operator.add
<built-in function add>


>
> The way I find is to add a dummy variable opplus = (x+y).operator() and
> then test
>
> elif op == opplus : ...
>
> I don't find it's a pretty code.
>>>  From my point of view, the hardest  aspect is the B-point.
>>>
>>
>> I personally didn't understand what you meant by B above, actually.
>>
> This point is about missing ginac primitives in sage :
>
> test if an expression is an atomic variable, if an expression is a
> (defined) integer, and so.
> Very few primitives are missing (and some are present in ginac, but not
> in sage), but it's impossible to climb in an expression by Sage if one
> of theses functions are missing.
>
> F. (I hope I'm more expressive in this message)
>
> >
>



Francois Maltey

unread,
Nov 14, 2009, 1:45:03 PM11/14/09
to sage-...@googlegroups.com
Many thanks for the 2 previous help !

About operator.add and expr.variables()...

The (real-?) last question is

a=4*x
b=4/3*x
c=4.0*x
d=4*I*x

I can get the constant by a.operands(), a.operands()[-1], but how can I
test (without error) if this term is an integer, a rational, a float or
a complex before next Sage improvement ?

I can force a coerce by expr._integer(), but I get an error if expr (an
expression) isn't a integer ?
Must I define a function with a trap error ? There is also a
_rational_() method for this retract.
I don't find the method for float and complex.

F. again...


ma...@mendelu.cz

unread,
Nov 14, 2009, 2:06:01 PM11/14/09
to sage-devel


On 14 lis, 18:30, Francois Maltey <fmal...@nerim.fr> wrote:
> a'-Extract and test sin in sin(x) is easy, but recognize the + in x+y is
> heavy.
>

And perhaps even worse for x+z+z+z_1

The paper of RJF can be perhaps useful (examples written in Maxima,
but general ideas) to deal with addition and multiplication:
http://www.cs.berkeley.edu/~fateman/papers/partition.pdf

Robert

Nils Bruin

unread,
Nov 14, 2009, 4:13:09 PM11/14/09
to sage-devel
On Nov 14, 10:03 am, Jason Grout <jason-s...@creativetrax.com> wrote:
> William Stein wrote:
> > Burcin -- does this needs to be added?  I can't figure out how to do
> > it either?  It used to be easy with the old symbolics, but not with
> > the new ones.

What you are looking for is is_SymbolicVariable(), I think.

I think currently, whenever expr.operator() == None and
is_SymbolicVariable(expr) == False
the expr.python() will succeed.

William Stein

unread,
Nov 14, 2009, 4:32:39 PM11/14/09
to sage-...@googlegroups.com
On Sat, Nov 14, 2009 at 1:13 PM, Nils Bruin <nbr...@sfu.ca> wrote:
>
> On Nov 14, 10:03 am, Jason Grout <jason-s...@creativetrax.com> wrote:
>> William Stein wrote:
>> > Burcin -- does this needs to be added?  I can't figure out how to do
>> > it either?  It used to be easy with the old symbolics, but not with
>> > the new ones.
>
> What you are looking for is is_SymbolicVariable(), I think.

Thanks. Note that is_SymbolicVariable (and all other is_Type)
functions are deprecated. However,

sage.symbolic.all.is_SymbolicVariable is *not* deprecated:

sage: sage.symbolic.all.is_SymbolicVariable(x)
True
sage: sage.symbolic.all.is_SymbolicVariable(x+x)
False
sage: sage.symbolic.all.is_SymbolicVariable(sqrt(2))
False


Here's what is_SymbolicVariable does:

def is_SymbolicVariable(x):
...
return is_Expression(x) and is_a_symbol((<Expression>x)._gobj)

So there is a pynac function is_a_symbol that gets used.

William

Reply all
Reply to author
Forward
0 new messages