Why does sympy.Min cause a TypeError?

49 Views Asked by At

The following minimalistic script crashes with SymPy 1.12 and Python 3.11:

import sympy as sp

u, v = sp.symbols("u v")
sp.Min(u**1.0*v, v**1.0*u)

The result is a TypeError: cannot determine truth value of Relational. I have this situation arising implicitly in a general framework, so just dropping the (here) unnecessary minimum or the **1.0 is not feasible for me. Using something implicit to simplify the expression would be fine, but for example calling sp.simplify on the first or second argument doesn't succeed at simplifying the expression.

2

There are 2 best solutions below

0
Jamel Eddine Lassoued On

Sympy.Min is a Relational type. Meaning it evaluates the relation between u**1.0*v==uv and v**1.0*u==vu==uv. And since both of those expressions essentially are the same thing, it can't evaluate (i.e. It is not of the correct type). Put simply, it's like comparing x to x itself.

What you need to do here is simply something like sp.Min(u**(1.0*v), v**(1.0*u)) (if this is what you wanted).

See this also.

1
hpaulj On

Here's the full error message. Yes, sympy does show a lot of intermediate steps, but often it's worth paying attention to it - all the way to the end.

In [212]: Min(u**1.0*v, v**1.0*u)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[212], line 1
----> 1 Min(u**1.0*v, v**1.0*u)

File ~/.local/lib/python3.10/site-packages/sympy/functions/elementary/miscellaneous.py:394, in MinMaxBase.__new__(cls, *args, **assumptions)
    392     return cls.zero
    393 # remove redundant args that are easily identified
--> 394 args = cls._collapse_arguments(args, **assumptions)
    395 # find local zeros
    396 args = cls._find_localzeros(args, **assumptions)

File ~/.local/lib/python3.10/site-packages/sympy/functions/elementary/miscellaneous.py:436, in MinMaxBase._collapse_arguments(cls, args, **assumptions)
    434 if not args:
    435     return args
--> 436 args = list(ordered(args))
    437 if cls == Min:
    438     other = Max

File ~/.local/lib/python3.10/site-packages/sympy/core/sorting.py:309, in ordered(seq, keys, default, warn)
    306         if len(u) > 1:
    307             raise ValueError(
    308                 'not enough keys to break ties: %s' % u)
--> 309 yield from value

File ~/.local/lib/python3.10/site-packages/sympy/core/sorting.py:309, in ordered(seq, keys, default, warn)
    306         if len(u) > 1:
    307             raise ValueError(
    308                 'not enough keys to break ties: %s' % u)
--> 309 yield from value

File ~/.local/lib/python3.10/site-packages/sympy/core/sorting.py:297, in ordered(seq, keys, default, warn)
    294         raise ValueError('if default=False then keys must be provided')
    295     d[None].extend(seq)
--> 297 for k, value in sorted(d.items()):
    298     if len(value) > 1:
    299         if keys:

File ~/.local/lib/python3.10/site-packages/sympy/core/relational.py:510, in Relational.__bool__(self)
    509 def __bool__(self):
--> 510     raise TypeError("cannot determine truth value of Relational")

TypeError: cannot determine truth value of Relational

It's trying to order/sort the arguments, and to do that it has to determine which is smaller than the other, e.g. bool(a<b).

With numpy arrays we often see SO questions about a ambiguity error, when the poster tries to compare 2 arrays, and does so in a context that expects just one True/False value. This is the sympy equivalent - comparing the size of 2 or more expressions.

In some cases Min is returned unevaluated, awaiting more specific values

In [213]: Min(u**1.0*v, 0)
Out[213]: Min(0, u**1.0*v)
In [214]: Min(u**1.0*v, 0).subs({u:1, v:-1})
Out[214]: -1

Just tweaking the float value in your arguments does that:

In [215]: Min(u**1.0*v, v**2.0*u)
Out[215]: Min(u**1.0*v, u*v**2.0)
In [217]: Min(u**1*v, v**1*u)
Out[217]: u⋅v

I don't know why the use of 1.0 raises the error; but often in sympy, the use of floats does force a different evaluation route.