physdes-py 0.5__tar.gz → 0.7__tar.gz

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.
Files changed (278) hide show
  1. {physdes_py-0.5 → physdes_py-0.7}/.benchmarks/test_area.py +2 -2
  2. {physdes_py-0.5 → physdes_py-0.7}/.flake8 +1 -1
  3. physdes_py-0.7/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  4. physdes_py-0.7/.github/ISSUE_TEMPLATE/documentation.md +29 -0
  5. physdes_py-0.7/.github/ISSUE_TEMPLATE/feature_request.md +25 -0
  6. physdes_py-0.7/.github/PULL_REQUEST_TEMPLATE.md +57 -0
  7. {physdes_py-0.5 → physdes_py-0.7}/.github/workflows/multi-platforms.yml +6 -7
  8. physdes_py-0.7/.github/workflows/python-app.yml +89 -0
  9. {physdes_py-0.5 → physdes_py-0.7}/.gitignore +13 -0
  10. {physdes_py-0.5 → physdes_py-0.7}/.pre-commit-config.yaml +2 -0
  11. physdes_py-0.7/AGENTS.md +273 -0
  12. physdes_py-0.7/CHANGELOG.md +16 -0
  13. physdes_py-0.7/CHANGELOG.rst +40 -0
  14. {physdes_py-0.5 → physdes_py-0.7}/CONTRIBUTING.rst +43 -108
  15. physdes_py-0.7/PKG-INFO +154 -0
  16. physdes_py-0.7/README.md +120 -0
  17. physdes_py-0.7/alpha10.svg +71 -0
  18. physdes_py-0.7/alpha12.svg +67 -0
  19. physdes_py-0.7/alpha14.svg +63 -0
  20. physdes_py-0.7/alpha8.svg +67 -0
  21. physdes_py-0.7/alpha9998.svg +71 -0
  22. physdes_py-0.7/changelog/1.misc.rst +14 -0
  23. physdes_py-0.7/changelog/README.md +25 -0
  24. physdes_py-0.7/coverage.json +1 -0
  25. physdes_py-0.7/demo_overlap.py +155 -0
  26. physdes_py-0.7/demo_overlap.svg +502 -0
  27. physdes_py-0.7/dme_algorithm-slides.html +1308 -0
  28. physdes_py-0.7/dme_algorithm-slides.md +993 -0
  29. physdes_py-0.7/docs/build_from_md.py +86 -0
  30. physdes_py-0.7/docs/build_remark.py +660 -0
  31. physdes_py-0.7/docs/build_slides.py +655 -0
  32. {physdes_py-0.5 → physdes_py-0.7}/docs/conf.py +67 -10
  33. {physdes_py-0.5 → physdes_py-0.7}/docs/contributing.md +20 -18
  34. physdes_py-0.7/docs/essays/essay.md +252 -0
  35. physdes_py-0.7/docs/essays/polygon_vs_rpolygon_comparison.html +1172 -0
  36. physdes_py-0.7/docs/essays/polygon_vs_rpolygon_comparison.md +830 -0
  37. physdes_py-0.7/docs/examples/plot_cts.py +78 -0
  38. physdes_py-0.7/docs/examples/plot_global_router.py +85 -0
  39. physdes_py-0.7/docs/examples/plot_rectangles.py +58 -0
  40. physdes_py-0.7/docs/examples/plot_rpolygon.py +40 -0
  41. physdes_py-0.7/docs/figures_demo.rst +61 -0
  42. {physdes_py-0.5 → physdes_py-0.7}/docs/index.rst +1 -0
  43. {physdes_py-0.5 → physdes_py-0.7}/docs/license.rst +1 -1
  44. physdes_py-0.7/docs/misc/report.md +124 -0
  45. physdes_py-0.7/docs/my_congestion.svg +63 -0
  46. physdes_py-0.7/docs/proposals/fyproj2026.md +194 -0
  47. physdes_py-0.7/docs/proposals/fyproj2026.md.bad +41 -0
  48. physdes_py-0.7/docs/proposals/fyproj2026_cts.md +220 -0
  49. physdes_py-0.7/docs/proposals/fyproj2026_cts_2d.md +215 -0
  50. physdes_py-0.7/docs/proposals/mulit-fpga-routing.md +266 -0
  51. physdes_py-0.7/docs/readme.rst +7 -0
  52. {physdes_py-0.5 → physdes_py-0.7}/docs/requirements.txt +1 -1
  53. physdes_py-0.7/docs/slides_content.md +654 -0
  54. physdes_py-0.7/docs/steiner_forest_diagonal.svg +1 -0
  55. {physdes_py-0.5 → physdes_py-0.7}/environment.yml +1 -0
  56. physdes_py-0.7/example_route3d_with_constraint_and_keepouts.svg +71 -0
  57. physdes_py-0.7/example_route3d_with_steiner_and_keepouts.svg +71 -0
  58. physdes_py-0.7/example_route_with_delay_constraint.svg +71 -0
  59. physdes_py-0.7/example_route_with_keepouts.svg +66 -0
  60. physdes_py-0.7/example_route_with_steiner.svg +63 -0
  61. physdes_py-0.7/example_route_with_steiner_and_keepouts.svg +66 -0
  62. physdes_py-0.7/example_route_with_steiner_special.svg +83 -0
  63. physdes_py-0.7/examples/steiner_forest_grid_example.py +77 -0
  64. physdes_py-0.7/examples/steiner_forest_grid_large_example.py +81 -0
  65. physdes_py-0.7/examples/steiner_forest_simple_example.py +81 -0
  66. physdes_py-0.7/experimental/distance_comparison.png +0 -0
  67. physdes_py-0.7/experimental/rectilinear_distance_field.png +0 -0
  68. physdes_py-0.7/experimental/rectilinear_voronoi.ipynb +588 -0
  69. physdes_py-0.7/experimental/rectilinear_voronoi.py +392 -0
  70. physdes_py-0.7/experimental/rectilinear_voronoi_diamond.png +0 -0
  71. physdes_py-0.7/experimental/rectilinear_voronoi_grid.png +0 -0
  72. physdes_py-0.7/experimental/rectilinear_voronoi_random.png +0 -0
  73. physdes_py-0.7/experimental/steiner_trees_demo.py +123 -0
  74. physdes_py-0.7/global_router-slides.html +1223 -0
  75. physdes_py-0.7/global_router-slides.md +904 -0
  76. physdes_py-0.7/my_congestion.svg +63 -0
  77. physdes_py-0.7/mypy.ini +6 -0
  78. physdes_py-0.7/neg_specical10.svg +103 -0
  79. physdes_py-0.7/outputs/comparison.svg +47 -0
  80. physdes_py-0.7/outputs/delay_model_comparison.svg +203 -0
  81. physdes_py-0.7/outputs/delay_model_comparison3d.svg +203 -0
  82. physdes_py-0.7/outputs/elmore_model_clock_tree.svg +105 -0
  83. physdes_py-0.7/outputs/elmore_model_clock_tree3d.svg +105 -0
  84. physdes_py-0.7/outputs/example_route3d_with_constraint.svg +75 -0
  85. physdes_py-0.7/outputs/example_route3d_with_constraint_and_keepouts.svg +65 -0
  86. physdes_py-0.7/outputs/example_route3d_with_steiner.svg +75 -0
  87. physdes_py-0.7/outputs/example_route3d_with_steiner_and_keepouts.svg +65 -0
  88. physdes_py-0.7/outputs/example_route_with_constraint.svg +75 -0
  89. physdes_py-0.7/outputs/example_route_with_constraint_specical.svg +103 -0
  90. physdes_py-0.7/outputs/example_route_with_delay_constraint.svg +71 -0
  91. physdes_py-0.7/outputs/example_route_with_keepouts.svg +65 -0
  92. physdes_py-0.7/outputs/example_route_with_steiner.svg +63 -0
  93. physdes_py-0.7/outputs/example_route_with_steiner_and_keepouts.svg +65 -0
  94. physdes_py-0.7/outputs/example_route_with_steiner_special.svg +83 -0
  95. physdes_py-0.7/outputs/linear_model_clock_tree.svg +105 -0
  96. physdes_py-0.7/outputs/linear_model_clock_tree3d.svg +105 -0
  97. physdes_py-0.7/outputs/my_congestion.svg +63 -0
  98. physdes_py-0.7/outputs/neg_specical10.svg +103 -0
  99. physdes_py-0.7/outputs/rpolygon_convex_cut.svg +13 -0
  100. physdes_py-0.7/outputs/rpolygon_cut_explicit.svg +22 -0
  101. physdes_py-0.7/outputs/steiner_forest.svg +1 -0
  102. physdes_py-0.7/outputs/steiner_forest_diagonal.svg +1 -0
  103. physdes_py-0.7/plot_alpha.py +33 -0
  104. physdes_py-0.7/presentation_overlap_detection.html +821 -0
  105. physdes_py-0.7/presentation_overlap_detection.md +438 -0
  106. physdes_py-0.7/pyproject.toml +96 -0
  107. {physdes_py-0.5 → physdes_py-0.7}/requirements/default.txt +2 -1
  108. physdes_py-0.7/requirements/dev.txt +17 -0
  109. physdes_py-0.7/requirements/extras.txt +1 -0
  110. {physdes_py-0.5 → physdes_py-0.7}/requirements/test.txt +1 -1
  111. physdes_py-0.7/requirements.txt +17 -0
  112. physdes_py-0.7/rpolygon-slides.html +1073 -0
  113. physdes_py-0.7/rpolygon-slides.md +862 -0
  114. {physdes_py-0.5 → physdes_py-0.7}/setup.cfg +12 -2
  115. physdes_py-0.7/src/physdes/__init__.py +17 -0
  116. physdes_py-0.7/src/physdes/cts/clk_tree3d_vis.py +611 -0
  117. physdes_py-0.7/src/physdes/cts/clk_tree_vis.py +617 -0
  118. physdes_py-0.7/src/physdes/cts/dme_algorithm.py +746 -0
  119. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/generic.py +168 -43
  120. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/interval.py +316 -103
  121. physdes_py-0.7/src/physdes/manhattan_arc.py +321 -0
  122. physdes_py-0.7/src/physdes/manhattan_arc_3d.py +351 -0
  123. physdes_py-0.7/src/physdes/manhattan_arc_3d.tpy +292 -0
  124. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/point.py +369 -74
  125. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/polygon.py +217 -109
  126. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/rdllist.py +66 -3
  127. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/recti.py +62 -34
  128. physdes_py-0.7/src/physdes/router/global_router.py +168 -0
  129. physdes_py-0.7/src/physdes/router/global_router3d.tpy +93 -0
  130. physdes_py-0.7/src/physdes/router/routing_tree.py +892 -0
  131. physdes_py-0.7/src/physdes/router/routing_tree3d.tpy +891 -0
  132. physdes_py-0.7/src/physdes/router/routing_visualizer.py +483 -0
  133. physdes_py-0.7/src/physdes/router/steiner_forest.md +204 -0
  134. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/rpolygon.py +302 -393
  135. physdes_py-0.7/src/physdes/rpolygon_cut.py +335 -0
  136. physdes_py-0.7/src/physdes/skeleton.py +3 -0
  137. physdes_py-0.7/src/physdes/steiner_forest/congestion_map.py +129 -0
  138. physdes_py-0.7/src/physdes/steiner_forest/my_congestion.svg +63 -0
  139. physdes_py-0.7/src/physdes/steiner_forest/steiner_forest.md +204 -0
  140. physdes_py-0.7/src/physdes/steiner_forest/steiner_forest.svg +1 -0
  141. physdes_py-0.7/src/physdes/steiner_forest/steiner_forest_diagonal.svg +1 -0
  142. physdes_py-0.7/src/physdes/steiner_forest/steiner_forest_grid.py +469 -0
  143. physdes_py-0.7/src/physdes/to_polygon.py +55 -0
  144. physdes_py-0.7/src/physdes/vector2.py +459 -0
  145. physdes_py-0.7/src/physdes_py.egg-info/PKG-INFO +154 -0
  146. physdes_py-0.7/src/physdes_py.egg-info/SOURCES.txt +250 -0
  147. {physdes_py-0.5 → physdes_py-0.7}/src/physdes_py.egg-info/requires.txt +11 -2
  148. physdes_py-0.7/src/physdes_py.egg-info/scm_file_list.json +246 -0
  149. physdes_py-0.7/src/physdes_py.egg-info/scm_version.json +8 -0
  150. physdes_py-0.7/test.svg +35 -0
  151. physdes_py-0.7/tests/__init__.py +0 -0
  152. physdes_py-0.7/tests/conftest.py +128 -0
  153. physdes_py-0.7/tests/golden.txt +0 -0
  154. physdes_py-0.7/tests/run_failing_tests.py +16 -0
  155. physdes_py-0.7/tests/test_alpha.py +157 -0
  156. physdes_py-0.7/tests/test_clk_tree_vis.py +698 -0
  157. physdes_py-0.7/tests/test_dme_algorithm.py +650 -0
  158. physdes_py-0.7/tests/test_generic_functions.py +196 -0
  159. physdes_py-0.7/tests/test_global_router.py +120 -0
  160. physdes_py-0.7/tests/test_global_router3d.py +41 -0
  161. physdes_py-0.7/tests/test_global_router3d.tpy +87 -0
  162. physdes_py-0.7/tests/test_global_router3d_with_keepouts.py +94 -0
  163. physdes_py-0.7/tests/test_global_router3d_with_keepouts2.py +42 -0
  164. physdes_py-0.7/tests/test_global_router_logic.py +60 -0
  165. physdes_py-0.7/tests/test_global_router_logic3d.tpy +36 -0
  166. physdes_py-0.7/tests/test_global_router_with_keepouts.py +51 -0
  167. physdes_py-0.7/tests/test_global_router_with_keepouts2.py +49 -0
  168. physdes_py-0.7/tests/test_interval.py +556 -0
  169. physdes_py-0.7/tests/test_manhattan_arc_3d.py +336 -0
  170. physdes_py-0.7/tests/test_manhattan_arc_3d.tpy +155 -0
  171. physdes_py-0.7/tests/test_merge.py +99 -0
  172. physdes_py-0.7/tests/test_merge3d.tpy +66 -0
  173. physdes_py-0.7/tests/test_nearest_point_to.tpy +10 -0
  174. physdes_py-0.7/tests/test_overlap.py +10 -0
  175. {physdes_py-0.5 → physdes_py-0.7}/tests/test_point.py +20 -15
  176. physdes_py-0.7/tests/test_point_extended.py +81 -0
  177. physdes_py-0.7/tests/test_point_hypothesis.py +411 -0
  178. {physdes_py-0.5 → physdes_py-0.7}/tests/test_polygon.py +18 -67
  179. physdes_py-0.7/tests/test_polygon_convex_decomposition.py +174 -0
  180. physdes_py-0.7/tests/test_polygon_hypothesis.py +471 -0
  181. {physdes_py-0.5 → physdes_py-0.7}/tests/test_rdllist.py +5 -5
  182. {physdes_py-0.5 → physdes_py-0.7}/tests/test_rect3d.py +8 -8
  183. physdes_py-0.7/tests/test_recti.py +161 -0
  184. physdes_py-0.7/tests/test_recti_hypothesis.py +500 -0
  185. physdes_py-0.7/tests/test_routing_tree.py +632 -0
  186. physdes_py-0.7/tests/test_routing_tree3d.tpy +316 -0
  187. physdes_py-0.7/tests/test_routing_visualizer.py +69 -0
  188. {physdes_py-0.5 → physdes_py-0.7}/tests/test_rpolygon.py +81 -117
  189. physdes_py-0.7/tests/test_rpolygon_convex_cut.py +46 -0
  190. physdes_py-0.7/tests/test_rpolygon_convex_hull.py +38 -0
  191. physdes_py-0.7/tests/test_rpolygon_cut.py +48 -0
  192. physdes_py-0.7/tests/test_steiner_forest_grid.py +425 -0
  193. physdes_py-0.7/tests/test_to_polygon.py +29 -0
  194. {physdes_py-0.5 → physdes_py-0.7}/tests/test_vector2.py +5 -5
  195. physdes_py-0.7/tests/test_vector2_hypothesis.py +402 -0
  196. physdes_py-0.7/wirelength_vs_alpha.png +0 -0
  197. physdes_py-0.7/wirelength_vs_alpha_small.png +0 -0
  198. physdes_py-0.5/.github/workflows/python-app.yml +0 -48
  199. physdes_py-0.5/CHANGELOG.rst +0 -10
  200. physdes_py-0.5/LICENSE.txt +0 -21
  201. physdes_py-0.5/PKG-INFO +0 -55
  202. physdes_py-0.5/README.md +0 -29
  203. physdes_py-0.5/README.rst +0 -39
  204. physdes_py-0.5/docs/readme.rst +0 -2
  205. physdes_py-0.5/mypy.ini +0 -24
  206. physdes_py-0.5/pyproject.toml +0 -9
  207. physdes_py-0.5/requirements/extras.txt +0 -1
  208. physdes_py-0.5/requirements.txt +0 -19
  209. physdes_py-0.5/src/physdes/__init__.py +0 -16
  210. physdes_py-0.5/src/physdes/merge_obj.py +0 -274
  211. physdes_py-0.5/src/physdes/skeleton.py +0 -149
  212. physdes_py-0.5/src/physdes/vector2.py +0 -386
  213. physdes_py-0.5/src/physdes_py.egg-info/PKG-INFO +0 -55
  214. physdes_py-0.5/src/physdes_py.egg-info/SOURCES.txt +0 -109
  215. physdes_py-0.5/tests/conftest.py +0 -10
  216. physdes_py-0.5/tests/test_interval.py +0 -250
  217. physdes_py-0.5/tests/test_merge.py +0 -51
  218. physdes_py-0.5/tests/test_overlap.py +0 -10
  219. physdes_py-0.5/tests/test_recti.py +0 -91
  220. physdes_py-0.5/tests/test_rpolygon.svg +0 -4
  221. physdes_py-0.5/tests/test_rpolygon_convex_cut.py +0 -52
  222. physdes_py-0.5/tests/test_rpolygon_convex_hull.py +0 -42
  223. physdes_py-0.5/tests/test_skeleton.py +0 -36
  224. physdes_py-0.5/tests/travis_install.sh +0 -60
  225. {physdes_py-0.5 → physdes_py-0.7}/.coveragerc +0 -0
  226. {physdes_py-0.5 → physdes_py-0.7}/.github/workflows/jekyll-gh-pages.yml +0 -0
  227. {physdes_py-0.5 → physdes_py-0.7}/.github/workflows/python-publish.yml +0 -0
  228. {physdes_py-0.5 → physdes_py-0.7}/.gitpod.Dockerfile +0 -0
  229. {physdes_py-0.5 → physdes_py-0.7}/.gitpod.yml +0 -0
  230. {physdes_py-0.5 → physdes_py-0.7}/.hadolint.yaml +0 -0
  231. {physdes_py-0.5 → physdes_py-0.7}/.isort.cfg +0 -0
  232. {physdes_py-0.5 → physdes_py-0.7}/.markdownlint.yaml +0 -0
  233. {physdes_py-0.5 → physdes_py-0.7}/.readthedocs.yml +0 -0
  234. {physdes_py-0.5 → physdes_py-0.7}/.shellcheckrc +0 -0
  235. {physdes_py-0.5 → physdes_py-0.7}/AUTHORS.rst +0 -0
  236. {physdes_py-0.5 → physdes_py-0.7}/GEMINI.md +0 -0
  237. {physdes_py-0.5 → physdes_py-0.7}/LICENSE +0 -0
  238. {physdes_py-0.5 → physdes_py-0.7}/_config.yml +0 -0
  239. {physdes_py-0.5 → physdes_py-0.7}/diagram.bob +0 -0
  240. {physdes_py-0.5 → physdes_py-0.7}/docs/Makefile +0 -0
  241. {physdes_py-0.5 → physdes_py-0.7}/docs/_static/.gitignore +0 -0
  242. {physdes_py-0.5 → physdes_py-0.7}/docs/authors.rst +0 -0
  243. {physdes_py-0.5 → physdes_py-0.7}/docs/changelog.rst +0 -0
  244. {physdes_py-0.5 → physdes_py-0.7}/docs/contributing.rst +0 -0
  245. {physdes_py-0.5 → physdes_py-0.7/docs/misc}/note.md +0 -0
  246. {physdes_py-0.5 → physdes_py-0.7}/oryx-build-commands.txt +0 -0
  247. {physdes_py-0.5 → physdes_py-0.7/outputs}/convex_hull.svg +0 -0
  248. {physdes_py-0.5 → physdes_py-0.7}/outputs/polygon_convex_hull.svg +0 -0
  249. {physdes_py-0.5 → physdes_py-0.7}/outputs/polygon_convex_hull13.svg +0 -0
  250. {physdes_py-0.5 → physdes_py-0.7/outputs}/rectilinear-shapes-for-vlsi-physical-desgin.svg +0 -0
  251. {physdes_py-0.5 → physdes_py-0.7}/outputs/rpolyon_convex_hull.svg +0 -0
  252. {physdes_py-0.5 → physdes_py-0.7}/outputs/rpolyon_convex_hull13.svg +0 -0
  253. {physdes_py-0.5 → physdes_py-0.7}/outputs/rpolyon_cut_convex.svg +0 -0
  254. {physdes_py-0.5 → physdes_py-0.7}/outputs/rpolyon_cut_convex2.svg +0 -0
  255. {physdes_py-0.5 → physdes_py-0.7}/outputs/rpolyon_xmono.svg +0 -0
  256. {physdes_py-0.5 → physdes_py-0.7}/outputs/rpolyon_xmono_hull.svg +0 -0
  257. {physdes_py-0.5 → physdes_py-0.7}/outputs/rpolyon_ymono_hull.svg +0 -0
  258. {physdes_py-0.5 → physdes_py-0.7}/outputs/test.svg +0 -0
  259. {physdes_py-0.5 → physdes_py-0.7/outputs}/xmono_hull.svg +0 -0
  260. {physdes_py-0.5 → physdes_py-0.7}/requirements/README.md +0 -0
  261. {physdes_py-0.5 → physdes_py-0.7}/requirements/doc.txt +0 -0
  262. {physdes_py-0.5 → physdes_py-0.7}/setup.py +0 -0
  263. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/generic.tpy +0 -0
  264. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/point.tpy +0 -0
  265. /physdes_py-0.5/tests/golden.txt → /physdes_py-0.7/src/physdes/py.typed +0 -0
  266. {physdes_py-0.5 → physdes_py-0.7}/src/physdes/vector2.tpy +0 -0
  267. {physdes_py-0.5 → physdes_py-0.7}/src/physdes_py.egg-info/dependency_links.txt +0 -0
  268. {physdes_py-0.5 → physdes_py-0.7}/src/physdes_py.egg-info/not-zip-safe +0 -0
  269. {physdes_py-0.5 → physdes_py-0.7}/src/physdes_py.egg-info/top_level.txt +0 -0
  270. {physdes_py-0.5 → physdes_py-0.7}/svgo.config.js +0 -0
  271. {physdes_py-0.5 → physdes_py-0.7}/tests/mysvg.css +0 -0
  272. {physdes_py-0.5 → physdes_py-0.7}/tests/pnrpoly.svg +0 -0
  273. {physdes_py-0.5 → physdes_py-0.7}/tests/test_polygon.svg +0 -0
  274. {physdes_py-0.5 → physdes_py-0.7}/tests/xmono_polygon.svg +0 -0
  275. {physdes_py-0.5 → physdes_py-0.7}/tests/xmono_polygon2.svg +0 -0
  276. {physdes_py-0.5 → physdes_py-0.7}/tests/ymono_polygon.svg +0 -0
  277. {physdes_py-0.5 → physdes_py-0.7}/tests/ymono_rpolygon.svg +0 -0
  278. {physdes_py-0.5 → physdes_py-0.7}/tox.ini +0 -0
