TEORİDEN UYGULAMAYA · PYTHON EŞLİKÇİSİ

Elips

Prof. Dr. Zühal Küçükarslan Yüzbaşı · Prof. Dr. Bahadır Yüzbaşı

Bölüm 13 · v1.0 · Türkçe

Bu bölümün laboratuvarı, kitaptaki örnekleri yeniden üretmek ve sayısal sonuçları incelemek için hazırlanmıştır. Matematiksel tanımlar, ispatlar ve sorular kitapta yer alır.

Laboratuvarı indir (.py) Tam Python paketi (.zip)

Laboratuvar kodu

"""Bölüm 13: ideal eliptik akustik/optik yansıtıcı laboratuvarı.

Model yalnız iki boyutlu bir elips kesitini ve geometrik ışın yansımasını
temsil eder. Kırınım, soğurma, faz, yüzey kusuru, kaynak yönlülüğü ve gerçek
bir yapının akustik ya da optik performansı modele dahil değildir.
"""

from __future__ import annotations

import numpy as np

from agbook import (
    canonical_array_sha256,
    ellipse_algebraic_residuals,
    ellipse_focal_sum_residuals,
    ellipse_frame_from_center_axes,
    ellipse_points,
    ellipse_reflection_diagnostics,
    ellipse_tangent_line,
    focus_directrix_diagnostics,
    rotation_matrix_2d,
)


