
    bi9                         d Z ddlmZ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 ddlmZmZmZmZ defd	Z G d
 de      Zy)a  
Copyright 2013 Steven Diamond

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


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.
    )ListTupleN)Elementwise)
Constraint)cvxtypes)	is_power2pow_highpow_midpow_negreturnc                 >    t        | t        j                               S N)
isinstancer   constant)ps    X/home/cdr/jupyterlab/.venv/lib/python3.12/site-packages/cvxpy/atoms/elementwise/power.py	_is_constr      s    a**,--    c                   *    e Zd ZdZddeddf fdZej                  d        Zde	e
e
f   fdZde
fdZde
fd	Zd
 Zde
fdZde
fdZde
f fdZde
fdZde
fdZde
fdZde
fdZde
fdZde
fdZd Zdee   fdZd ZdddZdefdZ xZ S )powera   Elementwise power function :math:`f(x) = x^p`.

    If ``expr`` is a CVXPY expression, then ``expr**p``
    is equivalent to ``power(expr, p)``.

    For DCP problems, the exponent `p` must be a numeric constant. For DGP
    problems, `p` can also be a scalar Parameter.


    Specifically, the atom is given by the cases

    .. math::

        \begin{array}{ccl}
        p = 0 & f(x) = 1 & \text{constant, positive} \\
        p = 1 & f(x) = x & \text{affine, increasing, same sign as $x$} \\
        p = 2,4,8,\ldots &f(x) = |x|^p  & \text{convex, signed monotonicity, positive} \\
        p < 0 & f(x) = \begin{cases} x^p & x > 0 \\ +\infty & x \leq 0 \end{cases}
          & \text{convex, decreasing, positive} \\
        0 < p < 1 & f(x) = \begin{cases} x^p & x \geq 0 \\ -\infty & x < 0 \end{cases}
          & \text{concave, increasing, positive} \\
        p > 1,\ p \neq 2,4,8,\ldots & f(x) = \begin{cases} x^p & x \geq 0 \\
          +\infty & x < 0 \end{cases} & \text{convex, increasing, positive}.
        \end{array}


    .. note::

        For DCP problems, ``power`` assumes ``p`` has a rational representation
        with a small denominator. **Approximations** are employed when this is not
        the case. Specifically, ``power`` computes a rational approximation
        to ``p`` with a denominator up to ``max_denom``.
        Increasing ``max_denom`` can give better approximations.
        When ``p`` is an ``int`` or ``Fraction`` object, the approximation
        is usually *exact*. No such approximation
        is used for DGP problems.

        CVXPY supports exponential cone and power cone constraints.
        Such constraints could be used to handle the ``power`` atom in DCP problems
        without relying on approximations. Such an approach would also result in
        fewer variables than the current method, even when the current method is
        an exact reformulation. If you're interested in helping enhance CVXPY with
        this ability, please get in touch with us and check out
        `GitHub Issue 1222 <https://github.com/cvxpy/cvxpy/issues/1222>`_!

    .. note::

        The final domain, sign, monotonicity, and curvature of the ``power`` atom
        are determined by the rational approximation to ``p``, **not** the input parameter ``p``.

        For example,

        >>> from cvxpy import Variable, power
        >>> x = Variable()
        >>> g = power(x, 1.001)
        >>> g.p
        Fraction(1001, 1000)
        >>> g
        Expression(CONVEX, POSITIVE, (1, 1))
        results in a convex atom with implicit constraint :math:`x \geq 0`, while
        >>> g = power(x, 1.0001)
        >>> g.p
        1
        >>> g
        Expression(AFFINE, UNKNOWN, (1, 1))

        results in an affine atom with no constraint on ``x``.

    - When :math:`p > 1` and ``p`` is not a power of two, the monotonically increasing version
      of the function with full domain,

      .. math::

          f(x) = \begin{cases} x^p & x \geq 0 \\ 0 & x < 0 \end{cases}

      can be formed with the composition ``power(pos(x), p)``.

    - The symmetric version with full domain,

      .. math::

          f(x) = |x|^p

      can be formed with the composition ``power(abs(x), p)``.


    Parameters
    ----------

    x : cvxpy.Variable

    p : int, float, Fraction, or Parameter.
        Scalar power. ``p`` may be a Parameter in DGP programs, but not
        in DCP programs.

    max_denom : int
        The maximum denominator considered in forming a rational approximation
        of ``p``; only relevant when solving as a DCP program.
    	max_denomr   Nc                 r   || _         t        j                         j                  |      | _        t        | j                  t        j                               s=t        | j                  t        j                               st        dt        |            || _
        d | _        t        | j                  t        j                               rt        | j                   t        j                               s| j                   }n| j                  j                  }|dkD  rt        ||      \  }}n2d|cxk  rdk  rn nt        ||      \  }}n|dk  rt        ||      \  }}|dk(  rd}d }|dk(  rd}d }|c| _        | _        t#        t%        | j                  |z
              | _        t(        t*        | [  |       y )NzDThe exponent `p` must be either a Constant or a Parameter; received    r   )_p_origr   
