pepflow 0.1.4a1__py3-none-any.whl → 0.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pepflow/solver.py CHANGED
@@ -46,6 +46,14 @@ def evaled_scalar_to_cvx_express(
46
46
 
47
47
 
48
48
  class DualVariableManager:
49
+ """
50
+ A class to access the dual variables associated with the constraints
51
+ of the Primal PEP. Should not be instantiated directly. Automatically
52
+ generated as a member variable of the :class:`PEPResult` object
53
+ returned when calling :py:func:`pepflow.PEPBuilder.solve_primal`.
54
+ """
55
+
56
+ # It is used in the primal PEP to get the dual variables.
49
57
  def __init__(self, named_constraints: list[tuple[str, cvxpy.Constraint]]):
50
58
  self.named_constraints = {}
51
59
  for name, c in named_constraints:
@@ -63,6 +71,19 @@ class DualVariableManager:
63
71
  self.named_constraints[name] = constraint
64
72
 
65
73
  def dual_value(self, name: str) -> float | None:
74
+ """
75
+ Given the name of a :class:`Constraint` object that represents a
76
+ constraint in Primal PEP, return the value of its corresponding
77
+ dual variable.
78
+
79
+ Args:
80
+ name (str): The name of the :class:`Constraint` object whose
81
+ associated dual variable we want to retrieve.
82
+
83
+ Returns:
84
+ float: The value of the dual variable corresponding to the
85
+ :class:`Constraint` object associated with the `name` argument.
86
+ """
66
87
  if name not in self.named_constraints:
67
88
  return None # Is this good choice?
68
89
  dual_value = self.named_constraints[name].dual_value
@@ -71,7 +92,65 @@ class DualVariableManager:
71
92
  return dual_value
72
93
 
73
94
 
74
- class CVXSolver:
95
+ class PrimalVariableManager:
96
+ """
97
+ A class to access the primal variables of the Dual PEP. The primal
98
+ variables of the Dual PEP are the dual variables associated with the
99
+ constraints of the Primal PEP. Should not be instantiated directly.
100
+ Automatically generated as a member variable of the :class:`PEPResult`
101
+ object returned when calling :py:func:`pepflow.PEPBuilder.solve_dual`.
102
+ """
103
+
104
+ # It is used in the dual PEP to get the primal variables.
105
+ def __init__(self, named_variables: list[tuple[str, cvxpy.Variable]]):
106
+ self.named_variables = {}
107
+ for name, v in named_variables:
108
+ self.add_variable(name, v)
109
+
110
+ def cvx_variables(self) -> list[cvxpy.Variable]:
111
+ return list(self.named_variables.values())
112
+
113
+ def clear(self) -> None:
114
+ self.named_variables.clear()
115
+
116
+ def add_variable(self, name: str, variable: cvxpy.Variable) -> None:
117
+ if name in self.named_variables:
118
+ raise KeyError(f"There is already a variable named {name}")
119
+ self.named_variables[name] = variable
120
+
121
+ def get_variable(self, name: str) -> cvxpy.Variable:
122
+ if name not in self.named_variables:
123
+ raise KeyError(f"Cannot find a variable named {name}")
124
+ return self.named_variables[name]
125
+
126
+ def primal_value(self, name: str) -> float | None:
127
+ """
128
+ The primal variables of the Dual PEP are the dual variables associated
129
+ with the constraints of the Primal PEP.
130
+
131
+ Given the name of a :class:`Constraint` object that represents a
132
+ constraint in the Primal PEP, return the value of the corresponding
133
+ primal variable of the Dual PEP.
134
+
135
+ Args:
136
+ name (str): The name of the :class:`Constraint` object whose
137
+ corresponding primal variable of the Dual PEP we want to
138
+ retrieve.
139
+
140
+ Returns:
141
+ float: The value of the primal variable of the Dual PEP
142
+ corresponding to the :class:`Constraint` object associated with
143
+ the `name` argument.
144
+ """
145
+ if name not in self.named_variables:
146
+ return None # Is this good choice?
147
+ primal_value = self.named_variables[name].value
148
+ if primal_value is None:
149
+ return None
150
+ return primal_value
151
+
152
+
153
+ class CVXPrimalSolver:
75
154
  def __init__(
76
155
  self,
77
156
  perf_metric: sc.Scalar,
@@ -83,8 +162,10 @@ class CVXSolver:
83
162
  self.dual_var_manager = DualVariableManager([])
84
163
  self.context = context
85
164
 
86
- def build_problem(self) -> cvxpy.Problem:
87
- em = exm.ExpressionManager(self.context)
165
+ def build_problem(
166
+ self, resolve_parameters: dict[str, utils.NUMERICAL_TYPE] | None = None
167
+ ) -> cvxpy.Problem:
168
+ em = exm.ExpressionManager(self.context, resolve_parameters=resolve_parameters)
88
169
  f_var = cvxpy.Variable(em._num_basis_scalars)
89
170
  g_var = cvxpy.Variable(
90
171
  (em._num_basis_points, em._num_basis_points), symmetric=True
@@ -121,3 +202,89 @@ class CVXSolver:
121
202
  problem = self.build_problem()
122
203
  result = problem.solve(**kwargs)
123
204
  return result
205
+
206
+
207
+ class CVXDualSolver:
208
+ def __init__(
209
+ self,
210
+ perf_metric: sc.Scalar,
211
+ constraints: list[ctr.Constraint],
212
+ context: pc.PEPContext,
213
+ ):
214
+ self.perf_metric = perf_metric
215
+ self.constraints = constraints
216
+ self.primal_var_manager = PrimalVariableManager([])
217
+ self.context = context
218
+
219
+ def build_problem(
220
+ self, resolve_parameters: dict[str, utils.NUMERICAL_TYPE] | None = None
221
+ ) -> cvxpy.Problem:
222
+ # The primal problem is always the following form:
223
+ #
224
+ # max_{F, G}: <perf.vec, F> + Tr(G perf.Mat) + perf.const
225
+ # s.t. <constraint.vec, F> + Tr(G constraint.Mat) + constraint.const <= 0
226
+ # G >= 0
227
+ # Caveat: we use max instead of min in primal problem.
228
+ #
229
+ # Dual prob = min_{l, S} [max_{F, G} (<perf.vec, F> + Tr(G perf.Mat) - l * (constraint) + Tr(S*G))]
230
+ # Note the sign above.
231
+ # Becaus F is unbounded and the Lagrangian w.r.t. F is linear, the coefficients of F must be 0.
232
+ # Similarly, the Lagrangian w.r.t. G is linear and G is PSD, the coefficients of G must << 0.
233
+ dual_constraints = []
234
+ lambd_constraints = []
235
+ em = exm.ExpressionManager(self.context, resolve_parameters=resolve_parameters)
236
+ # The one corresponding to G >= 0
237
+ S = cvxpy.Variable((em._num_basis_points, em._num_basis_points), PSD=True)
238
+ evaled_perf_metric_scalar = em.eval_scalar(self.perf_metric)
239
+
240
+ extra_constraints = []
241
+ obj = evaled_perf_metric_scalar.constant
242
+ F_coef_vec = 0
243
+ G_coef_mat = 0
244
+ # l * (Tr(G*eval_s.Matrix) + <F, eval_s.vec> + eval_s.const)
245
+ for c in self.constraints:
246
+ lambd = cvxpy.Variable()
247
+ self.primal_var_manager.add_variable(c.name, lambd)
248
+ evaled_scalar = em.eval_scalar(c.scalar)
249
+ if c.comparator == utils.Comparator.GT:
250
+ sign = 1
251
+ lambd_constraints.append(lambd >= 0)
252
+ elif c.comparator == utils.Comparator.LT:
253
+ sign = -1 # We flip f(x) <=0 into -f(x) >= 0
254
+ lambd_constraints.append(lambd >= 0)
255
+ elif c.comparator == utils.Comparator.EQ:
256
+ sign = 1
257
+ else:
258
+ raise RuntimeError(
259
+ f"Unknown comparator in constraint {c.anme}: get {c.comparator=}"
260
+ )
261
+ G_coef_mat += sign * lambd * evaled_scalar.matrix
262
+ F_coef_vec += sign * lambd * evaled_scalar.vector
263
+ obj += sign * lambd * evaled_scalar.constant
264
+
265
+ # We can add extra constraints to directly manipulate the primal variable in dual PEP.
266
+ for comparator, val in c.associated_dual_var_constraints:
267
+ if c.comparator == utils.Comparator.GT:
268
+ extra_constraints.append(lambd >= val)
269
+ elif c.comparator == utils.Comparator.LT:
270
+ extra_constraints.append(lambd <= val)
271
+ elif c.comparator == utils.Comparator.EQ:
272
+ extra_constraints.append(lambd == val)
273
+ else:
274
+ raise RuntimeError(
275
+ f"Unknown comparator in constraint {c.anme} associated dual one:"
276
+ f"get {c.comparator=}"
277
+ )
278
+
279
+ dual_constraints.append(F_coef_vec + evaled_perf_metric_scalar.vector == 0)
280
+ dual_constraints.append(S + evaled_perf_metric_scalar.matrix + G_coef_mat == 0)
281
+
282
+ return cvxpy.Problem(
283
+ cvxpy.Minimize(obj),
284
+ dual_constraints + lambd_constraints + extra_constraints,
285
+ )
286
+
287
+ def solve(self, **kwargs):
288
+ problem = self.build_problem()
289
+ result = problem.solve(**kwargs)
290
+ return result
pepflow/solver_test.py CHANGED
@@ -32,7 +32,7 @@ def test_cvx_solver_case1():
32
32
  s2 = -(1 + p1 * p1)
33
33
  constraints = [(p1 * p1).gt(1, name="x^2 >= 1"), s1.gt(0, name="s1 > 0")]
34
34
 
35
- solver = ps.CVXSolver(
35
+ solver = ps.CVXPrimalSolver(
36
36
  perf_metric=s2,
37
37
  constraints=constraints,
38
38
  context=pep_builder.get_context("test"),
@@ -55,7 +55,7 @@ def test_cvx_solver_case2():
55
55
  s2 = -p1 * p1 + 2
56
56
  constraints = [(p1 * p1).lt(1, name="x^2 <= 1"), s1.gt(0, name="s1 > 0")]
57
57
 
58
- solver = ps.CVXSolver(
58
+ solver = ps.CVXPrimalSolver(
59
59
  perf_metric=s2,
60
60
  constraints=constraints,
61
61
  context=pep_builder.get_context("test"),
@@ -68,3 +68,51 @@ def test_cvx_solver_case2():
68
68
 
69
69
  assert np.isclose(solver.dual_var_manager.dual_value("x^2 <= 1"), 0)
70
70
  assert solver.dual_var_manager.dual_value("s1 > 0") == 0
71
+
72
+
73
+ def test_cvx_dual_solver_case1():
74
+ pep_builder = pep.PEPBuilder()
75
+ with pep_builder.make_context("test"):
76
+ p1 = pp.Point(is_basis=True, tags=["p1"])
77
+ s1 = pp.Scalar(is_basis=True, tags=["s1"])
78
+ s2 = -(1 + p1 * p1)
79
+ constraints = [(p1 * p1).gt(1, name="x^2 >= 1"), s1.gt(0, name="s1 > 0")]
80
+
81
+ dual_solver = ps.CVXDualSolver(
82
+ perf_metric=s2,
83
+ constraints=constraints,
84
+ context=pep_builder.get_context("test"),
85
+ )
86
+ problem = dual_solver.build_problem()
87
+ result = problem.solve()
88
+ assert abs(-result - 2) < 1e-6
89
+
90
+ assert np.isclose(dual_solver.primal_var_manager.primal_value("x^2 >= 1"), 1)
91
+ assert np.isclose(dual_solver.primal_var_manager.primal_value("s1 > 0"), 0)
92
+
93
+
94
+ def test_cvx_dual_solver_case2():
95
+ pep_builder = pep.PEPBuilder()
96
+ with pep_builder.make_context("test"):
97
+ p1 = pp.Point(is_basis=True, tags=["p1"])
98
+ s1 = pp.Scalar(is_basis=True, tags=["s1"])
99
+ s2 = -p1 * p1 + 2
100
+ constraints = [(p1 * p1).lt(1, name="x^2 <= 1"), s1.gt(0, name="s1 > 0")]
101
+
102
+ dual_solver = ps.CVXDualSolver(
103
+ perf_metric=s2,
104
+ constraints=constraints,
105
+ context=pep_builder.get_context("test"),
106
+ )
107
+
108
+ # It is a simple `min_x x^2-2; s.t. x^2 <= 1` problem.
109
+ problem = dual_solver.build_problem()
110
+ result = problem.solve()
111
+ assert abs(-result + 2) < 1e-6
112
+
113
+ assert np.isclose(
114
+ dual_solver.primal_var_manager.primal_value("x^2 <= 1"), 0, atol=1e-7
115
+ )
116
+ assert np.isclose(
117
+ dual_solver.primal_var_manager.primal_value("s1 > 0"), 0, atol=1e-7
118
+ )
pepflow/utils.py CHANGED
@@ -24,6 +24,7 @@ import numbers
24
24
  from typing import TYPE_CHECKING, Any
25
25
 
26
26
  import numpy as np
27
+ import sympy as sp
27
28
 
28
29
  if TYPE_CHECKING:
29
30
  from pepflow.function import Function
@@ -31,13 +32,17 @@ if TYPE_CHECKING:
31
32
  from pepflow.scalar import Scalar
32
33
 
33
34
 
34
- def SOP(v, w):
35
+ NUMERICAL_TYPE = numbers.Number | sp.Rational
36
+
37
+
38
+ def SOP(v, w, sympy_mode: bool = False) -> np.ndarray:
35
39
  """Symmetric Outer Product."""
36
- return 1 / 2 * (np.outer(v, w) + np.outer(w, v))
40
+ coef = sp.S(1) / 2 if sympy_mode else 1 / 2
41
+ return coef * (np.outer(v, w) + np.outer(w, v))
37
42
 
38
43
 
39
- def SOP_self(v):
40
- return SOP(v, v)
44
+ def SOP_self(v, sympy_mode: bool = False) -> np.ndarray:
45
+ return SOP(v, v, sympy_mode=sympy_mode)
41
46
 
42
47
 
43
48
  class Op(enum.Enum):
@@ -54,12 +59,39 @@ class Comparator(enum.Enum):
54
59
 
55
60
 
56
61
  def is_numerical(val: Any) -> bool:
57
- return isinstance(val, numbers.Number)
62
+ return isinstance(val, numbers.Number) or isinstance(val, sp.Rational)
63
+
64
+
65
+ def is_numerical_or_parameter(val: Any) -> bool:
66
+ from pepflow import parameter as param
67
+
68
+ return is_numerical(val) or isinstance(val, param.Parameter)
69
+
70
+
71
+ def numerical_str(val: Any) -> str:
72
+ from pepflow import parameter as param
73
+
74
+ if not is_numerical_or_parameter(val):
75
+ raise ValueError(
76
+ "Cannot call numerical_str for {val} since it is not numerical."
77
+ )
78
+ if isinstance(val, param.Parameter):
79
+ return str(val)
80
+ return str(val) if isinstance(val, sp.Rational) else f"{val:.4g}"
58
81
 
59
82
 
60
83
  def parenthesize_tag(val: Point | Scalar | Function) -> str:
61
84
  tmp_tag = val.tag
62
85
  if not val.is_basis:
63
- if val.eval_expression.op == Op.ADD or val.eval_expression.op == Op.SUB:
64
- tmp_tag = f"({val.tag})"
86
+ if op := getattr(val.eval_expression, "op", None):
87
+ if op in (Op.ADD, Op.SUB):
88
+ tmp_tag = f"({val.tag})"
65
89
  return tmp_tag
90
+
91
+
92
+ def str_to_latex(s: str) -> str:
93
+ """Convert string into latex style."""
94
+ s = s.replace("star", r"\star")
95
+ s = s.replace("gradient_", r"\nabla ")
96
+ s = s.replace("|", r"\|")
97
+ return rf"$\displaystyle {s}$"
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pepflow
3
- Version: 0.1.4a1
3
+ Version: 0.1.5
4
4
  Summary: PEPFlow: A framework for Performance Estimation Problem (PEP) Workflow
5
- Requires-Python: >=3.9
5
+ Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
7
7
  License-File: LICENSE
8
8
  Requires-Dist: attrs>=25.3.0
@@ -37,6 +37,7 @@ uv sync; source .venv/bin/activate;
37
37
 
38
38
  In windows, use `.venv\Scripts\activate` instead.
39
39
 
40
+ ### Lint & Testing
40
41
  We use `ruff` to do the format and lint and `isort` to do the import ordering.
41
42
 
42
43
  ```bash
@@ -45,14 +46,18 @@ ruff check .;
45
46
  isort .;
46
47
  ```
47
48
 
48
- ### Testing
49
-
50
49
  We use `pytest` framework to do the test. To run all unit tests, run the following command:
51
50
 
52
- ```python
51
+ ```bash
53
52
  pytest -s -vv pepflow
54
53
  ```
55
54
 
55
+ We have a convenient script to above
56
+ ```bash
57
+ scripts/check.sh [format|lint|typecheck|test]
58
+ ```
59
+ See the script for the options.
60
+
56
61
  ### Build doc website
57
62
 
58
63
  Install the required library (one-time) and `pandoc` in order to build ipynb.
@@ -62,13 +67,9 @@ pip install -r docs/requirements.txt
62
67
 
63
68
  To build the website, run
64
69
  ```bash
65
- cd docs; make html
66
- ```
67
- Make sure it succeeded, then examine it locally through
68
- ```bash
69
- cd build/html; python -m http.server
70
+ scripts/build_doc.sh [--serve-only]
70
71
  ```
71
-
72
+ The argument `--serve-only` is optional for hosting the website locally.
72
73
 
73
74
 
74
75
 
@@ -0,0 +1,28 @@
1
+ pepflow/__init__.py,sha256=uF-c0NyR8z9sASDj8nvd3Vz1a4gFm7ZcdH-SyR3h0bs,2250
2
+ pepflow/constants.py,sha256=t29CDRE8kw773zgKS0ZZCYGegwagaDDdLfpSaeDpK14,871
3
+ pepflow/constraint.py,sha256=aFcdOprdBc5peT7oL5IXlfnvnGw1qadPLtKsy1Cbrac,3555
4
+ pepflow/constraint_test.py,sha256=6MF__r67NooqOVXHtkeOVcg_ebycMF_xI9OpFDFiV4c,2676
5
+ pepflow/e2e_test.py,sha256=jo4pWoXq9XJFmdfvJeSUdCIlmdmk_Qp2QCjOLelPqMY,3701
6
+ pepflow/expression_manager.py,sha256=AD2AHQGvmjRltsKgXiG9QV5oUZFpQsTgd-dky5uNRi0,17875
7
+ pepflow/expression_manager_test.py,sha256=ZzwZGc-rP5iey8aXMakeq_0PbMW6Tf7DmMxzSeJe2Bg,5493
8
+ pepflow/function.py,sha256=19TocYEjO5Wn24IpJYmzP_UTwyR_Pg3uzE_-zluC3CM,22867
9
+ pepflow/function_test.py,sha256=RBBm_Z6SKD3Vd03eUAO4XPONyXXueT8w1eiRLeA4IuI,8263
10
+ pepflow/interactive_constraint.py,sha256=mB3AQt21kIdRR0yqtvUksoELSLSoTDkMeu07ThKPerE,12757
11
+ pepflow/parameter.py,sha256=yknpFWzj91gfDKjRVgRDMG57mKeKE1Qqcnm4i2tZzok,6246
12
+ pepflow/parameter_test.py,sha256=fLmKvoLKu_-GULDXcpXmoAZA17mx0m9Zm3twfXQUin0,4199
13
+ pepflow/pep.py,sha256=hCB2jXjLCU_5jgykZD6jwch4fDvdvy-aX4jmQpF6jWs,16222
14
+ pepflow/pep_context.py,sha256=Y6JD28TAf39SB8G_FuqQnd4HVgit1viGIOTs4lzdzgg,9184
15
+ pepflow/pep_context_test.py,sha256=B12M4eni0MVL_30v6yAf4ognWc1YxNTaR50_F01iGnI,4052
16
+ pepflow/pep_test.py,sha256=-diI87sk10417oBnPRgWxY6XhiKOPoK7m5-MTkmlTcw,2788
17
+ pepflow/point.py,sha256=pv0yr4oQsfBlzKLPMWPeR6WfdF4W-l_AaR5GFg_Me7o,12570
18
+ pepflow/point_test.py,sha256=Rm-uOvB9GjIwH3XGnWr5UfTRqzlZRb8u-esV5b-bgtY,5667
19
+ pepflow/scalar.py,sha256=oZjsfXZEhofxszk21pmcvNQOh8_N_6G_PfH3STbugH4,18315
20
+ pepflow/scalar_test.py,sha256=fYtKfe-nO4GhAIIrZrW0Lx_fbFHqIxsKbPPA-G5udnE,7082
21
+ pepflow/solver.py,sha256=ZThfiaSDru-gHxn21PC8T71ePzTykAhSRCteOaOBbcQ,11381
22
+ pepflow/solver_test.py,sha256=NuH6yF-NTItkv3x0U40HFJ7xbSNi407qg4QGlVmXqHU,4063
23
+ pepflow/utils.py,sha256=-Uu0TlJyqpGNT4DmdLtvXWNFPHn06zKHF7Jr1NHz7LQ,2743
24
+ pepflow-0.1.5.dist-info/licenses/LICENSE,sha256=na5oVXAps-5f1hLGG4SYnwFdavQeXgYUeN-E3MxOA_s,11361
25
+ pepflow-0.1.5.dist-info/METADATA,sha256=ULyUflh7uT2lqFhobLqMqWxU4uPwfKoBWPa5u7Ojmvc,1867
26
+ pepflow-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ pepflow-0.1.5.dist-info/top_level.txt,sha256=0YEPCZQQa6yIAIwMumzDg4pj7AME8aXu2sXkuq8xM6M,8
28
+ pepflow-0.1.5.dist-info/RECORD,,
@@ -1,26 +0,0 @@
1
- pepflow/__init__.py,sha256=xvtX_jzS-wEqjHicdWWRp-lL71VbGv3vhuvfKncRFsQ,1985
2
- pepflow/constants.py,sha256=t29CDRE8kw773zgKS0ZZCYGegwagaDDdLfpSaeDpK14,871
3
- pepflow/constraint.py,sha256=n-01dcQplvsXB7V4fceJBImbwSr-Wa9k9tE7ZcVmi3o,1153
4
- pepflow/constraint_test.py,sha256=6MF__r67NooqOVXHtkeOVcg_ebycMF_xI9OpFDFiV4c,2676
5
- pepflow/e2e_test.py,sha256=7FDFUe-TfxiJ5LN57gxO1OzdqnGHgRJe_Eoega6TpMI,2193
6
- pepflow/expression_manager.py,sha256=94G1PyD-W1uS72AgyeCMwDEcLWwuhdIimuZ1nXjMNJA,7680
7
- pepflow/expression_manager_test.py,sha256=1NmFZUoxZ3Lf0qP10uYQplWMX4-OYSAnvhiVLBXvt3U,4164
8
- pepflow/function.py,sha256=bhL8cVX_KctJC9JyT_fgxXM-9HjnNJ0b6SlTBkwdzOw,16305
9
- pepflow/function_test.py,sha256=RBBm_Z6SKD3Vd03eUAO4XPONyXXueT8w1eiRLeA4IuI,8263
10
- pepflow/interactive_constraint.py,sha256=mB3AQt21kIdRR0yqtvUksoELSLSoTDkMeu07ThKPerE,12757
11
- pepflow/pep.py,sha256=cEFhnY-81OZTJ-1rwVReIBehH4S8qF5TOHkYiy02trk,6380
12
- pepflow/pep_context.py,sha256=p1cN4THwH8WKQfkzp8nw8PiQMRIzhCtSd3lkZqsGBPg,4804
13
- pepflow/pep_context_test.py,sha256=iNbsr1PRlVBBoKpgmochmdOjpHCNDlY86NPTwSqJrt4,3392
14
- pepflow/pep_test.py,sha256=-diI87sk10417oBnPRgWxY6XhiKOPoK7m5-MTkmlTcw,2788
15
- pepflow/point.py,sha256=vSKCuivJL3zyUCnV48rfM5XpAGsVbdQ8YWdO3fKrViI,8514
16
- pepflow/point_test.py,sha256=vuG8GbEU9vLf-btyax0XWEgiQm5hZMxscYk8HdyKjSE,5270
17
- pepflow/scalar.py,sha256=8E-D5pgZCDpyEX13VwrFARo87v-HWAUs4gAD_-Ty_g8,9653
18
- pepflow/scalar_test.py,sha256=mzLJOtNdZd54wJir5uiaEoMtcwEWiYh9C-oRWxbeb_A,6472
19
- pepflow/solver.py,sha256=WzeN_IWNBs9IpE212jenhYMWFuuwH890h0vaFmJRM6I,4312
20
- pepflow/solver_test.py,sha256=-aCEe-oQ26xJUWR64b-CIIfFOK_pNJnMlOly2bagk68,2457
21
- pepflow/utils.py,sha256=Xd-DwtUoUSMw_i6xjYsOxsHmn8l3ZbYCyptXEBfoyZk,1718
22
- pepflow-0.1.4a1.dist-info/licenses/LICENSE,sha256=na5oVXAps-5f1hLGG4SYnwFdavQeXgYUeN-E3MxOA_s,11361
23
- pepflow-0.1.4a1.dist-info/METADATA,sha256=NR2LXX5TJWYrEmHVTIIiUrre_n896lnnH0ffbx74Cyc,1752
24
- pepflow-0.1.4a1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
- pepflow-0.1.4a1.dist-info/top_level.txt,sha256=0YEPCZQQa6yIAIwMumzDg4pj7AME8aXu2sXkuq8xM6M,8
26
- pepflow-0.1.4a1.dist-info/RECORD,,