physdes-py 0.7__tar.gz → 0.9__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.
- physdes_py-0.9/CHANGELOG.md +57 -0
- {physdes_py-0.7/src/physdes_py.egg-info → physdes_py-0.9}/PKG-INFO +1 -2
- {physdes_py-0.7 → physdes_py-0.9}/demo_overlap.py +0 -49
- {physdes_py-0.7 → physdes_py-0.9}/docs/requirements.txt +2 -0
- {physdes_py-0.7 → physdes_py-0.9}/example_route3d_with_constraint_and_keepouts.svg +9 -15
- {physdes_py-0.7 → physdes_py-0.9}/example_route3d_with_steiner_and_keepouts.svg +9 -15
- {physdes_py-0.7 → physdes_py-0.9}/requirements/default.txt +0 -1
- {physdes_py-0.7 → physdes_py-0.9}/setup.cfg +0 -3
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/cts/clk_tree_vis.py +103 -18
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/cts/dme_algorithm.py +38 -26
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/generic.py +0 -44
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/interval.py +0 -39
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/manhattan_arc.py +0 -26
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/point.py +0 -19
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/polygon.py +5 -5
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/recti.py +0 -19
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/router/routing_tree.py +143 -90
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/router/routing_visualizer.py +0 -15
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/rpolygon.py +3 -43
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/rpolygon_cut.py +125 -130
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/steiner_forest/congestion_map.py +9 -8
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/steiner_forest/steiner_forest_grid.py +67 -67
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/vector2.py +0 -20
- {physdes_py-0.7 → physdes_py-0.9/src/physdes_py.egg-info}/PKG-INFO +1 -2
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes_py.egg-info/SOURCES.txt +1 -2
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes_py.egg-info/requires.txt +0 -1
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes_py.egg-info/scm_file_list.json +202 -203
- physdes_py-0.9/src/physdes_py.egg-info/scm_version.json +8 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/conftest.py +13 -0
- physdes_py-0.9/tests/test_benchmarks.py +126 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_clk_tree_vis.py +46 -0
- physdes_py-0.7/.benchmarks/test_area.py +0 -29
- physdes_py-0.7/CHANGELOG.md +0 -16
- physdes_py-0.7/src/physdes/skeleton.py +0 -3
- physdes_py-0.7/src/physdes_py.egg-info/scm_version.json +0 -8
- {physdes_py-0.7 → physdes_py-0.9}/.coveragerc +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.flake8 +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.github/workflows/jekyll-gh-pages.yml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.github/workflows/multi-platforms.yml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.github/workflows/python-app.yml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.github/workflows/python-publish.yml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.gitignore +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.gitpod.Dockerfile +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.gitpod.yml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.hadolint.yaml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.isort.cfg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.markdownlint.yaml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.pre-commit-config.yaml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.readthedocs.yml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/.shellcheckrc +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/AGENTS.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/AUTHORS.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/CHANGELOG.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/CONTRIBUTING.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/GEMINI.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/LICENSE +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/README.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/_config.yml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/alpha10.svg +15 -15
- {physdes_py-0.7 → physdes_py-0.9}/alpha12.svg +12 -12
- {physdes_py-0.7 → physdes_py-0.9}/alpha14.svg +9 -9
- {physdes_py-0.7 → physdes_py-0.9}/alpha8.svg +12 -12
- {physdes_py-0.7 → physdes_py-0.9}/alpha9998.svg +15 -15
- {physdes_py-0.7 → physdes_py-0.9}/changelog/1.misc.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/changelog/README.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/coverage.json +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/demo_overlap.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/diagram.bob +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/dme_algorithm-slides.html +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/dme_algorithm-slides.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/Makefile +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/_static/.gitignore +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/authors.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/build_from_md.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/build_remark.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/build_slides.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/changelog.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/conf.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/contributing.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/contributing.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/essays/essay.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/essays/polygon_vs_rpolygon_comparison.html +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/essays/polygon_vs_rpolygon_comparison.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/examples/plot_cts.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/examples/plot_global_router.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/examples/plot_rectangles.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/examples/plot_rpolygon.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/figures_demo.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/index.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/license.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/misc/note.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/misc/report.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/my_congestion.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/proposals/fyproj2026.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/proposals/fyproj2026.md.bad +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/proposals/fyproj2026_cts.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/proposals/fyproj2026_cts_2d.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/proposals/mulit-fpga-routing.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/readme.rst +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/slides_content.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/docs/steiner_forest_diagonal.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/environment.yml +0 -0
- {physdes_py-0.7/outputs → physdes_py-0.9}/example_route_with_delay_constraint.svg +15 -15
- {physdes_py-0.7 → physdes_py-0.9}/example_route_with_keepouts.svg +9 -9
- {physdes_py-0.7/outputs → physdes_py-0.9}/example_route_with_steiner.svg +9 -9
- {physdes_py-0.7 → physdes_py-0.9}/example_route_with_steiner_and_keepouts.svg +9 -9
- {physdes_py-0.7/outputs → physdes_py-0.9}/example_route_with_steiner_special.svg +12 -12
- {physdes_py-0.7 → physdes_py-0.9}/examples/steiner_forest_grid_example.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/examples/steiner_forest_grid_large_example.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/examples/steiner_forest_simple_example.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/experimental/distance_comparison.png +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/experimental/rectilinear_distance_field.png +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/experimental/rectilinear_voronoi.ipynb +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/experimental/rectilinear_voronoi.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/experimental/rectilinear_voronoi_diamond.png +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/experimental/rectilinear_voronoi_grid.png +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/experimental/rectilinear_voronoi_random.png +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/experimental/steiner_trees_demo.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/global_router-slides.html +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/global_router-slides.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/my_congestion.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/mypy.ini +0 -0
- {physdes_py-0.7/outputs → physdes_py-0.9}/neg_specical10.svg +27 -27
- {physdes_py-0.7 → physdes_py-0.9}/oryx-build-commands.txt +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/comparison.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/convex_hull.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/delay_model_comparison.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/delay_model_comparison3d.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/elmore_model_clock_tree.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/elmore_model_clock_tree3d.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/example_route3d_with_constraint.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/example_route3d_with_constraint_and_keepouts.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/example_route3d_with_steiner.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/example_route3d_with_steiner_and_keepouts.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/example_route_with_constraint.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/example_route_with_constraint_specical.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9/outputs}/example_route_with_delay_constraint.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/example_route_with_keepouts.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9/outputs}/example_route_with_steiner.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/example_route_with_steiner_and_keepouts.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9/outputs}/example_route_with_steiner_special.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/linear_model_clock_tree.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/linear_model_clock_tree3d.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/my_congestion.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9/outputs}/neg_specical10.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/polygon_convex_hull.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/polygon_convex_hull13.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rectilinear-shapes-for-vlsi-physical-desgin.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rpolygon_convex_cut.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rpolygon_cut_explicit.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rpolyon_convex_hull.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rpolyon_convex_hull13.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rpolyon_cut_convex.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rpolyon_cut_convex2.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rpolyon_xmono.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rpolyon_xmono_hull.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/rpolyon_ymono_hull.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/steiner_forest.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/steiner_forest_diagonal.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/test.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/outputs/xmono_hull.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/plot_alpha.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/presentation_overlap_detection.html +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/presentation_overlap_detection.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/pyproject.toml +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/requirements/README.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/requirements/dev.txt +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/requirements/doc.txt +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/requirements/extras.txt +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/requirements/test.txt +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/requirements.txt +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/rpolygon-slides.html +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/rpolygon-slides.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/setup.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/__init__.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/cts/clk_tree3d_vis.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/generic.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/manhattan_arc_3d.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/manhattan_arc_3d.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/point.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/py.typed +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/rdllist.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/router/global_router.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/router/global_router3d.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/router/routing_tree3d.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/router/steiner_forest.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/steiner_forest/my_congestion.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/steiner_forest/steiner_forest.md +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/steiner_forest/steiner_forest.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/steiner_forest/steiner_forest_diagonal.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/to_polygon.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes/vector2.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes_py.egg-info/dependency_links.txt +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes_py.egg-info/not-zip-safe +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/src/physdes_py.egg-info/top_level.txt +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/svgo.config.js +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/test.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/__init__.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/golden.txt +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/mysvg.css +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/pnrpoly.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/run_failing_tests.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_alpha.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_dme_algorithm.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_generic_functions.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_global_router.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_global_router3d.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_global_router3d.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_global_router3d_with_keepouts.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_global_router3d_with_keepouts2.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_global_router_logic.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_global_router_logic3d.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_global_router_with_keepouts.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_global_router_with_keepouts2.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_interval.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_manhattan_arc_3d.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_manhattan_arc_3d.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_merge.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_merge3d.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_nearest_point_to.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_overlap.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_point.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_point_extended.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_point_hypothesis.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_polygon.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_polygon.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_polygon_convex_decomposition.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_polygon_hypothesis.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_rdllist.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_rect3d.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_recti.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_recti_hypothesis.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_routing_tree.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_routing_tree3d.tpy +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_routing_visualizer.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_rpolygon.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_rpolygon_convex_cut.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_rpolygon_convex_hull.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_rpolygon_cut.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_steiner_forest_grid.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_to_polygon.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_vector2.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/test_vector2_hypothesis.py +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/xmono_polygon.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/xmono_polygon2.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/ymono_polygon.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tests/ymono_rpolygon.svg +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/tox.ini +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/wirelength_vs_alpha.png +0 -0
- {physdes_py-0.7 → physdes_py-0.9}/wirelength_vs_alpha_small.png +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Version 0.9 (2026-10-09)
|
|
4
|
+
|
|
5
|
+
### Performance
|
|
6
|
+
- **Hot-path allocation & debug-I/O cuts**: `manhattan_arc` drops live `ic()` calls from the DME embedding path (and removes `icecream` from the runtime deps); `congestion_map` guards its demo behind `__main__`; `steiner_forest_grid` uses an iterative `UnionFind.find`, hoists finds 4→2 per edge, indexes `paid` by edge, and replaces O(|F|²) reverse-delete with union-of-paths pruning (~1.7×); `routing_tree` gets a scalar 2D fast path in `_find_insertion_point` and list-join `get_tree_structure` (~4× insertion); `dme_algorithm` precomputes keys and does a single-pass stable partition in `_build_merging_tree` (1.2–1.5×). Output-identical, verified by differential tests. (#10a4e9f)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
- **Unbounded wirelength sentinel**: `insert_terminal_with_steiner` previously ignored the tree's `worst_wirelength` by passing a literal `10**12`; the default is now `float('inf')` and Steiner insertion passes it through, so the unconstrained variant honors any caller-set bound. (#0947827)
|
|
10
|
+
|
|
11
|
+
### Testing & Code Quality
|
|
12
|
+
- **Temp-cwd isolation for tests**: Added an autouse `_isolate_cwd` fixture so visualization tests' relative-path SVG writes land in pytest's temporary directory instead of the repository root. (#409d422)
|
|
13
|
+
- **New benchmarks**: Added `test_benchmarks.py` (5 benchmarks). (#10a4e9f)
|
|
14
|
+
|
|
15
|
+
### Code Cleanup
|
|
16
|
+
- **SVG EOF newlines**: Added trailing newlines to the example SVGs and formatted the sources. (#0c698e0)
|
|
17
|
+
|
|
18
|
+
### Build & CI
|
|
19
|
+
- **Dropped `icecream` runtime dep**: Removed it from `setup.cfg` and `requirements/default.txt`. (#10a4e9f)
|
|
20
|
+
|
|
21
|
+
## Version 0.8 (2026-09-04)
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
- **Builder pattern for ClockTreeVisualizer**: Added fluent `ClockTreeVisualizerBuilder` (`builder().margin(..).node_radius(..)...build()`) mirroring the C++/Rust siblings; `create_interactive_svg` and `create_comparison_visualization` now use it. (#311848a)
|
|
25
|
+
|
|
26
|
+
### Refactoring
|
|
27
|
+
- **Template Method in rpolygon cut decomposition**: Collapsed the duplicated convex/explicit recursive decomposers into one `rpolygon_cut_recur` Template Method plus shared `rpolygon_cut_impl`; public entry points unchanged. (#3666c82)
|
|
28
|
+
- **Factory Method in global routing tree**: Concentrated 5 duplicated ID-generation/registration sites behind a single `_create_node` factory, preserving the `insert_node_on_branch` ValueError contract and ordering constraints. (#2e03732)
|
|
29
|
+
- **Module-level logging**: Replaced `skeleton._logger` with standard module-level `logging`. (#6c863fd)
|
|
30
|
+
|
|
31
|
+
### Testing & Code Quality
|
|
32
|
+
- **Builder tests**: Added tests for builder output, default-equivalence and fluent reuse, plus a doctest on the builder class. (#311848a)
|
|
33
|
+
- **mypy fixes**: Resolved None checks and type annotations. (#2a5f7b2)
|
|
34
|
+
|
|
35
|
+
### Code Cleanup
|
|
36
|
+
- **Removed AI slop**: Stripped boilerplate from docstrings and comments. (#587ad95)
|
|
37
|
+
- **Deduped route3d legends**: Removed duplicated legend entries in example SVGs. (#678aa21)
|
|
38
|
+
- **Stripped empty `entry_points`**: Removed dead section from setup.cfg. (#fd06baf)
|
|
39
|
+
- **EOF newlines in example SVGs**: Added trailing newlines to 15 figures and formatted sources. (#23aaf16)
|
|
40
|
+
|
|
41
|
+
### Build & CI
|
|
42
|
+
- **RTD doc build**: Added matplotlib and numpy to `docs/requirements.txt`. (#41cad71)
|
|
43
|
+
|
|
44
|
+
## Version 0.7 (2026-07-16)
|
|
45
|
+
|
|
46
|
+
### Performance
|
|
47
|
+
- **`__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)
|
|
48
|
+
|
|
49
|
+
### Bug Fixes
|
|
50
|
+
- **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)
|
|
51
|
+
- **NodeType rename**: Changed `ALL_CAPS` enum values to `PascalCase` to align with Rust naming conventions. (#0267be3)
|
|
52
|
+
|
|
53
|
+
### Documentation
|
|
54
|
+
- **Doc build scripts**: Updated remark and slide build scripts. Updated example plot scripts for RPolygon, CTS, and global router. (#0a613b3)
|
|
55
|
+
|
|
56
|
+
### Code Cleanup
|
|
57
|
+
- **Removed PyScaffold boilerplate**: Deleted `skeleton.py`/`test_skeleton.py`, removed Python < 3.9 compat, unused mypy ignores, stale files. (#e594991)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: physdes-py
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9
|
|
4
4
|
Summary: Physical Design Python Code
|
|
5
5
|
Home-page: https://github.com/luk036/physdes-py/
|
|
6
6
|
Author: Wai-Shing Luk
|
|
@@ -13,7 +13,6 @@ Classifier: Programming Language :: Python
|
|
|
13
13
|
Description-Content-Type: text/markdown; charset=UTF-8
|
|
14
14
|
Requires-Dist: typing_extensions
|
|
15
15
|
Requires-Dist: mywheel
|
|
16
|
-
Requires-Dist: icecream
|
|
17
16
|
Provides-Extra: testing
|
|
18
17
|
Requires-Dist: setuptools; extra == "testing"
|
|
19
18
|
Requires-Dist: pytest; extra == "testing"
|
|
@@ -9,7 +9,6 @@ from typing import Generator
|
|
|
9
9
|
|
|
10
10
|
from lds_gen.ilds import Halton
|
|
11
11
|
|
|
12
|
-
# from physdes.interval import Interval
|
|
13
12
|
from physdes.point import Point
|
|
14
13
|
from physdes.recti import detect_overlap_gen
|
|
15
14
|
|
|
@@ -59,24 +58,6 @@ def visualize_overlap_svg(
|
|
|
59
58
|
f'<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="{height}" style="background-color:#f8f9fa;">',
|
|
60
59
|
]
|
|
61
60
|
|
|
62
|
-
# legend_y = 30
|
|
63
|
-
# svg_parts.append(f'<text x="{margin}" y="{legend_y}" font-size="14" fill="#333">Rectangles</text>')
|
|
64
|
-
# legend_y += 20
|
|
65
|
-
# svg_parts.append(f'<rect x="{margin}" y="{legend_y - 12}" width="16" height="12" fill="#4a90d9" stroke="#333"/>')
|
|
66
|
-
# svg_parts.append(f'<text x="{margin + 20}" y="{legend_y}" font-size="12" fill="#333">Non-overlapping</text>')
|
|
67
|
-
# legend_y += 20
|
|
68
|
-
# svg_parts.append(f'<rect x="{margin}" y="{legend_y - 12}" width="16" height="12" fill="#e74c3c" stroke="#c0392b"/>')
|
|
69
|
-
# svg_parts.append(f'<text x="{margin + 20}" y="{legend_y}" font-size="12" fill="#333">Overlapping</text>')
|
|
70
|
-
# if overlapping_pair:
|
|
71
|
-
# legend_y += 20
|
|
72
|
-
# svg_parts.append(f'<text x="{margin + 20}" y="{legend_y}" font-size="12" fill="#e74c3c">Overlap detected!</text>')
|
|
73
|
-
# legend_y += 20
|
|
74
|
-
# pair1_str = f"({overlapping_pair[0].xcoord}, {overlapping_pair[0].ycoord})"
|
|
75
|
-
# svg_parts.append(f'<text x="{margin + 20}" y="{legend_y}" font-size="11" fill="#666">{pair1_str}</text>')
|
|
76
|
-
# legend_y += 15
|
|
77
|
-
# pair2_str = f"({overlapping_pair[1].xcoord}, {overlapping_pair[1].ycoord})"
|
|
78
|
-
# svg_parts.append(f'<text x="{margin + 20}" y="{legend_y}" font-size="11" fill="#666">{pair2_str}</text>')
|
|
79
|
-
|
|
80
61
|
for idx, r in enumerate(rectangles):
|
|
81
62
|
x1 = to_svg_x(r.xcoord.lb)
|
|
82
63
|
y1 = to_svg_y(r.ycoord.ub)
|
|
@@ -96,10 +77,6 @@ def visualize_overlap_svg(
|
|
|
96
77
|
f'<rect x="{x1}" y="{y1}" width="{w}" height="{h}" fill="{fill}" stroke="{stroke}" stroke-width="2" opacity="{opacity}"/>'
|
|
97
78
|
)
|
|
98
79
|
|
|
99
|
-
# cx = x1 + w / 2
|
|
100
|
-
# cy = y1 + h / 2
|
|
101
|
-
# svg_parts.append(f'<text x="{cx}" y="{cy + 4}" text-anchor="middle" font-size="11" fill="white" font-weight="bold">{idx + 1}</text>')
|
|
102
|
-
|
|
103
80
|
svg_parts.append("</svg>")
|
|
104
81
|
return "\n".join(svg_parts)
|
|
105
82
|
|
|
@@ -111,38 +88,12 @@ def demo() -> None:
|
|
|
111
88
|
coords = [hgen.pop() for _ in range(500)]
|
|
112
89
|
svg_rects = [Point(coord[0], coord[1]).enlarge_with(10) for coord in coords]
|
|
113
90
|
|
|
114
|
-
# svg_rects = [
|
|
115
|
-
# Rectangle(Interval(0, 4), Interval(0, 4)),
|
|
116
|
-
# Rectangle(Interval(2, 6), Interval(2, 6)),
|
|
117
|
-
# Rectangle(Interval(5, 9), Interval(5, 9)),
|
|
118
|
-
# Rectangle(Interval(8, 12), Interval(8, 12)),
|
|
119
|
-
# Rectangle(Interval(11, 15), Interval(11, 15)),
|
|
120
|
-
# Rectangle(Interval(3, 7), Interval(10, 14)),
|
|
121
|
-
# Rectangle(Interval(14, 18), Interval(14, 18)),
|
|
122
|
-
# Rectangle(Interval(16, 20), Interval(4, 8)),
|
|
123
|
-
# Rectangle(Interval(6, 10), Interval(6, 10)),
|
|
124
|
-
# Rectangle(Interval(9, 13), Interval(12, 16)),
|
|
125
|
-
# Rectangle(Interval(0, 3), Interval(8, 11)),
|
|
126
|
-
# ]
|
|
127
|
-
|
|
128
|
-
# print(f"Testing with {len(svg_rects)} rectangles:")
|
|
129
|
-
# for i, r in enumerate(svg_rects):
|
|
130
|
-
# print(f" {i + 1}: ({r.xcoord}, {r.ycoord})")
|
|
131
|
-
|
|
132
91
|
print()
|
|
133
92
|
print("=" * 50)
|
|
134
93
|
print("Overlap Detection Result")
|
|
135
94
|
print("=" * 50)
|
|
136
95
|
overlap_result_gen = detect_overlap_gen(svg_rects)
|
|
137
96
|
|
|
138
|
-
# for overlap_result in overlap_result_gen:
|
|
139
|
-
# r1, r2 = overlap_result
|
|
140
|
-
# print("OVERLAP DETECTED between:")
|
|
141
|
-
# print(f" Rect A: ({r1.xcoord}, {r1.ycoord})")
|
|
142
|
-
# print(f" Rect B: ({r2.xcoord}, {r2.ycoord})")
|
|
143
|
-
# else:
|
|
144
|
-
# print("No overlap found")
|
|
145
|
-
|
|
146
97
|
svg = visualize_overlap_svg(svg_rects, overlap_result_gen)
|
|
147
98
|
|
|
148
99
|
with open("demo_overlap.svg", "w") as f:
|
|
@@ -24,27 +24,27 @@
|
|
|
24
24
|
<circle cx="455.64903846153845" cy="357.6923076923077" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
25
25
|
<text x="463.64903846153845" y="361.6923076923077" font-family="Arial" font-size="10" fill="black">T2</text>
|
|
26
26
|
<text x="455.64903846153845" y="346.6923076923077" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(377,216)</text>
|
|
27
|
-
<circle cx="163.58173076923077" cy="396.15384615384613" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
28
|
-
<text x="171.58173076923077" y="400.15384615384613" font-family="Arial" font-size="10" fill="black">S1</text>
|
|
29
|
-
<text x="163.58173076923077" y="385.15384615384613" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-595,344)</text>
|
|
30
27
|
<circle cx="236.59855769230768" cy="50.0" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
31
28
|
<text x="244.59855769230768" y="54.0" font-family="Arial" font-size="10" fill="black">T3</text>
|
|
32
29
|
<text x="236.59855769230768" y="39.0" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-352,-808)</text>
|
|
33
|
-
<circle cx="
|
|
34
|
-
<text x="
|
|
35
|
-
<text x="
|
|
30
|
+
<circle cx="163.58173076923077" cy="396.15384615384613" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
31
|
+
<text x="171.58173076923077" y="400.15384615384613" font-family="Arial" font-size="10" fill="black">S1</text>
|
|
32
|
+
<text x="163.58173076923077" y="385.15384615384613" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-595,344)</text>
|
|
36
33
|
<circle cx="382.63221153846155" cy="242.3076923076923" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
37
34
|
<text x="390.63221153846155" y="246.3076923076923" font-family="Arial" font-size="10" fill="black">T4</text>
|
|
38
35
|
<text x="382.63221153846155" y="231.3076923076923" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(134,-168)</text>
|
|
36
|
+
<circle cx="382.63221153846155" cy="357.6923076923077" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
37
|
+
<text x="390.63221153846155" y="361.6923076923077" font-family="Arial" font-size="10" fill="black">S2</text>
|
|
38
|
+
<text x="382.63221153846155" y="346.6923076923077" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(134,216)</text>
|
|
39
39
|
<circle cx="601.6826923076923" cy="550.0" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
40
40
|
<text x="609.6826923076923" y="554.0" font-family="Arial" font-size="10" fill="black">T5</text>
|
|
41
41
|
<text x="601.6826923076923" y="539.0" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(863,856)</text>
|
|
42
|
-
<circle cx="236.59855769230768" cy="88.46153846153845" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
43
|
-
<text x="244.59855769230768" y="92.46153846153845" font-family="Arial" font-size="10" fill="black">S3</text>
|
|
44
|
-
<text x="236.59855769230768" y="77.46153846153845" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-352,-680)</text>
|
|
45
42
|
<circle cx="528.6658653846154" cy="88.46153846153845" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
46
43
|
<text x="536.6658653846154" y="92.46153846153845" font-family="Arial" font-size="10" fill="black">T6</text>
|
|
47
44
|
<text x="528.6658653846154" y="77.46153846153845" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(620,-680)</text>
|
|
45
|
+
<circle cx="236.59855769230768" cy="88.46153846153845" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
46
|
+
<text x="244.59855769230768" y="92.46153846153845" font-family="Arial" font-size="10" fill="black">S3</text>
|
|
47
|
+
<text x="236.59855769230768" y="77.46153846153845" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-352,-680)</text>
|
|
48
48
|
<circle cx="674.6995192307692" cy="203.84615384615384" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
49
49
|
<text x="682.6995192307692" y="207.84615384615384" font-family="Arial" font-size="10" fill="black">T7</text>
|
|
50
50
|
<text x="674.6995192307692" y="192.84615384615384" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(1106,-296)</text>
|
|
@@ -57,12 +57,6 @@
|
|
|
57
57
|
<text x="30" y="60" font-family="Arial" font-size="10">Steiner</text>
|
|
58
58
|
<circle cx="20" cy="76" r="4" fill="green" stroke="black"/>
|
|
59
59
|
<text x="30" y="80" font-family="Arial" font-size="10">Terminal</text>
|
|
60
|
-
<circle cx="20" cy="36" r="4" fill="red" stroke="black"/>
|
|
61
|
-
<text x="30" y="40" font-family="Arial" font-size="10">Source</text>
|
|
62
|
-
<circle cx="20" cy="56" r="4" fill="blue" stroke="black"/>
|
|
63
|
-
<text x="30" y="60" font-family="Arial" font-size="10">Steiner</text>
|
|
64
|
-
<circle cx="20" cy="76" r="4" fill="green" stroke="black"/>
|
|
65
|
-
<text x="30" y="80" font-family="Arial" font-size="10">Terminal</text>
|
|
66
60
|
<text x="20" y="110" font-family="Arial" font-size="10" font-weight="bold">Statistics:</text>
|
|
67
61
|
<text x="20" y="125" font-family="Arial" font-size="9">Total Nodes: 11</text>
|
|
68
62
|
<text x="20" y="140" font-family="Arial" font-size="9">Terminals: 7</text>
|
|
@@ -24,27 +24,27 @@
|
|
|
24
24
|
<circle cx="455.64903846153845" cy="357.6923076923077" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
25
25
|
<text x="463.64903846153845" y="361.6923076923077" font-family="Arial" font-size="10" fill="black">T2</text>
|
|
26
26
|
<text x="455.64903846153845" y="346.6923076923077" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(377,216)</text>
|
|
27
|
-
<circle cx="163.58173076923077" cy="396.15384615384613" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
28
|
-
<text x="171.58173076923077" y="400.15384615384613" font-family="Arial" font-size="10" fill="black">S1</text>
|
|
29
|
-
<text x="163.58173076923077" y="385.15384615384613" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-595,344)</text>
|
|
30
27
|
<circle cx="236.59855769230768" cy="50.0" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
31
28
|
<text x="244.59855769230768" y="54.0" font-family="Arial" font-size="10" fill="black">T3</text>
|
|
32
29
|
<text x="236.59855769230768" y="39.0" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-352,-808)</text>
|
|
33
|
-
<circle cx="
|
|
34
|
-
<text x="
|
|
35
|
-
<text x="
|
|
30
|
+
<circle cx="163.58173076923077" cy="396.15384615384613" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
31
|
+
<text x="171.58173076923077" y="400.15384615384613" font-family="Arial" font-size="10" fill="black">S1</text>
|
|
32
|
+
<text x="163.58173076923077" y="385.15384615384613" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-595,344)</text>
|
|
36
33
|
<circle cx="382.63221153846155" cy="242.3076923076923" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
37
34
|
<text x="390.63221153846155" y="246.3076923076923" font-family="Arial" font-size="10" fill="black">T4</text>
|
|
38
35
|
<text x="382.63221153846155" y="231.3076923076923" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(134,-168)</text>
|
|
36
|
+
<circle cx="382.63221153846155" cy="357.6923076923077" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
37
|
+
<text x="390.63221153846155" y="361.6923076923077" font-family="Arial" font-size="10" fill="black">S2</text>
|
|
38
|
+
<text x="382.63221153846155" y="346.6923076923077" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(134,216)</text>
|
|
39
39
|
<circle cx="601.6826923076923" cy="550.0" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
40
40
|
<text x="609.6826923076923" y="554.0" font-family="Arial" font-size="10" fill="black">T5</text>
|
|
41
41
|
<text x="601.6826923076923" y="539.0" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(863,856)</text>
|
|
42
|
-
<circle cx="236.59855769230768" cy="88.46153846153845" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
43
|
-
<text x="244.59855769230768" y="92.46153846153845" font-family="Arial" font-size="10" fill="black">S3</text>
|
|
44
|
-
<text x="236.59855769230768" y="77.46153846153845" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-352,-680)</text>
|
|
45
42
|
<circle cx="528.6658653846154" cy="88.46153846153845" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
46
43
|
<text x="536.6658653846154" y="92.46153846153845" font-family="Arial" font-size="10" fill="black">T6</text>
|
|
47
44
|
<text x="528.6658653846154" y="77.46153846153845" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(620,-680)</text>
|
|
45
|
+
<circle cx="236.59855769230768" cy="88.46153846153845" r="6" fill="blue" stroke="black" stroke-width="1"/>
|
|
46
|
+
<text x="244.59855769230768" y="92.46153846153845" font-family="Arial" font-size="10" fill="black">S3</text>
|
|
47
|
+
<text x="236.59855769230768" y="77.46153846153845" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(-352,-680)</text>
|
|
48
48
|
<circle cx="674.6995192307692" cy="203.84615384615384" r="6" fill="green" stroke="black" stroke-width="1"/>
|
|
49
49
|
<text x="682.6995192307692" y="207.84615384615384" font-family="Arial" font-size="10" fill="black">T7</text>
|
|
50
50
|
<text x="674.6995192307692" y="192.84615384615384" font-family="Arial" font-size="8" fill="gray" text-anchor="middle">(1106,-296)</text>
|
|
@@ -57,12 +57,6 @@
|
|
|
57
57
|
<text x="30" y="60" font-family="Arial" font-size="10">Steiner</text>
|
|
58
58
|
<circle cx="20" cy="76" r="4" fill="green" stroke="black"/>
|
|
59
59
|
<text x="30" y="80" font-family="Arial" font-size="10">Terminal</text>
|
|
60
|
-
<circle cx="20" cy="36" r="4" fill="red" stroke="black"/>
|
|
61
|
-
<text x="30" y="40" font-family="Arial" font-size="10">Source</text>
|
|
62
|
-
<circle cx="20" cy="56" r="4" fill="blue" stroke="black"/>
|
|
63
|
-
<text x="30" y="60" font-family="Arial" font-size="10">Steiner</text>
|
|
64
|
-
<circle cx="20" cy="76" r="4" fill="green" stroke="black"/>
|
|
65
|
-
<text x="30" y="80" font-family="Arial" font-size="10">Terminal</text>
|
|
66
60
|
<text x="20" y="110" font-family="Arial" font-size="10" font-weight="bold">Statistics:</text>
|
|
67
61
|
<text x="20" y="125" font-family="Arial" font-size="9">Total Nodes: 11</text>
|
|
68
62
|
<text x="20" y="140" font-family="Arial" font-size="9">Terminals: 7</text>
|
|
@@ -24,7 +24,6 @@ package_dir =
|
|
|
24
24
|
install_requires =
|
|
25
25
|
typing_extensions
|
|
26
26
|
mywheel
|
|
27
|
-
icecream
|
|
28
27
|
|
|
29
28
|
[options.packages.find]
|
|
30
29
|
where = src
|
|
@@ -50,8 +49,6 @@ dev =
|
|
|
50
49
|
safety
|
|
51
50
|
towncrier
|
|
52
51
|
|
|
53
|
-
[options.entry_points]
|
|
54
|
-
|
|
55
52
|
[tool:pytest]
|
|
56
53
|
addopts =
|
|
57
54
|
--verbose
|
|
@@ -14,6 +14,84 @@ from physdes.cts.dme_algorithm import Sink
|
|
|
14
14
|
from physdes.point import Point
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
class ClockTreeVisualizerBuilder:
|
|
18
|
+
"""
|
|
19
|
+
Fluent builder for configuring a ClockTreeVisualizer.
|
|
20
|
+
|
|
21
|
+
Unset options fall back to the same defaults as ``ClockTreeVisualizer()``.
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
>>> viz = ClockTreeVisualizerBuilder().margin(10).node_radius(5).build()
|
|
25
|
+
>>> viz.margin
|
|
26
|
+
10
|
|
27
|
+
>>> viz.node_radius
|
|
28
|
+
5
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self) -> None:
|
|
32
|
+
self._margin = 50
|
|
33
|
+
self._node_radius = 8
|
|
34
|
+
self._wire_width = 2
|
|
35
|
+
self._sink_color = "#4CAF50"
|
|
36
|
+
self._internal_color = "#2196F3"
|
|
37
|
+
self._root_color = "#F44336"
|
|
38
|
+
self._wire_color = "#666666"
|
|
39
|
+
self._text_color = "#333333"
|
|
40
|
+
|
|
41
|
+
def margin(self, value: int) -> "ClockTreeVisualizerBuilder":
|
|
42
|
+
"""Set the margin around the drawing."""
|
|
43
|
+
self._margin = value
|
|
44
|
+
return self
|
|
45
|
+
|
|
46
|
+
def node_radius(self, value: int) -> "ClockTreeVisualizerBuilder":
|
|
47
|
+
"""Set the radius of node circles."""
|
|
48
|
+
self._node_radius = value
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
def wire_width(self, value: int) -> "ClockTreeVisualizerBuilder":
|
|
52
|
+
"""Set the width of wire lines."""
|
|
53
|
+
self._wire_width = value
|
|
54
|
+
return self
|
|
55
|
+
|
|
56
|
+
def sink_color(self, value: str) -> "ClockTreeVisualizerBuilder":
|
|
57
|
+
"""Set the color for sink nodes."""
|
|
58
|
+
self._sink_color = value
|
|
59
|
+
return self
|
|
60
|
+
|
|
61
|
+
def internal_color(self, value: str) -> "ClockTreeVisualizerBuilder":
|
|
62
|
+
"""Set the color for internal nodes."""
|
|
63
|
+
self._internal_color = value
|
|
64
|
+
return self
|
|
65
|
+
|
|
66
|
+
def root_color(self, value: str) -> "ClockTreeVisualizerBuilder":
|
|
67
|
+
"""Set the color for the root node."""
|
|
68
|
+
self._root_color = value
|
|
69
|
+
return self
|
|
70
|
+
|
|
71
|
+
def wire_color(self, value: str) -> "ClockTreeVisualizerBuilder":
|
|
72
|
+
"""Set the color for wires."""
|
|
73
|
+
self._wire_color = value
|
|
74
|
+
return self
|
|
75
|
+
|
|
76
|
+
def text_color(self, value: str) -> "ClockTreeVisualizerBuilder":
|
|
77
|
+
"""Set the color for text labels."""
|
|
78
|
+
self._text_color = value
|
|
79
|
+
return self
|
|
80
|
+
|
|
81
|
+
def build(self) -> "ClockTreeVisualizer":
|
|
82
|
+
"""Build the configured ClockTreeVisualizer."""
|
|
83
|
+
return ClockTreeVisualizer(
|
|
84
|
+
margin=self._margin,
|
|
85
|
+
node_radius=self._node_radius,
|
|
86
|
+
wire_width=self._wire_width,
|
|
87
|
+
sink_color=self._sink_color,
|
|
88
|
+
internal_color=self._internal_color,
|
|
89
|
+
root_color=self._root_color,
|
|
90
|
+
wire_color=self._wire_color,
|
|
91
|
+
text_color=self._text_color,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
17
95
|
class ClockTreeVisualizer:
|
|
18
96
|
"""Visualizes clock trees in SVG format"""
|
|
19
97
|
|
|
@@ -57,6 +135,11 @@ class ClockTreeVisualizer:
|
|
|
57
135
|
self.wire_color = wire_color
|
|
58
136
|
self.text_color = text_color
|
|
59
137
|
|
|
138
|
+
@classmethod
|
|
139
|
+
def builder(cls) -> ClockTreeVisualizerBuilder:
|
|
140
|
+
"""Return a fluent builder for customizing the visualizer appearance."""
|
|
141
|
+
return ClockTreeVisualizerBuilder()
|
|
142
|
+
|
|
60
143
|
def visualize_tree(
|
|
61
144
|
self,
|
|
62
145
|
root: Any,
|
|
@@ -344,15 +427,17 @@ def create_interactive_svg(
|
|
|
344
427
|
SVG string content
|
|
345
428
|
"""
|
|
346
429
|
|
|
347
|
-
visualizer =
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
430
|
+
visualizer = (
|
|
431
|
+
ClockTreeVisualizer.builder()
|
|
432
|
+
.margin(60)
|
|
433
|
+
.node_radius(10)
|
|
434
|
+
.wire_width(3)
|
|
435
|
+
.sink_color("#2E7D32")
|
|
436
|
+
.internal_color("#1565C0")
|
|
437
|
+
.root_color("#C62828")
|
|
438
|
+
.wire_color("#455A64")
|
|
439
|
+
.text_color("#263238")
|
|
440
|
+
.build()
|
|
356
441
|
)
|
|
357
442
|
|
|
358
443
|
svg_content = visualizer.visualize_tree(
|
|
@@ -421,13 +506,15 @@ def create_comparison_visualization(
|
|
|
421
506
|
'<rect width="100%" height="100%" fill="white"/>',
|
|
422
507
|
]
|
|
423
508
|
|
|
424
|
-
visualizer =
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
509
|
+
visualizer = (
|
|
510
|
+
ClockTreeVisualizer.builder()
|
|
511
|
+
.margin(40)
|
|
512
|
+
.node_radius(6)
|
|
513
|
+
.wire_width(2)
|
|
514
|
+
.sink_color("#4CAF50")
|
|
515
|
+
.internal_color("#2196F3")
|
|
516
|
+
.root_color("#F44336")
|
|
517
|
+
.build()
|
|
431
518
|
)
|
|
432
519
|
|
|
433
520
|
for i, tree_data in enumerate(trees_data):
|
|
@@ -539,8 +626,6 @@ def visualize_example_tree() -> Tuple[str, str, str]:
|
|
|
539
626
|
LinearDelayCalculator,
|
|
540
627
|
)
|
|
541
628
|
|
|
542
|
-
# coords = generate_random_points_for_sinks()
|
|
543
|
-
# example_sinks = [Sink(f"s{i}", Point(x * 100, y * 100), 1.0) for i, (x, y) in enumerate(coords)]
|
|
544
629
|
# Generate example clock tree with both delay models
|
|
545
630
|
example_sinks = [
|
|
546
631
|
Sink("s1", Point(-100, 40), 1.0),
|
|
@@ -22,13 +22,15 @@ Key components of the module include:
|
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
24
|
import doctest
|
|
25
|
+
import logging
|
|
25
26
|
from abc import ABC, abstractmethod
|
|
26
27
|
from typing import Any, Dict, List, Optional, Tuple, Type, Union
|
|
27
28
|
|
|
28
29
|
from physdes.manhattan_arc import ManhattanArc
|
|
29
30
|
from physdes.manhattan_arc_3d import ManhattanArc3D
|
|
30
31
|
from physdes.point import Point
|
|
31
|
-
|
|
32
|
+
|
|
33
|
+
_logger = logging.getLogger(__name__)
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
class Sink:
|
|
@@ -74,7 +76,7 @@ class TreeNode:
|
|
|
74
76
|
self.left = left
|
|
75
77
|
self.right = right
|
|
76
78
|
self.parent = parent
|
|
77
|
-
self.segment = None # merging segment, set during DME
|
|
79
|
+
self.segment: Any = None # merging segment, set during DME
|
|
78
80
|
self.wire_length = wire_length
|
|
79
81
|
self.delay = delay
|
|
80
82
|
self.capacitance = capacitance
|
|
@@ -374,9 +376,7 @@ class DMEAlgorithm:
|
|
|
374
376
|
) -> "TreeNode":
|
|
375
377
|
"""Build balanced merging tree using median-partition (like Rust's select_nth_unstable_by)."""
|
|
376
378
|
if hi is None:
|
|
377
|
-
nodes.sort(
|
|
378
|
-
key=lambda n: n.position.ycoord
|
|
379
|
-
)
|
|
379
|
+
nodes.sort(key=lambda n: n.position.ycoord)
|
|
380
380
|
hi = len(nodes)
|
|
381
381
|
|
|
382
382
|
count = hi - lo
|
|
@@ -386,21 +386,25 @@ class DMEAlgorithm:
|
|
|
386
386
|
raise ValueError("Empty node range")
|
|
387
387
|
|
|
388
388
|
mid = lo + count // 2
|
|
389
|
-
key_fn = (lambda n: n.position.xcoord) if vertical else (lambda n: n.position.ycoord)
|
|
390
389
|
|
|
391
|
-
# Median-partition in O(n): like Rust's select_nth_unstable_by / C++ nth_element
|
|
392
390
|
sub = nodes[lo:hi]
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
391
|
+
keys = (
|
|
392
|
+
[n.position.xcoord for n in sub]
|
|
393
|
+
if vertical
|
|
394
|
+
else [n.position.ycoord for n in sub]
|
|
395
|
+
)
|
|
396
|
+
median_val = sorted(keys)[count // 2]
|
|
397
|
+
lt: List["TreeNode"] = []
|
|
398
|
+
eq: List["TreeNode"] = []
|
|
399
|
+
gt: List["TreeNode"] = []
|
|
400
|
+
for node, value in zip(sub, keys):
|
|
401
|
+
if value < median_val:
|
|
402
|
+
lt.append(node)
|
|
403
|
+
elif value == median_val:
|
|
404
|
+
eq.append(node)
|
|
405
|
+
else:
|
|
406
|
+
gt.append(node)
|
|
407
|
+
nodes[lo:hi] = lt + eq + gt
|
|
404
408
|
|
|
405
409
|
left_child = self._build_merging_tree(nodes, not vertical, lo, mid)
|
|
406
410
|
right_child = self._build_merging_tree(nodes, not vertical, mid, hi)
|
|
@@ -441,11 +445,16 @@ class DMEAlgorithm:
|
|
|
441
445
|
distance = left_ms.min_dist_with(right_ms) # type: ignore[arg-type]
|
|
442
446
|
|
|
443
447
|
# Pure calculator: no node mutation inside
|
|
444
|
-
(
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
448
|
+
(
|
|
449
|
+
extend_left,
|
|
450
|
+
raw_extend_left,
|
|
451
|
+
delay_left,
|
|
452
|
+
) = self.delay_calculator.calculate_tapping_point(
|
|
453
|
+
distance,
|
|
454
|
+
node.left.delay,
|
|
455
|
+
node.right.delay,
|
|
456
|
+
node.left.capacitance,
|
|
457
|
+
node.right.capacitance,
|
|
449
458
|
)
|
|
450
459
|
|
|
451
460
|
# Apply elongation logic (matches Rust/C++ TappingResult handling)
|
|
@@ -500,15 +509,18 @@ class DMEAlgorithm:
|
|
|
500
509
|
|
|
501
510
|
if parent_segment is None:
|
|
502
511
|
node_segment = node.segment
|
|
512
|
+
if node_segment is None:
|
|
513
|
+
return
|
|
503
514
|
if self.source is None:
|
|
504
515
|
node.position = node_segment.get_upper_corner()
|
|
505
516
|
else:
|
|
506
517
|
node.position = node_segment.nearest_point_to(self.source)
|
|
507
518
|
else:
|
|
508
519
|
node_segment = node.segment
|
|
509
|
-
if node.parent:
|
|
510
|
-
|
|
511
|
-
|
|
520
|
+
if node_segment is None or node.parent is None:
|
|
521
|
+
return
|
|
522
|
+
node.position = node_segment.nearest_point_to(node.parent.position)
|
|
523
|
+
node.wire_length = node.position.min_dist_with(node.parent.position)
|
|
512
524
|
|
|
513
525
|
embed_node(node.left, node.segment)
|
|
514
526
|
embed_node(node.right, node.segment)
|
|
@@ -234,50 +234,6 @@ def nearest(lhs: Any, rhs: Any) -> Any:
|
|
|
234
234
|
return lhs
|
|
235
235
|
|
|
236
236
|
|
|
237
|
-
# def min_dist_change(lhs, rhs):
|
|
238
|
-
# """
|
|
239
|
-
# The `min_dist_change` function calculates the minimum Manhattan distance change between two objects.
|
|
240
|
-
#
|
|
241
|
-
# :param lhs: The `lhs` parameter represents the left-hand side value or object that you want to
|
|
242
|
-
# compare
|
|
243
|
-
# :param rhs: The `rhs` parameter represents the right-hand side value or object that we want to
|
|
244
|
-
# compare with the `lhs` parameter
|
|
245
|
-
# :return: The function `min_dist_change` returns the minimum Manhattan distance change between `lhs` and `rhs`.
|
|
246
|
-
#
|
|
247
|
-
# Examples:
|
|
248
|
-
# >>> min_dist_change(1, 1)
|
|
249
|
-
# 0
|
|
250
|
-
# >>> min_dist_change(1, 3)
|
|
251
|
-
# 2
|
|
252
|
-
# >>> min_dist_change(Interval(1, 2), Interval(2, 3))
|
|
253
|
-
# 0
|
|
254
|
-
# >>> min_dist_change(Interval(1, 2), Interval(3, 4))
|
|
255
|
-
# 1
|
|
256
|
-
# >>> min_dist_change(Interval(1, 2), 2)
|
|
257
|
-
# 0
|
|
258
|
-
# >>> min_dist_change(Interval(1, 2), 4)
|
|
259
|
-
# 2
|
|
260
|
-
# >>> min_dist_change(2, Interval(2, 3))
|
|
261
|
-
# 0
|
|
262
|
-
# >>> min_dist_change(1, Interval(3, 4))
|
|
263
|
-
# 2
|
|
264
|
-
# >>> min_dist_change(1, Interval(1, 2))
|
|
265
|
-
# 0
|
|
266
|
-
# >>> min_dist_change(Interval(1, 2), Interval(1, 2))
|
|
267
|
-
# 0
|
|
268
|
-
# >>> min_dist_change(Interval(1, 2), Interval(2, 3))
|
|
269
|
-
# 0
|
|
270
|
-
# >>> min_dist_change(Interval(1, 2), 2)
|
|
271
|
-
# 0
|
|
272
|
-
# """
|
|
273
|
-
# if hasattr(lhs, "min_dist_change_with"):
|
|
274
|
-
# return lhs.min_dist_change_with(rhs)
|
|
275
|
-
# elif hasattr(rhs, "min_dist_change_with"):
|
|
276
|
-
# return rhs.min_dist_change_with(lhs)
|
|
277
|
-
# else: # assume scalar
|
|
278
|
-
# return abs(lhs - rhs)
|
|
279
|
-
|
|
280
|
-
|
|
281
237
|
def measure_of(obj: Any) -> Union[int, Any]:
|
|
282
238
|
"""
|
|
283
239
|
The `measure_of` function calculates the measure of an object.
|