问题

Problem 类是进入指定和解决优化问题的入口点。每个 Problem 实例封装了一个优化问题,即一个目标和一组约束。 solve() 方法要么解决实例编码的问题,返回最优值并将变量值设置为最优点,要么报告问题实际上是不可行或无界的。您可以构建一个问题,解决它,并检查其值及其变量的值,如下所示:

problem = Problem(Minimize(expression), constraints)
problem.solve()
if problem.status not in ["infeasible", "unbounded"]:
    # Otherwise, problem.value is inf or -inf, respectively.
    print("Optimal value: %s" % problem.value)
    for variable in problem.variables():
        print("Variable %s: value %s" % (variable.name(), variable.value))

问题在创建后是不可变的,除非通过指定Parameter的值。这意味着在创建问题后,你不能修改问题的目标或约束。如果你发现自己想要向现有问题添加约束,你应该使用以下惯用法创建一个新问题:

problem = Problem(Minimize(expression), constraints)
problem = Problem(problem.objective, problem.constraints + new_constraints)

大多数用户不需要了解关于 Problem 类的任何信息,除了如何实例化它, 如何解决问题实例(solve()), 以及如何查询求解器结果 (statusvalue)。

关于问题实例大小的信息以及最近一次求解调用的统计信息分别由 SizeMetricsSolverStats 类捕获,并且可以通过 Problem 类的 size_metrics()solver_stats() 属性访问。

最小化

class cvxpy.Minimize(expr)[source]

最小化的优化目标。

Parameters:
expr : Expression

要最小化的表达式。必须是一个标量。

Raises:

ValueError – 如果 expr 不是标量。

is_dcp(dpp: bool = False) bool[source]

目标必须是凸的。

is_dgp(dpp: bool = False) bool[source]

目标必须是log-log凸的。

最大化

class cvxpy.Maximize(expr)[源代码]

一个用于最大化的优化目标。

Parameters:
expr : Expression

要最大化的表达式。必须是一个标量。

Raises:

ValueError – 如果 expr 不是标量。

is_dcp(dpp: bool = False) bool[源代码]

目标必须是凹的。

is_dgp(dpp: bool = False) bool[源代码]

目标必须是log-log凹的。

问题

class cvxpy.Problem(objective: Minimize | Maximize, constraints: list[Constraint] | None = None)[source]

一个凸优化问题。

问题是不可变的,除非通过指定Parameter进行修改

Parameters:
objective : Minimize or Maximize

问题的目标。

constraints : list

问题变量的约束条件。

atoms() list[Atom][source]

原子的访问器方法。

Returns:

问题中的原子类型列表;请注意,此列表包含类,而不是实例。

Return type:

Atom的列表

backward() None[source]

计算解决方案相对于参数的梯度。

该方法通过问题的解映射进行微分,获得解相对于参数的梯度。换句话说,它计算了参数相对于最优变量值扰动的敏感性。这对于将CVXPY集成到自动微分工具包中非常有用。

backward() 作为副作用填充问题中每个参数的 gradient 属性。它只能在调用 solve() 时使用 requires_grad=True 之后调用。

下面是一个简单的例子:

import cvxpy as cp
import numpy as np

p = cp.Parameter()
x = cp.Variable()
quadratic = cp.square(x - 2 * p)
problem = cp.Problem(cp.Minimize(quadratic), [x >= 0])
p.value = 3.0
problem.solve(requires_grad=True, eps=1e-10)
# backward() populates the gradient attribute of the parameters
problem.backward()
# Because x* = 2 * p, dx*/dp = 2
np.testing.assert_allclose(p.gradient, 2.0)

在上述示例中,梯度可以很容易地手动计算。 backward() 很有用,因为对于几乎所有问题,梯度无法通过解析方法计算。

此方法可用于通过任何DCP或DGP问题进行区分,只要问题符合DPP(即,problem.is_dcp(dpp=True)problem.is_dgp(dpp=True) 评估为 True)。

此方法使用链式法则来评估标量值函数相对于参数的变量的梯度。例如,设x为变量,p为参数;x和p可能是标量、向量或矩阵。设f为标量值函数,z = f(x)。然后此方法计算dz/dp = (dz/dx) (dx/p)。默认情况下,dz/dx选择为全1向量,对应于选择f为求和函数。您可以通过在变量上设置gradient属性来指定dz/dx的自定义值。例如,

import cvxpy as cp
import numpy as np


