phimaker 0.3.0__cp313-none-win_amd64.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.
phimaker/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from .phimaker import compute_ensemble, compute_ensemble_cylinder, zero_overlap
2
+
3
+ __all__ = [ "compute_ensemble", "compute_ensemble_cylinder", "zero_overlap" ]
4
+ # from ._washboard_interface import WashboardServer, build_washboard_object
@@ -0,0 +1,199 @@
1
+ from wsgiref.simple_server import make_server
2
+ from pyramid.config import Configurator
3
+ from pyramid.view import view_config
4
+ from pyramid.response import FileResponse
5
+ from pyramid.response import Response
6
+ from pathlib import Path
7
+ import threading
8
+ import signal
9
+ from contextlib import redirect_stdout
10
+ import io
11
+ import webbrowser
12
+
13
+
14
+ def build_washboard_object(
15
+ dgms, max_diagram_dim, truncation, dimensions, entrance_times
16
+ ):
17
+ def make_pairing_obj(dgm, additional_max_dim=0, dim_shift=0):
18
+ pairings = {"paired": list(dgm.paired), "unpaired": list(dgm.unpaired)}
19
+ pairings = remove_trivial_pairings(pairings)
20
+ pairings = filter_by_dimension(pairings, additional_max_dim, dim_shift)
21
+ pairings = group_by_dimension(pairings, additional_max_dim, dim_shift)
22
+ return pairings
23
+
24
+ # Remove pairings with 0 lifetime
25
+ def remove_trivial_pairings(pairings):
26
+ new_pairings = []
27
+ for pairing in pairings["paired"]:
28
+ if entrance_times[pairing[0]] == entrance_times[pairing[1]]:
29
+ continue
30
+ new_pairings.append(pairing)
31
+ pairings["paired"] = new_pairings
32
+ return pairings
33
+
34
+ # Remove pairings in too high a dimension
35
+ def filter_by_dimension(pairings, additional_max_dim, dim_shift):
36
+ new_paired = []
37
+ new_unpaired = []
38
+ for pairing in pairings["paired"]:
39
+ dim = dimensions[pairing[0]] - dim_shift
40
+ if dim > max_diagram_dim + additional_max_dim:
41
+ continue
42
+ new_paired.append(pairing)
43
+ for unpaired in pairings["unpaired"]:
44
+ dim = dimensions[unpaired] - dim_shift
45
+ # Only add additional_max_dim to pairings
46
+ if dim > max_diagram_dim:
47
+ continue
48
+ new_unpaired.append(unpaired)
49
+ pairings["paired"] = new_paired
50
+ pairings["unpaired"] = new_unpaired
51
+ return pairings
52
+
53
+ def group_by_dimension(pairings, additional_max_dim, dim_shift):
54
+ diagrams_by_dimension = [
55
+ [] for _ in range(max_diagram_dim + additional_max_dim + 1)
56
+ ]
57
+ for pairing in pairings["paired"]:
58
+ dim = dimensions[pairing[0]] - dim_shift
59
+ diagrams_by_dimension[dim].append(pairing)
60
+ for unpaired in pairings["unpaired"]:
61
+ dim = dimensions[unpaired] - dim_shift
62
+ diagrams_by_dimension[dim].append([unpaired])
63
+ return diagrams_by_dimension
64
+
65
+ def add_empty_relations(all_pairings, key):
66
+ base_pairings = all_pairings[key]
67
+ for d, diagram_d in enumerate(base_pairings):
68
+ for idx, pairing in enumerate(diagram_d):
69
+ base_pairings[d][idx] = [pairing, {}]
70
+ return base_pairings
71
+
72
+ def fill_relations(all_pairings, key):
73
+ base_pairings = all_pairings[key]
74
+ for d, diagram_d in enumerate(base_pairings):
75
+ for idx, pairing_relations in enumerate(diagram_d):
76
+ pairing = pairing_relations[0]
77
+ relations = compute_relations(all_pairings, key, pairing)
78
+ base_pairings[d][idx] = [pairing, relations]
79
+ return base_pairings
80
+
81
+ def compute_relations(all_pairings, base_key, pairing):
82
+ relations = {}
83
+ for key in all_pairings.keys():
84
+ if key == base_key:
85
+ continue
86
+ these_relations = []
87
+ diagram = all_pairings[key]
88
+ for d, diagram_d in enumerate(diagram):
89
+ for idx, other_pairing in enumerate(diagram_d):
90
+ if not set(pairing).isdisjoint(other_pairing[0]):
91
+ these_relations.append([d, idx])
92
+ relations[key] = these_relations
93
+ return relations
94
+
95
+ def replace_with_f_times(all_pairings):
96
+ for _, diagrams in all_pairings.items():
97
+ for diagram in diagrams:
98
+ for pairing_relations in diagram:
99
+ pairing = pairing_relations[0]
100
+ coords = [entrance_times[idx] for idx in pairing]
101
+ pairing_relations[0] = coords
102
+ return all_pairings
103
+
104
+ obj = {}
105
+ obj["max_dim"] = max_diagram_dim
106
+ obj["pseudo_inf"] = truncation * 1.05
107
+ pairings = {
108
+ "codomain": make_pairing_obj(dgms.f),
109
+ "domain": make_pairing_obj(dgms.g),
110
+ "image": make_pairing_obj(dgms.im),
111
+ "kernel": make_pairing_obj(dgms.ker, dim_shift=1),
112
+ "cokernel": make_pairing_obj(dgms.cok),
113
+ "relative": make_pairing_obj(dgms.rel, additional_max_dim=1),
114
+ }
115
+ for key in pairings.keys():
116
+ pairings[key] = add_empty_relations(pairings, key)
117
+ for key in pairings.keys():
118
+ pairings[key] = fill_relations(pairings, key)
119
+ obj["pairings"] = replace_with_f_times(pairings)
120
+ return obj
121
+
122
+
123
+ class WashboardServer:
124
+ def __init__(self, washboard_obj=None, host="0.0.0.0", port=6543):
125
+ self.washboard_obj = washboard_obj
126
+ self.host = host
127
+ self.port = port
128
+ self.server = self._setup_server()
129
+
130
+ def _setup_server(self):
131
+ def data_route(request):
132
+ return self.washboard_obj
133
+
134
+ def main_page(request):
135
+ index_file_path = (
136
+ Path(__file__).parent / "washboard/dist/index.html"
137
+ ).resolve()
138
+ response = FileResponse(
139
+ index_file_path,
140
+ request=request,
141
+ content_type="text/html",
142
+ )
143
+ return response
144
+
145
+ with Configurator() as config:
146
+ config.add_route("home", "/")
147
+ config.add_view(main_page, route_name="home")
148
+ config.add_route("data", "/data.json")
149
+ config.add_view(data_route, renderer="json", route_name="data")
150
+ config.scan()
151
+ app = config.make_wsgi_app()
152
+ return make_server(self.host, self.port, app)
153
+
154
+ def serve_forever(self):
155
+ self.server.serve_forever()
156
+
157
+ def shutdown(self):
158
+ self.server.shutdown()
159
+
160
+ @staticmethod
161
+ def _get_link(text):
162
+ return f"\u001b]8;;{text}\u001b\\{text}\u001b]8;;\u001b\\"
163
+
164
+ def open(self, open_browser=True):
165
+ server_thread = threading.Thread(
166
+ target=lambda: self.serve_forever(), name="WashboardServer"
167
+ )
168
+ server_thread.start()
169
+ link = f"http://{self.host}:{self.port}"
170
+ link_to_print = self._get_link(link)
171
+ print(f"Hosting on {link_to_print}")
172
+
173
+ def signal_handler(sig, frame):
174
+ print("Closing down server")
175
+ self.shutdown()
176
+
177
+ signal.signal(signal.SIGINT, signal_handler)
178
+ print("Press Ctrl+C to stop")
179
+
180
+ if open_browser:
181
+ webbrowser.open(link)
182
+
183
+ signal.pause()
184
+
185
+ @classmethod
186
+ def build(
187
+ cls,
188
+ dgms,
189
+ max_diagram_dim,
190
+ truncation,
191
+ dimensions,
192
+ entrance_times,
193
+ host="0.0.0.0",
194
+ port=6543,
195
+ ):
196
+ obj = build_washboard_object(
197
+ dgms, max_diagram_dim, truncation, dimensions, entrance_times
198
+ )
199
+ return cls(obj, host=host, port=port)
Binary file
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.1
2
+ Name: phimaker
3
+ Version: 0.3.0
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: Implementation :: CPython
6
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
9
+
10
+ <div align="center">
11
+
12
+ <h1>phimaker</h1>
13
+
14
+ <b>P</b>ersitent <b>h</b>omology of <b>im</b>ages <b>a</b>nd (co)<b>ker</b>nels.
15
+
16
+ </div>
17
+
18
+ ## Overview
19
+
20
+ Phimaker is a Rust library implementing the algorithm introduced in [[1]](#1) for computing persistent homology for kernels, images and cokernels.
21
+ Python bindings are provided via PyO3.
22
+
23
+ Install via
24
+ ```
25
+ pip install phimaker
26
+ ```
27
+
28
+ ## References
29
+
30
+ <a id="1">[1]</a>
31
+ Cohen-Steiner, D., Edelsbrunner, H., Harer, J. and Morozov, D., 2009, January.
32
+ Persistent homology for kernels, images, and cokernels.
33
+ In Proceedings of the twentieth annual ACM-SIAM symposium on Discrete algorithms (pp. 1011-1020).
34
+ Society for Industrial and Applied Mathematics.
35
+
@@ -0,0 +1,6 @@
1
+ phimaker-0.3.0.dist-info/METADATA,sha256=xP8oUXpmJvGdhl9YhTKwgmMnvSuILWZSVxnC7-zhWvA,1040
2
+ phimaker-0.3.0.dist-info/WHEEL,sha256=Js3_SR0tO8oIlen-a8NLrjdvVkPOf2AEShAJt-5BUcU,95
3
+ phimaker/_washboard_interface.py,sha256=yeAGaIgQyDQak2IshG5UGKy054FeOMd_x9GmuBq8qoY,7241
4
+ phimaker/__init__.py,sha256=2DIEQ9q2noc_ejC4-IYLgV15JxdFKJsMLztmyLN-J8o,239
5
+ phimaker/phimaker.cp313-win_amd64.pyd,sha256=yaUWuXeBn1muIUau5uSTiqaD3gvjzB9TpGJLOys1-T4,864768
6
+ phimaker-0.3.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.0.1)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-none-win_amd64