Skip to content

Commit 34bcef7

Browse files
committed
Attempt of Complex Systems with oscillator chain
1 parent 0bbcfc4 commit 34bcef7

27 files changed

Lines changed: 2550 additions & 497 deletions

CHANGELOG.md

Lines changed: 0 additions & 249 deletions
Large diffs are not rendered by default.

src/complex_problems/__init__.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Complex problems module — specialized cases with custom solvers and visualizations."""
2+
3+
from __future__ import annotations
4+
5+
from complex_problems.problem_registry import PROBLEM_REGISTRY
6+
7+
__all__ = [
8+
"ComplexProblemsDialog",
9+
"PROBLEM_REGISTRY",
10+
]
11+
12+
13+
def __getattr__(name: str):
14+
"""Lazy-load ComplexProblemsDialog on first access."""
15+
if name == "ComplexProblemsDialog":
16+
from complex_problems.complex_problems_dialog import ComplexProblemsDialog
17+
18+
return ComplexProblemsDialog
19+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
"""Dialog for selecting which complex problem to solve."""
2+
3+
from __future__ import annotations
4+
5+
import tkinter as tk
6+
from tkinter import ttk
7+
8+
from complex_problems.problem_registry import PROBLEM_REGISTRY
9+
from config import get_env_from_schema
10+
from frontend.ui_dialogs import ToolTip, setup_arrow_enter_navigation
11+
from frontend.window_utils import bind_wraplength, fit_and_center, make_modal
12+
from utils import get_logger
13+
14+
logger = get_logger(__name__)
15+
16+
17+
class ComplexProblemsDialog:
18+
"""Window for selecting a complex problem to solve.
19+
20+
Args:
21+
parent: Parent window.
22+
"""
23+
24+
def __init__(self, parent: tk.Tk | tk.Toplevel) -> None:
25+
self.parent = parent
26+
self.win = tk.Toplevel(parent)
27+
self.win.title("Complex Problems")
28+
29+
bg: str = get_env_from_schema("UI_BACKGROUND")
30+
self.win.configure(bg=bg)
31+
32+
self._build_ui()
33+
34+
fit_and_center(self.win, min_width=640, min_height=680, resizable=True)
35+
make_modal(self.win, parent)
36+
logger.info("Complex problems dialog opened")
37+
38+
def _build_ui(self) -> None:
39+
"""Construct the dialog layout."""
40+
pad: int = get_env_from_schema("UI_PADDING")
41+
42+
main_frame = ttk.Frame(self.win, padding=pad * 2)
43+
main_frame.pack(fill=tk.BOTH, expand=True)
44+
45+
ttk.Label(
46+
main_frame,
47+
text="Complex Problems",
48+
style="Title.TLabel",
49+
).pack(pady=(0, pad))
50+
51+
desc = ttk.Label(
52+
main_frame,
53+
text=(
54+
"Select a special problem to solve. Each problem has\n"
55+
"custom parameters, statistics, and visualizations."
56+
),
57+
style="Small.TLabel",
58+
justify=tk.CENTER,
59+
)
60+
desc.pack(pady=(0, pad * 2))
61+
bind_wraplength(main_frame, desc, pad=4 * pad, min_wrap=200)
62+
63+
# Buttons for each problem
64+
btn_frame = ttk.Frame(main_frame)
65+
btn_frame.pack(fill=tk.BOTH, expand=True)
66+
67+
for i, (prob_id, descriptor) in enumerate(PROBLEM_REGISTRY.items()):
68+
btn = ttk.Button(
69+
btn_frame,
70+
text=descriptor.name,
71+
command=self._make_open_callback(descriptor),
72+
)
73+
btn.pack(fill=tk.X, padx=pad, pady=pad // 2)
74+
ToolTip(btn, descriptor.description)
75+
76+
btn_close = ttk.Button(
77+
main_frame,
78+
text="Close",
79+
style="Cancel.TButton",
80+
command=self.win.destroy,
81+
)
82+
btn_close.pack(pady=(pad * 2, 0))
83+
84+
setup_arrow_enter_navigation([[btn_close]])
85+
btn_close.focus_set()
86+
87+
def _make_open_callback(self, descriptor):
88+
"""Create a callback that opens the problem dialog and closes this one."""
89+
90+
def _on_click() -> None:
91+
self.win.destroy()
92+
descriptor.open_dialog(self.parent)
93+
94+
return _on_click
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""Coupled harmonic oscillators — one-dimensional chain with configurable parameters."""
2+
3+
from __future__ import annotations
4+
5+
from complex_problems.coupled_oscillators.model import build_ode_function
6+
from complex_problems.coupled_oscillators.solver import solve_coupled_oscillators
7+
8+
__all__ = [
9+
"build_ode_function",
10+
"solve_coupled_oscillators",
11+
]

0 commit comments

Comments
 (0)