eqc-bio 0.1.2__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_bio/protein_design/__init__.py +30 -0
- eqc_bio/protein_design/base.py +168 -0
- eqc_bio/protein_design/fixed_backbone.py +723 -0
- eqc_bio/protein_design/rotamers.py +337 -0
- eqc_bio/protein_design/sidechains.py +207 -0
- eqc_bio/protein_design/viewer.py +281 -0
- eqc_bio/radiotherapy/__init__.py +1 -0
- eqc_bio/radiotherapy/proton_beam.py +638 -0
- eqc_bio/utils/__init__.py +3 -0
- eqc_bio/utils/general.py +23 -0
- eqc_bio/utils/graph.py +41 -0
- eqc_bio-0.1.2.dist-info/METADATA +143 -0
- eqc_bio-0.1.2.dist-info/RECORD +16 -0
- eqc_bio-0.1.2.dist-info/WHEEL +5 -0
- eqc_bio-0.1.2.dist-info/licenses/LICENSE.txt +202 -0
- eqc_bio-0.1.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# (C) Quantum Computing Inc., 2024.
|
|
2
|
+
from .fixed_backbone import ProteinDesignFixed
|
|
3
|
+
from .viewer import (
|
|
4
|
+
build_designed_pdb,
|
|
5
|
+
get_backbone_dihedrals,
|
|
6
|
+
get_rotamer_angles,
|
|
7
|
+
view_pdb,
|
|
8
|
+
)
|
|
9
|
+
from .rotamers import (
|
|
10
|
+
download_rotamer_library,
|
|
11
|
+
load_rotamer_library,
|
|
12
|
+
parse_dunbrack_library,
|
|
13
|
+
resolve_rotamer_library,
|
|
14
|
+
check_rotamer_counts,
|
|
15
|
+
get_chi_angles,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"ProteinDesignFixed",
|
|
20
|
+
"build_designed_pdb",
|
|
21
|
+
"get_backbone_dihedrals",
|
|
22
|
+
"get_rotamer_angles",
|
|
23
|
+
"view_pdb",
|
|
24
|
+
"download_rotamer_library",
|
|
25
|
+
"load_rotamer_library",
|
|
26
|
+
"parse_dunbrack_library",
|
|
27
|
+
"resolve_rotamer_library",
|
|
28
|
+
"check_rotamer_counts",
|
|
29
|
+
"get_chi_angles",
|
|
30
|
+
]
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import warnings
|
|
4
|
+
import logging
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
from eqc_models.base import ModelSolver, SolutionResults
|
|
9
|
+
from eqc_models.solvers.qciclient import Dirac3CloudSolver
|
|
10
|
+
from eqc_models import QuadraticModel
|
|
11
|
+
from eqc_bio.utils import timer
|
|
12
|
+
from eqc_bio.utils import metis_partition
|
|
13
|
+
|
|
14
|
+
warnings.filterwarnings("ignore")
|
|
15
|
+
log = logging.getLogger(name=__name__)
|
|
16
|
+
|
|
17
|
+
# Seconds per unit for SolutionResults.time_units
|
|
18
|
+
TIME_UNIT_SECONDS = {"ns": 1e-9, "s": 1.0}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ProteinDesign:
|
|
22
|
+
def __init__(self, solver: ModelSolver = None):
|
|
23
|
+
# Defaults to a cloud solver configured from QCI_API_URL/QCI_TOKEN
|
|
24
|
+
self.solver = solver
|
|
25
|
+
|
|
26
|
+
def get_dirac3_time(self, results: SolutionResults):
|
|
27
|
+
"""Return the device time of a solve in seconds."""
|
|
28
|
+
device_time = results.device_time
|
|
29
|
+
if device_time is None:
|
|
30
|
+
log.warning("Device timing not available for this solve")
|
|
31
|
+
return 0.0
|
|
32
|
+
|
|
33
|
+
return np.sum(device_time) * TIME_UNIT_SECONDS[results.time_units]
|
|
34
|
+
|
|
35
|
+
def run_dirac3(self, J, C, sum_constraint, n_vars, num_samples):
|
|
36
|
+
model = QuadraticModel(C, J)
|
|
37
|
+
model.upper_bound = np.array([1] * n_vars)
|
|
38
|
+
|
|
39
|
+
solver = self.solver
|
|
40
|
+
if solver is None:
|
|
41
|
+
solver = Dirac3CloudSolver()
|
|
42
|
+
|
|
43
|
+
results = solver.solve(
|
|
44
|
+
model,
|
|
45
|
+
sum_constraint=sum_constraint,
|
|
46
|
+
relaxation_schedule=self.relaxation_schedule,
|
|
47
|
+
num_samples=num_samples,
|
|
48
|
+
mean_photon_number=self.mean_photon_number,
|
|
49
|
+
quantum_fluctuation_coefficient=self.quantum_fluctuation_coefficient,
|
|
50
|
+
)
|
|
51
|
+
log.info(results)
|
|
52
|
+
|
|
53
|
+
dirac3_time = self.get_dirac3_time(results)
|
|
54
|
+
|
|
55
|
+
return results, dirac3_time
|
|
56
|
+
|
|
57
|
+
def run_dirac3_iterative(
|
|
58
|
+
self,
|
|
59
|
+
J,
|
|
60
|
+
C,
|
|
61
|
+
sum_constraint,
|
|
62
|
+
n_vars,
|
|
63
|
+
positions,
|
|
64
|
+
position_graph,
|
|
65
|
+
position_index_hash,
|
|
66
|
+
):
|
|
67
|
+
batch_count = int(round(n_vars / self.batch_size))
|
|
68
|
+
|
|
69
|
+
X = np.random.rand(n_vars)
|
|
70
|
+
|
|
71
|
+
if sum_constraint is not None:
|
|
72
|
+
X = X * (sum_constraint / np.sum(X))
|
|
73
|
+
|
|
74
|
+
tmp_group_list = metis_partition(position_graph, k=batch_count)
|
|
75
|
+
tmp_hash = dict(enumerate(positions))
|
|
76
|
+
position_groups = []
|
|
77
|
+
for tmp_group in tmp_group_list:
|
|
78
|
+
position_groups.append([tmp_hash[item] for item in tmp_group])
|
|
79
|
+
|
|
80
|
+
groups = []
|
|
81
|
+
for position_group in position_groups:
|
|
82
|
+
tmp_list = []
|
|
83
|
+
for position in position_group:
|
|
84
|
+
tmp_list += position_index_hash[position]
|
|
85
|
+
groups.append(tmp_list)
|
|
86
|
+
|
|
87
|
+
sols = []
|
|
88
|
+
energies = []
|
|
89
|
+
dirac3_time = 0.0
|
|
90
|
+
for epoch in range(self.n_epochs):
|
|
91
|
+
order = np.random.permutation(batch_count)
|
|
92
|
+
for i in order:
|
|
93
|
+
idx_p = groups[i]
|
|
94
|
+
idx_q = np.setdiff1d(np.arange(n_vars), idx_p)
|
|
95
|
+
Cp = C[idx_p]
|
|
96
|
+
Cq = C[idx_q]
|
|
97
|
+
Xq = X[idx_q]
|
|
98
|
+
Jpp = J[np.ix_(idx_p, idx_p)]
|
|
99
|
+
Jpq = J[np.ix_(idx_p, idx_q)]
|
|
100
|
+
Jqp = J[np.ix_(idx_q, idx_p)]
|
|
101
|
+
Jqq = J[np.ix_(idx_q, idx_q)]
|
|
102
|
+
|
|
103
|
+
tmp_v = 2 * Jpq @ Xq
|
|
104
|
+
tmp_v = tmp_v.reshape((tmp_v.shape[0], 1))
|
|
105
|
+
tmp_C = Cp + tmp_v
|
|
106
|
+
tmp_J = Jpp
|
|
107
|
+
|
|
108
|
+
if sum_constraint is not None:
|
|
109
|
+
tmp_sum_constraint = sum_constraint - np.sum(Xq)
|
|
110
|
+
else:
|
|
111
|
+
tmp_sum_constraint = None
|
|
112
|
+
|
|
113
|
+
sub_response, sub_dirac3_time = self.run_dirac3(
|
|
114
|
+
tmp_J,
|
|
115
|
+
tmp_C,
|
|
116
|
+
max(1.0, tmp_sum_constraint),
|
|
117
|
+
tmp_C.shape[0],
|
|
118
|
+
self.n_samples,
|
|
119
|
+
)
|
|
120
|
+
dirac3_time += sub_dirac3_time
|
|
121
|
+
|
|
122
|
+
sub_sols = sub_response.solutions
|
|
123
|
+
|
|
124
|
+
glob_loc_hash = {}
|
|
125
|
+
for loc_k, glob_k in enumerate(idx_p):
|
|
126
|
+
glob_loc_hash[glob_k] = loc_k
|
|
127
|
+
|
|
128
|
+
for sub_sol in sub_sols:
|
|
129
|
+
sub_sol = np.array(sub_sol)
|
|
130
|
+
feasible_flag = True
|
|
131
|
+
for position in position_groups[i]:
|
|
132
|
+
glob_indexes = position_index_hash[position]
|
|
133
|
+
loc_indexes = [
|
|
134
|
+
glob_loc_hash[item] for item in glob_indexes
|
|
135
|
+
]
|
|
136
|
+
if np.sum(sub_sol[loc_indexes]) == 0:
|
|
137
|
+
feasible_flag = False
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
if feasible_flag:
|
|
141
|
+
break
|
|
142
|
+
|
|
143
|
+
Xp = sub_sol
|
|
144
|
+
fct = np.sum(Xp)
|
|
145
|
+
if fct != 0:
|
|
146
|
+
fct = tmp_sum_constraint / fct
|
|
147
|
+
Xp = fct * np.array(Xp)
|
|
148
|
+
X[idx_p] = Xp
|
|
149
|
+
|
|
150
|
+
sol = np.array(X)
|
|
151
|
+
energy = sol.T @ J @ sol + sol.T @ C
|
|
152
|
+
energy = energy[0]
|
|
153
|
+
|
|
154
|
+
sols.append(sol)
|
|
155
|
+
energies.append(energy)
|
|
156
|
+
|
|
157
|
+
# Device time is summed over the sub-solves and returned separately
|
|
158
|
+
results = SolutionResults(
|
|
159
|
+
solutions=np.array(sols),
|
|
160
|
+
energies=np.array(energies),
|
|
161
|
+
counts=np.ones(len(sols)),
|
|
162
|
+
objectives=None,
|
|
163
|
+
run_time=None,
|
|
164
|
+
preprocessing_time=None,
|
|
165
|
+
postprocessing_time=None,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return results, dirac3_time
|