eqc-models 0.9.8__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.
- eqc_models-0.9.8.data/platlib/compile_extensions.py +23 -0
- eqc_models-0.9.8.data/platlib/eqc_models/__init__.py +15 -0
- eqc_models-0.9.8.data/platlib/eqc_models/algorithms/__init__.py +4 -0
- eqc_models-0.9.8.data/platlib/eqc_models/algorithms/base.py +10 -0
- eqc_models-0.9.8.data/platlib/eqc_models/algorithms/penaltymultiplier.py +169 -0
- eqc_models-0.9.8.data/platlib/eqc_models/allocation/__init__.py +6 -0
- eqc_models-0.9.8.data/platlib/eqc_models/allocation/allocation.py +367 -0
- eqc_models-0.9.8.data/platlib/eqc_models/allocation/portbase.py +128 -0
- eqc_models-0.9.8.data/platlib/eqc_models/allocation/portmomentum.py +137 -0
- eqc_models-0.9.8.data/platlib/eqc_models/assignment/__init__.py +5 -0
- eqc_models-0.9.8.data/platlib/eqc_models/assignment/qap.py +82 -0
- eqc_models-0.9.8.data/platlib/eqc_models/assignment/setpartition.py +170 -0
- eqc_models-0.9.8.data/platlib/eqc_models/base/__init__.py +72 -0
- eqc_models-0.9.8.data/platlib/eqc_models/base/base.py +150 -0
- eqc_models-0.9.8.data/platlib/eqc_models/base/constraints.py +276 -0
- eqc_models-0.9.8.data/platlib/eqc_models/base/operators.py +201 -0
- eqc_models-0.9.8.data/platlib/eqc_models/base/polyeval.c +11363 -0
- eqc_models-0.9.8.data/platlib/eqc_models/base/polyeval.cpython-310-darwin.so +0 -0
- eqc_models-0.9.8.data/platlib/eqc_models/base/polyeval.pyx +72 -0
- eqc_models-0.9.8.data/platlib/eqc_models/base/polynomial.py +274 -0
- eqc_models-0.9.8.data/platlib/eqc_models/base/quadratic.py +250 -0
- eqc_models-0.9.8.data/platlib/eqc_models/decoding.py +20 -0
- eqc_models-0.9.8.data/platlib/eqc_models/graph/__init__.py +5 -0
- eqc_models-0.9.8.data/platlib/eqc_models/graph/base.py +63 -0
- eqc_models-0.9.8.data/platlib/eqc_models/graph/hypergraph.py +307 -0
- eqc_models-0.9.8.data/platlib/eqc_models/graph/maxcut.py +155 -0
- eqc_models-0.9.8.data/platlib/eqc_models/graph/maxkcut.py +184 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/__init__.py +15 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/classifierbase.py +99 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/classifierqboost.py +423 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/classifierqsvm.py +237 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/clustering.py +323 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/clusteringbase.py +112 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/decomposition.py +363 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/forecast.py +255 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/forecastbase.py +139 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/regressor.py +220 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/regressorbase.py +97 -0
- eqc_models-0.9.8.data/platlib/eqc_models/ml/reservoir.py +106 -0
- eqc_models-0.9.8.data/platlib/eqc_models/sequence/__init__.py +5 -0
- eqc_models-0.9.8.data/platlib/eqc_models/sequence/tsp.py +217 -0
- eqc_models-0.9.8.data/platlib/eqc_models/solvers/__init__.py +12 -0
- eqc_models-0.9.8.data/platlib/eqc_models/solvers/qciclient.py +707 -0
- eqc_models-0.9.8.data/platlib/eqc_models/utilities/__init__.py +6 -0
- eqc_models-0.9.8.data/platlib/eqc_models/utilities/fileio.py +38 -0
- eqc_models-0.9.8.data/platlib/eqc_models/utilities/polynomial.py +137 -0
- eqc_models-0.9.8.data/platlib/eqc_models/utilities/qplib.py +375 -0
- eqc_models-0.9.8.dist-info/LICENSE.txt +202 -0
- eqc_models-0.9.8.dist-info/METADATA +139 -0
- eqc_models-0.9.8.dist-info/RECORD +52 -0
- eqc_models-0.9.8.dist-info/WHEEL +5 -0
- eqc_models-0.9.8.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# (C) Quantum Computing Inc., 2024.
|
|
2
|
+
from .polynomial import evaluate_polynomial, convert_hamiltonian_to_polynomial
|
|
3
|
+
from .fileio import read_coefficient_file, read_config_file, read_index_file
|
|
4
|
+
|
|
5
|
+
__all__ = ["evaluate_polynomial",
|
|
6
|
+
"read_coefficient_file", "read_index_file", "read_config_file", "convert_hamiltonian_to_polynomial"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# (C) Quantum Computing Inc., 2024.
|
|
2
|
+
import csv
|
|
3
|
+
|
|
4
|
+
def read_config_file(filename):
|
|
5
|
+
config = {}
|
|
6
|
+
with open(filename, 'r') as file:
|
|
7
|
+
for line in file:
|
|
8
|
+
line = line.strip()
|
|
9
|
+
if line and '=' in line:
|
|
10
|
+
key, value = line.split('=', 1)
|
|
11
|
+
config[key.strip()] = value.strip()
|
|
12
|
+
return config
|
|
13
|
+
|
|
14
|
+
def read_coefficient_file(filename):
|
|
15
|
+
with open(filename, 'r') as file:
|
|
16
|
+
reader = csv.reader(file)
|
|
17
|
+
coefficients = [float(x) for x, in reader]
|
|
18
|
+
return coefficients
|
|
19
|
+
|
|
20
|
+
def read_index_file(filename):
|
|
21
|
+
indices = []
|
|
22
|
+
with open(filename, 'r') as file:
|
|
23
|
+
reader = csv.reader(file)
|
|
24
|
+
for item in reader:
|
|
25
|
+
indices.append([int(x.strip()) for x in item])
|
|
26
|
+
return indices
|
|
27
|
+
|
|
28
|
+
def write_coefficient_file(filename, coefficients):
|
|
29
|
+
with open(filename, "w") as fp:
|
|
30
|
+
for val in coefficients:
|
|
31
|
+
fp.write(f"{val}\n")
|
|
32
|
+
|
|
33
|
+
def write_indices_file(filename, indices):
|
|
34
|
+
with open(filename, "w") as fp:
|
|
35
|
+
writer = csv.writer(fp)
|
|
36
|
+
for row in indices:
|
|
37
|
+
writer.writerow(row)
|
|
38
|
+
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# (C) Quantum Computing Inc., 2024.
|
|
2
|
+
import itertools
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def evaluate_polynomial(terms, solution):
|
|
6
|
+
val = 0
|
|
7
|
+
# print(solution)
|
|
8
|
+
for k, coeff in terms.items():
|
|
9
|
+
term = coeff
|
|
10
|
+
for idx in k:
|
|
11
|
+
if idx > 0:
|
|
12
|
+
idx -= 1
|
|
13
|
+
term *= solution[idx]
|
|
14
|
+
# if term != 0:
|
|
15
|
+
# print(k, term)
|
|
16
|
+
val += term
|
|
17
|
+
return val
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def convert_hamiltonian_to_polynomial(
|
|
21
|
+
A,
|
|
22
|
+
B,
|
|
23
|
+
C,
|
|
24
|
+
D,
|
|
25
|
+
num_vars,
|
|
26
|
+
):
|
|
27
|
+
"""Converts a hamiltonian of up to fourth order to a polynomial.
|
|
28
|
+
|
|
29
|
+
D_{ijkl} x_i x_j x_k x_l + C_{ijk} x_i x_j x_k + B_{ij} x_i x_j
|
|
30
|
+
+ A_i x_i
|
|
31
|
+
|
|
32
|
+
Input:
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
A: First order hamiltonian.
|
|
36
|
+
B: Second order hamiltonian.
|
|
37
|
+
C: Third order hamiltonian.
|
|
38
|
+
D: Fourth order hamiltonian.
|
|
39
|
+
num_vars: Number of variables.
|
|
40
|
+
|
|
41
|
+
Output:
|
|
42
|
+
|
|
43
|
+
polynomial_indices, polynomila_coefs: Indices and coefficients of
|
|
44
|
+
polynomial that respresents the hamiltonian.
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
assert num_vars >= 1, "Invalid number of variables <%d>!" % num_vars
|
|
49
|
+
|
|
50
|
+
if D is not None:
|
|
51
|
+
assert D.shape[0] == num_vars, "Inconsistent dimensions!"
|
|
52
|
+
assert D.shape[1] == num_vars, "Inconsistent dimensions!"
|
|
53
|
+
assert D.shape[2] == num_vars, "Inconsistent dimensions!"
|
|
54
|
+
assert D.shape[3] == num_vars, "Inconsistent dimensions!"
|
|
55
|
+
poly_order = 4
|
|
56
|
+
elif C is not None:
|
|
57
|
+
assert C.shape[0] == num_vars, "Inconsistent dimensions!"
|
|
58
|
+
assert C.shape[1] == num_vars, "Inconsistent dimensions!"
|
|
59
|
+
assert C.shape[2] == num_vars, "Inconsistent dimensions!"
|
|
60
|
+
poly_order = 3
|
|
61
|
+
elif B is not None:
|
|
62
|
+
assert B.shape[0] == num_vars, "Inconsistent dimensions!"
|
|
63
|
+
assert B.shape[1] == num_vars, "Inconsistent dimensions!"
|
|
64
|
+
poly_order = 2
|
|
65
|
+
elif A is not None:
|
|
66
|
+
assert A.shape[0] == num_vars, "Inconsistent dimensions!"
|
|
67
|
+
poly_order = 1
|
|
68
|
+
else:
|
|
69
|
+
assert False, "No hamiltonian provided!"
|
|
70
|
+
|
|
71
|
+
poly_indices = []
|
|
72
|
+
poly_coefs = []
|
|
73
|
+
|
|
74
|
+
if A is not None:
|
|
75
|
+
for i in range(num_vars):
|
|
76
|
+
coef_val = A[i]
|
|
77
|
+
|
|
78
|
+
if coef_val != 0:
|
|
79
|
+
poly_coefs.append(coef_val)
|
|
80
|
+
poly_indices.append([0] * (poly_order - 1) + [i + 1])
|
|
81
|
+
|
|
82
|
+
if B is not None:
|
|
83
|
+
for i in range(num_vars):
|
|
84
|
+
for j in range(i, num_vars):
|
|
85
|
+
if i == j:
|
|
86
|
+
coef_val = B[i][i]
|
|
87
|
+
else:
|
|
88
|
+
coef_val = B[i][j] + B[j][i]
|
|
89
|
+
|
|
90
|
+
if coef_val != 0:
|
|
91
|
+
poly_coefs.append(coef_val)
|
|
92
|
+
poly_indices.append(
|
|
93
|
+
[0] * (poly_order - 2) + [i + 1, j + 1]
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if C is not None:
|
|
97
|
+
for i in range(num_vars):
|
|
98
|
+
for j in range(i, num_vars):
|
|
99
|
+
for k in range(j, num_vars):
|
|
100
|
+
unique_perms = [
|
|
101
|
+
list(item)
|
|
102
|
+
for item in set(itertools.permutations([i, j, k]))
|
|
103
|
+
]
|
|
104
|
+
coef_val = 0.0
|
|
105
|
+
for item in unique_perms:
|
|
106
|
+
coef_val += C[item[0]][item[1]][item[2]]
|
|
107
|
+
|
|
108
|
+
if coef_val != 0:
|
|
109
|
+
poly_coefs.append(coef_val)
|
|
110
|
+
poly_indices.append(
|
|
111
|
+
[0] * (poly_order - 3) + [i + 1, j + 1, k + 1]
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if D is not None:
|
|
115
|
+
for i in range(num_vars):
|
|
116
|
+
for j in range(i, num_vars):
|
|
117
|
+
for k in range(j, num_vars):
|
|
118
|
+
for l in range(k, num_vars):
|
|
119
|
+
unique_perms = [
|
|
120
|
+
list(item)
|
|
121
|
+
for item in set(
|
|
122
|
+
itertools.permutations([i, j, k, l])
|
|
123
|
+
)
|
|
124
|
+
]
|
|
125
|
+
coef_val = 0.0
|
|
126
|
+
for item in unique_perms:
|
|
127
|
+
coef_val += D[item[0]][item[1]][item[2]][
|
|
128
|
+
item[3]
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
if coef_val != 0:
|
|
132
|
+
poly_coefs.append(coef_val)
|
|
133
|
+
poly_indices.append(
|
|
134
|
+
[i + 1, j + 1, k + 1, l + 1]
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return poly_indices, poly_coefs
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# (C) Quantum Computing Inc., 2024.
|
|
2
|
+
"""
|
|
3
|
+
Read the file format from QPLIB (https://doi.org/10.1007/s12532-018-0147-4)
|
|
4
|
+
|
|
5
|
+
The "problem type" is a string of three characters.
|
|
6
|
+
|
|
7
|
+
The first character indicates the type of objective function used. It must be one of the following:
|
|
8
|
+
|
|
9
|
+
L a linear objective function
|
|
10
|
+
D a convex quadratic objective function whose Hessian is a diagonal matrix
|
|
11
|
+
C a convex quadratic objective function
|
|
12
|
+
Q a quadratic objective function whose Hessian may be indefinite
|
|
13
|
+
|
|
14
|
+
The second character indicates the types of variables that are present. It must be one of the following:
|
|
15
|
+
|
|
16
|
+
C all the variables are continuous
|
|
17
|
+
B all the variables are binary (0-1)
|
|
18
|
+
M the variables are a mix of continuous and binary
|
|
19
|
+
I all the variables are integer
|
|
20
|
+
G the variables are a mix of continuous, binary and integer
|
|
21
|
+
|
|
22
|
+
The third character indicates the type of the (most extreme) constraint function used; other constraints may be of a lesser type. It must be one of the following:
|
|
23
|
+
|
|
24
|
+
N there are no constraints
|
|
25
|
+
B some of the variables lie between lower and upper bounds (box constraints)
|
|
26
|
+
L the constraint functions are linear
|
|
27
|
+
D the constraint functions are convex quadratics with diagonal Hessians
|
|
28
|
+
C the constraint functions are convex quadratics
|
|
29
|
+
Q the constraint functions are quadratics whose Hessians may be indefinite
|
|
30
|
+
|
|
31
|
+
Thus for continuous problems, we would have
|
|
32
|
+
|
|
33
|
+
LCL a linear program
|
|
34
|
+
LCC or LCQ a linear program with quadratic constraints
|
|
35
|
+
CCB or QCB a bound-constrained quadratic program
|
|
36
|
+
CCL or QCL a quadratic program
|
|
37
|
+
CCC or CCQ or a quadratic program with quadratic constraints
|
|
38
|
+
QCC or QCQ
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
# "problem name" (character string)
|
|
43
|
+
# "problem type" (character string)
|
|
44
|
+
# "problem sense" i.e. one of the words minimize or maximize (character string) (Y)
|
|
45
|
+
# "number of variables" (integer)
|
|
46
|
+
# "number of general linear constraints" (integer) [1]
|
|
47
|
+
# "number of nonzeros in lower triangle of H" (integer) [2]
|
|
48
|
+
# "row" "column" "value" for each entry of H (if any), one triple on each line
|
|
49
|
+
# "default value for entries in g"
|
|
50
|
+
# "number of non-default entries in g"
|
|
51
|
+
# "index" "value" for each non-default term in g (if any), one pair per line (Y)
|
|
52
|
+
# "value of f"
|
|
53
|
+
# "number of nonzeros in lower triangles of H_c" (integer) [1,3]
|
|
54
|
+
# "constraint" "row" "column" "value" for each entry of H_c (if any),
|
|
55
|
+
# one quadruple on each line
|
|
56
|
+
# "number of nonzeros in A" (integer) [1]
|
|
57
|
+
# "row" "column" "value" for each entry of A (if any), one triple on each line
|
|
58
|
+
# "value for infinity" for bounds - any bound greater than or equal to this
|
|
59
|
+
# in absolute value is infinite
|
|
60
|
+
# "default value for entries in c_l" [1]
|
|
61
|
+
# "number of non-default entries in c_l" (integer) [1]
|
|
62
|
+
# "index" "value" for each non-default term in c_l (if any), one pair per line
|
|
63
|
+
# "default value for entries in c_u" [1]
|
|
64
|
+
# "number of non-default entries in c_u" (integer) [1]
|
|
65
|
+
# "index" "value" for each non-default term in c_u (if any), one pair per line
|
|
66
|
+
# "default value for entries in x_l" [4]
|
|
67
|
+
# "number of non-default entries in x_l" (integer) [4]
|
|
68
|
+
# "index" "value" for each non-default term in x_l (if any), one pair per line [4]
|
|
69
|
+
# "default value for entries in x_u" [4]
|
|
70
|
+
# "number of non-default entries in x_u" (integer) [4]
|
|
71
|
+
# "index" "value" for each non-default term in x_u (if any), one pair per line [4]
|
|
72
|
+
# "default variable type" (0 for continuous variable, 1 for integer) [5]
|
|
73
|
+
# "number of non-default variables" (integer) [5]
|
|
74
|
+
# "index" "value" for each non-default variable type (if any), one pair per line
|
|
75
|
+
# "default value for starting value for variables x"
|
|
76
|
+
# "number of non-default starting entries in x" (integer)
|
|
77
|
+
# "index" "value" for each non-default term in x (if any), one pair per line
|
|
78
|
+
# "default value for starting value for Lagrange multipliers y for constraints"[1]
|
|
79
|
+
# "number of non-default starting entries in y" (integer) [1]
|
|
80
|
+
# "index" "value" for each non-default term in y (if any), one pair per line
|
|
81
|
+
# "default value for starting value for dual variables z for simple bounds"
|
|
82
|
+
# "number of non-default starting entries in z" (integer)
|
|
83
|
+
# "index" "value" for each non-default term in z (if any), one pair per line
|
|
84
|
+
# "number of non-default names of variables" - default for variable i is "i"
|
|
85
|
+
# "index" "name" for each non-default name for variable x_i with index i (if any)
|
|
86
|
+
# "number of non-default names of constraints" - default for constraint i is "i"
|
|
87
|
+
# "index" "name" for each non-default name for constraint with index i (if any)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
from typing import Dict, List, TextIO, Tuple
|
|
91
|
+
import logging
|
|
92
|
+
import numpy as np
|
|
93
|
+
from eqc_models.base.quadratic import QuadraticModel, ConstrainedQuadraticModel
|
|
94
|
+
logger = logging.getLogger(name=__name__)
|
|
95
|
+
class QBBModel(QuadraticModel):
|
|
96
|
+
"""
|
|
97
|
+
QBB - Quadratic objective, binary variable type, unconstrained
|
|
98
|
+
|
|
99
|
+
This model type is the same as a QUBO model, but the linear portion is
|
|
100
|
+
specified separately, instead of in the diagonal.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
-------------
|
|
104
|
+
|
|
105
|
+
:C: np.ndarray - linear portion of the objective
|
|
106
|
+
:J: np.ndarray - quadratic portion of the objective
|
|
107
|
+
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
class QGLModel(ConstrainedQuadraticModel):
|
|
111
|
+
"""
|
|
112
|
+
QGL - Quadratic objective, General variable type, Linear constraints
|
|
113
|
+
Handles QCL, QIL, QBL, QML problems
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
------------
|
|
117
|
+
|
|
118
|
+
:C: np.ndarray - linear portion of the objective
|
|
119
|
+
:J: np.ndarray - quadratic portion of the objective
|
|
120
|
+
:A: np.ndarray - left hand side of the linear constraints
|
|
121
|
+
:b: np.ndarray - right hand side of the linear constraints
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def read_line(fp : TextIO) -> Dict:
|
|
126
|
+
line = fp.readline()
|
|
127
|
+
line = line.strip()
|
|
128
|
+
line = line.replace("\t", " ")
|
|
129
|
+
values = line.split(" ")
|
|
130
|
+
values = [v for v in values if v != ""]
|
|
131
|
+
if "#" in values:
|
|
132
|
+
values = values[:values.index("#")]
|
|
133
|
+
if "%" in values:
|
|
134
|
+
values = values[:values.index("%")]
|
|
135
|
+
if "!" in values:
|
|
136
|
+
values = values[:values.index("!")]
|
|
137
|
+
for i in range(len(values)):
|
|
138
|
+
try:
|
|
139
|
+
v1 = float(values[i])
|
|
140
|
+
except ValueError:
|
|
141
|
+
v1 = ""
|
|
142
|
+
try:
|
|
143
|
+
v2 = int(values[i])
|
|
144
|
+
except:
|
|
145
|
+
v2 = None
|
|
146
|
+
if v2 == v1:
|
|
147
|
+
values[i] = v2
|
|
148
|
+
elif v1 != "":
|
|
149
|
+
values[i] = v1
|
|
150
|
+
return values
|
|
151
|
+
|
|
152
|
+
def process_file(fp, DTYPE=np.float32):
|
|
153
|
+
"""
|
|
154
|
+
Read the file line by line, saving the parts objective (C, Q) and constraints (A, b)
|
|
155
|
+
"""
|
|
156
|
+
# read the problem name
|
|
157
|
+
name = read_line(fp)[0]
|
|
158
|
+
# problem type QML, QCL, etc
|
|
159
|
+
problem_type = read_line(fp)[0]
|
|
160
|
+
# type: minimize/maximize
|
|
161
|
+
sense = read_line(fp)[0].lower()
|
|
162
|
+
if problem_type not in ("QCL", "QIL", "QBL", "QML", "QGL", "QBB"):
|
|
163
|
+
raise ValueError(f"Problem type {problem_type} is not supported")
|
|
164
|
+
if sense not in ("minimize", "maximize"):
|
|
165
|
+
raise ValueError(f"Unknown problem sense: {sense}")
|
|
166
|
+
# variable count
|
|
167
|
+
num_variables = read_line(fp)[0]
|
|
168
|
+
if problem_type[2] not in ("B", "N"):
|
|
169
|
+
# number of constaints
|
|
170
|
+
num_linear_constraints = read_line(fp)[0]
|
|
171
|
+
else:
|
|
172
|
+
num_linear_constraints = 0
|
|
173
|
+
# number of quadratic terms in objective
|
|
174
|
+
if problem_type[0] != "L":
|
|
175
|
+
num_Q_entries = read_line(fp)[0]
|
|
176
|
+
J = np.zeros((num_variables, num_variables), dtype=DTYPE)
|
|
177
|
+
for i in range(num_Q_entries):
|
|
178
|
+
values = read_line(fp)
|
|
179
|
+
i, j, val = values
|
|
180
|
+
# Q.append({"i": i, "j": j, "val": val})
|
|
181
|
+
# if i==j:
|
|
182
|
+
val /= 2
|
|
183
|
+
J[i-1, j-1] = val
|
|
184
|
+
# J is the lower triangular portion of the Hessian
|
|
185
|
+
# print(J)
|
|
186
|
+
# print(np.tril(J, -1).T)
|
|
187
|
+
# J += np.tril(J, -1).T
|
|
188
|
+
# print(J)
|
|
189
|
+
J += J.T
|
|
190
|
+
J /= 2
|
|
191
|
+
else:
|
|
192
|
+
num_Q_entries = 0
|
|
193
|
+
J = None
|
|
194
|
+
# default for linear terms
|
|
195
|
+
default_linear = read_line(fp)[0]
|
|
196
|
+
# number of non default linear terms
|
|
197
|
+
non_default_entries = read_line(fp)[0]
|
|
198
|
+
C = default_linear * np.ones((num_variables,1), dtype=DTYPE)
|
|
199
|
+
for i in range(non_default_entries):
|
|
200
|
+
i, val = read_line(fp)
|
|
201
|
+
# C.append({"i": i, "val": val})
|
|
202
|
+
C[i-1, 0] = val
|
|
203
|
+
# objective constant
|
|
204
|
+
obj_const = read_line(fp)[0]
|
|
205
|
+
# number of linear terms in constraints
|
|
206
|
+
num_A_entries = read_line(fp)[0]
|
|
207
|
+
if np.isinf(num_A_entries):
|
|
208
|
+
num_A_entries = 0
|
|
209
|
+
A = np.zeros((num_linear_constraints, num_variables), dtype=DTYPE)
|
|
210
|
+
for idx in range(num_A_entries):
|
|
211
|
+
i, j, val = read_line(fp)[:3]
|
|
212
|
+
try:
|
|
213
|
+
A[i-1, j-1] = val
|
|
214
|
+
except IndexError:
|
|
215
|
+
raise IndexError(f"Incorrect index {(i,j)} for shape {A.shape}")
|
|
216
|
+
infty = read_line(fp)[0]
|
|
217
|
+
# default lhs value
|
|
218
|
+
# QPLIB uses LHS values to indicate constraint type: EQ or LE
|
|
219
|
+
default_cons = read_line(fp)[0]
|
|
220
|
+
# LHS value of 1 means EQ constraint
|
|
221
|
+
# -1 means LE constraint
|
|
222
|
+
num_non_default_cons = int(read_line(fp)[0])
|
|
223
|
+
cons = default_cons * np.ones((num_linear_constraints, 1), dtype=DTYPE)
|
|
224
|
+
for idx in range(num_non_default_cons):
|
|
225
|
+
i, val = read_line(fp)[:2]
|
|
226
|
+
cons[i-1, 0] = val
|
|
227
|
+
cons = ["EQ" if c == 1 else "LE" for c in cons]
|
|
228
|
+
# default rhs value
|
|
229
|
+
default_rhs = read_line(fp)[0]
|
|
230
|
+
# number of non-default right hand sides
|
|
231
|
+
num_rhs_entries = int(read_line(fp)[0])
|
|
232
|
+
b = default_rhs * np.ones((num_linear_constraints, 1), dtype=DTYPE)
|
|
233
|
+
for idx in range(num_rhs_entries):
|
|
234
|
+
i, val = read_line(fp)[:2]
|
|
235
|
+
b[i-1, 0] = val
|
|
236
|
+
# default lower bound
|
|
237
|
+
# variable upper bound
|
|
238
|
+
if problem_type[1] != "B":
|
|
239
|
+
var_lb = read_line(fp)[0]
|
|
240
|
+
# number of non-default lower bounds
|
|
241
|
+
num_non_default_lb = int(read_line(fp)[0])
|
|
242
|
+
lb = var_lb * np.ones((num_variables,1), dtype=DTYPE)
|
|
243
|
+
for idx in range(num_non_default_lb):
|
|
244
|
+
i, val = read_line(fp)[:2]
|
|
245
|
+
lb[i-1, 0] = val
|
|
246
|
+
var_ub = read_line(fp)[0]
|
|
247
|
+
# number of non-default upper bounds
|
|
248
|
+
num_non_default_ub = int(read_line(fp)[0])
|
|
249
|
+
ub = var_ub * np.ones((num_variables,1), dtype=DTYPE)
|
|
250
|
+
for idx in range(num_non_default_ub):
|
|
251
|
+
i, val = read_line(fp)[:2]
|
|
252
|
+
ub[i-1, 0] = val
|
|
253
|
+
else:
|
|
254
|
+
# binary variables
|
|
255
|
+
lb = np.zeros((num_variables,1), dtype=DTYPE)
|
|
256
|
+
var_ub = 1
|
|
257
|
+
ub = var_ub * np.ones((num_variables,1), dtype=DTYPE)
|
|
258
|
+
# get variable types
|
|
259
|
+
variable_types = {0: "REAL", 1: "INT"}
|
|
260
|
+
if problem_type[1] not in ("C", "B", "I"):
|
|
261
|
+
default_variable_type = read_line(fp)[0]
|
|
262
|
+
# number of non-default variable types
|
|
263
|
+
num_non_default_types = int(read_line(fp)[0])
|
|
264
|
+
types = [variable_types[default_variable_type] for i in range(num_variables)]
|
|
265
|
+
for idx in range(num_non_default_types):
|
|
266
|
+
i, val = read_line(fp)[:2]
|
|
267
|
+
val = int(val)
|
|
268
|
+
types[i-1] = variable_types[val]
|
|
269
|
+
elif problem_type[1] == "C":
|
|
270
|
+
default_variable_type = 0
|
|
271
|
+
types = [variable_types[default_variable_type] for i in range(num_variables)]
|
|
272
|
+
else:
|
|
273
|
+
default_variable_type = 1
|
|
274
|
+
types = [variable_types[default_variable_type] for i in range(num_variables)]
|
|
275
|
+
if problem_type[2] not in ["B", "N"]:
|
|
276
|
+
# default primal value in starting point
|
|
277
|
+
default_primal_value = read_line(fp)[0]
|
|
278
|
+
# number of non default primal values
|
|
279
|
+
num_non_default_primal_values = read_line(fp)[0]
|
|
280
|
+
if types == ["INT" for j in range(num_variables)]:
|
|
281
|
+
primal_dtype = np.int32
|
|
282
|
+
else:
|
|
283
|
+
primal_dtype = DTYPE
|
|
284
|
+
starting_primal = default_primal_value * np.ones((num_variables, 1), dtype=primal_dtype)
|
|
285
|
+
# read non-default primals
|
|
286
|
+
for idx in range(num_non_default_primal_values):
|
|
287
|
+
i, val = read_line(fp)[0]
|
|
288
|
+
starting_primal[i-1, 0] = val
|
|
289
|
+
# default constraint dual value in starting point
|
|
290
|
+
default_constraint_dual = read_line(fp)[0]
|
|
291
|
+
# number of non default constraint dual values
|
|
292
|
+
num_non_default_dual_values = read_line(fp)[0]
|
|
293
|
+
starting_constraint_dual = default_constraint_dual * np.ones(
|
|
294
|
+
(num_linear_constraints, 1), dtype=DTYPE)
|
|
295
|
+
# read non-default constraint duals
|
|
296
|
+
for idx in range(num_non_default_dual_values):
|
|
297
|
+
i, val = read_line(fp)[:2]
|
|
298
|
+
starting_constraint_dual[i-1, 0] = val
|
|
299
|
+
# default variable bound dual value in starting point
|
|
300
|
+
default_variable_bound_dual = read_line(fp)[0]
|
|
301
|
+
# number of non default variable bound dual values
|
|
302
|
+
num_non_default_bound_dual_values = read_line(fp)[0]
|
|
303
|
+
starting_bound_dual = default_variable_bound_dual * np.ones(
|
|
304
|
+
(num_variables, 1), dtype=DTYPE
|
|
305
|
+
)
|
|
306
|
+
# read non-default variable bound dual values
|
|
307
|
+
for idx in range(num_non_default_bound_dual_values):
|
|
308
|
+
i, val = read_line(fp)[:2]
|
|
309
|
+
starting_bound_dual[i-1, 0] = val
|
|
310
|
+
variable_names = [f"x{j}" for j in range(num_variables)]
|
|
311
|
+
# read variable names
|
|
312
|
+
try:
|
|
313
|
+
item = read_line(fp)
|
|
314
|
+
num_non_default_variable_names = item[0]
|
|
315
|
+
except IndexError:
|
|
316
|
+
print(item)
|
|
317
|
+
raise
|
|
318
|
+
for i in range(num_non_default_variable_names):
|
|
319
|
+
i, val = read_line(fp)[:2]
|
|
320
|
+
variable_names[i-1] = val
|
|
321
|
+
constraint_names = [f"c{i}" for i in range(num_linear_constraints)]
|
|
322
|
+
# read constraint names
|
|
323
|
+
num_non_default_constraint_names = read_line(fp)[0]
|
|
324
|
+
for i in range(num_non_default_constraint_names):
|
|
325
|
+
i, val = read_line(fp)[:2]
|
|
326
|
+
constraint_names[i-1] = val
|
|
327
|
+
del fp
|
|
328
|
+
return locals()
|
|
329
|
+
|
|
330
|
+
def file_to_model(fp : TextIO, DTYPE=np.float32) -> QGLModel:
|
|
331
|
+
|
|
332
|
+
parts = process_file(fp, DTYPE)
|
|
333
|
+
problem_type = parts["problem_type"]
|
|
334
|
+
if parts["sense"] == "maximize":
|
|
335
|
+
parts["C"] *= -1
|
|
336
|
+
parts["J"] *= -1
|
|
337
|
+
if problem_type == "QBB":
|
|
338
|
+
# QUBO
|
|
339
|
+
model = QBBModel(parts["C"], parts["J"])
|
|
340
|
+
else:
|
|
341
|
+
model = QGLModel(parts["C"], parts["J"], parts["A"], parts["b"])
|
|
342
|
+
if not np.isinf(parts["ub"]).any():
|
|
343
|
+
model.upper_bound = np.squeeze(parts["ub"].astype(np.int64))
|
|
344
|
+
else:
|
|
345
|
+
upper_bounds = np.array(parts["ub"])
|
|
346
|
+
upper_bounds[upper_bounds==np.inf] = 10000 # max for any value in Dirac-3
|
|
347
|
+
n = parts["C"].shape[0]
|
|
348
|
+
model.upper_bound = upper_bounds.reshape((n,))
|
|
349
|
+
return model
|
|
350
|
+
|
|
351
|
+
def file_to_polynomial(fp : TextIO, DTYPE=np.float32, penalty_multiplier=1) -> Tuple[List, List]:
|
|
352
|
+
"""
|
|
353
|
+
Create a pair of lists describing a polynomial that
|
|
354
|
+
represents the file contained in the qplib-formatted file
|
|
355
|
+
descriptor fp. Sets a guess for the sum constraint when constructing
|
|
356
|
+
the model, but it has no effect on the polynomial file output.
|
|
357
|
+
|
|
358
|
+
Parameters
|
|
359
|
+
:fp: File descriptor for qplib-formatted file
|
|
360
|
+
:DTYPE: Default numeric datatype for non-integer numeric values
|
|
361
|
+
|
|
362
|
+
Returns
|
|
363
|
+
:coefficients:, :indices:
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
parts = process_file(fp, DTYPE)
|
|
367
|
+
sum_constraint = float(np.sum(parts["b"]))
|
|
368
|
+
model = QGLModel(parts["C"], parts["J"], parts["A"], parts["b"])
|
|
369
|
+
model.penalty_multiplier = penalty_multiplier
|
|
370
|
+
model.upper_bound = np.array([sum_constraint for i in range(model.linear_objective.shape[0])])
|
|
371
|
+
logger.info("Dynamic Range: %f", model.dynamic_range)
|
|
372
|
+
polynomial = model.polynomial
|
|
373
|
+
coefficients = polynomial.coefficients
|
|
374
|
+
indices = polynomial.indices
|
|
375
|
+
return coefficients, indices, sum_constraint
|