
    bi                    z    d Z ddlmZ ddlmZ ddlZddlmZ ddl	m
Z
 ddlmZ ddlmZ dd	lmZ  G d
 de      Zy)a,  
Copyright, the CVXPY authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
    )annotations)TupleN)Atom)is_param_free)
Expression)Variable)scopesc                  p     e Zd ZdZdd fdZd fdZddZddZddZddZ	ddZ
dd	Zdd
Zd Z xZS )perspectiveaL  Implements the perspective transform of a convex or concave scalar
    expression. Uses the fact that given a cone form for the epigraph of :math:`f` via

    :math:`\{ (t, x) \in \mathbb{R}^{n+1} : t \geq f(x) \}`
    :math:`= \{ (t,x) : Fx + gt + e \in K \},`

    the epigraph of the perspective transform
    of f can be given by

    :math:`\{ (t, x, s) \in \mathbb{R}^{n+2} : t \geq sf(x/s) \}`
    :math:`= \{ (t,x,s) : Fx + gt + se \in K \},`

    (see https://web.stanford.edu/~boyd/papers/pdf/sw_aff_ctrl.pdf).

    Note that this is the perspective transform of a scalar expression viewed as
    a function of its underlying variables. The perspective atom does not return
    a `Callable`, so you cannot create compositions such as :math:`p(g(x),s)`, where
    :math:`p(z,s) = sf(z/s)` is the perpective transform of :math:`f`.
    c                f    || _         || _        t        t        |   |g|j                           y N)ff_recessionsuperr   __init__	variables)selfr   sr   	__class__s       R/home/cdr/jupyterlab/.venv/lib/python3.12/site-packages/cvxpy/atoms/perspective.pyr   zperspective.__init__3   s,    &k4)!<akkm<    c                "   | j                   j                  dk(  sJ | j                  d   j                  dk(  sJ t        | j                  d   t              sJ d       | j                  d   j                         sJ d       t        |          S )N   r   zs must be a variablez s must be a nonnegative variable)r   sizeargs
isinstancer   	is_nonnegr   validate_arguments)r   r   s    r   r   zperspective.validate_arguments8   s    vv{{ayy|  A%%%$))A,1I3II1yy|%%'K)KK'w)++r   c                   |d   dk\  sJ t        j                  |d         }| j                  t        j                  |d   d      r$| j                  J d       | j                  d|d<   j                         D cg c]  }|j                   }}fd} ||dd |d          t        j                  j                  |z  g      } ||d       |S c c}w )z>
        Compute the perspective sf(x/s) numerically.
        r   g        Nz9To handle s = 0, pass in a recession function f_recessionr   c                ^    t        j                         |       D ]  \  }}||z  |_         y r   )zipr   value)valss_valvarvalr   s       r   set_valsz%perspective.numeric.<locals>.set_valsU   s.    t4 &SI	&r   )r$   )nparrayr   iscloser   r   r"   )r   valuesr$   r%   
old_x_valsr'   ret_valr   s          @r   numericzperspective.numeric?   s    
 ayA~~# FF::fQi% ##/ K/   AF1I+,;;=9Ccii9
9	& 	6!9-((AGGEM?+1% :s   ?Cc                    | j                   j                         }| j                   j                         }| j                  d   j                         }|sJ |xr |}|xr |}||fS )Nr   )r   r   	is_nonposr   )r   f_posf_negs_posis_positiveis_negatives         r   sign_from_argszperspective.sign_from_argsa   s`      "  "		!&&(uK''r   c                    t        j                         rt        | j                        sy| j                  j	                         xr | j
                  d   j                         S )zIs the atom convex?
        Fr   )r	   dpp_scope_activer   r   	is_convexr   r   r   s    r   is_atom_convexzperspective.is_atom_convexm   sG     ""$]466-B66##%B$))A,*@*@*BBr   c                    t        j                         rt        | j                        sy| j                  j	                         xr | j
                  d   j                         S )zIs the atom concave?
        Fr   )r	   r8   r   r   
is_concaver   r   r:   s    r   is_atom_concavezperspective.is_atom_concaveu   sG     ""$]466-B66$$&C499Q<+A+A+CCr   c                     y)z;Is the composition non-decreasing in argument idx?
        F r   idxs     r   is_incrzperspective.is_incr}        r   c                     y)z;Is the composition non-increasing in argument idx?
        Fr@   rA   s     r   is_decrzperspective.is_decr   rD   r   c                .    | j                   j                  S )z8Returns the (row, col) shape of the expression.
        )r   shaper:   s    r   shape_from_argszperspective.shape_from_args   s     vv||r   c                    t               )a+  Gives the (sub/super)gradient of the atom w.r.t. each argument.

        Matrix expressions are vectorized, so the gradient is a matrix.

        Args:
            values: A list of numeric values for the arguments.

        Returns:
            A list of SciPy CSC sparse matrices or None.
        )NotImplementedError)r   r+   s     r   _gradzperspective._grad   s     "##r   r   )r   r   r   r   r   r   returnNone)rM   rN   )r+   zlist[np.ndarray, np.ndarray]rM   z
np.ndarray)rM   ztuple[bool, bool])rM   bool)rB   intrM   rO   )rM   zTuple[int, ...])__name__
__module____qualname____doc__r   r   r.   r6   r;   r>   rC   rF   rI   rL   __classcell__)r   s   @r   r   r      s=    (=
, D
(CD


$r   r   )rT   
__future__r   typingr   numpyr(   cvxpy.atoms.atomr   %cvxpy.expressions.constants.parameterr   cvxpy.expressions.expressionr   cvxpy.expressions.variabler   cvxpy.utilitiesr	   r   r@   r   r   <module>r^      s2     #   ! ? 3 / "z$$ z$r   