Held recursion

35 views
Skip to first unread message

erentar2002

unread,
Aug 25, 2024, 4:17:16 PMAug 25
to sage-s...@googlegroups.com
Greetings,

I am trying to return a function call from the function itself with the
context `hold`

The following example does not behave as i'd want:

```
def g(x):
    with hold:
        held = sqrt(x)
    return held

g(4)
> 2
```

To get around this, i make the change SR(x):

```
def g(x):
    with hold:
        held = sqrt(SR(x))
    return held

g(4)
> sqrt(4)
```

This is what i want.

Now, i want to return the function call `g(4)` rather than `sqrt(4)`.
This is what i've tried:

```
def g(x):
    with hold:
        held = g(SR(x))
    return held
```

Sadly it reaches recursion limit and exits, which means it does not hold
the function call.

How can i return the function call from the function itself?

Nils Bruin

unread,
Aug 25, 2024, 5:33:29 PMAug 25
to sage-support
Dear erentar,

There are two types of objects involved here: "symbolic functions" that live as objects in SR and "python functions" which are part of python itself. "hold" is only a directive that applies to symbolic expressions, whereas "def" defines a python function. Hence, the "hold" directive never applies.

Looking into what you are trying to compute, it would seem you want to replace g(x) by g(SR(x)). Replacing that another time would get you g(SR(SR(x))). However, no matter what x is, if SR(x) succeeds properly, then y=SR(x) will be an element of the symbolic ring and applying SR to an element of the symbolic ring should return exactly the same thing, so SR(y=SR(SR(x))=SR(x).

But then g(SR(SR(SR(x))))=g(SR(x)) and g(SR(SR(SR(SR(x)))))=g(SR(x)) . So by the properties of the system, applying SR repeatedly is not going to make a difference.

Is it that you want to define a symbolic function `g` *and* a convenience python function that forces the argument into SR? I don't think you need that, since symbolic functions will try to put their argument into SR when called (because SR arguments are the only thing they can work on. Hence, if I'm right in guessing what you want, the following would already do the job:

sage: g = function('g')  ## on top-level you could also just use `function('g')` for convenience
sage: a=10
sage: parent(a) #a is not an object in SR
Integer Ring
sage: E = g(a); E
g(10)
sage: E.operands()[0]
10
sage: parent(E.operands()[0]) #but the argument in the expression E is
Symbolic Ring

Note that g is not a python function:
sage: type(g)
<class 'sage.symbolic.function_factory.function_factory.<locals>.NewSymbolicFunction'>

(quite a mouth-full, but notably different from the type of an object that results from a "def" statement)

erentar2002

unread,
Aug 25, 2024, 10:09:03 PMAug 25
to sage-s...@googlegroups.com

Thank you very much for your reply, i learned a lot

My initial intention when asking the prior question was to define a function where some evaluations would return itself, while other evaluations would not. Such as

```
def f(x):
    if x%2==0:
        return hold(f(x))
    else:
        return x^2+1
```

In fact, I am trying to define the total differential in the following way, this is my final intention.

```
def Dt(expression1):
    if len(expression1.args()) == 1 \
    and expression1.args()[0]==expression1:
        # if the expression has only one variable
        # and that variable is the entire expression
        print("a")
        with hold:
            held = Dt(SR(expression1))
        return held
    else:
        return sum(map(lambda arg:diff(expression1,arg)*Dt(arg),expression1.args()))
```

How can I define this as a symbolic function? Perhaps multiple dispatch?
--
You received this message because you are subscribed to the Google Groups "sage-support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sage-support...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sage-support/4695021e-be4f-4eb8-a929-1097e7271dban%40googlegroups.com.

erentar2002

unread,
Aug 25, 2024, 10:09:13 PMAug 25
to sage-s...@googlegroups.com

Whoops, I have sent an old version of the function by mistake.

I meant to send

```
def Dt(expression1):
    if len(expression1.args()) == 1 \
    and expression1.args()[0]==expression1:
        # if the expression has only one variable
        # and that variable is the entire expression

        return hold( Dt(expression1) )


    else:
        return sum(map(lambda arg:diff(expression1,arg)*Dt(arg),expression1.args()))
```

Apologies.

Nils Bruin

unread,
Aug 25, 2024, 11:47:27 PMAug 25
to sage-support
"hold" is going to be a rather tenuous construction anyway, because there are going to be various places where the expression will be "deholded" and there is very poor control over where those hold removals occur. It's not a very well-supported feature -- mainly because its semantic meaning is murky.

As a first approximation, you could do
Dt_symbolic = function('Dt') #define it to print as "Dt", but bind to another python name so that it doesn't clash with the python function
and then define

```
def Dt(expression1):
    if len(expression1.args()) == 1 \
    and expression1.args()[0]==expression1:
        # if the expression has only one variable
        # and that variable is the entire expression

        return Dt_symbolic(expression1)


    else:
        return sum(map(lambda arg:diff(expression1,arg)*Dt(arg),expression1.args()))
```

That at least forms the expression you seem to want. You could look at the various hooks that symbolic functions have for returning appropriate derivatives, but that leads to very advanced use of the symbolic expression machinery. I'm not sure you'd want that. See https://doc.sagemath.org/html/en/reference/calculus/sage/symbolic/function_factory.html

I suspect that what you need is already available. Consider

function('g'); function('f1'); function('f2'); function('f3');
diff( g(f1(x),f2(x),f3(x)),x)

it applies chain rules appropriately. Notice the D[0](g), D[1](g), .. operators: those are "derivative of g wrt its first argument" etc.
Reply all
Reply to author
Forward
0 new messages