Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tsp report #536

Open
wants to merge 98 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
ce04099
first version of tsp report + changes (many more requirements added)
pchtsp May 17, 2024
dad9f0e
add how-to reports to README
pchtsp May 17, 2024
c6f4c0f
added documentation on developing reports
pchtsp May 17, 2024
5780bff
unsuccessful tests with quarto library to call quarto and generate re…
pchtsp Jun 7, 2024
1b7378d
Merge branch 'master' into tsp_report
pchtsp Jun 7, 2024
f6b4704
added reports model, endpoint, schemas. Each report has an execution_…
pchtsp Jun 11, 2024
17e9173
fixed some wrong comments
pchtsp Jun 11, 2024
4496e11
migrations to database for reports
pchtsp Jun 12, 2024
a3bcdaf
pass executions tests
pchtsp Jun 12, 2024
82f0aa9
delete airflow dependency
pchtsp Jun 12, 2024
f30ee6d
added some additional I/O methods to the Experiment and a `generate_r…
pchtsp Jun 21, 2024
0b1619f
now it's possible to run the create the report from python using a js…
pchtsp Jun 21, 2024
409662f
New activate_dags (#543)
ggsdc Jun 28, 2024
9f83a97
Fixed numpy and pandas conoined error
ggsdc Jun 28, 2024
5c0fb2d
make tests valid with env. var CF_ALARMS_ENDPOINT=0
pchtsp Jun 28, 2024
59ad52b
Merge remote-tracking branch 'origin/tsp_report' into tsp_report
pchtsp Jun 28, 2024
132a0c3
added quarto to github actions
pchtsp Jun 28, 2024
e0737aa
quarto is needed in test_dags
pchtsp Jun 28, 2024
83610f8
Small adjustments to pass unit tests on local and on github actions
ggsdc Jun 28, 2024
0427605
some working tests on reports.
pchtsp Jul 1, 2024
ee96b79
Merge remote-tracking branch 'origin/tsp_report' into tsp_report
pchtsp Jul 1, 2024
4050939
Adjustments to file storage.
ggsdc Jul 2, 2024
082eff9
Added test for main get
ggsdc Jul 2, 2024
3da8771
fix uploading tests: add static and use absolute path for e.v. UPLOAD…
pchtsp Jul 3, 2024
0be825a
some comments
pchtsp Jul 3, 2024
3a47e13
Added some more funtionalities
ggsdc Jul 3, 2024
a6ecb0d
added endpoint to client and finished code in dag.
pchtsp Jul 3, 2024
9268ac9
Merge remote-tracking branch 'origin/tsp_report' into tsp_report
pchtsp Jul 3, 2024
5b566f9
Merge branch 'develop' into tsp_report
ggsdc Jul 15, 2024
b8d711f
Small change for CodeQL
ggsdc Jul 15, 2024
35d9cc8
Some more checks on path building to restrict where the reports can b…
ggsdc Jul 15, 2024
b1d79db
Made delete endpoint to delete report file.
ggsdc Jul 16, 2024
95535bf
Added test for creation of report
ggsdc Jul 16, 2024
6077e20
Fixed wrong path
ggsdc Jul 16, 2024
0171fd8
added some unittests and integration tests for reports (incomplete)
pchtsp Jul 16, 2024
039cf08
Merge remote-tracking branch 'origin/tsp_report' into tsp_report
pchtsp Jul 16, 2024
bdfb141
Modified default location of reports.
ggsdc Jul 16, 2024
b2ca5c1
More fixes to tests
ggsdc Jul 16, 2024
778aad2
Modified cornflow dockerfile
ggsdc Jul 16, 2024
68f4989
Modified default location of reports.
ggsdc Jul 16, 2024
824d472
Some print and error catching to get the error on Github actions
ggsdc Jul 17, 2024
4853159
More debugging
ggsdc Jul 17, 2024
3529616
Modified the way the error is built to be able to decode it as a JSON
ggsdc Jul 17, 2024
fba7418
The problem was that the destination folder for the files was not cor…
ggsdc Jul 17, 2024
8a2502a
Added test for the PUT of reports
ggsdc Jul 17, 2024
a3e5871
Changed the way get one report reports back the name of the report an…
ggsdc Jul 17, 2024
f955e62
Fixed status code on failing test
ggsdc Jul 17, 2024
c698a17
Fixed error on client test
ggsdc Jul 17, 2024
35913d5
Added tests for base client
ggsdc Jul 17, 2024
e4bdf9e
Added some typing
ggsdc Jul 17, 2024
ffcef7c
integration tests passing for tsp and timer reports
pchtsp Jul 18, 2024
63363e3
Merge remote-tracking branch 'origin/tsp_report' into tsp_report
pchtsp Jul 18, 2024
06dd07c
added more time to tests for github actions
pchtsp Jul 19, 2024
b9a97c5
reports now can be created and edited with a file by the service_user…
pchtsp Jul 24, 2024
8236957
(previous was an incomplete commit)
pchtsp Jul 24, 2024
862f8c4
minor fixes to pass failing tests
pchtsp Jul 24, 2024
fe26094
another failing test
pchtsp Jul 24, 2024
eba17e4
fixed some errors in tests. some print statements for debugging
pchtsp Jul 24, 2024
9452cbc
Changes to Dockerfile toc reate the reports folder on the container
ggsdc Jul 26, 2024
ecdebff
Modified workflows and order of installation of cornflow-client depen…
ggsdc Jul 26, 2024
8a017c9
Undo change on DOCKERFILE
ggsdc Jul 26, 2024
45e2988
Debug log to have the name on the test
ggsdc Jul 26, 2024
4ca157b
Activated debug mode on testing configuration
ggsdc Jul 26, 2024
65eafb2
Added error logs on log in
ggsdc Jul 26, 2024
de3f636
Changed name of service user on cornflow integration testing yaml
ggsdc Jul 26, 2024
ec91924
Some small changes to tests to have them more organized
ggsdc Jul 26, 2024
7d0e2f5
Merge branch 'develop' into tsp_report
ggsdc Jul 26, 2024
9990309
Merge branch 'refs/heads/develop' into tsp_report
ggsdc Jul 26, 2024
698495a
Merge remote-tracking branch 'origin/tsp_report' into tsp_report
ggsdc Jul 26, 2024
94e871c
take out prints
pchtsp Jul 29, 2024
fb529b0
update swagger REST API doc
pchtsp Jul 29, 2024
37cf3a2
graph coloring report
pchtsp Jul 31, 2024
a89c67f
fixed all tests
pchtsp Jul 31, 2024
8fbd570
take out hexaly from requirements
pchtsp Jul 31, 2024
6c98216
Fixed errors that caused test to fail
ggsdc Aug 2, 2024
ad57525
fix the report schema errors
pchtsp Aug 2, 2024
a5aea1a
Bump version for new client alpha
ggsdc Aug 2, 2024
8e51d58
Merge branch 'refs/heads/develop' into tsp_report
ggsdc Aug 2, 2024
c1d8803
Updated workflows for publishing
ggsdc Aug 2, 2024
6b9ae3a
Merge branch 'develop' into tsp_report
ggsdc Aug 2, 2024
c464839
Bump cornflow and airflow versions for new image building
ggsdc Aug 5, 2024
5a80ae8
Merge remote-tracking branch 'origin/tsp_report' into tsp_report
ggsdc Aug 5, 2024
d1beb92
change in where to get the get_cmap function from recent versions of …
pchtsp Aug 5, 2024
74077ba
fixed schema modification for reports
pchtsp Aug 7, 2024
31a2f54
fix: now we do not move the report, we just return the path to it.
pchtsp Aug 7, 2024
d055170
Bump cornflow-client version
ggsdc Aug 8, 2024
18871c6
Bump version for new client alpha
ggsdc Aug 8, 2024
495537e
Bump cornflow-client version on requirements file
ggsdc Aug 8, 2024
6845f53
Fixed error on requirements file
ggsdc Aug 8, 2024
bae1109
complete example of sudoku
pchtsp Aug 12, 2024
9b044db
changes while testing the windproblem
pchtsp Aug 15, 2024
9621e26
Merge branch 'sudoku' into tsp_report
pchtsp Aug 15, 2024
31c5c06
fixes to cornflowclient + tests for WindProblem
pchtsp Aug 16, 2024
0228868
take out github repo link + bump version of cornflowclient
pchtsp Aug 16, 2024
5767e21
added already deployed of cornflowclient and github link to installat…
pchtsp Aug 16, 2024
ec4f332
sudoku changes
pchtsp Sep 20, 2024
c4753aa
improve README + filter tests with flag
pchtsp Sep 20, 2024
ca1a24d
minor fixes
pchtsp Sep 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 32 additions & 14 deletions cornflow-dags/DAG/activate_dags.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so the main issue is that this new version of activate dags seems like it does not work properly, or at least I am not able to make it work (for now) on my machine

Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import cornflow_client.airflow.dag_utilities as utils
from airflow import DAG
from airflow.operators.python import PythonOperator
from airflow.secrets.environment_variables import EnvironmentVariablesBackend
from airflow.decorators import dag, task
from airflow.models.baseoperator import chain
from airflow.exceptions import AirflowSkipException

from update_all_schemas import get_new_apps


def create_dag(app):
def solve(**kwargs):
return utils.cf_solve_app(app, EnvironmentVariablesBackend(), **kwargs)

if app.default_args is not None:
default_args = app.default_args
Expand All @@ -19,26 +19,44 @@ def solve(**kwargs):
if app.extra_args is not None:
kwargs = app.extra_args

dag = DAG(
@dag(
app.name,
description=app.description,
default_args=default_args,
schedule_interval=None,
tags=["model"],
**kwargs
)
with dag:
notify = getattr(app, "notify", True)
if not notify:
t1 = PythonOperator(task_id=app.name, python_callable=solve)
else:
t1 = PythonOperator(
task_id=app.name,
python_callable=solve,
on_failure_callback=utils.callback_email,
def taskflow_dag():
@task
def solve_app():
def solve(**kwargs):
return utils.cf_solve_app(app, EnvironmentVariablesBackend(), **kwargs)

notify = getattr(app, "notify", True)
if not notify:
return PythonOperator(task_id=app.name, python_callable=solve)
else:
return PythonOperator(
task_id=app.name,
python_callable=solve,
on_failure_callback=utils.callback_email,
)

@task
def run_report():
def run(**kwargs):
return utils.cf_report(app, EnvironmentVariablesBackend(), **kwargs)

file_name = PythonOperator(
task_id=app.name + "_report", python_callable=run
)
return dict(file_name=file_name)

return dag
# Define dependencies and call task functions
chain(solve_app(), run_report())

return taskflow_dag


for app in get_new_apps():
Expand Down
70 changes: 57 additions & 13 deletions cornflow-dags/DAG/tsp/core/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,35 @@
from .instance import Instance
from .solution import Solution

import json, tempfile
from quarto import render


class Experiment(ExperimentCore):
schema_checks = load_json(
os.path.join(os.path.dirname(__file__), "../schemas/solution_checks.json")
)

def to_dict(self) -> dict:
return dict(instance=self.instance.to_dict(), solution=self.solution.to_dict())

@classmethod
def from_dict(cls, data: dict):
return cls(
Instance.from_dict(data["instance"]), Solution.from_dict(data["solution"])
)

@classmethod
def from_json(cls, path: str) -> "Experiment":
with open(path, "r") as f:
data_json = json.load(f)
return cls.from_dict(data_json)

def to_json(self, path: str) -> None:
data = self.to_dict()
with open(path, "w") as f:
json.dump(data, f, indent=4, sort_keys=True)

@property
def instance(self) -> Instance:
return super().instance
Expand All @@ -25,31 +48,52 @@ def solution(self, value):
self._solution = value

def get_objective(self) -> float:
# if solution is empty, we return 0
if len(self.solution.data["route"]) == 0:
return 0
# we get a sorted list of nodes by position
route = (
TupList(self.solution.data["route"])
.sorted(key=lambda v: v["pos"])
.vapply(lambda v: v["node"])
)
weight = {(el["n1"], el["n2"]): el["w"] for el in self.instance.data["arcs"]}
# we sum all arcs in the solution
return (
sum([weight[n1, n2] for n1, n2 in zip(route, route[1:])])
+ weight[route[-1], route[0]]
)
arcs = self.solution.get_used_arcs()

# we sum all arc weights in the solution
return sum(self.get_used_arc_weights().values())

def get_used_arc_weights(self) -> dict:
arcs = self.solution.get_used_arcs()
weight = self.instance.get_indexed_arcs()
return arcs.to_dict(None).kapply(lambda k: weight[k]["w"])

def check_missing_nodes(self):
nodes_in = TupList(v["n1"] for v in self.instance.data["arcs"]).to_set()
nodes_out = TupList(n["node"] for n in self.solution.data["route"]).to_set()
return [{"node": n} for n in (nodes_in - nodes_out)]
return TupList({"node": n} for n in (nodes_in - nodes_out))

def check_missing_positions(self):
nodes_in = TupList(v["n1"] for v in self.instance.data["arcs"]).to_set()
positions = TupList(n["pos"] for n in self.solution.data["route"]).to_set()
return [{"position": p} for p in set(range(len(nodes_in))) - positions]
return TupList({"position": p} for p in set(range(len(nodes_in))) - positions)

def check_solution(self, *args, **kwargs) -> SuperDict:
return SuperDict(
missing_nodes=self.check_missing_nodes(),
missing_positions=self.check_missing_positions(),
)

def generate_report(self, report_path: str, report_name="report") -> None:
# a user may give the full "report.qmd" name.
# We want to take out the extension
report_base = os.path.splitext(report_name)[0]
path_without_ext = os.path.join(
os.path.dirname(__file__), "../report/", report_base
)
path_to_qmd = path_without_ext + ".qmd"
path_to_output = path_without_ext + ".html"
with tempfile.TemporaryDirectory() as tmp:
path = os.path.join(tmp, "experiment.json")
# write a json with instance and solution to temp file
self.to_json(path)
# pass the path to the report to render
# it generates a report with path = path_to_output
render(input=path_to_qmd, execute_params=dict(file_name=path))
# quarto always writes the report in the .qmd directory.
# thus, we need to move it where we want to:
os.replace(path_to_output, report_path)
29 changes: 25 additions & 4 deletions cornflow-dags/DAG/tsp/core/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,24 @@
from cornflow_client import InstanceCore, get_empty_schema
from cornflow_client.core.tools import load_json
from pytups import TupList, SuperDict
import networkx as nx


class Instance(InstanceCore):
schema = load_json(os.path.join(os.path.dirname(__file__), "../schemas/input.json"))
schema_checks = get_empty_schema()

def __init__(self, data):
def __init__(self, data: dict):
data = SuperDict(data)
data["arcs"] = TupList(data["arcs"])
super().__init__(data)

@classmethod
def from_tsplib_file(cls, path):
def from_tsplib_file(cls, path: str):
return cls.from_tsplib95(tsp.load(path))

@classmethod
def from_tsplib95(cls, problem):
def from_tsplib95(cls, problem: tsp.models.StandardProblem):
nodes = list(problem.get_nodes())
edge_to_dict = lambda e: dict(
n1=nodes[e[0]], n2=nodes[e[1]], w=problem.get_weight(*e)
Expand All @@ -29,7 +30,7 @@ def from_tsplib95(cls, problem):
return cls(dict(arcs=arcs))

def to_tsplib95(self):
arcs = TupList(self.data["arcs"])
arcs = TupList(self.get_arcs())
nodes = (arcs.take("n1") + arcs.take("n2")).unique()
pos = {k: v for v, k in enumerate(nodes)}
arc_dict = arcs.to_dict(
Expand Down Expand Up @@ -57,7 +58,27 @@ def to_tsplib95(self):
edge_weight_format=edge_weight_format,
edge_weights=arc_weights,
)

return tsp.models.StandardProblem(**dict_data)

def get_arcs(self) -> TupList:
return self.data["arcs"]

def get_indexed_arcs(self) -> TupList:
return self.data["arcs"].to_dict(
result_col=None, indices=["n1", "n2"], is_list=False
)

def get_nodes(self) -> TupList:
arcs = self.get_arcs()
return (arcs.take("n1") + arcs.take("n2")).unique()

def get_graph(self) -> nx.Graph:
nodes = self.get_nodes()
arcs = self.get_arcs()
G = nx.DiGraph()
for node in nodes:
G.add_node(node)
for arc in arcs:
G.add_edge(arc["n1"], arc["n2"], weight=arc["w"])
return G
16 changes: 16 additions & 0 deletions cornflow-dags/DAG/tsp/core/solution.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import os
from cornflow_client import SolutionCore
from cornflow_client.core.tools import load_json
import pytups as pt


class Solution(SolutionCore):
schema = load_json(
os.path.join(os.path.dirname(__file__), "../schemas/output.json")
)

def get_route(self):
return self.data["route"]

def get_tour(self):
return pt.TupList(self.get_route()).sorted(key=lambda v: v["pos"]).take("node")

def get_used_arcs(self):
tour = self.get_tour()

if len(tour) <= 1:
return pt.TupList()
edges = pt.TupList(zip(tour, tour[1:]))
edges.append((tour[-1], tour[0]))
return edges
1 change: 1 addition & 0 deletions cornflow-dags/DAG/tsp/report/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.quarto/
Loading
Loading