@@ -16,14 +16,14 @@ def rectilinear_polygon_points():
16
16
  return [Point(x, y) for x, y in RECTILINEAR_POLYGON_COORDS]
17
17
 
18
18
 
19
- def test_polygon_signed_area(benchmark, rectilinear_polygon_points):
19
+ def test_polygon_signed_area(benchmark, rectilinear_polygon_points) -> None:
20
20
  rp = RPolygon(rectilinear_polygon_points)
21
21
  p: Polygon = rp.to_polygon()
22
22
  result = benchmark(lambda: p.signed_area_x2)
23
23
  assert abs(result) == 150
24
24
 
25
25
 
26
- def test_rpolygon_signed_area(benchmark, rectilinear_polygon_points):
26
+ def test_rpolygon_signed_area(benchmark, rectilinear_polygon_points) -> None:
27
27
  rp = RPolygon(rectilinear_polygon_points)
28
28
  result = benchmark(lambda: rp.signed_area)
29
29
  assert abs(result) == 75
@@ -1,3 +1,3 @@
1
1
  # Autoformatter friendly flake8 config (all formatting rules disabled)
2
2
  [flake8]
3
- extend-ignore = E1, E2, E3, E501, W1, W2, W3, W5
3
+ extend-ignore = E1, E2, E3, E501, W1, W2, W3, W5, S314
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: Bug report
3
+ about: 'Create a report to help us improve'
4
+ title: '[BUG] <title>'
5
+
6
+ ---
7
+
8
+ **Describe the bug**
9
+ A clear and concise description of what the bug is.
10
+
11
+ **To Reproduce**
12
+ Steps to reproduce the behavior:
13
+ 1. Go to '...'
14
+ 2. Click on '....'
15
+ 3. Scroll down to '....'
16
+ 4. See error
17
+
18
+ **Expected behavior**
19
+ A clear and concise description of what you expected to happen.
20
+
21
+ **Actual behavior**
22
+ A clear and concise description of what actually happened.
23
+
24
+ **Screenshots**
25
+ If applicable, add screenshots to help explain your problem.
26
+
27
+ **Environment**
28
+ - OS: [e.g., Windows, macOS, Linux]
29
+ - Python version: [e.g., 3.8, 3.9, 3.10]
30
+ - physdes-py version: [e.g., 0.1.0]
31
+ - How did you install physdes-py?: [pip install, git clone, conda]
32
+
33
+ **Additional context**
34
+ Add any other context about the problem here.
35
+
36
+ **Code snippet**
37
+ If relevant, please provide a minimal code snippet that reproduces the issue:
38
+
39
+ ```python
40
+ # Your code here
41
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Documentation
3
+ about: 'Suggest improvements or report issues with documentation'
4
+ title: '[DOCS] <title>'
5
+
6
+ ---
7
+
8
+ **Describe the documentation issue**
9
+ A clear and concise description of what's wrong or what could be improved.
10
+
11
+ **Which documentation?**
12
+ Please specify which documentation has issue:
13
+ - README.md
14
+ - AGENTS.md
15
+ - CONTRIBUTING.rst
16
+ - API documentation (docs/)
17
+ - Other (please specify)
18
+
19
+ **What needs to be fixed/improved?**
20
+ Describe what's missing, unclear, or incorrect.
21
+
22
+ **Suggested fix**
23
+ If you have a suggestion for how to improve documentation, please describe it here.
24
+
25
+ **Screenshots (if applicable)**
26
+ Add screenshots to help illustrate the documentation issue.
27
+
28
+ **Additional context**
29
+ Add any other context about the documentation issue here.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: Feature request
3
+ about: 'Suggest an idea for physdes-py'
4
+ title: '[FEATURE] <title>'
5
+
6
+ ---
7
+
8
+ **Is your feature request related to a problem? Please describe**
9
+ A clear and concise description of what problem is. Ex. I'm always frustrated when [...]
10
+
11
+ **Describe the solution you'd like**
12
+ A clear and concise description of what you want to happen.
13
+
14
+ **Describe alternatives you've considered**
15
+ A clear and concise description of any alternative solutions or features you've considered.
16
+
17
+ **Additional context**
18
+ Add any other context or screenshots about the feature request here.
19
+
20
+ **Use cases**
21
+ Please describe specific use cases for this feature. This helps us understand how feature would be used in practice.
22
+
23
+ Example use cases:
24
+ - "When I'm working with X, I need Y because..."
25
+ - "In my project, I want to implement Z, but I can't because..."
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: Pull Request
3
+ about: 'Create a pull request to contribute changes'
4
+
5
+ ---
6
+
7
+ ## Description
8
+ Please include a summary of changes and motivation behind them.
9
+
10
+ ## Type of change
11
+ - [ ] Bug fix (non-breaking change which fixes an issue)
12
+ - [ ] New feature (non-breaking change which adds functionality)
13
+ - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
14
+ - [ ] Documentation update
15
+ - [ ] Performance improvement
16
+ - [ ] Code refactoring (no functional changes, no API changes)
17
+ - [ ] Other (please describe):
18
+
19
+ ## Related Issues
20
+ Fixes #<issue_number>
21
+ Related to #<issue_number>
22
+
23
+ ## How Has This Been Tested?
24
+ Please describe the tests that you ran to verify your changes:
25
+ - [ ] Unit tests added/updated
26
+ - [ ] All existing tests pass
27
+ - [ ] Manual testing performed (describe steps)
28
+ - [ ] Tested on Python 3.8
29
+ - [ ] Tested on Python 3.9
30
+ - [ ] Tested on Python 3.10
31
+ - [ ] Tested on Python 3.11
32
+ - [ ] Tested on Python 3.12
33
+
34
+ ## Checklist:
35
+ - [ ] My code follows the style guidelines of this project
36
+ - [ ] I have performed a self-review of my own code
37
+ - [ ] I have commented my code, particularly in hard-to-understand areas
38
+ - [ ] I have made corresponding changes to the documentation
39
+ - [ ] My changes generate no new warnings
40
+ - [ ] I have added tests that prove my fix is effective or that my feature works
41
+ - [ ] New and existing unit tests pass locally with my changes
42
+ - [ ] I have updated the CHANGELOG (if applicable) using towncrier
43
+
44
+ ## Additional Notes
45
+ Add any other notes or context about the pull request here.
46
+
47
+ ### Breaking Changes
48
+ If this PR introduces breaking changes, please describe them here:
49
+ - API changes that may break existing code
50
+ - Configuration changes
51
+ - Migration steps needed
52
+
53
+ ### Performance Impact
54
+ If this PR affects performance, please describe:
55
+ - Benchmarks before
56
+ - Benchmarks after
57
+ - Performance improvements
@@ -8,10 +8,10 @@ jobs:
8
8
  strategy:
9
9
  matrix:
10
10
  os: ["ubuntu-latest", "windows-latest"]
11
- version: ["3.10", "3.12"]
11
+ version: ["3.10", "3.11"]
12
12
  steps:
13
- - uses: actions/checkout@v2
14
- - uses: conda-incubator/setup-miniconda@v2
13
+ - uses: actions/checkout@v3
14
+ - uses: conda-incubator/setup-miniconda@v3
15
15
  with:
16
16
  activate-environment: test
17
17
  environment-file: environment.yml
@@ -31,9 +31,8 @@ jobs:
31
31
  shell: bash -l {0}
32
32
  run: |
33
33
  conda install pytest
34
- python -m pip install --upgrade pip
34
+ conda install pip
35
+ conda install setuptools wheel setuptools_scm
35
36
  if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
36
- pip install git+https://github.com/luk036/lds-gen.git
37
- pip install git+https://github.com/luk036/mywheel.git
38
- python setup.py develop
37
+ pip install -e .
39
38
  pytest
@@ -0,0 +1,89 @@
1
+ # This workflow will install Python dependencies, run tests and lint with multiple Python versions
2
+ # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3
+
4
+ name: Python application
5
+
6
+ on:
7
+ push:
8
+ branches: [ main, dev ]
9
+ pull_request:
10
+ branches: [ main, dev ]
11
+
12
+ jobs:
13
+ build:
14
+ strategy:
15
+ matrix:
16
+ python-version: ["3.10", "3.11", "3.12"]
17
+ os: [ubuntu-latest]
18
+
19
+ runs-on: ${{ matrix.os }}
20
+ env:
21
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
22
+
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+
26
+ - name: Set up Python ${{ matrix.python-version }}
27
+ uses: actions/setup-python@v5
28
+ with:
29
+ python-version: ${{ matrix.python-version }}
30
+
31
+ - name: Cache pip dependencies
32
+ uses: actions/cache@v4
33
+ with:
34
+ path: ~/.cache/pip
35
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
36
+ restore-keys: |
37
+ ${{ runner.os }}-pip-
38
+
39
+ - name: Install dependencies
40
+ run: |
41
+ python -m pip install --upgrade pip
42
+ pip install flake8 pytest pytest-cov pytest-benchmark bandit safety
43
+ if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
44
+ pip install -e .
45
+ pip install pre-commit
46
+ # pip install mypy
47
+
48
+ - name: Lint with flake8
49
+ run: |
50
+ # stop the build if there are Python syntax errors or undefined names
51
+ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
52
+ # exit-zero treats all errors as warnings. The GitHub editor is 188 chars wide
53
+ flake8 . --count --exit-zero --max-complexity=10 --max-line-length=188 --statistics
54
+
55
+ # - name: Type check with mypy
56
+ # run: |
57
+ # mypy src/physdes
58
+
59
+ # - name: Install and run pre-commit
60
+ # env:
61
+ # SKIP: no-commit-to-branch
62
+ # run: |
63
+ # pre-commit install
64
+ # pre-commit run --all-files --show-diff-on-failure
65
+ #
66
+ # - name: Security scan with bandit
67
+ # run: |
68
+ # bandit -r src/ -f screen
69
+ #
70
+ # - name: Security check with safety
71
+ # run: |
72
+ # safety check --full-report
73
+
74
+ - name: Test with pytest
75
+ run: |
76
+ pytest --cov=src/ --cov-report=term-missing --cov-report=xml --cov-fail-under=80 -v
77
+
78
+ - name: Run benchmarks
79
+ run: |
80
+ pytest --benchmark-only --benchmark-autosave
81
+
82
+ - name: Upload coverage to Codecov
83
+ uses: codecov/codecov-action@v4
84
+ with:
85
+ token: ${{ secrets.CODECOV_TOKEN }}
86
+ files: ./coverage.xml
87
+ flags: unittests
88
+ name: codecov-umbrella
89
+ fail_ci_if_error: true
@@ -176,3 +176,16 @@ MANIFEST
176
176
 
177
177
  # my stuffs
178
178
  .hypothesis
179
+
180
+ # Temporary log files
181
+ *.log
182
+ coverage.json
183
+ mypy_error.log
184
+
185
+ # Build artifacts
186
+ diagram.bob
187
+ oryx-build-commands.txt
188
+
189
+ # Cache dirs
190
+ .ruff_cache/
191
+ .benchmarks/
@@ -14,8 +14,10 @@ repos:
14
14
  - id: debug-statements
15
15
  - id: end-of-file-fixer
16
16
  - id: requirements-txt-fixer
17
+ exclude: "requirements/dev[.]txt$"
17
18
  - id: mixed-line-ending
18
19
  args: ["--fix=auto"] # replace 'auto' with 'lf' to enforce Linux/Mac line endings or 'crlf' for Windows
20
+ exclude: "requirements[.]txt$"
19
21
 
20
22
  ## If you want to avoid flake8 errors due to unused vars or imports:
21
23
  # - repo: https://github.com/myint/autoflake
@@ -0,0 +1,273 @@
1
+ # AGENTS.md - physdes-py
2
+
3
+ This file guides agentic coding agents working in the physdes-py repository.
4
+
5
+ ## Build/Lint/Test Commands
6
+
7
+ ### Testing
8
+ ```bash
9
+ # Run all tests
10
+ pytest
11
+
12
+ # Run single test
13
+ pytest tests/test_module.py::test_function_name
14
+
15
+ # Run with coverage (already enabled by default)
16
+ pytest --cov physdes --cov-report term-missing
17
+
18
+ # Run tests in specific directory
19
+ pytest tests/test_point.py
20
+
21
+ # Run with verbose output (default)
22
+ pytest -v
23
+ ```
24
+
25
+ ### Linting/Formatting
26
+ ```bash
27
+ # Run pre-commit hooks (includes isort, black, flake8)
28
+ pre-commit run --all-files
29
+
30
+ # Format code with black
31
+ black src/physdes tests/
32
+
33
+ # Sort imports with isort
34
+ isort src/physdes tests/
35
+
36
+ # Run flake8 linting
37
+ flake8 src/physdes tests/
38
+ ```
39
+
40
+ ### Build
41
+ ```bash
42
+ # Build package
43
+ python -m build
44
+
45
+ # Or using tox
46
+ tox -e build
47
+ ```
48
+
49
+ ### Docs
50
+ ```bash
51
+ # Build documentation
52
+ sphinx-build -b html docs/ docs/_build/html
53
+ ```
54
+
55
+ ## Code Style Guidelines
56
+
57
+ ### Imports
58
+ - **Standard library imports first**, then third-party, then project imports
59
+ - Use explicit `from typing import` statements:
60
+ ```python
61
+ from typing import Any, Generic, TypeVar, Union, Optional, List, Tuple, Dict, Callable, TYPE_CHECKING
62
+ ```
63
+ - Use relative imports for project modules:
64
+ ```python
65
+ from .generic import center, contain, displacement
66
+ from .interval import enlarge, hull
67
+ ```
68
+ - For Python version compatibility (supports 3.8+):
69
+ ```python
70
+ if sys.version_info[:2] >= (3, 8):
71
+ from importlib.metadata import PackageNotFoundError, version
72
+ else:
73
+ from importlib_metadata import PackageNotFoundError, version
74
+ ```
75
+ - Import debugging tools with `# type: ignore`:
76
+ ```python
77
+ from icecream import ic # type: ignore
78
+ ```
79
+
80
+ ### Formatting
81
+ - **Line length**: 188 characters (configured in setup.cfg)
82
+ - **Formatter**: Black (version 23.7.0) with line length 188
83
+ - **Import sorter**: isort (version 5.12.0)
84
+ - **Linting**: flake8 with these exceptions: `E203, W503` (black-compatible)
85
+ - **Line endings**: Mixed line endings fixed automatically via pre-commit
86
+
87
+ ### Type Hints
88
+ - **Required**: All functions and methods must have type hints
89
+ - **Generic types**: Use `TypeVar` and `Generic` for reusable classes:
90
+ ```python
91
+ T = TypeVar("T", int, float)
92
+ class Interval(Generic[T]):
93
+ def __init__(self, lb: T, ub: T) -> None: ...
94
+ ```
95
+ - **Union types**: Use pipe syntax for Python 3.10+, `Union` for older:
96
+ ```python
97
+ def min_dist_with(self, obj: Union["Interval[T]", T]) -> T | int:
98
+ ```
99
+ - **Forward references**: Use string quotes for types not yet defined:
100
+ ```python
101
+ def __lt__(self, other: "Point[T1, T2]") -> bool:
102
+ ```
103
+ - **Ignore sparingly**: Use `# type: ignore` only when unavoidable (e.g., icecream, mywheel imports)
104
+
105
+ ### Naming Conventions
106
+ - **Classes**: `PascalCase` (e.g., `Point`, `Interval`, `Vector2`)
107
+ - **Functions/Methods**: `snake_case` (e.g., `hull_with`, `min_dist_with`, `get_center`)
108
+ - **Variables**: `snake_case` (e.g., `xcoord`, `ycoord`, `lower_bound`)
109
+ - **Constants**: `UPPER_SNAKE_CASE` (less common in this codebase)
110
+ - **Properties**: Use `@property` for computed attributes:
111
+ ```python
112
+ @property
113
+ def lb(self) -> T:
114
+ return self._lb
115
+ ```
116
+ - **Private attributes**: Prefix with underscore (e.g., `_lb`, `_ub`)
117
+
118
+ ### Operator Overloading
119
+ - Implement dunder methods for mathematical operations:
120
+ ```python
121
+ def __add__(self, rhs: Union["Interval[T]", T]) -> "Interval[T]":
122
+ def __iadd__(self, rhs: Union["Interval[T]", T]) -> "Interval[T]":
123
+ def __lt__(self, other: Union["Interval[T]", T]) -> bool:
124
+ ```
125
+ - Return `NotImplemented` for unsupported type comparisons:
126
+ ```python
127
+ def __eq__(self, other: object) -> bool:
128
+ if not isinstance(other, Point):
129
+ return NotImplemented
130
+ return (self.xcoord, self.ycoord) == (other.xcoord, other.ycoord)
131
+ ```
132
+
133
+ ### Documentation
134
+ - **Docstrings required** for all public classes and methods
135
+ - **Style**: Google-style or similar (examples show detailed parameter descriptions)
136
+ - **Include**: Parameters, return types, and examples:
137
+ ```python
138
+ def hull_with(self, other: "Point[T1, T2]") -> "Point[Any, Any]":
139
+ """
140
+ The `hull_with` function takes another object and returns a new object
141
+ with the hull of the x and y coordinates of both objects.
142
+
143
+ :param other: The `other` parameter is an object of the same type as `self`.
144
+ :return: an instance of the same class as `self`.
145
+ """
146
+ ```
147
+ - **Examples**: Use doctest format when appropriate:
148
+ ```python
149
+ Examples:
150
+ >>> a = Point(3, 5)
151
+ >>> print(a.hull_with(b))
152
+ ([3, 5], [4, 6])
153
+ ```
154
+ - **ASCII art**: Use `svgbob` for geometric diagrams:
155
+ ```python
156
+ .. svgbob::
157
+ :align: center
158
+
159
+ .-----------.------.
160
+ | self | |
161
+ '-----------' |
162
+ ```
163
+
164
+ ### Error Handling
165
+ - **Minimal explicit error handling** - rely on Python's natural exceptions
166
+ - **Use assertions** for preconditions:
167
+ ```python
168
+ assert lhs == rhs
169
+ ```
170
+ - **Return invalid objects** when appropriate (e.g., `Interval` with `lb > ub`):
171
+ ```python
172
+ def is_invalid(self) -> bool:
173
+ return self.lb > self.ub
174
+ ```
175
+ - Avoid empty catch blocks (`except: pass`)
176
+
177
+ ### Testing
178
+ - **Framework**: pytest with doctest support enabled
179
+ - **Coverage**: Required (--cov physdes --cov-report term-missing)
180
+ - **Property-based testing**: Use hypothesis for complex algorithms
181
+ - **Test naming**: `test_` prefix with descriptive names:
182
+ ```python
183
+ def test_point() -> None:
184
+ def test_displacement() -> None:
185
+ def test_hull() -> None:
186
+ ```
187
+ - **Assertions**: Use plain `assert` statements
188
+ - **Fixtures**: Use `conftest.py` for shared test data (random point generation)
189
+
190
+ ### Code Organization
191
+ - **Structure**: `src/physdes/` for source, `tests/` for tests
192
+ - **Namespace package**: Use `__init__.py` for version info
193
+ - **Separation of concerns**: Core algorithms in dedicated modules (e.g., `dme_algorithm.py`, `global_router.py`)
194
+ - **Utility functions**: Generic operations in `generic.py` that work with multiple types via `hasattr()` checks:
195
+ ```python
196
+ def overlap(lhs: Any, rhs: Any) -> bool:
197
+ if hasattr(lhs, "overlaps"):
198
+ result = lhs.overlaps(rhs)
199
+ elif hasattr(rhs, "overlaps"):
200
+ result = rhs.overlaps(lhs)
201
+ else: # assume scalar
202
+ result = lhs == rhs
203
+ return bool(result)
204
+ ```
205
+
206
+ ### Pre-commit Hooks
207
+ - **Required**: All code must pass pre-commit checks before committing
208
+ - **Hooks configured**:
209
+ - `trailing-whitespace`
210
+ - `check-added-large-files`
211
+ - `check-ast`
212
+ - `check-merge-conflict`
213
+ - `isort`
214
+ - `black`
215
+ - `flake8`
216
+
217
+ ### Development Guidelines
218
+ - **Python version**: Support 3.8+ (based on version checks in `__init__.py`)
219
+ - **Dependencies**: Minimal external deps (mywheel, icecream, lds_gen for testing)
220
+ - **Backward compatibility**: Use conditional imports for Python < 3.9
221
+ - **Documentation**: Docstrings with parameter descriptions and examples
222
+ - **Type safety**: Use type hints throughout, avoid `as any` or `@ts-ignore` equivalent
223
+
224
+ ### Example Class Template
225
+ ```python
226
+ from typing import Any, Generic, TypeVar, Union
227
+
228
+ T = TypeVar("T", int, float)
229
+
230
+
231
+ class ClassName(Generic[T]):
232
+ """
233
+ Brief description of the class.
234
+
235
+ This code defines...
236
+ """
237
+
238
+ __slots__ = ("_attr1", "_attr2")
239
+
240
+ def __init__(self, attr1: T, attr2: T) -> None:
241
+ """
242
+ Initialize the object.
243
+
244
+ :param attr1: Description of attr1
245
+ :param attr2: Description of attr2
246
+ """
247
+ self._attr1: T = attr1
248
+ self._attr2: T = attr2
249
+
250
+ @property
251
+ def attr1(self) -> T:
252
+ """Return attr1 value."""
253
+ return self._attr1
254
+
255
+ def method_name(self, other: Any) -> Any:
256
+ """
257
+ Method description.
258
+
259
+ :param other: Description of parameter
260
+ :return: Description of return value
261
+ """
262
+ # Implementation
263
+ pass
264
+ ```
265
+
266
+ ## Key Project Context
267
+
268
+ physdes-py implements VLSI physical design algorithms:
269
+ - **Rectilinear polygons**: 2D/3D geometric operations
270
+ - **Clock tree synthesis**: DME (Deferred Merge Embedding) algorithm
271
+ - **Global routing**: Multiple strategies with constraints
272
+ - **Steiner forests**: Grid-based routing algorithms
273
+ - **Key dependencies**: `mywheel` (dllist), `lds_gen` (Halton sequences), `icecream` (debugging)
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## Version 0.7 (2026-07-16)
4
+
5
+ ### Performance
6
+ - **`__slots__` on core geometry classes**: Added `__slots__` to `Point`, `ManhattanArc`, `Polygon`, `RPolygon`, `TreeNode`, `Sink` — saving ~176 bytes per instance. Most impactful on `Point` which is used everywhere in the codebase. (#64242a6)
7
+
8
+ ### Bug Fixes
9
+ - **DME alignment with Rust**: Fixed elongation calculation with `raw_extend_left` to match Rust/C++. Replaced `sorted()` with median-partition in `build_merging_tree` (matches Rust `nth_element`). (#0267be3)
10
+ - **NodeType rename**: Changed `ALL_CAPS` enum values to `PascalCase` to align with Rust naming conventions. (#0267be3)
11
+
12
+ ### Documentation
13
+ - **Doc build scripts**: Updated remark and slide build scripts. Updated example plot scripts for RPolygon, CTS, and global router. (#0a613b3)
14
+
15
+ ### Code Cleanup
16
+ - **Removed PyScaffold boilerplate**: Deleted `skeleton.py`/`test_skeleton.py`, removed Python < 3.9 compat, unused mypy ignores, stale files. (#e594991)
@@ -0,0 +1,40 @@
1
+ # Changelog
2
+ ===========
3
+
4
+ All notable changes to this project will be documented in this file.
5
+
6
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
7
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
+
9
+ This file is managed by towncrier. To add a changelog entry:
10
+
11
+ 1. Create a new file in `changelog/` directory:
12
+ - `changelog/<ISSUE_NUMBER>.<TYPE>.rst`
13
+ - Types: `feature`, `bugfix`, `doc`, `removal`, `misc`
14
+
15
+ 2. Write your change in markdown format using issue number
16
+
17
+ Example: `changelog/123.feature.rst`
18
+ ```rst
19
+ Add automated changelog management (#123)
20
+ ```
21
+
22
+ 3. The changelog will be automatically updated on next release
23
+
24
+ ## [Unreleased]
25
+
26
+ ### Added
27
+ ### Changed
28
+ ### Deprecated
29
+ ### Removed
30
+ ### Fixed
31
+ ### Security
32
+
33
+
34
+ ## Version 0.1
35
+ ==============
36
+
37
+ - Initial release
38
+ - Feature A added
39
+ - FIX: nasty bug #1729 fixed
40
+ - add your changes here!