def main() -> None:
    semi_major_m = 10.0
    semi_minor_m = 6.0
    center_m = np.array([0.0, 0.0])
    major_axis = np.array([1.0, 0.0])
    frame = ellipse_frame_from_center_axes(
        center_m,
        major_axis,
        semi_major_m,
        semi_minor_m,
    )

    parameters_rad = np.linspace(0.0, 2.0 * np.pi, 12, endpoint=False)
    boundary_points_m = ellipse_points(
        frame.center,
        frame.major_direction,
        frame.semi_major,
        frame.semi_minor,
        parameters_rad,
    )
    algebraic_residuals = ellipse_algebraic_residuals(
        boundary_points_m,
        frame.center,
        frame.major_direction,
        frame.semi_major,
        frame.semi_minor,
    )
    focal_sum_residuals_m = ellipse_focal_sum_residuals(
        boundary_points_m,
        frame.first_focus,
        frame.second_focus,
        frame.semi_major,
    )
    focus_directrix = focus_directrix_diagnostics(
        boundary_points_m,
        frame.second_focus,
        frame.second_directrix,
        frame.eccentricity,
        reference_scale=2.0 * frame.semi_major,
    )
    reflection = ellipse_reflection_diagnostics(
        frame.center,
        frame.major_direction,
        frame.semi_major,
        frame.semi_minor,
        parameters_rad,
    )
    tangent_lines = np.vstack(
        [
            ellipse_tangent_line(
                frame.center,
                frame.major_direction,
                frame.semi_major,
                frame.semi_minor,
                parameter,
            )
            for parameter in parameters_rad
        ]
    )
    tangent_point_residuals_m = np.sum(
        tangent_lines[:, :2] * boundary_points_m,
        axis=1,
    ) + tangent_lines[:, 2]

    np.testing.assert_allclose(algebraic_residuals, 0.0, atol=4e-15)
    np.testing.assert_allclose(focal_sum_residuals_m, 0.0, atol=4e-15)
    np.testing.assert_allclose(tangent_point_residuals_m, 0.0, atol=4e-15)
    np.testing.assert_allclose(reflection.focal_path_lengths, 20.0, atol=4e-14)
    assert focus_directrix.maximum_absolute_residual < 4e-15
    assert reflection.maximum_direction_error < 2e-15
    assert reflection.maximum_focus_line_residual < 2e-14

    rotation = rotation_matrix_2d(np.deg2rad(31.0))
    translation_m = np.array([13.0, -7.0])
    moved_center_m = rotation @ frame.center + translation_m
    moved_axis = rotation @ frame.major_direction
    moved = ellipse_reflection_diagnostics(
        moved_center_m,
        moved_axis,
        frame.semi_major,
        frame.semi_minor,
        parameters_rad,
    )
    expected_moved_points_m = boundary_points_m @ rotation.T + translation_m
    np.testing.assert_allclose(moved.points, expected_moved_points_m, atol=4e-14)
    np.testing.assert_allclose(
        moved.reflected_directions,
        reflection.reflected_directions @ rotation.T,
        atol=4e-14,
    )

    scaled = ellipse_frame_from_center_axes(
        1000.0 * frame.center,
        frame.major_direction,
        1000.0 * frame.semi_major,
        1000.0 * frame.semi_minor,
    )
    np.testing.assert_allclose(scaled.eccentricity, frame.eccentricity)
    np.testing.assert_allclose(scaled.focal_distance, 1000.0 * frame.focal_distance)

    signature_values = np.concatenate(
        [
            np.array(
                [
                    frame.semi_major,
                    frame.semi_minor,
                    frame.focal_distance,
                    frame.eccentricity,
                ]
            ),
            frame.center,
            frame.first_focus,
            frame.second_focus,
            frame.first_directrix,
            frame.second_directrix,
            parameters_rad,
            boundary_points_m.ravel(),
            tangent_lines.ravel(),
            reflection.reflected_directions.ravel(),
            reflection.focal_path_lengths,
            rotation.ravel(),
            translation_m,
            moved.points.ravel(),
        ]
    )

    print("birim: m")
    print("model: sentetik_iki_boyutlu_ideal_eliptik_yansitici")
    print("gercek_akustik_veya_optik_tasarim_mi: False")
    print("yari_buyuk_eksen_m:", frame.semi_major)
    print("yari_kucuk_eksen_m:", frame.semi_minor)
    print("dogrusal_dismerkezlik_m:", frame.focal_distance)
    print("dismerkezlik:", frame.eccentricity)
    print("birinci_odak_m:", frame.first_focus)
    print("ikinci_odak_m:", frame.second_focus)
    print("sinir_noktasi_sayisi:", boundary_points_m.shape[0])
    print("sabit_kirik_yol_m:", 2.0 * frame.semi_major)
    print(
        "en_buyuk_cebirsel_artik:",
        f"{np.max(np.abs(algebraic_residuals)):.3e}",
    )
    print(
        "en_buyuk_odak_toplam_artigi_m:",
        f"{np.max(np.abs(focal_sum_residuals_m)):.3e}",
    )
    print(
        "en_buyuk_odak_dogrultman_artigi_m:",
        f"{focus_directrix.maximum_absolute_residual:.3e}",
    )
    print(
        "en_buyuk_teget_nokta_artigi_m:",
        f"{np.max(np.abs(tangent_point_residuals_m)):.3e}",
    )
    print(
        "en_buyuk_yansima_yon_hatasi:",
        f"{reflection.maximum_direction_error:.3e}",
    )
    print(
        "en_buyuk_odak_cizgisi_artigi_m:",
        f"{reflection.maximum_focus_line_residual:.3e}",
    )
    print(
        "rijit_noktalar_korundu_mu:",
        bool(np.allclose(moved.points, expected_moved_points_m)),
    )
    print("mm_olceginde_dogrusal_dismerkezlik:", scaled.focal_distance)
    print("bilimsel_imza:", canonical_array_sha256(signature_values))


if __name__ == "__main__":
    main()
Doğrulama çalıştırmasının çıktısı
birim: m
model: sentetik_iki_boyutlu_ideal_eliptik_yansitici
gercek_akustik_veya_optik_tasarim_mi: False
yari_buyuk_eksen_m: 10.0
yari_kucuk_eksen_m: 6.0
dogrusal_dismerkezlik_m: 8.0
dismerkezlik: 0.8
birinci_odak_m: [-8.  0.]
ikinci_odak_m: [8. 0.]
sinir_noktasi_sayisi: 12
sabit_kirik_yol_m: 20.0
en_buyuk_cebirsel_artik: 2.220e-16
en_buyuk_odak_toplam_artigi_m: 0.000e+00
en_buyuk_odak_dogrultman_artigi_m: 3.553e-15
en_buyuk_teget_nokta_artigi_m: 1.776e-15
en_buyuk_yansima_yon_hatasi: 5.901e-16
en_buyuk_odak_cizgisi_artigi_m: 8.882e-15
rijit_noktalar_korundu_mu: True
mm_olceginde_dogrusal_dismerkezlik: 8000.0
bilimsel_imza: 6051839a41c2e2967ac4503ce684f862c6324ab8aea3a27b2a6ae219e9ba80fb
Metindeki Python kodları

