1from typing import TYPE_CHECKING, List, Tuple
2
3if TYPE_CHECKING:
4    from cvxpy.expressions.expression import Expression
5
6"""
7Copyright 2013 Steven Diamond
8
9Licensed under the Apache License, Version 2.0 (the "License");
10you may not use this file except in compliance with the License.
11You may obtain a copy of the License at
12
13    http://www.apache.org/licenses/LICENSE-2.0
14
15Unless required by applicable law or agreed to in writing, software
16distributed under the License is distributed on an "AS IS" BASIS,
17WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18See the License for the specific language governing permissions and
19limitations under the License.
20"""
21
22
23def sum_signs(exprs: List['Expression']) -> Tuple[bool, bool]:
24    """Give the sign resulting from summing a list of expressions.
25
26    Args:
27        shapes: A list of sign (is pos, is neg) tuples.
28
29    Returns:
30        The sign (is pos, is neg) of the sum.
31    """
32    is_pos = all(expr.is_nonneg() for expr in exprs)
33    is_neg = all(expr.is_nonpos() for expr in exprs)
34    return (is_pos, is_neg)
35
36
37def mul_sign(lh_expr: 'Expression', rh_expr: 'Expression') -> Tuple[bool, bool]:
38    """Give the sign resulting from multiplying two expressions.
39
40    Args:
41        lh_expr: An expression.
42        rh_expr: An expression.
43
44    Returns:
45        The sign (is pos, is neg) of the product.
46    """
47    # ZERO * ANYTHING == ZERO
48    # POSITIVE * POSITIVE == POSITIVE
49    # NEGATIVE * POSITIVE == NEGATIVE
50    # NEGATIVE * NEGATIVE == POSITIVE
51
52    lh_nonneg = lh_expr.is_nonneg()
53    rh_nonneg = rh_expr.is_nonneg()
54    lh_nonpos = lh_expr.is_nonpos()
55    rh_nonpos = rh_expr.is_nonpos()
56
57    lh_zero = lh_nonneg and lh_nonpos
58    rh_zero = rh_nonneg and rh_nonpos
59
60    is_zero = lh_zero or rh_zero
61
62    is_pos = is_zero or (lh_nonneg and rh_nonneg) or (lh_nonpos and rh_nonpos)
63    is_neg = is_zero or (lh_nonneg and rh_nonpos) or (lh_nonpos and rh_nonneg)
64    return (is_pos, is_neg)
65