expressioncast_to_constr   r   r   	parameter
ValueErrortyper   
p_rationalvaluer	   r
   r   wfloatabsapprox_errorsuperr   __init__)selfxr   r   r"   	__class__s        r   r'   zpower.__init__   sm    $$&44Q74668#4#4#674668#5#5#78 67;Aw@ @"dffh//12 dllH,?,?,AB LLFFLL1u9-1Qq),1Qq),1 AvAv&'#DOTV %c$//A*=&> ?DeT#A&r   c                 n    t        j                  |d   t        | j                  j                              S Nr   )npr   r#   r   r!   )r(   valuess     r   numericzpower.numeric   s$    xxq	5#677r   c                     | j                   j                  dk(  r:| j                  d   j                         | j                  d   j	                         fS y)zCReturns sign (is positive, is negative) of the expression.
        r   r   )TF)r   r!   args	is_nonneg	is_nonposr(   s    r   sign_from_argszpower.sign_from_args   sF     66<<1IIaL**,diil.D.D.FGG !r   c                     t        | j                        xr4 | j                  j                  dk  xs | j                  j                  dk\  S )zIs the atom convex?
        r   r   r   r   r!   r4   s    r   is_atom_convexzpower.is_atom_convex   s7      Mdfflla&7&L466<<1;LMr   c                 x    t        | j                        xr$ d| j                  j                  cxk  xr dk  S c S )zIs the atom concave?
        r   r   r7   r4   s    r   is_atom_concavezpower.is_atom_concave   s0      ;Q$&&,,%;!%;;%;;r   c                 r    | j                   d   j                         | j                  j                         z   S r,   )r1   