b = cp.Parameter()
x = cp.Variable()
quadratic = cp.square(x - 2 * b)
problem = cp.Problem(cp.Minimize(quadratic), [x >= 0])
b.value = 3.
problem.solve(requires_grad=True, eps=1e-10)
x.gradient = 4.
problem.backward()
# dz/dp = dz/dx dx/dp = 4. * 2. == 8.
np.testing.assert_allclose(b.gradient, 8.)

变量上的gradient属性也可以解释为其最优值的扰动。

Raises:
  • ValueError – 如果调用solve时未使用requires_grad=True

  • SolverError – 如果问题不可行或无界

constants() list[Constant][source]

常量的访问器方法。

Returns:

问题中的常量列表。

Return type:

Constant的列表

derivative() None[source]

将解映射的导数应用于参数中的扰动

此方法将解映射的导数应用于参数中的扰动,以获得变量最优值的扰动。换句话说,它告诉你变量的最优值会如何因参数的微小变化而改变。

你可以通过设置参数的delta属性来指定扰动(如果未指定,扰动默认为0)。

此方法作为副作用填充变量的delta属性。

此方法只能在调用solve()并设置requires_grad=True之后调用。它兼容DCP和DGP问题(这些问题也符合DPP要求)。

下面是一个简单的例子:

import cvxpy as cp
import numpy as np

p = cp.Parameter()
x = cp.Variable()
quadratic = cp.square(x - 2 * p)
problem = cp.Problem(cp.Minimize(quadratic), [x >= 0])
p.value = 3.0
problem.solve(requires_grad=True, eps=1e-10)
# derivative() populates the delta attribute of the variables
p.delta = 1e-3
problem.derivative()
# Because x* = 2 * p, dx*/dp = 2, so (dx*/dp)(p.delta) == 2e-3
np.testing.assert_allclose(x.delta, 2e-3)
Raises:
  • ValueError – 如果调用solve时未使用requires_grad=True

  • SolverError – 如果问题不可行或无界

get_problem_data(solver, gp: bool = False, enforce_dpp: bool = False, ignore_dpp: bool = False, verbose: bool = False, canon_backend: str | None = None, solver_opts: dict | None = None)[source]

返回用于调用求解器的问题数据。

当问题被解决时,CVXPY 会创建一个包含在 SolvingChain 中的简化链,并将其编译为与目标求解器兼容的某种低级表示形式。此方法返回该低级表示形式。

对于一些求解链,这种低级表示是一个字典,它恰好包含提供给求解器的那些参数;然而,对于其他求解链,数据是一个中间表示,它由求解器接口进一步编译。

可以通过调用返回的求解链的solve_via_data方法,从数据中获取等效低级问题的解决方案,该方法是对CVXPY外部代码的薄包装,进一步处理和解决问题。调用unpack_results方法以恢复原始问题的解决方案。

例如:

objective = ...
constraints = ...
problem = cp.Problem(objective, constraints)
data, chain, inverse_data = problem.get_problem_data(cp.SCS)
# calls SCS using `data`
soln = chain.solve_via_data(problem, data)
# unpacks the solution returned by SCS into `problem`
problem.unpack_results(soln, chain, inverse_data)

或者,此方法返回的data字典包含足够的信息,可以绕过CVXPY并直接调用求解器。

例如:

problem = cp.Problem(objective, constraints)
data, _, _ = problem.get_problem_data(cp.SCS)

import scs
probdata = {
  'A': data['A'],
  'b': data['b'],
  'c': data['c'],
}
cone_dims = data['dims']
cones = {
    "f": cone_dims.zero,
    "l": cone_dims.nonneg,
    "q": cone_dims.soc,
    "ep": cone_dims.exp,
    "s": cone_dims.psd,
}
soln = scs.solve(data, cones)

CVXPY 返回的数据字典的结构取决于求解器。有关详细信息,请参阅 cvxpy/reductions/solvers 中的求解器接口。

Parameters:
solver : str

求解器所针对的问题数据。

gp : bool, optional

如果为True,则将问题解析为有纪律的几何程序,而不是有纪律的凸程序。

enforce_dpp : bool, optional

当为True时,尝试解析非DPP问题时将抛出DPPError(而不仅仅是警告)。默认为False。

ignore_dpp : bool, optional

当为True时,DPP问题将被视为非DPP问题,这可能会加快编译速度。默认为False。

canon_backend : str, optional

‘CPP’ (默认) | ‘SCIPY’ 指定用于规范化的后端,这可能会影响编译时间。默认为 None,即选择默认后端。

verbose : bool, optional

如果为True,则打印与问题编译相关的详细输出。

solver_opts : dict, optional

一个将传递给特定求解器的选项字典。 通常,这些选项将覆盖由cvxpy施加的任何默认设置。

