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 kodu
"""Bölüm 23: sayısal kararlılık ve geometrik model uydurma laboratuvarı.
Sabit tohumlu sentetik bir ölçüm plakası üzerinde doğru, çember, elips ve
elipsoid uydurulur. Veriler gerçek ölçüm değildir; bütün uzunluklar mm'dir.
Tek kirletilmiş çember noktası açıkça korunur ve sağlam kayıp yalnız belirtilen
ölçekle etkinleştirilir. Hiçbir gözlem silinmez veya yeniden kodlanmaz.
"""
from __future__ import annotations
import math
import numpy as np
from agbook import (
canonical_array_sha256,
fit_circle_geometric,
fit_ellipse_direct,
fit_line_tls,
fit_line_vertical_ols,
fit_quadric_implicit,
)
def rotation_2d(angle: float) -> np.ndarray:
cosine, sine = math.cos(angle), math.sin(angle)
return np.array([[cosine, -sine], [sine, cosine]])
def rotation_xyz(ax: float, ay: float, az: float) -> np.ndarray:
cx, sx = math.cos(ax), math.sin(ax)
cy, sy = math.cos(ay), math.sin(ay)
cz, sz = math.cos(az), math.sin(az)
rx = np.array([[1, 0, 0], [0, cx, -sx], [0, sx, cx]], dtype=float)
ry = np.array([[cy, 0, sy], [0, 1, 0], [-sy, 0, cy]], dtype=float)
rz = np.array([[cz, -sz, 0], [sz, cz, 0], [0, 0, 1]], dtype=float)
return rz @ ry @ rx
def main() -> None:
seed = 2301
rng = np.random.default_rng(seed)
length_unit = "mm"
line_direction = np.array([0.82, 0.5723635208501674])
line_normal = np.array([-line_direction[1], line_direction[0]])
line_parameter = np.linspace(-55.0, 55.0, 70)
line_points = np.array([-25.0, 18.0]) + line_parameter[:, None] * line_direction
line_points += rng.normal(scale=0.35, size=(line_parameter.size, 1)) * line_normal
line_tls = fit_line_tls(line_points)
line_ols = fit_line_vertical_ols(line_points)
circle_center = np.array([42.0, -28.0])
circle_radius = 24.0
circle_theta = np.linspace(0.0, 2.0 * np.pi, 72, endpoint=False)
circle_radial = circle_radius + rng.normal(scale=0.28, size=circle_theta.size)
circle_points = circle_center + circle_radial[:, None] * np.column_stack(
(np.cos(circle_theta), np.sin(circle_theta))
)
contaminated_index = 9
circle_points[contaminated_index] += np.array([11.0, -7.0])
circle_least_squares = fit_circle_geometric(
circle_points,
measurement_sigma=0.28,
)
circle_robust = fit_circle_geometric(
circle_points,
loss="soft_l1",
loss_scale=0.6,
)
ellipse_center = np.array([-36.0, 31.0])
ellipse_axes = np.array([30.0, 13.0])
ellipse_rotation = rotation_2d(math.radians(27.0))
ellipse_theta = np.linspace(0.0, 2.0 * np.pi, 100, endpoint=False)
ellipse_local = np.column_stack(
(ellipse_axes[0] * np.cos(ellipse_theta), ellipse_axes[1] * np.sin(ellipse_theta))
)
ellipse_points = ellipse_local @ ellipse_rotation.T + ellipse_center
ellipse_points += rng.normal(scale=0.18, size=ellipse_points.shape)
ellipse_fit = fit_ellipse_direct(ellipse_points)
ellipsoid_center = np.array([18.0, -12.0, 9.0])
ellipsoid_axes = np.array([21.0, 14.0, 8.0])
ellipsoid_rotation = rotation_xyz(0.22, -0.31, 0.47)
azimuth = np.linspace(0.0, 2.0 * np.pi, 18, endpoint=False)
polar = np.linspace(0.22, np.pi - 0.22, 9)
aa, pp = np.meshgrid(azimuth, polar)
ellipsoid_local = np.column_stack(
(
ellipsoid_axes[0] * np.sin(pp.ravel()) * np.cos(aa.ravel()),
ellipsoid_axes[1] * np.sin(pp.ravel()) * np.sin(aa.ravel()),
ellipsoid_axes[2] * np.cos(pp.ravel()),
)
)
ellipsoid_points = ellipsoid_local @ ellipsoid_rotation.T + ellipsoid_center
ellipsoid_points += rng.normal(scale=0.12, size=ellipsoid_points.shape)
quadric_fit = fit_quadric_implicit(ellipsoid_points)
assert abs(line_tls.direction @ line_direction) > 0.99999
assert line_tls.rms_orthogonal < 0.45
assert circle_least_squares.final_sum_squares <= circle_least_squares.initial_sum_squares
assert np.linalg.norm(circle_robust.center - circle_center) < np.linalg.norm(
circle_least_squares.center - circle_center
)
assert abs(circle_robust.radius - circle_radius) < abs(
circle_least_squares.radius - circle_radius
)
assert ellipse_fit.conic_diagnostics.locus_type == "ellipse"
assert quadric_fit.quadric_diagnostics.locus_type == "ellipsoid"
np.testing.assert_allclose(
ellipse_fit.conic_diagnostics.center,
ellipse_center,
atol=0.15,
)
np.testing.assert_allclose(
np.sort(ellipse_fit.conic_diagnostics.semi_axes),
np.sort(ellipse_axes),
atol=0.2,
)
np.testing.assert_allclose(
quadric_fit.quadric_diagnostics.center,
ellipsoid_center,
atol=0.12,
)
np.testing.assert_allclose(
np.sort(quadric_fit.quadric_diagnostics.semi_axes),
np.sort(ellipsoid_axes),
atol=0.15,
)
signature_values = np.concatenate(
(
line_points.ravel(),
line_tls.coefficients,
[line_tls.rms_orthogonal, line_ols.rms_vertical],
circle_points.ravel(),
circle_least_squares.center,
[circle_least_squares.radius, circle_least_squares.rms_geometric],
circle_robust.center,
[circle_robust.radius, circle_robust.rms_geometric],
ellipse_points.ravel(),
ellipse_fit.coefficients,
ellipse_fit.conic_diagnostics.center,
ellipse_fit.conic_diagnostics.semi_axes,
ellipsoid_points.ravel(),
quadric_fit.coefficients,
quadric_fit.quadric_diagnostics.center,
quadric_fit.quadric_diagnostics.semi_axes,
)
)
print("tohum:", seed)
print("uzunluk_birimi:", length_unit)
print("veri: sentetik_olcum_plakasi")
print("olculmus_veri_mi: False")
print("eksik_deger_islemi: yok")
print("gozlem_silindi_mi: False")
print("dogru_tls_katsayilari:", line_tls.coefficients)
print("dogru_tls_rms_mm:", f"{line_tls.rms_orthogonal:.9f}")
print("dogru_ols_dikey_rms_mm:", f"{line_ols.rms_vertical:.9f}")
print("cember_kirletilmis_indis:", contaminated_index)
print("cember_ls_merkez_mm:", circle_least_squares.center)
print("cember_ls_yaricap_mm:", f"{circle_least_squares.radius:.9f}")
print("cember_ls_standart_hatalar_mm:", circle_least_squares.standard_errors)
print("cember_robust_merkez_mm:", circle_robust.center)
print("cember_robust_yaricap_mm:", f"{circle_robust.radius:.9f}")
print("cember_robust_kayip:", circle_robust.loss)
print("cember_robust_kayip_olcegi_mm:", circle_robust.loss_scale)
print("elips_sinifi:", ellipse_fit.conic_diagnostics.locus_type)
print("elips_merkez_mm:", ellipse_fit.conic_diagnostics.center)
print("elips_yari_eksenler_mm:", ellipse_fit.conic_diagnostics.semi_axes)
print("elips_tasarim_ranki:", ellipse_fit.diagnostics.effective_rank)
print("elips_nullspace_araligi:", ellipse_fit.diagnostics.nullspace_gap)
print("kuadrik_sinifi:", quadric_fit.quadric_diagnostics.locus_type)
print("kuadrik_merkez_mm:", quadric_fit.quadric_diagnostics.center)
print("kuadrik_yari_eksenler_mm:", quadric_fit.quadric_diagnostics.semi_axes)
print("kuadrik_tasarim_ranki:", quadric_fit.diagnostics.effective_rank)
print("kuadrik_nullspace_araligi:", quadric_fit.diagnostics.nullspace_gap)
print("bilimsel_imza:", canonical_array_sha256(signature_values))
if __name__ == "__main__":
main()
Doğrulama çalıştırmasının çıktısı
tohum: 2301
uzunluk_birimi: mm
veri: sentetik_olcum_plakasi
olculmus_veri_mi: False
eksik_deger_islemi: yok
gozlem_silindi_mi: False
dogru_tls_katsayilari: [ -0.57358722 0.81914449 -29.07421489]
dogru_tls_rms_mm: 0.348263749
dogru_ols_dikey_rms_mm: 0.425143271
cember_kirletilmis_indis: 9
cember_ls_merkez_mm: [ 42.1592895 -27.90317228]
cember_ls_yaricap_mm: 24.060698726
cember_ls_standart_hatalar_mm: [0.04641723 0.04692385 0.03300004]
cember_robust_merkez_mm: [ 42.02769068 -27.95747329]
cember_robust_yaricap_mm: 23.999879324
cember_robust_kayip: soft_l1
cember_robust_kayip_olcegi_mm: 0.6
elips_sinifi: ellipse
elips_merkez_mm: [-35.98431752 30.98696831]
elips_yari_eksenler_mm: [29.96742543 12.9971687 ]
elips_tasarim_ranki: 6
elips_nullspace_araligi: 47.21158044468563
kuadrik_sinifi: ellipsoid
kuadrik_merkez_mm: [ 17.9954167 -12.02247577 8.98762276]
kuadrik_yari_eksenler_mm: [21.01573467 14.03668937 8.00341117]
kuadrik_tasarim_ranki: 10
kuadrik_nullspace_araligi: 31.386652518643867
bilimsel_imza: 1cf21d5b37678090855dbbb478b2755e957478709c26a6fa05a57f59afedf595
Metindeki Python kodları
# Kitaptaki kod blokları; bu dosya içinde sırayla çalıştırılır.
# --- 1. Doğru, çember, elips ve elipsoid uydurma ---
import runpy
runpy.run_path(
"labs/bolum_23_sayisal_kararlilik_model_uydurma.py",
run_name="__main__",
)
Kaydedilen çıktı
1. Doğru, çember, elips ve elipsoid uydurma
tohum: 2301
uzunluk_birimi: mm
veri: sentetik_olcum_plakasi
olculmus_veri_mi: False
eksik_deger_islemi: yok
gozlem_silindi_mi: False
dogru_tls_katsayilari: [ -0.57358722 0.81914449 -29.07421489]
dogru_tls_rms_mm: 0.348263749
dogru_ols_dikey_rms_mm: 0.425143271
cember_kirletilmis_indis: 9
cember_ls_merkez_mm: [ 42.1592895 -27.90317228]
cember_ls_yaricap_mm: 24.060698726
cember_ls_standart_hatalar_mm: [0.04641723 0.04692385 0.03300004]
cember_robust_merkez_mm: [ 42.02769068 -27.95747329]
cember_robust_yaricap_mm: 23.999879324
cember_robust_kayip: soft_l1
cember_robust_kayip_olcegi_mm: 0.6
elips_sinifi: ellipse
elips_merkez_mm: [-35.98431752 30.98696831]
elips_yari_eksenler_mm: [29.96742543 12.9971687 ]
elips_tasarim_ranki: 6
elips_nullspace_araligi: 47.21158044468563
kuadrik_sinifi: ellipsoid
kuadrik_merkez_mm: [ 17.9954167 -12.02247577 8.98762276]
kuadrik_yari_eksenler_mm: [21.01573467 14.03668937 8.00341117]
kuadrik_tasarim_ranki: 10
kuadrik_nullspace_araligi: 31.386652518643867
bilimsel_imza: 1cf21d5b37678090855dbbb478b2755e957478709c26a6fa05a57f59afedf595
Çözümlerdeki Python kodları
# Kitaptaki kod blokları; bu dosya içinde sırayla çalıştırılır.
# --- 1. TLS için dönme ve ölçek metamorfik testi ---
import numpy as np
from agbook import fit_line_tls
rng = np.random.default_rng(2311)
t = np.linspace(-4, 4, 50)
v = np.array([0.8, 0.6])
n = np.array([-0.6, 0.8])
points = t[:, None]*v + rng.normal(0, 0.04, (50, 1))*n
base = fit_line_tls(points)
for angle in np.linspace(0, 2*np.pi, 20, endpoint=False):
c, s = np.cos(angle), np.sin(angle)
R = np.array([[c, -s], [s, c]])
moved = 7*(points @ R.T) + np.array([12.0, -5.0])
got = fit_line_tls(moved)
assert abs(got.direction @ (R @ base.direction)) > 1-1e-12
np.testing.assert_allclose(
got.rms_orthogonal, 7*base.rms_orthogonal, rtol=2e-12
)
# --- 2. Çember geometrik amacının başlangıcı iyileştirmesi ---
import numpy as np
from agbook import fit_circle_geometric
rng = np.random.default_rng(2312)
theta = np.linspace(0, 2*np.pi, 80, endpoint=False)
radial = 5 + rng.normal(0, 0.12, theta.size)
points = np.array([3.0, -2.0]) + radial[:, None]*np.c_[
np.cos(theta), np.sin(theta)
]
fit = fit_circle_geometric(points)
assert fit.final_sum_squares <= fit.initial_sum_squares + 1e-12
print(fit.initial_sum_squares, fit.final_sum_squares)
# --- 3. Elips yaylarında nullspace ayrışması ---
import numpy as np
from agbook import fit_conic_implicit
for degrees in (360, 90, 30, 10):
width = np.deg2rad(degrees)
theta = np.linspace(-width/2, width/2, 120)
points = np.c_[4*np.cos(theta), 1.5*np.sin(theta)]
fit = fit_conic_implicit(points)
print(
degrees,
fit.diagnostics.singular_values,
fit.diagnostics.nullspace_gap,
fit.conic_diagnostics.locus_type,
)
# --- 4. Elipsoid uydurmasının benzerlik testi ---
import numpy as np
from agbook import fit_quadric_implicit
azimuth, polar = np.meshgrid(
np.linspace(0, 2*np.pi, 24, endpoint=False),
np.linspace(0.15, np.pi-0.15, 12),
)
points = np.c_[
5*np.sin(polar.ravel())*np.cos(azimuth.ravel()),
3*np.sin(polar.ravel())*np.sin(azimuth.ravel()),
2*np.cos(polar.ravel()),
] + np.array([1., -2., 3.])
base = fit_quadric_implicit(points)
Q, _ = np.linalg.qr(np.random.default_rng(2314).normal(size=(3, 3)))
if np.linalg.det(Q) < 0:
Q[:, -1] *= -1
t = np.array([7.0, -4.0, 2.0])
moved_points = 1000*(points @ Q.T + t)
moved = fit_quadric_implicit(moved_points)
np.testing.assert_allclose(
moved.quadric_diagnostics.center,
1000*(Q @ base.quadric_diagnostics.center + t),
rtol=2e-10,
)
np.testing.assert_allclose(
np.sort(moved.quadric_diagnostics.semi_axes),
1000*np.sort(base.quadric_diagnostics.semi_axes),
rtol=2e-10,
)
assert moved.quadric_diagnostics.locus_type == \
base.quadric_diagnostics.locus_type
# --- 5. Tam elipsoid ile dar kutup yamasını karşılaştırma ---
import numpy as np
from agbook import fit_quadric_implicit
rng = np.random.default_rng(2344)
azimuth = np.linspace(0, 2*np.pi, 24, endpoint=False)
noise = rng.normal(0, 0.002, (288, 3))
def sampled_ellipsoid(polar):
aa, pp = np.meshgrid(azimuth, polar)
return np.c_[
5*np.sin(pp.ravel())*np.cos(aa.ravel()),
3*np.sin(pp.ravel())*np.sin(aa.ravel()),
2*np.cos(pp.ravel()),
] + np.array([1., -2., 3.]) + noise
full_points = sampled_ellipsoid(np.linspace(0.15, np.pi-0.15, 12))
polar_patch_points = sampled_ellipsoid(np.linspace(0.15, 0.35, 12))
full = fit_quadric_implicit(full_points)
patch = fit_quadric_implicit(polar_patch_points)
for name, fit in (("tam", full), ("yama", patch)):
print(name)
print("tekil_degerler", fit.diagnostics.singular_values)
print("rank", fit.diagnostics.effective_rank)
print("nullspace_boslugu", fit.diagnostics.nullspace_gap)
print("sinif", fit.quadric_diagnostics.locus_type)
print("merkez", fit.quadric_diagnostics.center)
print("yari_eksenler", fit.quadric_diagnostics.semi_axes)
Kaydedilen çıktı
1. TLS için dönme ve ölçek metamorfik testi
2. Çember geometrik amacının başlangıcı iyileştirmesi
1.3217054302761628 1.32138108617027
3. Elips yaylarında nullspace ayrışması
360 [2.53298316e+01 1.45197717e+01 6.57910352e+00 5.40528459e+00
5.03625969e+00 1.25437653e-15] 4014950499731706.5 ellipse
90 [2.47535967e+01 1.62992267e+01 9.02669056e+00 6.75496709e+00
4.37600164e+00 2.78606180e-15] 1570676443350304.2 ellipse
30 [2.96641145e+01 1.56416891e+01 7.31430141e+00 3.30259680e+00
6.03693113e-01 8.69720869e-15] 69412283154415.77 ellipse
10 [3.04667377e+01 1.55089458e+01 7.05477833e+00 1.15798514e+00
6.86729316e-02 2.60677137e-14] 2634405628283.9546 ellipse
4. Elipsoid uydurmasının benzerlik testi
5. Tam elipsoid ile dar kutup yamasını karşılaştırma
tam
tekil_degerler [4.75154453e+01 2.27347343e+01 1.85702071e+01 1.57154789e+01
1.36423146e+01 1.26893321e+01 1.21219589e+01 1.21049451e+01
7.26631900e+00 1.87092589e-02]
rank 10
nullspace_boslugu 388.38090910571316
sinif ellipsoid
merkez [ 0.99966798 -2.00004857 3.00031982]
yari_eksenler [4.99869401 3.0002509 2.00012267]
yama
tekil_degerler [5.26285905e+01 2.51974713e+01 1.90768622e+01 1.75086802e+01
1.51268888e+01 6.24873857e+00 1.24289140e+00 7.46972412e-01
5.11303654e-02 3.97049382e-02]
rank 10
nullspace_boslugu 1.287758342445121
sinif ellipsoid
merkez [ 0.99864635 -2.00102972 4.90166561]
yari_eksenler [1.57396546 0.94792143 0.07642433]
Ç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_23_sayisal_kararlilik_model_uydurma.py
python -m pytestWindows 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_23_sayisal_kararlilik_model_uydurma.py
.venv\Scripts\python.exe -m pytest