praca_magisterska/pytania/generate_study_diagrams.py

603 lines
26 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""
Generate study diagrams for defense preparation:
1. PYTANIE 12: Network optimization models (mnemonic overview)
2. PYTANIE 21: Vector clock timeline
3. PYTANIE 22: Linearizability vs Sequential consistency, Paxos flow
4. PYTANIE 23: Segmentation types and over-segmentation
5. PYTANIE 24: HOG pipeline, SVM margin, R-CNN vs YOLO architecture
All: A4-compatible, B&W, 300 DPI, laser-printer-friendly.
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
import numpy as np
import os
DPI = 300
BG = 'white'
LN = 'black'
FS = 8
FS_TITLE = 12
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
os.makedirs(OUTPUT_DIR, exist_ok=True)
GRAY1 = '#E8E8E8'
GRAY2 = '#D0D0D0'
GRAY3 = '#B8B8B8'
GRAY4 = '#F5F5F5'
GRAY5 = '#C0C0C0'
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
fontweight='normal', ha='center', va='center', rounded=True):
if rounded:
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.05",
lw=lw, edgecolor=LN, facecolor=fill)
else:
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=LN, facecolor=fill)
ax.add_patch(rect)
ax.text(x + w/2, y + h/2, text, ha=ha, va=va, fontsize=fontsize,
fontweight=fontweight, wrap=True)
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN):
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
# ============================================================
# PYTANIE 12: Network Optimization Models (Mnemonic Overview)
# ============================================================
def draw_network_models():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 5))
ax.set_xlim(0, 10)
ax.set_ylim(0, 7)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('Sieciowe modele optymalizacji — „Nasz Mały Mikołaj Przydzielił Trasy Ciężarówkom Mapując"',
fontsize=10, fontweight='bold', pad=10)
models = [
(1, "Najkrótsza\nścieżka", "GPS, routing\nDijkstra, A*", "A→B najszybciej?", GRAY1),
(2, "Maksymalny\nprzepływ", "Przepustowość\nFord-Fulkerson", "Ile max przesłać?", GRAY4),
(3, "Min koszt\nprzepływu", "Najtańszy transport\nSieciowy simpleks", "X jednostek najtaniej?", GRAY4),
(4, "Przydział\n(assignment)", "n→n, min koszt\nAlg. Węgierski O(n³)", "Kto robi co?", GRAY2),
(5, "TSP\n(komiwojażer)", "Objazd miast\nNP-trudny, heurystyki", "Objazd wszystkiego?", GRAY3),
(6, "CPM/PERT", "Harmonogram\nŚcieżka krytyczna", "Ile trwa projekt?", GRAY2),
(7, "MST\n(drzewo rozp.)", "Min połączenie\nKruskal, Prim", "Połącz najtaniej?", GRAY1),
]
# Layout: 3 pairs + 1, arranged in labeled groups
group_positions = [
# (group_label, [(model_idx, x, y), ...])
("DROGI", [(0, 0.3, 4.0), (6, 0.3, 1.5)]),
("PRZEPŁYW", [(1, 3.3, 4.0), (2, 3.3, 1.5)]),
("ZARZĄDZANIE", [(3, 6.3, 4.0), (5, 6.3, 1.5)]),
]
box_w = 2.6
box_h = 1.8
for group_label, items in group_positions:
xs = [x for _, x, y in items]
ys = [y for _, x, y in items]
gx = min(xs) - 0.15
gy = min(ys) - 0.3
gw = box_w + 0.3
gh = max(ys) - min(ys) + box_h + 0.6
rect = mpatches.FancyBboxPatch((gx, gy), gw, gh,
boxstyle="round,pad=0.1",
lw=0.8, edgecolor=GRAY3,
facecolor='white', linestyle='--')
ax.add_patch(rect)
ax.text(gx + gw/2, gy + gh + 0.12, group_label, ha='center',
fontsize=8, fontweight='bold', color='#555555')
for idx, x, y in items:
num, name, detail, question, fill = models[idx]
draw_box(ax, x, y, box_w, box_h, '', fill=fill, fontsize=FS)
ax.text(x + box_w/2, y + box_h - 0.25, f"{num}. {name}",
ha='center', va='top', fontsize=8, fontweight='bold')
ax.text(x + box_w/2, y + box_h/2 - 0.1, detail,
ha='center', va='center', fontsize=7)
ax.text(x + box_w/2, y + 0.2, f'→ „{question}"',
ha='center', va='bottom', fontsize=6.5, style='italic')
# TSP alone at bottom center
idx = 4
x, y = 4.5, -0.1
num, name, detail, question, fill = models[idx]
rect = mpatches.FancyBboxPatch((x - 0.15, y - 0.15), box_w + 0.3, box_h + 0.3,
boxstyle="round,pad=0.1",
lw=0.8, edgecolor=GRAY3,
facecolor='white', linestyle='--')
ax.add_patch(rect)
ax.text(x + box_w/2, y + box_h + 0.3, "SAM (NP-trudny)",
ha='center', fontsize=8, fontweight='bold', color='#555555')
draw_box(ax, x, y, box_w, box_h, '', fill=fill, fontsize=FS)
ax.text(x + box_w/2, y + box_h - 0.25, f"{num}. {name}",
ha='center', va='top', fontsize=8, fontweight='bold')
ax.text(x + box_w/2, y + box_h/2 - 0.1, detail,
ha='center', va='center', fontsize=7)
ax.text(x + box_w/2, y + 0.2, f'→ „{question}"',
ha='center', va='bottom', fontsize=6.5, style='italic')
ax.set_ylim(-0.5, 7.2)
plt.tight_layout()
plt.savefig(os.path.join(OUTPUT_DIR, 'network_models_mnemonic.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close()
print(" ✓ network_models_mnemonic.png")
# ============================================================
# PYTANIE 21: Vector Clock Timeline
# ============================================================
def draw_vector_clock_timeline():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 4.5))
ax.set_xlim(-0.5, 11)
ax.set_ylim(-0.5, 4.5)
ax.axis('off')
ax.set_title('Zegary wektorowe — przykład z 3 procesami', fontsize=FS_TITLE, fontweight='bold', pad=10)
# Process lines
procs = [('P₁', 3.5), ('P₂', 2.0), ('P₃', 0.5)]
for name, y in procs:
ax.plot([0.5, 10.5], [y, y], color=LN, lw=1.5)
ax.text(0.1, y, name, ha='right', va='center', fontsize=10, fontweight='bold')
# Events
events = [
# (name, process_y, x, vector, fill)
('A', 3.5, 1.5, '[1,0,0]', GRAY1),
('B', 2.0, 2.5, '[0,1,0]', GRAY2),
('C', 2.0, 5.0, '[1,2,0]', GRAY2),
('D', 0.5, 4.0, '[0,0,1]', GRAY3),
('E', 3.5, 6.5, '[2,0,0]', GRAY1),
('F', 2.0, 8.0, '[2,3,0]', GRAY2),
]
for name, y, x, vec, fill in events:
circle = plt.Circle((x, y), 0.25, facecolor=fill, edgecolor=LN, lw=1.5)
ax.add_patch(circle)
ax.text(x, y, name, ha='center', va='center', fontsize=9, fontweight='bold')
ax.text(x, y + 0.45, vec, ha='center', va='bottom', fontsize=7,
fontfamily='monospace', color='#333333')
# Messages (arrows between processes)
# P1:A → P2:C (msg sent after A, received at C)
ax.annotate("", xy=(4.75, 2.0), xytext=(1.75, 3.5),
arrowprops=dict(arrowstyle='->', color='#444444', lw=1.5,
connectionstyle='arc3,rad=0.05'))
ax.text(3.0, 3.0, 'msg₁', ha='center', fontsize=7, color='#444444', style='italic')
# P1:E → P2:F
ax.annotate("", xy=(7.75, 2.0), xytext=(6.75, 3.5),
arrowprops=dict(arrowstyle='->', color='#444444', lw=1.5,
connectionstyle='arc3,rad=0.05'))
ax.text(7.0, 3.0, 'msg₂', ha='center', fontsize=7, color='#444444', style='italic')
# Concurrency annotations
ax.annotate('A ∥ B\n(współbieżne)', xy=(2.0, 1.2), fontsize=7, ha='center',
bbox=dict(boxstyle='round,pad=0.2', facecolor=GRAY4, edgecolor=GRAY5))
ax.annotate('C ∥ D\n(współbieżne)', xy=(4.5, 0.9), fontsize=7, ha='center',
bbox=dict(boxstyle='round,pad=0.2', facecolor=GRAY4, edgecolor=GRAY5))
ax.annotate('A → C\n(przyczynowe)', xy=(3.3, 4.2), fontsize=7, ha='center',
bbox=dict(boxstyle='round,pad=0.2', facecolor=GRAY1, edgecolor=GRAY3))
# Time arrow
ax.annotate("", xy=(10.5, -0.3), xytext=(0.5, -0.3),
arrowprops=dict(arrowstyle='->', color=GRAY3, lw=1.0))
ax.text(5.5, -0.45, 'czas →', ha='center', fontsize=8, color='#777777')
plt.tight_layout()
plt.savefig(os.path.join(OUTPUT_DIR, 'vector_clock_timeline.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close()
print(" ✓ vector_clock_timeline.png")
# ============================================================
# PYTANIE 22: Linearizability vs Sequential Consistency
# ============================================================
def draw_linearizability_vs_sequential():
fig, axes = plt.subplots(2, 1, figsize=(8.27, 5.5))
for i, (ax, title, subtitle, operations, result_text) in enumerate(zip(
axes,
['Linearizability', 'Sequential Consistency'],
['Operacja „wygląda" atomowo w czasie rzeczywistym',
'Globalny porządek zgodny z programem, ale NIE z czasem rzeczywistym'],
[
# Linearizability
[
('Klient A', 1, 3, 'write(x,1)', GRAY1),
('Klient B', 2, 4, 'read(x)→1 ✓', GRAY2),
('Klient A', 5, 7, 'write(x,2)', GRAY1),
],
# Sequential consistency
[
('Klient A', 1, 3, 'write(x,1)', GRAY1),
('Klient B', 2, 4, 'read(x)→0 ✓', GRAY2),
('Klient A', 5, 7, 'write(x,2)', GRAY1),
],
],
[
'read MUSI zwrócić 1 (write zakończony w czasie rzeczywistym)',
'read MOŻE zwrócić 0 (globalny porządek: read, write(1), write(2))',
]
)):
ax.set_xlim(0, 9)
ax.set_ylim(-0.5, 3.5)
ax.axis('off')
ax.set_title(f'{title}', fontsize=10, fontweight='bold')
ax.text(4.5, 3.2, subtitle, ha='center', fontsize=7, style='italic', color='#555555')
# Time axis
ax.plot([0.5, 8.5], [0, 0], color=GRAY3, lw=0.8)
for t in range(1, 9):
ax.plot([t, t], [-0.05, 0.05], color=GRAY3, lw=0.8)
ax.text(t, -0.2, f't{t}', ha='center', fontsize=6, color='#999999')
# Client labels
clients = list(dict.fromkeys([op[0] for op in operations]))
client_y = {c: 1.0 + idx * 1.2 for idx, c in enumerate(clients)}
for client_name, y_pos in client_y.items():
ax.text(0.3, y_pos, client_name, ha='right', va='center', fontsize=7, fontweight='bold')
ax.plot([0.5, 8.5], [y_pos, y_pos], color=GRAY5, lw=0.5, linestyle=':')
for client, t_start, t_end, label, fill in operations:
y = client_y[client]
rect = FancyBboxPatch((t_start, y - 0.2), t_end - t_start, 0.4,
boxstyle="round,pad=0.05", lw=1.2,
edgecolor=LN, facecolor=fill)
ax.add_patch(rect)
ax.text((t_start + t_end) / 2, y, label, ha='center', va='center', fontsize=7)
# Result annotation
ax.text(4.5, -0.45, result_text, ha='center', fontsize=7,
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=GRAY5))
plt.tight_layout()
plt.savefig(os.path.join(OUTPUT_DIR, 'linearizability_vs_sequential.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close()
print(" ✓ linearizability_vs_sequential.png")
# ============================================================
# PYTANIE 22: Paxos Protocol Flow
# ============================================================
def draw_paxos_flow():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 4))
ax.set_xlim(-0.5, 10.5)
ax.set_ylim(-0.5, 5)
ax.axis('off')
ax.set_title('Paxos — uproszczony przebieg (zapis x=5)', fontsize=FS_TITLE, fontweight='bold', pad=10)
# Actors
actors = [
('Proposer', 1.5, 4.0, GRAY1),
('A₁', 4.5, 4.0, GRAY2),
('A₂', 6.5, 4.0, GRAY2),
('A₃', 8.5, 4.0, GRAY2),
]
for name, x, y, fill in actors:
draw_box(ax, x - 0.6, y, 1.2, 0.6, name, fill=fill, fontsize=8, fontweight='bold')
# Phase 1: Prepare
ax.text(-0.3, 3.5, 'FAZA 1\nPrepare', ha='center', fontsize=7, fontweight='bold',
bbox=dict(boxstyle='round,pad=0.2', facecolor=GRAY4, edgecolor=GRAY5))
y_prep = 3.3
for target_x in [4.5, 6.5, 8.5]:
draw_arrow(ax, 2.1, y_prep + 0.15, target_x - 0.6, y_prep + 0.15, lw=1.0)
ax.text(3.3, y_prep + 0.35, 'Prepare(n=1)', fontsize=6, ha='center')
# Promises back
y_prom = 2.7
for target_x in [4.5, 6.5]:
draw_arrow(ax, target_x - 0.6, y_prom + 0.15, 2.1, y_prom + 0.15, lw=1.0, color='#555555')
ax.text(3.3, y_prom + 0.35, 'Promise(n=1) ✓', fontsize=6, ha='center', color='#555555')
ax.text(8.5, y_prom + 0.15, '(slow)', fontsize=6, ha='center', color='#999999')
ax.text(1.5, y_prom - 0.15, 'majority\n(2/3) ✓', fontsize=6, ha='center',
bbox=dict(boxstyle='round,pad=0.15', facecolor=GRAY1, edgecolor=GRAY3))
# Phase 2: Accept
ax.text(-0.3, 1.8, 'FAZA 2\nAccept', ha='center', fontsize=7, fontweight='bold',
bbox=dict(boxstyle='round,pad=0.2', facecolor=GRAY4, edgecolor=GRAY5))
y_acc = 1.6
for target_x in [4.5, 6.5, 8.5]:
draw_arrow(ax, 2.1, y_acc + 0.15, target_x - 0.6, y_acc + 0.15, lw=1.0)
ax.text(3.3, y_acc + 0.35, 'Accept(n=1, x=5)', fontsize=6, ha='center')
# Accepted back
y_accd = 1.0
for target_x in [4.5, 6.5]:
draw_arrow(ax, target_x - 0.6, y_accd + 0.15, 2.1, y_accd + 0.15, lw=1.0, color='#555555')
ax.text(3.3, y_accd + 0.35, 'Accepted ✓', fontsize=6, ha='center', color='#555555')
# Result
ax.text(5.0, 0.1, 'x=5 UZGODNIONE (majority zaakceptowała) → Linearizable!',
fontsize=8, ha='center', fontweight='bold',
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY1, edgecolor=LN))
plt.tight_layout()
plt.savefig(os.path.join(OUTPUT_DIR, 'paxos_flow.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close()
print(" ✓ paxos_flow.png")
# ============================================================
# PYTANIE 24: HOG Pipeline Overview
# ============================================================
def draw_hog_pipeline():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 3.5))
ax.set_xlim(0, 10)
ax.set_ylim(0, 4)
ax.axis('off')
ax.set_title('HOG + SVM — pipeline detekcji pieszych', fontsize=FS_TITLE, fontweight='bold', pad=10)
steps = [
(0.3, 'Obraz\nwejściowy', GRAY4),
(2.1, 'Oblicz\ngradienty\n(Gx, Gy)', GRAY1),
(3.9, 'Podziel na\nkomórki 8×8\nhistogramy', GRAY2),
(5.7, 'Normalizuj\nw blokach\n2×2', GRAY2),
(7.5, 'Wektor\ncech\n(3780-dim)', GRAY3),
(9.0, 'SVM\n→ pieszy\n/ nie', GRAY1),
]
box_w = 1.5
box_h = 1.8
y = 1.2
for i, (x, text, fill) in enumerate(steps):
draw_box(ax, x, y, box_w, box_h, '', fill=fill)
ax.text(x + box_w/2, y + box_h/2, text, ha='center', va='center', fontsize=7)
if i < len(steps) - 1:
next_x = steps[i+1][0]
draw_arrow(ax, x + box_w + 0.02, y + box_h/2, next_x - 0.02, y + box_h/2)
# Annotations below
annotations = [
(0.3 + box_w/2, 'pixel[x+1]-pixel[x-1]'),
(2.1 + box_w/2, 'magnitude + direction'),
(3.9 + box_w/2, '9 binów (0°-180°)'),
(5.7 + box_w/2, 'L2-normalizacja'),
(7.5 + box_w/2, 'wejście do SVM'),
(9.0 + box_w/2, 'hiperpłaszczyzna'),
]
for x, text in annotations:
ax.text(x, y - 0.15, text, ha='center', fontsize=5.5, color='#666666', style='italic')
# Title annotations
ax.text(1.05, y + box_h + 0.15, '① Gradient', ha='center', fontsize=7, fontweight='bold')
ax.text(2.85, y + box_h + 0.15, '② Histogram', ha='center', fontsize=7, fontweight='bold')
ax.text(4.65, y + box_h + 0.15, '③ Normalize', ha='center', fontsize=7, fontweight='bold')
ax.text(6.45, y + box_h + 0.15, '④ Feature vec', ha='center', fontsize=7, fontweight='bold')
ax.text(8.1, y + box_h + 0.15, '⑤ Classify', ha='center', fontsize=7, fontweight='bold')
plt.tight_layout()
plt.savefig(os.path.join(OUTPUT_DIR, 'hog_svm_pipeline.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close()
print(" ✓ hog_svm_pipeline.png")
# ============================================================
# PYTANIE 24: R-CNN Evolution
# ============================================================
def draw_rcnn_evolution():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 5))
ax.set_xlim(0, 10)
ax.set_ylim(0, 7)
ax.axis('off')
ax.set_title('Ewolucja detektorów: R-CNN → Fast R-CNN → Faster R-CNN → YOLO',
fontsize=10, fontweight='bold', pad=10)
models = [
{
'name': 'R-CNN (2014)',
'y': 5.3,
'steps': ['Selective\nSearch', '2000×\nCNN', '2000×\nSVM', 'NMS'],
'speed': '~50 sec/img',
'fill': GRAY4,
},
{
'name': 'Fast R-CNN (2015)',
'y': 3.7,
'steps': ['Selective\nSearch', 'CNN\n(1× cały)', 'ROI\nPooling', 'FC + NMS'],
'speed': '~2 sec/img',
'fill': GRAY2,
},
{
'name': 'Faster R-CNN (2015)',
'y': 2.1,
'steps': ['CNN\nbackbone', 'RPN\n(proposals)', 'ROI\nPooling', 'FC + NMS'],
'speed': '~0.2 sec (5 fps)',
'fill': GRAY1,
},
{
'name': 'YOLO (2016)',
'y': 0.5,
'steps': ['CNN\nbackbone', 'Siatka\nS×S', 'bbox+klasa\nper komórka', 'NMS'],
'speed': '~7-22 ms (45-155 fps)',
'fill': GRAY3,
},
]
for model in models:
y = model['y']
ax.text(0.2, y + 0.4, model['name'], fontsize=8, fontweight='bold', va='center')
ax.text(0.2, y + 0.05, model['speed'], fontsize=6, va='center', color='#666666')
bw = 1.5
bh = 0.8
for i, step in enumerate(model['steps']):
x = 2.5 + i * 1.9
draw_box(ax, x, y, bw, bh, step, fill=model['fill'], fontsize=6.5)
if i < len(model['steps']) - 1:
draw_arrow(ax, x + bw + 0.02, y + bh/2, x + 1.9 - 0.02, y + bh/2, lw=0.8)
# Speed improvement arrow on right
ax.annotate("", xy=(9.5, 5.7), xytext=(9.5, 0.9),
arrowprops=dict(arrowstyle='<->', color='#555555', lw=1.5))
ax.text(9.7, 3.3, '250×\nszybciej!', fontsize=8, fontweight='bold',
ha='center', va='center', rotation=90, color='#555555')
plt.tight_layout()
plt.savefig(os.path.join(OUTPUT_DIR, 'rcnn_evolution.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close()
print(" ✓ rcnn_evolution.png")
# ============================================================
# PYTANIE 23: Segmentation types comparison
# ============================================================
def draw_segmentation_types():
fig, axes = plt.subplots(1, 4, figsize=(8.27, 2.5))
fig.suptitle('Typy segmentacji obrazu', fontsize=FS_TITLE, fontweight='bold', y=1.02)
titles = ['Obraz wejściowy', 'Semantic\nSegmentation', 'Instance\nSegmentation', 'Panoptic\nSegmentation']
for ax, title in zip(axes, titles):
ax.set_xlim(0, 6)
ax.set_ylim(0, 6)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title(title, fontsize=8, fontweight='bold', pad=5)
# Image: sky (top), two cars (bottom), road
# Semantic: all sky=one color, all cars=one color, road=one color
# Instance: sky=one, car1=distinct, car2=distinct, road=one
# Panoptic: both
# Original image (stylized)
ax = axes[0]
ax.add_patch(mpatches.Rectangle((0, 4), 6, 2, facecolor='#DDDDDD', edgecolor=LN, lw=0.5)) # sky
ax.text(3, 5, 'niebo', ha='center', va='center', fontsize=7)
ax.add_patch(mpatches.Rectangle((0, 0), 6, 2.5, facecolor='#AAAAAA', edgecolor=LN, lw=0.5)) # road
ax.text(3, 1, 'droga', ha='center', va='center', fontsize=7)
ax.add_patch(mpatches.Rectangle((0.5, 2), 2, 1.5, facecolor='#888888', edgecolor=LN, lw=0.8)) # car1
ax.text(1.5, 2.75, 'auto', ha='center', va='center', fontsize=7, color='white')
ax.add_patch(mpatches.Rectangle((3.5, 2), 2, 1.5, facecolor='#666666', edgecolor=LN, lw=0.8)) # car2
ax.text(4.5, 2.75, 'auto', ha='center', va='center', fontsize=7, color='white')
# Semantic: same label for both cars
ax = axes[1]
ax.add_patch(mpatches.Rectangle((0, 4), 6, 2, facecolor='#E8E8E8', edgecolor=LN, lw=0.5))
ax.text(3, 5, 'niebo', ha='center', va='center', fontsize=7)
ax.add_patch(mpatches.Rectangle((0, 0), 6, 2.5, facecolor='#C8C8C8', edgecolor=LN, lw=0.5))
ax.text(3, 1, 'droga', ha='center', va='center', fontsize=7)
ax.add_patch(mpatches.Rectangle((0.5, 2), 2, 1.5, facecolor='#888888', edgecolor=LN, lw=0.8))
ax.text(1.5, 2.75, 'auto', ha='center', va='center', fontsize=6, color='white')
ax.add_patch(mpatches.Rectangle((3.5, 2), 2, 1.5, facecolor='#888888', edgecolor=LN, lw=0.8))
ax.text(4.5, 2.75, 'auto', ha='center', va='center', fontsize=6, color='white')
ax.text(3, -0.3, 'te same etykiety!', ha='center', fontsize=6, color='#555555', style='italic')
# Instance: different labels for cars
ax = axes[2]
ax.add_patch(mpatches.Rectangle((0, 4), 6, 2, facecolor='#E8E8E8', edgecolor=LN, lw=0.5))
ax.text(3, 5, '', ha='center', va='center', fontsize=7, color='#999999')
ax.add_patch(mpatches.Rectangle((0, 0), 6, 2.5, facecolor='#E8E8E8', edgecolor=LN, lw=0.5))
ax.text(3, 1, '', ha='center', va='center', fontsize=7, color='#999999')
ax.add_patch(mpatches.Rectangle((0.5, 2), 2, 1.5, facecolor='#888888', edgecolor=LN, lw=0.8))
ax.text(1.5, 2.75, 'auto#1', ha='center', va='center', fontsize=6, color='white')
ax.add_patch(mpatches.Rectangle((3.5, 2), 2, 1.5, facecolor='#555555', edgecolor=LN, lw=0.8))
ax.text(4.5, 2.75, 'auto#2', ha='center', va='center', fontsize=6, color='white')
ax.text(3, -0.3, 'RÓŻNE instancje!', ha='center', fontsize=6, color='#555555', style='italic')
# Panoptic: both semantic labels AND instance IDs
ax = axes[3]
ax.add_patch(mpatches.Rectangle((0, 4), 6, 2, facecolor='#E8E8E8', edgecolor=LN, lw=0.5))
ax.text(3, 5, 'niebo (stuff)', ha='center', va='center', fontsize=6)
ax.add_patch(mpatches.Rectangle((0, 0), 6, 2.5, facecolor='#C8C8C8', edgecolor=LN, lw=0.5))
ax.text(3, 1, 'droga (stuff)', ha='center', va='center', fontsize=6)
ax.add_patch(mpatches.Rectangle((0.5, 2), 2, 1.5, facecolor='#888888', edgecolor=LN, lw=0.8))
ax.text(1.5, 2.75, 'auto#1\n(thing)', ha='center', va='center', fontsize=5.5, color='white')
ax.add_patch(mpatches.Rectangle((3.5, 2), 2, 1.5, facecolor='#555555', edgecolor=LN, lw=0.8))
ax.text(4.5, 2.75, 'auto#2\n(thing)', ha='center', va='center', fontsize=5.5, color='white')
ax.text(3, -0.3, 'klasy + instancje!', ha='center', fontsize=6, color='#555555', style='italic')
plt.tight_layout()
plt.savefig(os.path.join(OUTPUT_DIR, 'segmentation_types.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close()
print(" ✓ segmentation_types.png")
# ============================================================
# PYTANIE 32: FSD and SSD visualization
# ============================================================
def draw_fsd_ssd():
fig, axes = plt.subplots(1, 2, figsize=(8.27, 3.5))
fig.suptitle('Dominacja stochastyczna — FSD i SSD', fontsize=FS_TITLE, fontweight='bold', y=1.02)
# FSD: CDF comparison
ax = axes[0]
ax.set_title('FSD: F_A(x) ≤ F_B(x) ∀x', fontsize=9, fontweight='bold')
x = np.linspace(-2, 6, 200)
# A ~ shifted right (better), B ~ shifted left
from scipy.stats import norm
F_A = norm.cdf(x, loc=2.5, scale=1.0)
F_B = norm.cdf(x, loc=1.5, scale=1.0)
ax.plot(x, F_A, 'k-', lw=2, label='F_A (lepsza — niżej)')
ax.plot(x, F_B, 'k--', lw=2, label='F_B (gorsza — wyżej)')
ax.fill_between(x, F_A, F_B, alpha=0.15, color='gray')
ax.set_xlabel('x (wynik)', fontsize=8)
ax.set_ylabel('F(x) = P(X ≤ x)', fontsize=8)
ax.legend(fontsize=7, loc='lower right')
ax.text(0, 0.8, 'A ≥_FSD B\nF_A zawsze pod F_B\n→ KAŻDY racjonalny\n wybierze A',
fontsize=7, bbox=dict(boxstyle='round', facecolor=GRAY4))
ax.grid(True, alpha=0.3)
ax.tick_params(labelsize=7)
# SSD: CDFs can cross, but integral is less
ax = axes[1]
ax.set_title('SSD: ∫F_A ≤ ∫F_B ∀x (CDFs mogą się krzyżować)', fontsize=9, fontweight='bold')
F_A2 = norm.cdf(x, loc=2.0, scale=0.8)
F_B2 = norm.cdf(x, loc=2.0, scale=1.5) # same mean, more spread
ax.plot(x, F_A2, 'k-', lw=2, label='F_A (mniej ryzyka)')
ax.plot(x, F_B2, 'k--', lw=2, label='F_B (więcej ryzyka)')
ax.fill_between(x, F_A2, F_B2, where=F_A2 < F_B2, alpha=0.15, color='gray')
ax.fill_between(x, F_A2, F_B2, where=F_A2 >= F_B2, alpha=0.08, color='gray',
hatch='///')
ax.set_xlabel('x (wynik)', fontsize=8)
ax.set_ylabel('F(x)', fontsize=8)
ax.legend(fontsize=7, loc='lower right')
ax.text(-1.5, 0.75, 'A ≥_SSD B\nCDFs się krzyżują,\nale ∫F_A ≤ ∫F_B\n→ risk-averse\n wybierze A',
fontsize=7, bbox=dict(boxstyle='round', facecolor=GRAY4))
ax.grid(True, alpha=0.3)
ax.tick_params(labelsize=7)
plt.tight_layout()
plt.savefig(os.path.join(OUTPUT_DIR, 'fsd_ssd_comparison.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close()
print(" ✓ fsd_ssd_comparison.png")
# ============================================================
# Main
# ============================================================
if __name__ == '__main__':
print("Generating study diagrams...")
draw_network_models()
draw_vector_clock_timeline()
draw_linearizability_vs_sequential()
draw_paxos_flow()
draw_hog_pipeline()
draw_rcnn_evolution()
draw_segmentation_types()
draw_fsd_ssd()
print(f"\nAll diagrams saved to {OUTPUT_DIR}/")