Returns:

  • 字典或对象 – 问题的最低级别表示

  • SolvingChain – 创建数据的解决链。

  • 列表 – 由链生成的反向数据。

Raises:

cvxpy.error.DPPError – 如果DPP设置无效,则抛出此错误。

is_dcp(dpp: bool = False) bool[source]

问题是否满足DCP规则?

Parameters:
dpp : bool, optional

如果为True,强制执行规范参数化编程(DPP)规则集;仅当问题涉及参数时相关。DPP是DCP的一个温和限制。当涉及参数的问题是DPP时,后续求解可以比第一次快得多。有关更多信息,请参阅文档

https://www.cvxpy.org/tutorial/advanced/index.html#disciplined-parametrized-programming

Returns:

如果表达式是DCP,则为True,否则为False。

Return type:

布尔

is_dgp(dpp: bool = False) bool[source]

问题是否满足DGP规则?

Parameters:
dpp : bool, optional

如果为True,强制执行规范参数化编程(DPP)规则集;仅当问题涉及参数时相关。DPP是DGP的一个温和限制。当涉及参数的问题是DPP时,后续求解可以比第一次快得多。有关更多信息,请参阅文档

https://www.cvxpy.org/tutorial/advanced/index.html#disciplined-parametrized-programming

Returns:

如果表达式是DGP,则为True,否则为False。

Return type:

布尔

is_dpp(context: str = 'dcp') bool[source]

问题是否满足DPP规则?

DPP 是 DGP 的一个温和限制。当涉及参数的问题是 DPP 时,后续的求解可以比第一次快得多。更多信息,请参阅文档

https://www.cvxpy.org/tutorial/advanced/index.html#disciplined-parametrized-programming

Parameters:
context : str