Kod dosyasını indir

# Kitaptaki kod blokları; bu dosya içinde sırayla çalıştırılır.
# --- 1. Bölüm 13: elips çerçevesi ve sınır noktaları ---
import numpy as np
from agbook import (
    ellipse_algebraic_residuals,
    ellipse_focal_sum_residuals,
    ellipse_frame_from_center_axes,
    ellipse_points,
    ellipse_reflection_diagnostics,
)

a, b = 10.0, 6.0  # metre
frame = ellipse_frame_from_center_axes([0., 0.], [1., 0.], a, b)
t = np.linspace(0.0, 2.0 * np.pi, 12, endpoint=False)
points = ellipse_points(frame.center, frame.major_direction, a, b, t)
r_alg = ellipse_algebraic_residuals(
    points, frame.center, frame.major_direction, a, b
)
r_sum = ellipse_focal_sum_residuals(
    points, frame.first_focus, frame.second_focus, a
)
reflection = ellipse_reflection_diagnostics(
    frame.center, frame.major_direction, a, b, t
)
print(frame.focal_distance, frame.eccentricity)
print(np.max(np.abs(r_alg)), np.max(np.abs(r_sum)))
print(reflection.maximum_direction_error)

# --- 2. Bölüm 13 laboratuvarı: teğet ve rijit değişmezlik ---
from agbook import ellipse_tangent_line, rotation_matrix_2d

tangents = np.vstack([
    ellipse_tangent_line(frame.center, frame.major_direction, a, b, value)
    for value in t
])
tangent_residuals = np.sum(tangents[:, :2] * points, axis=1) + tangents[:, 2]

Q = rotation_matrix_2d(np.deg2rad(31.0))
shift = np.array([13.0, -7.0])  # metre
moved = ellipse_reflection_diagnostics(
    Q @ frame.center + shift, Q @ frame.major_direction, a, b, t
)
expected_points = points @ Q.T + shift
print(np.max(np.abs(tangent_residuals)))
print(np.max(np.abs(moved.points - expected_points)))
print(np.max(np.abs(
    moved.reflected_directions - reflection.reflected_directions @ Q.T
)))

Kaydedilen çıktı

1. Bölüm 13: elips çerçevesi ve sınır noktaları
8.0 0.8
2.220446049250313e-16 0.0
5.900916318210353e-16

2. Bölüm 13 laboratuvarı: teğet ve rijit değişmezlik
1.7763568394002505e-15
1.7763568394002505e-15
6.661338147750939e-16
Çözümlerdeki Python kodları

Kod dosyasını indir

# Kitaptaki kod blokları; bu dosya içinde sırayla çalıştırılır.
# --- 1. İki elips kurucusunun eşdeğerliği ---
import numpy as np
from agbook import (
    ellipse_frame_from_center_axes,
    ellipse_frame_from_foci,
)

first = ellipse_frame_from_center_axes([1., -2.], [2., 1.], 7., 4.)
second = ellipse_frame_from_foci(
    first.first_focus, first.second_focus, first.semi_major
)

for name in ("center", "first_focus", "second_focus", "major_direction"):
    assert np.allclose(getattr(first, name), getattr(second, name))
assert np.isclose(first.semi_minor, second.semi_minor)
assert np.isclose(first.eccentricity, second.eccentricity)
print(first.focal_distance, first.eccentricity)

# --- 2. Üyelik ve teğet artıkları ---
import numpy as np
from agbook import (
    ellipse_algebraic_residuals,
    ellipse_focal_sum_residuals,
    ellipse_frame_from_center_axes,
    ellipse_points,
    ellipse_tangent_line,
)

frame = ellipse_frame_from_center_axes([0., 0.], [1., 0.], 5., 3.)
t = np.linspace(0., 2. * np.pi, 8, endpoint=False)
points = ellipse_points([0., 0.], [1., 0.], 5., 3., t)
r_alg = ellipse_algebraic_residuals(points, [0., 0.], [1., 0.], 5., 3.)
r_sum = ellipse_focal_sum_residuals(
    points, frame.first_focus, frame.second_focus, 5.
)
lines = np.vstack([
    ellipse_tangent_line([0., 0.], [1., 0.], 5., 3., value)
    for value in t
])
r_tan = np.sum(lines[:, :2] * points, axis=1) + lines[:, 2]
print(np.max(np.abs(r_alg)), np.max(np.abs(r_sum)), np.max(np.abs(r_tan)))
assert np.max(np.abs(r_alg)) < 2e-15
assert np.max(np.abs(r_sum)) < 1e-14
assert np.max(np.abs(r_tan)) < 1e-14