parametersr   r4   s    r   r<   zpower.parameters   s-      yy|&&(466+<+<+>>>r   c                     t         j                  j                         r>| j                  d   }| j                  }|j                         xr |j                          S y)z$Is the atom log-log convex?
        r   T)uscopesdpp_scope_activer1   r   r<   )r(   r)   r   s      r   is_atom_log_log_convexzpower.is_atom_log_log_convex   sI     88$$& 		!AA91<<>::r   c                 "    | j                         S )z%Is the atom log-log concave?
        )rA   r4   s    r   is_atom_log_log_concavezpower.is_atom_log_log_concave   s     **,,r   c                     t        | j                        xr | j                  j                  dk(  xs t        t        |          S )z$Is the expression constant?
        r   )r   r   r!   r&   r   is_constant)r(   r*   s    r   rE   zpower.is_constant   s5     $&&!7dfflla&7\E%<Z<\\r   c                 .   t        | j                        s9| j                  j                         xr | j                  |   j                         S | j                  }d|cxk  rdk  ry |dkD  r)t        |      r| j                  |   j                         S yy)z;Is the composition non-decreasing in argument idx?
        r   r   TF)r   r   r2   r1   r    r   r(   idxr   s      r   is_incrzpower.is_incr  s      66##%D$))C.*B*B*DDOO;Q; U|yy~//11r   c                     t        | j                        s9| j                  j                         xr | j                  |   j	                         S | j
                  }|dk  ry|dkD  r)t        |      r| j                  |   j                         S yy)z;Is the composition non-increasing in argument idx?
        r   Tr   F)r   r   r3   r1   r2   r    r   rG   s      r   is_decrzpower.is_decr  sw      66##%D$))C.*B*B*DDOO6U|yy~//11r   c                    t        | j                        sy| j                  }|dk(  ry|dk(  r| j                  d   j	                         S |dk(  r| j                  d   j                         S | j                  d   j                         S NFr   Tr      )r   r   r    r1   is_quadratic	is_affinerE   r(   r   s     r   rO   zpower.is_quadratic&  sw     OO6!V99Q<,,..!V99Q<))++99Q<++--r   c                     t        | j                        sy| j                  }|dk(  r| j                  d   j	                         S |dk(  ryy)a  Does the affine head of the expression contain a quadratic term?

        The affine head is all nodes with a path to the root node
        that does not pass through any non-affine atom. If the root node
        is non-affine, then the affine head is the root alone.
        Fr   r   rN   T)r   r   r    r1   has_quadratic_termrQ   s     r   rS   zpower.has_quadratic_term4  sG      OO699Q<2244!Vr   c                    t        | j                        sy| j                  }|dk(  ry|dk(  r| j                  d   j	                         S |dk(  r| j                  d   j                         S | j                  d   j                         S rM   )r   r   r    r1   is_qpwais_pwlrE   rQ   s     r   rU   zpower.is_qpwaF  sw     OO6!V99Q<''))!V99Q<&&((99Q<++--r   c                 "    | j                   }|dv S )z0Utility function to check if power is 0, 1 or 2.)r   r   rN   )r    rQ   s     r   _quadratic_powerzpower._quadratic_powerU  s    OOI~r   c                 R   | j                   d   j                  }| j                  }| j                  | j                  }n8| j                  j                  | j                  j                  }nt        d      |dk(  rt        j                  ||fd      gS t        |      s?t        j                  |d         dk  r$|dk  rdgS t        j                  |d   d      |d<   t        |      t        j                  |d   t        |      dz
        z  }t        j                  |||      gS )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.
        r   NzNCannot compute grad of parametrized power when parameter value is unspecified.float64)dtyper   )r1   sizer    r   r!   r   sp	csc_arrayr   r-   minmaximumr#   r   elemwise_grad_to_diag)r(   r.   rowscolsr   	grad_valss         r   _gradzpower._gradZ  s    yy|  yy??&AVV\\%A ? @ @ 6LL$Y?@@|vay 1Q 61uv JJvay!4q	!HRXXfQiq!<<	++ItTBCCr   c                    t        | j                  t        j                               s| j                  }n| j                  j
                  }|t        d      |dk  r|dk(  r|dkD  rt        |      s| j                  d   dk\  gS g S )z?Returns constraints describing the domain of the node.
        zPCannot compute domain of parametrized power when parameter value is unspecified.r   r   )	r   r   r   r   r   r!   r   r   r1   rQ   s     r   _domainzpower._domain  s~     $,,(;(;(=>AA9 ? @ @!eAFAilIIaLA%&&Ir   c                 2    | j                   | j                  gS r   )r   r   r4   s    r   get_datazpower.get_data  s    dnn--r   c                 f    || j                   }t        |d   | j                  | j                        S )a  Returns a shallow copy of the power atom.

        Parameters
        ----------
        args : list, optional
            The arguments to reconstruct the atom. If args=None, use the
            current args of the atom.

        Returns
        -------
        power atom
        r   )r1   r   r   r   )r(   r1   
id_objectss      r   copyz
power.copy  s-     <99DT!WdllDNN;;r   c                     | j                   j                  d| j                  d   j                         d| j                  j
                  dS )N(r   z, ))r*   __name__r1   namer   r!   r4   s    r   rq   z
power.name  s8    #~~66#yy|002#vv||- 	-r   )i   )NN)r   r   )!rp   
__module____qualname____doc__intr'   r   numpy_numericr/   r   boolr5   r8   r:   r<   rA   rC   rE   rI   rK   rO   rS   rU   rX   re   r   r   rg   ri   rl   strrq   __classcell__)r*   s   @r   r   r      s   bH-' -'t -'^ 8 8!dDj 1 !N N< <?$ ,- -
]T ]
d "d ".d .D $. .$ 
#DJj)  .<"-c -r   r   )rt   typingr   r   numpyr-   scipy.sparsesparser]   cvxpy.utilities	utilitiesr>   #cvxpy.atoms.elementwise.elementwiser   cvxpy.constraints.constraintr   cvxpy.expressionsr   cvxpy.utilities.power_toolsr   r	   r
   r   rw   r   r    r   r   <module>r      sA        ; 3 & M M.D .G-K G-r   