-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmain.py
More file actions
219 lines (194 loc) · 6.86 KB
/
main.py
File metadata and controls
219 lines (194 loc) · 6.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
"""
--------------------------------------------------------------------------------
Description:
Primary Entrypoint into Ibis
Written by W.R. Jackson, Ben Bremer, Eric South
--------------------------------------------------------------------------------
"""
import os
from pathlib import Path
from typing import (
List,
Optional,
)
import pkg_resources
import typer
from rich.console import Console
from ibis.datastucture import (
NetworkGeneticCircuit,
LogicNetwork,
)
from ibis.ingress import parse_sbol_xml_tree
from ibis.scoring import (
get_requirement_map,
get_scorer_map,
get_scorer_description,
generate_template_yaml,
get_available_scorers,
validate_input_file,
generate_requirement_classes,
)
from ibis.utility import (
plot_cell_edgelist,
)
console = Console()
app = typer.Typer()
# ----------------------- Command Line Utility Functions -----------------------
def name_callback(value: str) -> str:
"""
Checks whether the first input argument is a valid solver.
"""
score_map = get_requirement_map()
if value.lower() not in score_map.keys():
raise typer.BadParameter("Solver not identified")
return value
def solver_details_callback(value: bool):
"""
Provides a brief description of each solver.
"""
if value:
typer.secho("Available Solvers...", fg=typer.colors.GREEN)
for line in get_scorer_description():
typer.echo(f"{line}")
raise typer.Exit()
def version_callback(value: bool):
"""
Returns version of scoring-project when the --version or -v options are called.
"""
current_ver = pkg_resources.get_distribution("genetic-ibis").version
if value:
typer.echo(f"CLI Version: {current_ver}")
raise typer.Exit()
def complete_name(incomplete: str):
score_map = get_requirement_map()
for name, help_text in score_map:
if name.startswith(incomplete):
yield name, help_text
# ---------------------------- Application Commands ----------------------------
@app.command()
def generate_template(
requested_solvers: Optional[List[str]] = typer.Option(None),
output_fn: Optional[str] = "input.yml",
):
"""
Generates a template input file for the requested solvers.
"""
if requested_solvers is not None:
typer.echo(f"Generating template yaml file for all available solvers...")
else:
typer.echo(f"Generating template yaml file for the following solvers:")
for solver in requested_solvers:
typer.echo(
f" - {solver}",
)
generate_template_yaml(
requested_scorers=requested_solvers,
output_fn=output_fn,
)
typer.echo(f"Template File {output_fn} written to {os.getcwd()}")
@app.command()
def score(
requested_solvers: List[str] = typer.Argument(
...,
help="The Input Solvers",
),
sbol_filepath: str = typer.Option(
os.path.join(os.getcwd(), "tests", "test_cello", "example_and_gate.xml"),
help="Filepath: location of the SBOL file that constitutes the genetic "
"circuit",
),
parameter_filepath: str = typer.Option(
os.path.join(os.getcwd(), "input.yml"),
help="Filepath: location of the SBOL file that constitutes the genetic "
"circuit",
),
out_filepath: str = typer.Option(
"output", help="Filepath: location to write the output of the solved function"
),
):
"""
Takes an SBOL file, evaluates the quality of a genetic circuit, and then outputs performance metrics.
"""
# We take in our input values and normalize them.
requested_solvers = [solver.lower() for solver in requested_solvers]
available_solvers = get_available_scorers()
for solver in requested_solvers:
if solver not in available_solvers:
raise RuntimeError(
f"Unable to find a scorer with the name {solver}, please "
f"investigate."
)
# We then ensure that our filepaths are correct so we're not breaking down
# the line.
if not os.path.isfile(parameter_filepath):
raise RuntimeError(
f"Unable to locate input file {parameter_filepath}. Please Investigate."
)
# We assume that we'll have multiple forms of output, so what we're doing is
# validating the output is just an extant directory. If not, we try to
# generate one.
if not os.path.isdir(out_filepath):
os.mkdir(out_filepath)
# We now need to ensure that our files, while extant, contain the information
# required to compute the score. Individual errors are propagated via the
# function.
if not validate_input_file(
input_fp=parameter_filepath,
requested_scorers=requested_solvers,
):
raise RuntimeError(f"Input File failed to pass validation. Exiting.")
# We should now be good to go so we just move forward with parsing the input
# data and sending it off to the requested solvers.
gc = parse_sbol_xml_tree(sbol_filepath)
network = NetworkGeneticCircuit(gc)
requested_requirements = generate_requirement_classes(
parameter_filepath, requested_solvers
)
scoring_map = get_scorer_map()
for solver, requirement in zip(requested_solvers, requested_requirements):
solver_class = scoring_map[solver]
try:
solver_obj = solver_class(network, requirement)
except TypeError:
solver_obj = solver_class(requirement)
solver_obj.score()
solver_obj.report()
@app.command()
def synthesize_logic_graph(
input_fp: str,
visualize_graph: bool = True,
save_edgelist: bool = True,
output_fp: str = None,
):
if not os.path.exists(input_fp):
raise RuntimeError(f'Unable to find {input_fp}. Please investigate.')
fn = Path(input_fp).stem
if Path(input_fp).suffix != '.v':
raise RuntimeError(
f'Input File {fn} does not seem to be a verilog '
f'file. Please investigate.'
)
lnetwork = LogicNetwork(verilog_fp=input_fp)
# Maybe I put a truth table here?
if visualize_graph:
lnetwork.plot_graph(save_file=True, output_filename=f'{fn}.jpg')
if save_edgelist:
if output_fp is None:
output_fp = f'{fn}.edgelist'
lnetwork.save_netlist(output_fp=output_fp)
lnetwork.cleanup()
@app.command()
def visualize_edgelist(
input_fp: str,
):
if not os.path.exists(input_fp):
raise RuntimeError(f'Unable to find {input_fp}. Please investigate.')
fn = Path(input_fp).stem
if Path(input_fp).suffix != '.edgelist':
raise RuntimeError(
f'Input File {fn} does not seem to be a verilog '
f'file. Please investigate.'
)
plot_cell_edgelist(input_fp)
if __name__ == "__main__":
app()