# ----------------------------------------------------------------------------
# SymForce - Copyright 2022, Skydio, Inc.
# This source code is under the Apache 2.0 license found in the LICENSE file.
# ----------------------------------------------------------------------------
"""
Functions for dealing with logical operations represented by scalars
"""
import symforce.internal.symbolic as sf
[docs]def is_positive(x: sf.Scalar) -> sf.Scalar:
"""
Returns 1 if x is positive, 0 otherwise
"""
return sf.Max(sf.sign(x), 0)
[docs]def is_negative(x: sf.Scalar) -> sf.Scalar:
"""
Returns 1 if x is negative, 0 otherwise
"""
return sf.Max(sf.sign(-x), 0)
[docs]def is_nonnegative(x: sf.Scalar) -> sf.Scalar:
"""
Returns 1 if x is >= 0, 0 if x is negative
"""
return 1 - sf.Max(sf.sign(-x), 0)
[docs]def is_nonpositive(x: sf.Scalar) -> sf.Scalar:
"""
Returns 1 if x is <= 0, 0 if x is positive
"""
return 1 - sf.Max(sf.sign(x), 0)
[docs]def less_equal(x: sf.Scalar, y: sf.Scalar) -> sf.Scalar:
"""
Returns 1 if x <= y, 0 otherwise
"""
return is_nonpositive(x - y)
[docs]def greater_equal(x: sf.Scalar, y: sf.Scalar) -> sf.Scalar:
"""
Returns 1 if x >= y, 0 otherwise
"""
return is_nonnegative(x - y)
[docs]def less(x: sf.Scalar, y: sf.Scalar) -> sf.Scalar:
"""
Returns 1 if x < y, 0 otherwise
"""
return is_negative(x - y)
[docs]def greater(x: sf.Scalar, y: sf.Scalar) -> sf.Scalar:
"""
Returns 1 if x > y, 0 otherwise
"""
return is_positive(x - y)
[docs]def logical_and(*args: sf.Scalar, unsafe: bool = False) -> sf.Scalar:
"""
Logical ``and`` of two or more Scalars
Input values are treated as true if they are positive, false if they are 0 or negative.
The returned value is 1 for true, 0 for false.
If unsafe is True, the resulting expression is fewer ops but assumes the inputs are exactly
0 or 1; results for other (finite) inputs will be finite, but are otherwise undefined.
"""
if unsafe:
return sf.Min(*args)
else:
return sf.Max(sum(sf.sign(x) for x in args), len(args) - 1) - (len(args) - 1)
[docs]def logical_or(*args: sf.Scalar, unsafe: bool = False) -> sf.Scalar:
"""
Logical ``or`` of two or more Scalars
Input values are treated as true if they are positive, false if they are 0 or negative.
The returned value is 1 for true, 0 for false.
If unsafe is True, the resulting expression is fewer ops but assumes the inputs are exactly
0 or 1; results for other (finite) inputs will be finite, but are otherwise undefined.
"""
if unsafe:
return sf.Max(*args)
else:
return sf.Max(*[sf.sign(x) for x in args], 0)
[docs]def logical_not(a: sf.Scalar, unsafe: bool = False) -> sf.Scalar:
"""
Logical ``not`` of a Scalar
Input value is treated as true if it is positive, false if it is 0 or negative. The
returned value is 1 for true, 0 for false.
If unsafe is True, the resulting expression is fewer ops but assumes the inputs are exactly
0 or 1; results for other (finite) inputs will be finite, but are otherwise undefined.
"""
if unsafe:
return 1 - a
else:
return 1 - sf.Max(sf.sign(a), 0)