是否检查DCP或DGP的DPP合规性;context 应该是 'dcp''dgp'。调用 problem.is_dpp('dcp') 等同于 problem.is_dcp(dpp=True),而 problem.is_dpp(‘dgp’)` 等同于 problem.is_dgp(dpp=True)

Returns:

问题是否满足DPP规则。

Return type:

布尔

is_dqcp() bool[source]

问题是否满足DQCP规则?

is_qp() bool[source]

问题是一个二次规划吗?

parameters()[源代码]

参数的访问器方法。

Returns:

问题中的参数列表。

Return type:

Parameter的列表

classmethod register_solve(name: str, func) None[source]

向Problem类添加一个solve方法。

Parameters:
name : str

该方法的关键字。

func : function

执行solve方法的函数。此函数必须将问题实例作为其第一个参数来解决。

solve(*args, **kwargs)[source]

使用指定的方法编译并解决问题。

作为副作用,填充问题对象上的statusvalue属性。

Parameters:
solver : str, optional

使用的求解器。例如,‘CLARABEL’, ‘SCS’, 或 ‘OSQP’。

solver_path : list of (str, dict) tuples or strings, optional

使用的求解器及其可选参数。 该函数会按照给定的顺序尝试求解器,并返回第一个成功的求解器的解。 例如,[‘SCS’, (‘OSQP’, {‘max_iter’:10000})]

verbose : bool, optional

覆盖默认的隐藏求解器输出,并打印描述CVXPY编译过程的日志信息。

gp : bool, optional

如果为True,将问题解析为有纪律的几何程序,而不是有纪律的凸程序。

qcp : bool, optional

如果为True,将问题解析为规范的拟凸程序,而不是规范的凸程序。

requires_grad : bool, optional

使得在求解后通过调用problem.backward()来计算解决方案相对于参数的梯度成为可能,或者通过调用problem.derivative()来计算给定参数扰动的变量扰动。

梯度仅支持DCP和DGP问题,不支持拟凸问题。在计算梯度时(即当此参数为True时),问题必须满足DPP规则。

enforce_dpp : bool, optional

当为True时,尝试解决非DPP问题时会抛出DPPError(而不仅仅是警告)。仅适用于涉及参数的问题。默认为False。

ignore_dpp : bool, optional

当为True时,DPP问题将被视为非DPP问题,这可能会加快编译速度。默认为False。

method : function, optional

使用自定义的解决方法。

kwargs : keywords, optional

额外的求解器特定参数。请参阅下面的注释。

注释

CVXPY 与多种求解器接口;这些求解器使用的算法具有与停止标准相关的参数,以及提高解质量的策略。

没有一个参数选择是适用于每个问题的完美选择。如果你从求解器中没有得到满意的结果,你可以尝试改变它的参数。具体的方法取决于特定的求解器。以下是一些例子:

prob.solve(solver='ECOS', abstol=1e-6)
prob.solve(solver='OSQP', max_iter=10000).
mydict = {"MSK_DPAR_INTPNT_CO_TOL_NEAR_REL":  10}
prob.solve(solver='MOSEK', mosek_params=mydict).

您应该参考CVXPY的在线文档,了解如何传递求解器参数,文档可在以下网址找到:

https://www.cvxpy.org/tutorial/advanced/index.html#setting-solver-options

Returns:

问题的最优值,或指示问题无法解决原因的字符串。

Return type:

浮点数

Raises:
  • cvxpy.error.DCPError – 如果问题不是DCP且gp为False时抛出。

  • cvxpy.error.DGPError – 如果问题不是DGP且gp为True时抛出。

  • cvxpy.error.DPPError – 如果DPP设置无效,则抛出此错误。

  • cvxpy.error.SolverError – 如果没有在已安装的求解器中找到合适的求解器,或者遇到意外错误,则会引发此错误。

unpack_results(solution, chain: SolvingChain, inverse_data) None[source]

根据求解器结果更新问题状态。

更新问题状态、问题值以及原始和对偶变量的值。

Parameters:
solution : object

通过将链应用于问题并在结果数据上调用求解器返回的解决方案。

chain : SolvingChain

用于解决问题的解决链。

inverse_data : list

将链应用于问题后返回的逆数据。

Raises:

cvxpy.error.SolverError – 如果求解器失败

variables() list[Variable][source]

变量的访问器方法。

Returns:

问题中的变量列表。

Return type:

Variable的列表

property compilation_time : float | None

上次编译问题所花费的秒数。

Type:

浮点数

property constraints : list[Constraint]

问题约束的浅拷贝。

请注意,约束在创建后不能重新分配、追加或以其他方式修改,除非通过参数。

property objective : Minimize | Maximize

问题的目标。

请注意,目标在创建后不能被重新分配, 并且在创建后修改目标将导致未定义的行为。

Type:

MinimizeMaximize

property size_metrics : SizeMetrics

关于问题规模的信息。

Type:

SizeMetrics

property solver_stats : SolverStats

求解器返回的信息。

Type:

SolverStats

property status : str

上次解决问题时的状态;可能是最优、不可行或无界(带有或不带有不准确的后缀)。

Type:

字符串

property value

上次解决问题时的值(如果未解决则为None)。

Type:

浮点数

SizeMetrics

class cvxpy.problems.problem.SizeMetrics(problem: Problem)[source]

报告有关问题的各种指标。

num_scalar_variables

问题中的标量变量数量。

Type:

整数

num_scalar_data

问题中标量常数和参数的数量。问题中所有矩阵、向量使用的常数数量。 在构建问题时,一些常数并不明显:例如,sum_squares表达式是一个quad_over_lin表达式的包装器,分母中有一个常数1。

Type:

整数

num_scalar_eq_constr

问题中的标量等式约束的数量。

Type:

整数

num_scalar_leq_constr

问题中的标量不等式约束的数量。

Type:

整数

max_data_dimension

任何数据块约束或参数的最长维度。

Type:

整数

max_big_small_squared

问题中所有数据块的 (big)(small)^2 的最大值,其中 (big) 是每个数据块的较大维度,(small) 是较小维度。

Type:

整数

SolverStats

class cvxpy.problems.problem.SolverStats(solver_name: str, solve_time: float | None = None, setup_time: float | None = None, num_iters: int | None = None, extra_stats: dict | None = None)[source]

报告求解器在求解后返回的一些杂项信息,这些信息并未直接被问题实例捕获。

solver_name

求解器的名称。

Type:

字符串

solve_time

求解器解决问题所花费的时间(以秒为单位)。

Type:

双精度

setup_time

求解器设置问题所花费的时间(以秒为单位)。

Type:

双精度

num_iters

求解器必须经历的迭代次数以找到解决方案。

Type:

整数

extra_stats

特定于求解器的额外统计信息;这些统计信息通常直接从求解器返回,未经CVXPY修改。此对象可能是一个字典,或一个自定义的Python对象。

Type:

对象

extra_stats : dict | None = None
classmethod from_dict(attr: dict, solver_name: str) SolverStats[source]

从属性字典中构造一个SolverStats对象。

Parameters:
attr : dict

求解器返回的属性字典。

solver_name : str

求解器的名称。

Returns:

一个SolverStats对象。

Return type:

SolverStats

num_iters : int | None = None
setup_time : float | None = None
solve_time : float | None = None
solver_name : str