Skip to content

Commit

Permalink
Remove Python 2 compatibility code (cvxpy#2527)
Browse files Browse the repository at this point in the history
* Remove Python 2 compatibility code

* Remove duplicate ABCs

* Fix for real abstract classes

* Some more abc fixes

* Add test for ABCs

* Remove unused imports
  • Loading branch information
jonathanberthias authored Aug 25, 2024
1 parent fb0a746 commit 9707680
Show file tree
Hide file tree
Showing 37 changed files with 72 additions and 96 deletions.
2 changes: 0 additions & 2 deletions cvxpy/atoms/affine/affine_atom.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
import abc
from typing import Any, List, Tuple

import scipy.sparse as sp
Expand All @@ -29,7 +28,6 @@

class AffAtom(Atom):
""" Abstract base class for affine atoms. """
__metaclass__ = abc.ABCMeta
_allow_complex = True

def sign_from_args(self) -> Tuple[bool, bool]:
Expand Down
2 changes: 0 additions & 2 deletions cvxpy/atoms/affine/binary_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
limitations under the License.
"""

from __future__ import division

import operator as op
from functools import reduce
from typing import List, Tuple
Expand Down
1 change: 0 additions & 1 deletion cvxpy/atoms/atom.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@

class Atom(Expression):
""" Abstract base class for atoms. """
__metaclass__ = abc.ABCMeta
_allow_complex = False
# args are the expressions passed into the Atom constructor.

Expand Down
3 changes: 0 additions & 3 deletions cvxpy/atoms/axis_atom.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
limitations under the License.
"""

import abc
from typing import List, Optional, Tuple

import numpy as np
Expand All @@ -28,8 +27,6 @@ class AxisAtom(Atom):
An abstract base class for atoms that can be applied along an axis.
"""

__metaclass__ = abc.ABCMeta

def __init__(self, expr, axis: Optional[int] = None, keepdims: bool = False) -> None:
self.axis = axis
self.keepdims = keepdims
Expand Down
2 changes: 0 additions & 2 deletions cvxpy/atoms/elementwise/elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
limitations under the License.
"""

import abc
from typing import Tuple

import numpy as np
Expand All @@ -27,7 +26,6 @@

class Elementwise(Atom):
""" Abstract base class for elementwise atoms. """
__metaclass__ = abc.ABCMeta

def shape_from_args(self) -> Tuple[int, ...]:
"""Shape is the same as the sum of the arguments.
Expand Down
2 changes: 0 additions & 2 deletions cvxpy/atoms/elementwise/kl_div.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
limitations under the License.
"""

from __future__ import division

from typing import List, Optional, Tuple

import numpy as np
Expand Down
5 changes: 1 addition & 4 deletions cvxpy/atoms/elementwise/maximum.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,13 @@
limitations under the License.
"""

import sys
from functools import reduce
from typing import Any, List, Tuple

import numpy as np

from cvxpy.atoms.elementwise.elementwise import Elementwise

if sys.version_info >= (3, 0):
from functools import reduce


class maximum(Elementwise):
"""Elementwise maximum of a sequence of expressions.
Expand Down
5 changes: 1 addition & 4 deletions cvxpy/atoms/elementwise/minimum.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@
limitations under the License.
"""

import sys
from functools import reduce
from typing import Any, List, Tuple

import numpy as np

from cvxpy.atoms.elementwise.elementwise import Elementwise

if sys.version_info >= (3, 0):
from functools import reduce


class minimum(Elementwise):
"""Elementwise minimum of a sequence of expressions.
Expand Down
2 changes: 0 additions & 2 deletions cvxpy/atoms/elementwise/rel_entr.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
limitations under the License.
"""

from __future__ import division

from typing import List, Optional, Tuple

import numpy as np
Expand Down
14 changes: 14 additions & 0 deletions cvxpy/atoms/perspective.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,17 @@ def shape_from_args(self) -> Tuple[int, ...]:
"""Returns the (row, col) shape of the expression.
"""
return self.f.shape

def _grad(self, values):
"""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.
"""
# TODO
raise NotImplementedError()
2 changes: 0 additions & 2 deletions cvxpy/atoms/quad_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
limitations under the License.
"""

from __future__ import division

import warnings
from typing import Tuple

Expand Down
4 changes: 0 additions & 4 deletions cvxpy/constraints/cones.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
limitations under the License.
"""

import abc

from cvxpy.constraints.constraint import Constraint


Expand All @@ -40,8 +38,6 @@ class Cone(Constraint):
A unique id for the constraint.
"""

__metaclass__ = abc.ABCMeta

def __init__(self, args, constr_id=None) -> None:
super(Cone, self).__init__(args, constr_id)

Expand Down
15 changes: 2 additions & 13 deletions cvxpy/constraints/constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ class Constraint(u.Canonical):
A unique id for the constraint.
"""

__metaclass__ = abc.ABCMeta

def __init__(self, args, constr_id=None) -> None:
# TODO cast constants.
# self.args = [cvxtypes.expression().cast_to_const(arg) for arg in args]
Expand Down Expand Up @@ -129,7 +127,8 @@ def is_dpp(self, context='dcp') -> bool:
else:
raise ValueError("Unsupported context ", context)

@abc.abstractproperty
@property
@abc.abstractmethod
def residual(self):
"""The residual of the constraint.
Expand Down Expand Up @@ -213,16 +212,6 @@ def get_data(self):
"""
return [self.id]

def __nonzero__(self):
"""Raises an exception when called.
Python 2 version.
Called when evaluating the truth value of the constraint.
Raising an error here prevents writing chained constraints.
"""
return self._chain_constraints()

def _chain_constraints(self):
"""Raises an error due to chained constraints.
"""
Expand Down
2 changes: 0 additions & 2 deletions cvxpy/expressions/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,6 @@ class Expression(u.Canonical):
expressions (e.g., the sum of two expressions) and constraints.
"""

__metaclass__ = abc.ABCMeta

# Handles arithmetic operator overloading with Numpy.
__array_priority__ = 100

Expand Down
3 changes: 0 additions & 3 deletions cvxpy/expressions/leaf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"""
from __future__ import annotations

import abc
from typing import TYPE_CHECKING, Iterable

if TYPE_CHECKING:
Expand Down Expand Up @@ -95,8 +94,6 @@ class Leaf(expression.Expression):
An iterable of length two specifying lower and upper bounds.
"""

__metaclass__ = abc.ABCMeta

def __init__(
self, shape: int | tuple[int, ...], value=None, nonneg: bool = False,
nonpos: bool = False, complex: bool = False, imag: bool = False,
Expand Down
2 changes: 1 addition & 1 deletion cvxpy/expressions/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Variable(Leaf):
"""

def __init__(
self, shape: int | Iterable[int, ...] = (), name: str | None = None,
self, shape: int | Iterable[int] = (), name: str | None = None,
var_id: int | None = None, **kwargs: Any
):
if var_id is None:
Expand Down
3 changes: 1 addition & 2 deletions cvxpy/interface/base_matrix_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@
import cvxpy.interface.matrix_utilities


class BaseMatrixInterface:
class BaseMatrixInterface(metaclass=abc.ABCMeta):
"""
An interface between constants' internal values
and the target matrix used internally.
"""
__metaclass__ = abc.ABCMeta

@abc.abstractmethod
def const_to_matrix(self, value, convert_scalars: bool = False):
Expand Down
2 changes: 0 additions & 2 deletions cvxpy/performance_tests/test_warmstart.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
DO NOT CALL THESE FUNCTIONS IN YOUR CODE!
"""

from __future__ import print_function

import time
import unittest

Expand Down
7 changes: 3 additions & 4 deletions cvxpy/problems/param_prob.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,19 @@
import abc


class ParamProb:
class ParamProb(metaclass=abc.ABCMeta):
"""An abstract base class for parameterized problems.
Parameterized problems are produced during the first canonicalization
and allow canonicalization to be short-circuited for future solves.
"""
__metaclass__ = abc.ABCMeta

@abc.abstractproperty
@abc.abstractmethod
def is_mixed_integer(self) -> bool:
"""Is the problem mixed-integer?"""
raise NotImplementedError()

@abc.abstractproperty
@abc.abstractmethod
def apply_parameters(self, id_to_param_value=None, zero_offset: bool = False,
keep_zeros: bool = False):
"""Returns A, b after applying parameters (and reshaping).
Expand Down
3 changes: 0 additions & 3 deletions cvxpy/reductions/matrix_stuffing.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"""


import abc
from typing import List, Optional, Tuple

import numpy as np
Expand Down Expand Up @@ -106,8 +105,6 @@ def ravel_multi_index(multi_index, x, vert_offset):
class MatrixStuffing(Reduction):
"""Stuffs a problem into a standard form for a family of solvers."""

__metaclass__ = abc.ABCMeta

def apply(self, problem) -> None:
"""Returns a stuffed problem.
Expand Down
4 changes: 1 addition & 3 deletions cvxpy/reductions/reduction.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from abc import ABCMeta, abstractmethod


class Reduction:
class Reduction(metaclass=ABCMeta):
"""Abstract base class for reductions.
A reduction is an actor that transforms a problem into an
Expand Down Expand Up @@ -46,8 +46,6 @@ class Reduction:
A problem owned by this reduction; possibly None.
"""

__metaclass__ = ABCMeta

def __init__(self, problem=None) -> None:
"""Construct a reduction for reducing `problem`.
Expand Down
5 changes: 3 additions & 2 deletions cvxpy/reductions/solvers/conic_solvers/conic_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ def psd_format_mat(constr):
# Default is identity.
return sp.eye(constr.size, format='csc')

def format_constraints(self, problem, exp_cone_order):
@classmethod
def format_constraints(cls, problem, exp_cone_order):
"""
Returns a ParamConeProg whose problem data tensors will yield the
coefficient "A" and offset "b" for the constraint in the following
Expand Down Expand Up @@ -249,7 +250,7 @@ def format_constraints(self, problem, exp_cone_order):
arg_mats.append(space_mat)
restruct_mat.append(sp.hstack(arg_mats))
elif type(constr) == PSD:
restruct_mat.append(self.psd_format_mat(constr))
restruct_mat.append(cls.psd_format_mat(constr))
else:
raise ValueError("Unsupported constraint type.")

Expand Down
2 changes: 0 additions & 2 deletions cvxpy/reductions/solvers/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ class Solver(Reduction):
# There are separate ConeDims classes for cone programs vs QPs.
# See cone_matrix_stuffing.py and qp_matrix_stuffing.py for details.

__metaclass__ = abc.ABCMeta

# Solver capabilities.
MIP_CAPABLE = False
BOUNDED_VARIABLES = False
Expand Down
27 changes: 27 additions & 0 deletions cvxpy/tests/test_base_classes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import inspect

import pytest

from cvxpy.atoms.affine.affine_atom import AffAtom
from cvxpy.atoms.atom import Atom
from cvxpy.constraints.constraint import Constraint
from cvxpy.expressions.expression import Expression
from cvxpy.expressions.leaf import Leaf
from cvxpy.interface.base_matrix_interface import BaseMatrixInterface
from cvxpy.problems.param_prob import ParamProb
from cvxpy.reductions.reduction import Reduction
from cvxpy.reductions.solvers.conic_solvers.conic_solver import ConicSolver
from cvxpy.reductions.solvers.solver import Solver
from cvxpy.utilities.canonical import Canonical


@pytest.mark.parametrize("expected_abc", [
Canonical,
Expression, Atom, AffAtom, Leaf,
Constraint,
Reduction, Solver, ConicSolver,
ParamProb,
BaseMatrixInterface,
])
def test_is_abstract(expected_abc):
assert inspect.isabstract(expected_abc)
4 changes: 2 additions & 2 deletions cvxpy/tests/test_cone2cone.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def simulate_chain(in_prob):

# Dualize the problem, reconstruct a high-level cvxpy problem for the dual.
# Solve the problem, invert the dualize reduction.
cone_prog = ConicSolver().format_constraints(cone_prog, exp_cone_order=[0, 1, 2])
cone_prog = ConicSolver.format_constraints(cone_prog, exp_cone_order=[0, 1, 2])
data, inv_data = a2d.Dualize.apply(cone_prog)
A, b, c, K_dir = data[s.A], data[s.B], data[s.C], data['K_dir']
y = cp.Variable(shape=(A.shape[1],))
Expand Down Expand Up @@ -205,7 +205,7 @@ def simulate_chain(in_prob, affine, **solve_kwargs):

# apply the Slacks reduction, reconstruct a high-level problem,
# solve the problem, invert the reduction.
cone_prog = ConicSolver().format_constraints(cone_prog, exp_cone_order=[0, 1, 2])
cone_prog = ConicSolver.format_constraints(cone_prog, exp_cone_order=[0, 1, 2])
data, inv_data = a2d.Slacks.apply(cone_prog, affine)
G, h, f, K_dir, K_aff = data[s.A], data[s.B], data[s.C], data['K_dir'], data['K_aff']
G = sp.sparse.csc_matrix(G)
Expand Down
Loading

0 comments on commit 9707680

Please sign in to comment.