# --- 3. Yansımanın rijit hareket altında kovaryantlığı ---
import numpy as np
from agbook import ellipse_reflection_diagnostics, rotation_matrix_2d

t = np.linspace(0., 2. * np.pi, 19, endpoint=False)
before = ellipse_reflection_diagnostics([0., 0.], [1., 0.], 10., 6., t)
Q = rotation_matrix_2d(np.deg2rad(37.))
shift = np.array([5., -3.])
after = ellipse_reflection_diagnostics(shift, Q @ np.array([1., 0.]), 10., 6., t)

assert np.allclose(after.points, before.points @ Q.T + shift)
assert np.allclose(
    after.reflected_directions, before.reflected_directions @ Q.T
)
assert np.allclose(after.focal_path_lengths, before.focal_path_lengths)
print(before.maximum_direction_error, after.maximum_direction_error)

# --- 4. Ölçek değişmezliği ve açık sınır hataları ---
import numpy as np
from agbook import (
    ellipse_frame_from_center_axes,
    ellipse_points,
    ellipse_focal_sum_residuals,
    ellipse_reflection_diagnostics,
)

t = np.array([0.2, 1.1, 2.7])
m = ellipse_frame_from_center_axes([0., 0.], [1., 0.], 5., 3.)
mm = ellipse_frame_from_center_axes([0., 0.], [1., 0.], 5000., 3000.)
assert np.isclose(mm.focal_distance, 1000. * m.focal_distance)
assert np.isclose(mm.eccentricity, m.eccentricity)

p = ellipse_points([0., 0.], [1., 0.], 5., 3., t) + np.array([0.01, 0.])
r_m = ellipse_focal_sum_residuals(p, m.first_focus, m.second_focus, 5.)
r_mm = ellipse_focal_sum_residuals(
    1000. * p, mm.first_focus, mm.second_focus, 5000.
)
assert np.allclose(r_mm, 1000. * r_m)

for bad in ((5., 5.), (3., 5.)):
    try:
        ellipse_frame_from_center_axes([0., 0.], [1., 0.], *bad)
    except ValueError as error:
        print(type(error).__name__, str(error))

Kaydedilen çıktı

1. İki elips kurucusunun eşdeğerliği
5.744562646538029 0.8206518066482898

2. Üyelik ve teğet artıkları
1.1102230246251565e-16 0.0 4.440892098500626e-16

3. Yansımanın rijit hareket altında kovaryantlığı
4.577566798522237e-16 6.280369834735101e-16

4. Ölçek değişmezliği ve açık sınır hataları
ValueError Normal elips için semi_major > semi_minor > 0 olmalıdır; eşitlik çember sınırıdır.
ValueError Normal elips için semi_major > semi_minor > 0 olmalıdır; eşitlik çember sınırıdır.

Çalıştırma rehberi

Önce tam Python paketini indirin ve arşivi açın. Aşağıdaki komutları arşivin üst klasöründen başlatın. İlk kurulum internet bağlantısı ve Python 3.12 veya 3.13 gerektirir. Bağımlılıklar sabittir; sistem Python'unu değiştirmemek için ayrı sanal ortam kullanılır.

macOS / Linux
cd analitik-geometri-python-v1.0
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
python labs/bolum_13_elips_yansima.py
python -m pytest
Windows PowerShell
cd analitik-geometri-python-v1.0
py -3.13 -m venv .venv
.venv\Scripts\python.exe -m pip install -e ".[dev]"
.venv\Scripts\python.exe labs/bolum_13_elips_yansima.py
.venv\Scripts\python.exe -m pytest

Laboratuvar dosyaları agbook yardımcı paketini kullanır; tek bir dosyayı indirmek paketi kurmanın yerini tutmaz. Metin/çözüm kodları kendi dosyaları içinde sırayla çalıştırılır; gizli bir notebook oturumu gerekmez. Son ondalık basamaklar platforma göre değişebilir.