Spaces:
Sleeping
Sleeping
Upload 22 files
Browse files- Delusion/boss.py +57 -0
- Delusion/burst.py +18 -0
- Delusion/delusion.py +67 -0
- Delusion/heatmap.py +46 -0
- Delusion/readme.md +52 -0
- Dockerfile +26 -0
- Eleazar/__init__.py +6 -0
- Eleazar/eleazar.py +57 -0
- Eleazar/hospital.py +42 -0
- Eleazar/readme.md +60 -0
- Eleazar/solver.py +37 -0
- Irminsul/__init__.py +6 -0
- Irminsul/constants.py +34 -0
- Irminsul/kusanali.py +43 -0
- Irminsul/nahida.py +58 -0
- Irminsul/readme.md +48 -0
- Irminsul/trellis.py +87 -0
- README.md +96 -8
- app.py +7 -0
- handlers.py +278 -0
- requirements.txt +4 -0
- ui.py +129 -0
Delusion/boss.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import matplotlib.pyplot as plt
|
| 2 |
+
import numpy as np
|
| 3 |
+
import os
|
| 4 |
+
from delusion import activate_delusion as run_audit_for_plot
|
| 5 |
+
from burst import subjects
|
| 6 |
+
|
| 7 |
+
hp_ranges = np.linspace(10000, 1000000, 20)
|
| 8 |
+
|
| 9 |
+
plt.figure(figsize=(12, 7))
|
| 10 |
+
|
| 11 |
+
for sub in subjects:
|
| 12 |
+
costs = []
|
| 13 |
+
hps = []
|
| 14 |
+
budget = np.exp(-0.012 * sub["age"]) - 0.15 #
|
| 15 |
+
|
| 16 |
+
for hp in hp_ranges:
|
| 17 |
+
# We use a modified version of your audit that returns the 'res.fun' (cost)
|
| 18 |
+
cost = run_audit_for_plot(sub["name"], sub["age"], sub["vis"], sub["eff"], hp, silent=True)
|
| 19 |
+
if cost and cost <= budget:
|
| 20 |
+
costs.append(cost)
|
| 21 |
+
hps.append(hp)
|
| 22 |
+
else:
|
| 23 |
+
# If they die, we stop the line to show the 'Mortality Cliff'
|
| 24 |
+
break
|
| 25 |
+
|
| 26 |
+
# Ensure line is visible even if they die instantly
|
| 27 |
+
if len(hps) == 0:
|
| 28 |
+
# Add points to create a diagonal line segment matching other character styles
|
| 29 |
+
hps.append(0)
|
| 30 |
+
costs.append(0)
|
| 31 |
+
hps.append(hp_ranges[0])
|
| 32 |
+
costs.append(budget)
|
| 33 |
+
|
| 34 |
+
plt.plot(hps, costs, label=f"{sub['name']} (Budget: {budget:.2f})",
|
| 35 |
+
color=sub["color"], marker='o', linewidth=2)
|
| 36 |
+
|
| 37 |
+
# Mark the Death Point with a Skull
|
| 38 |
+
if len(hps) > 0:
|
| 39 |
+
# Check if the next HP tier resulted in 'Infeasible'
|
| 40 |
+
# We use the LaTeX skull symbol for the marker
|
| 41 |
+
plt.scatter(hps[-1], costs[-1],
|
| 42 |
+
marker='$\u2620$',
|
| 43 |
+
color='black',
|
| 44 |
+
s=250,
|
| 45 |
+
zorder=5,
|
| 46 |
+
label="Biological Collapse" if sub == subjects[0] else "")
|
| 47 |
+
|
| 48 |
+
plt.axhline(y=0.15, color='red', linestyle='--', alpha=0.5, label="Critical Instability (15%)")
|
| 49 |
+
plt.axhline(y=0, color='red', linestyle='--', alpha=0.5, label="Baseline (0%)")
|
| 50 |
+
plt.title("Delusion Forensic: Cumulative Biological Cost vs. Combat Output")
|
| 51 |
+
plt.xlabel("Total Damage Required (Boss HP)")
|
| 52 |
+
plt.ylabel("Gavrilov Redundancy Cost (R-Loss)")
|
| 53 |
+
plt.ylim(bottom=-0.1, top=1.1)
|
| 54 |
+
plt.legend()
|
| 55 |
+
plt.grid(True, which="both", ls="-", alpha=0.2)
|
| 56 |
+
plt.savefig(os.path.join(os.path.dirname(__file__), 'delusion_forensic_plot.png'))
|
| 57 |
+
plt.close()
|
Delusion/burst.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
try:
|
| 2 |
+
from .delusion import activate_delusion
|
| 3 |
+
except ImportError:
|
| 4 |
+
from Delusion.delusion import activate_delusion
|
| 5 |
+
|
| 6 |
+
subjects = [
|
| 7 |
+
{"name": "Childe", "age": 23, "vis": True, "eff": 0.65, "color": "#e67e22"},
|
| 8 |
+
{"name": "Arlecchino", "age": 30, "vis": True, "eff": 0.95, "color": "#c0392b"},
|
| 9 |
+
{"name": "Foolish NPC", "age": 16, "vis": False, "eff": 0.05, "color": "#7f8c8d"}
|
| 10 |
+
]
|
| 11 |
+
|
| 12 |
+
if __name__ == "__main__":
|
| 13 |
+
activate_delusion("Childe", 23, True, 0.65)
|
| 14 |
+
print("--------------------------------")
|
| 15 |
+
activate_delusion("Arlecchino", 30, True, 0.95)
|
| 16 |
+
print("--------------------------------")
|
| 17 |
+
activate_delusion("Foolish NPC", 16, False, 0.05)
|
| 18 |
+
print("--------------------------------")
|
Delusion/delusion.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from scipy.optimize import linprog
|
| 2 |
+
import numpy as np
|
| 3 |
+
|
| 4 |
+
def activate_delusion(name, age, has_vision, efficiency, boss_hp=500000, max_time=90, silent=False):
|
| 5 |
+
# 1. Biological Buffer (Gavrilov Reliability Logic)
|
| 6 |
+
initial_R = np.exp(-0.012 * age) #
|
| 7 |
+
budget = initial_R - 0.15 #
|
| 8 |
+
|
| 9 |
+
# 2. Mastery-Scaled Combat Mechanics
|
| 10 |
+
cooldown = 12 - (5 * efficiency) #
|
| 11 |
+
burst_req = 90 - (10 * efficiency) #
|
| 12 |
+
|
| 13 |
+
# Energy generation is now experience-scaled + Vision multiplier
|
| 14 |
+
base_energy = 10 + (17 * efficiency) + (8 * efficiency * efficiency) - 0.34 * age
|
| 15 |
+
energy_per_E = base_energy * (1.5 if has_vision else 1.0) #
|
| 16 |
+
|
| 17 |
+
# 3. Forensic Multipliers (The 'Human Tax')
|
| 18 |
+
k_age = np.exp(0.012 * (age - 20)) #
|
| 19 |
+
zeta = 0.05 if has_vision else 1.0 # Vision Grounding
|
| 20 |
+
waste = (1.0 - efficiency) * zeta * k_age #
|
| 21 |
+
|
| 22 |
+
# 4. Decision Variables: [t_NA (sec), n_E (count), n_Q (count)]
|
| 23 |
+
# 1. Jack up base cost by 50x
|
| 24 |
+
# 0.005 means a baseline human loses 0.3 redundancy (half their budget) in 60s of NA
|
| 25 |
+
base_cost_sec = 0.005 * waste
|
| 26 |
+
|
| 27 |
+
# 2. Scale Action Spikes
|
| 28 |
+
# Skills now cost a flat 1% of total potential redundancy per cast
|
| 29 |
+
cost_E = 0.01 * waste
|
| 30 |
+
|
| 31 |
+
# 3. The 'Human Tax' of the Burst
|
| 32 |
+
# At 350x toxicity for 5 seconds, this is the 'Mortality Cliff'
|
| 33 |
+
cost_Q_total = (350 * base_cost_sec * 5)
|
| 34 |
+
|
| 35 |
+
# Objective: Minimize Time to Victory (Efficiency Optimization)
|
| 36 |
+
c = [1, 1.5, 5]
|
| 37 |
+
|
| 38 |
+
# 5. Constraints Matrix
|
| 39 |
+
dmg_mult = 2.0 if has_vision else 1.0
|
| 40 |
+
A_ub = [
|
| 41 |
+
[base_cost_sec, cost_E, cost_Q_total], # Redundancy <= Budget
|
| 42 |
+
[-(300 * dmg_mult), -(11000 * dmg_mult), -(100000 * dmg_mult)], # Damage >= Boss_HP
|
| 43 |
+
[0, -energy_per_E, burst_req] # Energy Flow
|
| 44 |
+
]
|
| 45 |
+
b_ub = [budget, -boss_hp, 0]
|
| 46 |
+
|
| 47 |
+
# Mandatory Burst to confirm Delusion stability under load
|
| 48 |
+
bounds = [(0, max_time), (0, max_time/cooldown), (1, None)]
|
| 49 |
+
|
| 50 |
+
res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, integrality=[0, 1, 1], method='highs')
|
| 51 |
+
|
| 52 |
+
if res.success and res.fun <= max_time:
|
| 53 |
+
t_na, n_e, n_q = res.x
|
| 54 |
+
total_cost = (t_na * base_cost_sec) + (n_e * cost_E) + (n_q * cost_Q_total)
|
| 55 |
+
|
| 56 |
+
if total_cost <= budget:
|
| 57 |
+
if not silent:
|
| 58 |
+
print(f"--- {name} Forensic Audit ---")
|
| 59 |
+
print(f"Stats -> ER: {energy_per_E:.1f} | CD: {cooldown:.1f}s | Q: {burst_req:.0f}")
|
| 60 |
+
print(f"RESULT: SUCCESS. Time: {res.fun:.1f}s | Cost: {total_cost:.4f}/{budget:.4f}")
|
| 61 |
+
print(f"Rotation: {int(n_e)} Skills | {int(n_q)} Bursts\n")
|
| 62 |
+
return total_cost
|
| 63 |
+
|
| 64 |
+
if not silent:
|
| 65 |
+
print(f"--- {name} ---")
|
| 66 |
+
print("RESULT: FATAL. Subject biology failed to sustain required flux.\n")
|
| 67 |
+
return None
|
Delusion/heatmap.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import matplotlib.pyplot as plt
|
| 3 |
+
import os
|
| 4 |
+
from mpl_toolkits.mplot3d import Axes3D
|
| 5 |
+
from delusion import activate_delusion
|
| 6 |
+
|
| 7 |
+
# Assuming ultimate_forensic_audit returns the 'remaining_R'
|
| 8 |
+
def generate_3d_survival_ridge():
|
| 9 |
+
efficiencies = np.linspace(0.05, 0.95, 20)
|
| 10 |
+
hps = np.linspace(100000, 1500000, 20)
|
| 11 |
+
X, Y = np.meshgrid(efficiencies, hps)
|
| 12 |
+
Z = np.zeros(X.shape)
|
| 13 |
+
|
| 14 |
+
for i in range(len(hps)):
|
| 15 |
+
for j in range(len(efficiencies)):
|
| 16 |
+
# Simulate a 25-year-old with/without vision based on efficiency tier
|
| 17 |
+
has_vision = X[i, j] > 0.6
|
| 18 |
+
result_cost = activate_delusion("Subject", age=25, has_vision=has_vision,
|
| 19 |
+
efficiency=X[i, j], boss_hp=Y[i, j], silent=True)
|
| 20 |
+
|
| 21 |
+
initial_R = np.exp(-0.012 * 25)
|
| 22 |
+
if result_cost is not None:
|
| 23 |
+
remaining = initial_R - result_cost
|
| 24 |
+
# Cap at 0.15 for the 'Death Valley' visualization
|
| 25 |
+
Z[i, j] = max(0.15, remaining)
|
| 26 |
+
else:
|
| 27 |
+
Z[i, j] = 0.15
|
| 28 |
+
|
| 29 |
+
fig = plt.figure(figsize=(12, 8))
|
| 30 |
+
ax = fig.add_subplot(111, projection='3d')
|
| 31 |
+
|
| 32 |
+
surf = ax.plot_surface(X, Y, Z, cmap='inferno', edgecolor='none', alpha=0.9)
|
| 33 |
+
|
| 34 |
+
ax.set_title("Delusions: The 3D Survival Ridge", fontsize=14)
|
| 35 |
+
ax.set_xlabel("Mastery Efficiency (η)")
|
| 36 |
+
ax.set_ylabel("Combat Load (Boss HP)")
|
| 37 |
+
ax.set_zlabel("Biological Redundancy (R)")
|
| 38 |
+
|
| 39 |
+
# Add color bar for 'Mortality Heat'
|
| 40 |
+
fig.colorbar(surf, ax=ax, shrink=0.5, aspect=5, label='Survival Probability')
|
| 41 |
+
|
| 42 |
+
plt.savefig(os.path.join(os.path.dirname(__file__), 'heatmap.png'))
|
| 43 |
+
plt.close()
|
| 44 |
+
|
| 45 |
+
if __name__ == "__main__":
|
| 46 |
+
generate_3d_survival_ridge()
|
Delusion/readme.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Phase 3: Linear Programming and the "Human Tax" Optimization
|
| 2 |
+
## Project Overview
|
| 3 |
+
This project utilizes Constrained Optimization to quantify the active destruction caused by Delusion usage. We have evolved from basic decay models to a Combat Meta-Simulation that treats a subject's biological life force as a non-renewable currency used to "purchase" damage output.
|
| 4 |
+
|
| 5 |
+
## Problem Setup: The MILP Backend
|
| 6 |
+
|
| 7 |
+
We utilize `scipy.optimize.linprog` with integrality constraints to solve for the most bio-efficient combat rotation (Normal Attacks, Skills, and Bursts).
|
| 8 |
+
|
| 9 |
+
### Adaptive Optimization Parameters
|
| 10 |
+
|
| 11 |
+
To reflect lore-accurate combat mastery, the model now maps the Mastery-Efficiency Coefficient ($\eta$) to the following mechanical variables:
|
| 12 |
+
|
| 13 |
+
- **Skill Cooldown ($CD$)**: Ranges from 12s (Low Mastery) to 7s (High Mastery).
|
| 14 |
+
- **Burst Energy Requirement ($Q_{req}$)**: Ranges from 90 to 80 energy.
|
| 15 |
+
- **Energy Generation ($E_{gen}$)**: Scales from 10 to 40 energy per Skill, representing the subject's ability to capture elemental flux.
|
| 16 |
+
- **Vision-Damping Factor ($\zeta$)**: Acts as a 1.5x Energy Multiplier and provides a 0.05 safety grounding that reduces biological waste.
|
| 17 |
+
|
| 18 |
+
## Results
|
| 19 |
+
|
| 20 |
+
Our simulations against high-HP "Boss" targets reveal three critical findings:
|
| 21 |
+
|
| 22 |
+
### 1. The Energy-Redundancy Trap
|
| 23 |
+
|
| 24 |
+
For non-Vision holders (NPCs), the "Human Tax" to generate 80 energy exceeds their total Gavrilov Redundancy ($R$).
|
| 25 |
+
|
| 26 |
+
- **Result**: NPCs are mathematically barred from using Elemental Bursts.
|
| 27 |
+
- **Observation**: Attempting a single Burst triggers a 350x toxicity spike that consumes up to 80% of their life budget in 5 seconds.
|
| 28 |
+
|
| 29 |
+
### 2. The Harbinger "Survival Ridge"
|
| 30 |
+
|
| 31 |
+
Harbingers like Arlecchino occupy a unique mathematical plateau.
|
| 32 |
+
|
| 33 |
+
- **Efficiency Advantage**: At $\eta=0.95$, the "Waste Factor" is so low that the subject can afford multiple high-flux rotations.
|
| 34 |
+
- **Temporal Bottleneck**: Their only limit is the Time Constraint (90s), not biological failure.
|
| 35 |
+
|
| 36 |
+
### 3. The Mortality Cliff (Skull Analysis)
|
| 37 |
+
|
| 38 |
+
As shown in our 2D/3D visualizations, there is a Bifurcation Point at $\eta \approx 0.7$.
|
| 39 |
+
|
| 40 |
+
- **$\eta < 0.7$**: Total system failure. The solver returns "Infeasible", marked on our plots with a skull (☠) to indicate immediate biological liquidation.
|
| 41 |
+
- **$\eta > 0.7$**: The subject enters the Survival Ridge, where victory is possible at the cost of permanent, but non-fatal, redundancy loss.
|
| 42 |
+
|
| 43 |
+

|
| 44 |
+
|
| 45 |
+
*The 3D surface plot shows biological redundancy as a function of mastery efficiency and combat load (boss HP). The "Death Valley" at 0.15 represents the critical failure threshold where Delusion use becomes fatal.*
|
| 46 |
+
|
| 47 |
+

|
| 48 |
+
|
| 49 |
+
*The forensic plot shows cumulative biological cost vs. combat output for different subject classes. Each line represents a character's survivability curve, with skull markers (☠) indicating biological collapse points. The red dashed lines mark critical thresholds at 0% (baseline) and 15% (critical instability).*
|
| 50 |
+
|
| 51 |
+
## Conclusion
|
| 52 |
+
Delusion technology is a predatory resource-extraction system. It is mathematically impossible for standard humans to achieve the energy recharge required for high-flux actions (Bursts) without immediate systemic liquidation.
|
Dockerfile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.11-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
# Install system dependencies for matplotlib
|
| 6 |
+
RUN apt-get update && apt-get install -y \
|
| 7 |
+
libfreetype6-dev \
|
| 8 |
+
libpng-dev \
|
| 9 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
+
|
| 11 |
+
# Copy requirements first for better caching
|
| 12 |
+
COPY requirements.txt .
|
| 13 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 14 |
+
|
| 15 |
+
# Copy application code
|
| 16 |
+
COPY . .
|
| 17 |
+
|
| 18 |
+
# Expose the port that Hugging Face Spaces uses
|
| 19 |
+
EXPOSE 7860
|
| 20 |
+
|
| 21 |
+
# Set environment variables
|
| 22 |
+
ENV GRADIO_SERVER_NAME=0.0.0.0
|
| 23 |
+
ENV GRADIO_SERVER_PORT=7860
|
| 24 |
+
|
| 25 |
+
# Run the application
|
| 26 |
+
CMD ["python", "app.py"]
|
Eleazar/__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Eleazar package for modeling Eleazar disease progression."""
|
| 2 |
+
|
| 3 |
+
from .eleazar import eleazar_model
|
| 4 |
+
from .solver import run_simulation
|
| 5 |
+
|
| 6 |
+
__all__ = ['eleazar_model', 'run_simulation']
|
Eleazar/eleazar.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
def eleazar_model(y, t, age, has_vision, base_params):
|
| 4 |
+
"""
|
| 5 |
+
A System of Ordinary Differential Equations (ODEs) that models the
|
| 6 |
+
health dynamics of an Eleazar patient. The model is based on the following assumptions:
|
| 7 |
+
- Vision holders have more efficient regeneration and reduced corruption growth
|
| 8 |
+
- Reliability Theory of Aging (RTA) is used to model the age-dependent decline in regeneration efficiency
|
| 9 |
+
- Biological aging and the decline of functional systems are expressed through the
|
| 10 |
+
Gompertz-Makeham Law of Mortality and its underlying "redundancy" derivation
|
| 11 |
+
"""
|
| 12 |
+
V, C, S = y
|
| 13 |
+
alpha, beta, gamma, delta, kappa = base_params
|
| 14 |
+
|
| 15 |
+
# --- Gavrilov Reliability Parameters ---
|
| 16 |
+
# k: rate of redundancy exhaustion (the aging constant)
|
| 17 |
+
# Soften the aging constant to prevent 'instant death'
|
| 18 |
+
k = 0.035
|
| 19 |
+
# Reliability Modifier (Redundancy): P(survival) = (1 - (1-e^-kt)^n)
|
| 20 |
+
# Here we simplify to the metabolic reserve factor
|
| 21 |
+
redundancy_reserve = np.exp(-k * (age / 10))
|
| 22 |
+
|
| 23 |
+
# --- Updated Aegis-Gavrilov Logic ---
|
| 24 |
+
# NPC Child: High metabolic flux, high vulnerability
|
| 25 |
+
if not has_vision and age < 18:
|
| 26 |
+
phi = 1.0 # Normal regen
|
| 27 |
+
gamma_mod = 1.35 # Dottore's 'High Flux' observation: metabolism feeds the Abyss
|
| 28 |
+
metabolic_floor = 0.05
|
| 29 |
+
|
| 30 |
+
# Vision Holder: Superior protection with Aegis Redundancy Floor
|
| 31 |
+
elif has_vision:
|
| 32 |
+
phi = 1.30 # Superior Regen
|
| 33 |
+
gamma_mod = 0.30 # THE SHIELD: Vision blocks 70% of corruption spread
|
| 34 |
+
metabolic_floor = 0.45 # The Aegis Redundancy Floor
|
| 35 |
+
|
| 36 |
+
# Default case (adults without vision)
|
| 37 |
+
else:
|
| 38 |
+
phi = 1.0
|
| 39 |
+
gamma_mod = 1.0
|
| 40 |
+
metabolic_floor = 0.05
|
| 41 |
+
|
| 42 |
+
# Effective Vitality Reserve
|
| 43 |
+
R = max(metabolic_floor, redundancy_reserve)
|
| 44 |
+
|
| 45 |
+
# --- The Updated ODEs ---
|
| 46 |
+
# Vitality: Regeneration is now constrained by the Redundancy Reserve (R)
|
| 47 |
+
dVdt = (alpha * phi * R) * V * (1 - V/100) - (beta * C * V) - (delta * S)
|
| 48 |
+
|
| 49 |
+
# Corruption: Use a 'Safe Log' or 'Capped Multiplier' for the reliability influence
|
| 50 |
+
# This prevents the Elderly NPC from crashing in 2 days
|
| 51 |
+
reliability_impact = 1.0 / (R + 0.1)
|
| 52 |
+
dCdt = (gamma * gamma_mod * reliability_impact) * C - (0.02 * V * C)
|
| 53 |
+
|
| 54 |
+
# Scales: Physical petrification
|
| 55 |
+
dSdt = kappa * C * (1 - S/100)
|
| 56 |
+
|
| 57 |
+
return [dVdt, dCdt, dSdt]
|
Eleazar/hospital.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import matplotlib.pyplot as plt
|
| 3 |
+
try:
|
| 4 |
+
from .solver import run_simulation
|
| 5 |
+
except ImportError:
|
| 6 |
+
# Allow running as a script
|
| 7 |
+
from solver import run_simulation
|
| 8 |
+
|
| 9 |
+
scenarios = [
|
| 10 |
+
{"name": "Collei (Young, Dendro Vision)", "age": 18, "vision": True, "color": "#a6c938"},
|
| 11 |
+
{"name": "Child NPC (No Vision)", "age": 6, "vision": False, "color": "#75c2aa"},
|
| 12 |
+
{"name": "Elderly NPC (No Vision)", "age": 80, "vision": False, "color": "#ef7a35"}
|
| 13 |
+
]
|
| 14 |
+
|
| 15 |
+
t, results = run_simulation(scenarios)
|
| 16 |
+
|
| 17 |
+
# --- 4. Visualization ---
|
| 18 |
+
|
| 19 |
+
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
|
| 20 |
+
|
| 21 |
+
for sc in scenarios:
|
| 22 |
+
data = results[sc['name']]
|
| 23 |
+
ax1.plot(t, data[:, 0], label=f"{sc['name']} - Vitality", color=sc['color'], linewidth=2)
|
| 24 |
+
ax2.plot(t, data[:, 2], label=f"{sc['name']} - Scales", color=sc['color'], linestyle="--")
|
| 25 |
+
|
| 26 |
+
# Aesthetics
|
| 27 |
+
ax1.set_ylabel("Vitality (%)")
|
| 28 |
+
ax1.set_title("Eleazar: Vitality Dynamics (Gavrilov Reliability)")
|
| 29 |
+
ax1.axhline(15, color='black', linestyle=':', label="Critical Failure Threshold")
|
| 30 |
+
ax1.legend()
|
| 31 |
+
ax1.grid(alpha=0.3)
|
| 32 |
+
|
| 33 |
+
ax2.set_ylabel("Petrification (Scales %)")
|
| 34 |
+
ax2.set_xlabel("Days Since Exposure")
|
| 35 |
+
ax2.set_title("Eleazar Physical Progression")
|
| 36 |
+
ax2.legend()
|
| 37 |
+
ax2.grid(alpha=0.3)
|
| 38 |
+
|
| 39 |
+
plt.tight_layout()
|
| 40 |
+
output_path = os.path.join(os.path.dirname(__file__), 'eleazar_simulation.png')
|
| 41 |
+
plt.savefig(output_path, dpi=150, bbox_inches='tight')
|
| 42 |
+
plt.close()
|
Eleazar/readme.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Phase 2: Eleazar and Biological Reliability
|
| 2 |
+
|
| 3 |
+
## Project Overview
|
| 4 |
+
**Eleazar** is terminal condition caused by the "Withering" manifesting in human hosts.
|
| 5 |
+
This project applies a modified version of the **Reliability Theory of Aging** (Gavrilov Model)
|
| 6 |
+
to simulate the competition between cellular vitality and Abyssal contamination.
|
| 7 |
+
|
| 8 |
+
## The Gavrilov-Vision Model
|
| 9 |
+
We treat the human body as a system of redundant components.
|
| 10 |
+
Failure (Eleazar) occurs when the "redundancy reserve" is exhausted.
|
| 11 |
+
The *Gompertz-Makeham Law* is used to define the base mortality and age-dependent decay of a patient.
|
| 12 |
+
We also account for the effects of a *Vision*, which we mathematically define as a redundancy buffer,
|
| 13 |
+
providing a "metabolic floor" that prevents the exponential "avalanche of failures" typical in terminal Eleazar cases.
|
| 14 |
+
|
| 15 |
+
## ODE Setup
|
| 16 |
+
We implemented a system of three coupled Ordinary Differential Equations (ODEs) to track the patient's state over time:
|
| 17 |
+
- $V(t)$ (Vitality): Regenerative life force, constrained by the current redundancy reserve.
|
| 18 |
+
- $C(t)$ (Corruption): The concentration of "Forbidden Knowledge" within the body, which scales exponentially as biological reliability ($R$) drops
|
| 19 |
+
- $S(t)$ (Scales): The physical petrification rate, acting as a "drag" on vitality.
|
| 20 |
+
|
| 21 |
+
The system of ODEs is defined as:
|
| 22 |
+
|
| 23 |
+
$$\frac{dV}{dt} = (\alpha \cdot \phi \cdot R) \cdot V \cdot \left(1 - \frac{V}{100}\right) - (\beta \cdot C \cdot V) - (\delta \cdot S)$$
|
| 24 |
+
|
| 25 |
+
$$\frac{dC}{dt} = (\gamma \cdot \gamma_{mod} \cdot \text{reliability\_impact}) \cdot C - (0.02 \cdot V \cdot C)$$
|
| 26 |
+
|
| 27 |
+
$$\frac{dS}{dt} = \kappa \cdot C \cdot \left(1 - \frac{S}{100}\right)$$
|
| 28 |
+
|
| 29 |
+
where:
|
| 30 |
+
- $R = \max(\text{metabolic\_floor}, e^{-k \cdot (\text{age}/10)})$ is the effective vitality reserve (redundancy reserve)
|
| 31 |
+
- $\text{reliability\_impact} = \frac{1.0}{R + 0.1}$ is a capped multiplier preventing extreme crashes
|
| 32 |
+
- $\alpha, \beta, \gamma, \delta, \kappa$ are base parameters (regen, drain, virulence, scale drag, ossification)
|
| 33 |
+
- $\phi$ and $\gamma_{mod}$ are modifiers based on patient type (Vision holder, NPC child, etc.)
|
| 34 |
+
|
| 35 |
+
## Simulation Results
|
| 36 |
+
We simulated the model on three different patients, with different age and vision parameters affecting their vitality and resistance. Our simulations identified a Bifurcation Point: a critical threshold of initial corruption where the body's repair systems can no longer suppress the Abyssal contamination.
|
| 37 |
+
|
| 38 |
+
### Comparative Patient Analysis
|
| 39 |
+
|
| 40 |
+
| Patient | Age | Vision | $\phi$ | $\gamma_{mod}$ | Metabolic Floor | Outcome |
|
| 41 |
+
|---------|-----|--------|--------|----------------|-----------------|---------|
|
| 42 |
+
| **Collei** | 18 | ✓ (Dendro) | 1.30 | 0.30 | 0.45 | Stabilized Chronic - Reaches stable equilibrium via Aegis Effect |
|
| 43 |
+
| **Child NPC** | 6 | ✗ | 1.0 | 1.35 | 0.05 | High-Flux Catalyst - High metabolism feeds corruption ($1.35\gamma$) |
|
| 44 |
+
| **Elderly NPC** | 80 | ✗ | 1.0 | 1.0 | 0.05 | Exhausted Terminal - Low redundancy leads to rapid collapse |
|
| 45 |
+
|
| 46 |
+
**Key Observations:**
|
| 47 |
+
- **The High-Flux Child (NPC)**: High metabolic rates in children act as a "catalyst" for corruption ($1.35\gamma$), explaining Dottore's interest in youthful subjects for Abyssal testing.
|
| 48 |
+
- **The Stabilized Chronic (Collei)**: With a Vision, the patient reaches a Stable Equilibrium. The "Vision Effect" dampens corruption growth, allowing the patient to survive even high-load exposures that would be fatal to a non-Vision holder.
|
| 49 |
+
- **The Exhausted Terminal (Elderly NPC)**: Low initial redundancy (due to Gompertzian aging) leads to a rapid, irreversible collapse upon exposure.
|
| 50 |
+
|
| 51 |
+

|
| 52 |
+
|
| 53 |
+
*Simulation parameters: Initial state $V_0 = 85.0\%$, $C_0 = 18.5\%$, $S_0 = 10.0\%$; Base parameters $\alpha = 0.12$, $\beta = 0.06$, $\gamma = 0.22$, $\delta = 0.04$, $\kappa = 0.08$; Aging constant $k = 0.035$; Simulation duration: 120 days with 1200 time points.*
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
By changing the initial starting parameters, we can get different scenarios, where all patients recover or non Vision holders failing to recover. We also demonstrate the power of having a Vision in providing accelerated regeneration and contamination resistance, allowing **Collei** to fully recover despite having high initial contamination.
|
| 57 |
+
|
| 58 |
+

|
| 59 |
+
|
| 60 |
+
*Simulation parameters: Initial state $V_0 = 90.0\%$, $C_0 = 30.0\%$, $S_0 = 7.0\%$; Base parameters $\alpha = 0.12$, $\beta = 0.06$, $\gamma = 0.22$, $\delta = 0.04$, $\kappa = 0.08$; Aging constant $k = 0.035$; Simulation duration: 120 days with 1200 time points. This simulation demonstrates recovery scenarios with higher initial corruption, showing how Vision holders can overcome severe contamination.*
|
Eleazar/solver.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from scipy.integrate import odeint
|
| 3 |
+
try:
|
| 4 |
+
from tqdm import tqdm
|
| 5 |
+
except ImportError:
|
| 6 |
+
# Fallback if tqdm is not installed
|
| 7 |
+
def tqdm(iterable, *args, **kwargs):
|
| 8 |
+
return iterable
|
| 9 |
+
try:
|
| 10 |
+
from .eleazar import eleazar_model
|
| 11 |
+
except ImportError:
|
| 12 |
+
# Allow running as a script
|
| 13 |
+
from eleazar import eleazar_model
|
| 14 |
+
|
| 15 |
+
def run_simulation(scenarios, days=120):
|
| 16 |
+
"""
|
| 17 |
+
Runs a simulation of the Eleazar model for a given set of scenarios.
|
| 18 |
+
scenarios: A list of dictionaries, each containing the following keys:
|
| 19 |
+
- 'name': The name of the scenario
|
| 20 |
+
- 'age': The age of the patient
|
| 21 |
+
- 'vision': Whether the patient has vision or not
|
| 22 |
+
days: The number of days to run the simulation
|
| 23 |
+
Returns: A tuple containing the time array and a dictionary of results.
|
| 24 |
+
"""
|
| 25 |
+
t = np.linspace(0, days, 1200)
|
| 26 |
+
# [regen, drain, corruption_rate, scale_drag, ossification]
|
| 27 |
+
# Parameter set for "Chronic Struggle" - Phase 2 "Final Exam"
|
| 28 |
+
base_params = [0.12, 0.06, 0.22, 0.04, 0.08]
|
| 29 |
+
|
| 30 |
+
results = {}
|
| 31 |
+
for sc in tqdm(scenarios, desc="Running simulations", unit="scenario"):
|
| 32 |
+
# Starting with heavy exposure to a Withering Zone
|
| 33 |
+
y0 = [90.0, 30.0, 7.0]
|
| 34 |
+
sol = odeint(eleazar_model, y0, t, args=(sc['age'], sc['vision'], base_params))
|
| 35 |
+
results[sc['name']] = sol
|
| 36 |
+
|
| 37 |
+
return t, results
|
Irminsul/__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Irminsul package for elemental sequence restoration."""
|
| 2 |
+
|
| 3 |
+
from .constants import ELEMENTS, BASE_MATRIX, EMISSION_MATRIX, OBS_MAP
|
| 4 |
+
from .nahida import trikarma_purification
|
| 5 |
+
|
| 6 |
+
__all__ = ['ELEMENTS', 'BASE_MATRIX', 'EMISSION_MATRIX', 'OBS_MAP', 'trikarma_purification']
|
Irminsul/constants.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
ELEMENTS = [
|
| 4 |
+
'P', # Pyro
|
| 5 |
+
'H', # Hydro
|
| 6 |
+
'E', # Electro
|
| 7 |
+
'C', # Cryo
|
| 8 |
+
'A', # Anemo
|
| 9 |
+
'D', # Dendro
|
| 10 |
+
'G', # Geo
|
| 11 |
+
]
|
| 12 |
+
|
| 13 |
+
BASE_MATRIX = np.array([
|
| 14 |
+
[0.10, 0.25, 0.15, 0.05, 0.15, 0.25, 0.05], # Pyro: Loves Vape/Burn/Swirl
|
| 15 |
+
[0.25, 0.10, 0.15, 0.10, 0.15, 0.25, 0.00], # Hydro: Loves Vape/Bloom/Swirl/Freeze
|
| 16 |
+
[0.15, 0.20, 0.10, 0.05, 0.15, 0.30, 0.05], # Electro: Loves Quicken/EC/Swirl
|
| 17 |
+
[0.10, 0.25, 0.05, 0.15, 0.15, 0.03, 0.27], # Cryo: Loves Freeze/Swirl/Shatter
|
| 18 |
+
[0.22, 0.22, 0.22, 0.22, 0.04, 0.04, 0.04], # Anemo: Swirl Priority (P, H, E, C)
|
| 19 |
+
[0.25, 0.25, 0.30, 0.03, 0.02, 0.10, 0.05], # Dendro: Sticky with Pyro/Hydro/Electro
|
| 20 |
+
[0.20, 0.20, 0.20, 0.20, 0.02, 0.02, 0.16] # Geo: Crystallize (P, H, E, C)
|
| 21 |
+
])
|
| 22 |
+
|
| 23 |
+
EMISSION_MATRIX = np.array([
|
| 24 |
+
# P H E C A D G W (Withered State)
|
| 25 |
+
[0.60, 0.02, 0.02, 0.01, 0.02, 0.01, 0.02, 0.30], # True Pyro
|
| 26 |
+
[0.02, 0.60, 0.02, 0.02, 0.01, 0.02, 0.01, 0.30], # True Hydro
|
| 27 |
+
[0.02, 0.02, 0.60, 0.02, 0.02, 0.01, 0.01, 0.30], # True Electro
|
| 28 |
+
[0.01, 0.02, 0.02, 0.60, 0.02, 0.01, 0.02, 0.30], # True Cryo
|
| 29 |
+
[0.02, 0.02, 0.02, 0.02, 0.60, 0.01, 0.01, 0.30], # True Anemo
|
| 30 |
+
[0.01, 0.01, 0.01, 0.01, 0.01, 0.65, 0.00, 0.30], # True Dendro (more stable)
|
| 31 |
+
[0.02, 0.01, 0.01, 0.02, 0.01, 0.00, 0.63, 0.30], # True Geo
|
| 32 |
+
])
|
| 33 |
+
|
| 34 |
+
OBS_MAP = {'P':0, 'H':1, 'E':2, 'C':3, 'A':4, 'D':5, 'G':6, 'W':7}
|
Irminsul/kusanali.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
try:
|
| 3 |
+
from .nahida import trikarma_purification
|
| 4 |
+
from .constants import OBS_MAP, ELEMENTS
|
| 5 |
+
from .trellis import plot_viterbi_trellis
|
| 6 |
+
except ImportError:
|
| 7 |
+
# Allow running as a script
|
| 8 |
+
from nahida import trikarma_purification
|
| 9 |
+
from constants import OBS_MAP, ELEMENTS
|
| 10 |
+
from trellis import plot_viterbi_trellis
|
| 11 |
+
|
| 12 |
+
def kusanali():
|
| 13 |
+
"""
|
| 14 |
+
A simple, informative example of using Nahida's Elemental Skill (Trikarma Purification)
|
| 15 |
+
to restore a withered record (string of elements affected by the Withering).
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
pure_record = "DE" # Quicken
|
| 19 |
+
pure_record += "E" # Aggravate
|
| 20 |
+
pure_record += "E" # Electro, consumes aggravate
|
| 21 |
+
pure_record += "P" # Pyro, consumes quicken to create burning
|
| 22 |
+
pure_record += "A" # Anemo, swirls pyro
|
| 23 |
+
pure_record += "HH" # Hydro, causes vaporize x2
|
| 24 |
+
pure_record += "G" # Geo, creates crystallize
|
| 25 |
+
|
| 26 |
+
# Abyssal contamination causes the Withering to contaminate some information
|
| 27 |
+
withered_record = "DEWEPWHWG"
|
| 28 |
+
withered_indices = [OBS_MAP[c] for c in withered_record]
|
| 29 |
+
|
| 30 |
+
# Use Nahida's Elemental Skill
|
| 31 |
+
purified, path_indices = trikarma_purification(withered_indices, return_indices=True)
|
| 32 |
+
|
| 33 |
+
print(f"Original: {pure_record}")
|
| 34 |
+
print(f"Withered: {withered_record}")
|
| 35 |
+
print(f"Restored: {''.join(purified)}")
|
| 36 |
+
|
| 37 |
+
# Plot the trellis diagram
|
| 38 |
+
output_path = os.path.join(os.path.dirname(__file__), 'viterbi_trellis.png')
|
| 39 |
+
plot_viterbi_trellis(withered_record, ELEMENTS, path_indices, output_path, pure_record)
|
| 40 |
+
print(f"Trellis diagram saved to: {output_path}")
|
| 41 |
+
|
| 42 |
+
if __name__ == "__main__":
|
| 43 |
+
kusanali()
|
Irminsul/nahida.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
try:
|
| 3 |
+
from .constants import BASE_MATRIX, EMISSION_MATRIX, ELEMENTS
|
| 4 |
+
except ImportError:
|
| 5 |
+
# Allow running as a script
|
| 6 |
+
from constants import BASE_MATRIX, EMISSION_MATRIX, ELEMENTS
|
| 7 |
+
|
| 8 |
+
def trikarma_purification(
|
| 9 |
+
obs_sequence: str,
|
| 10 |
+
base_matrix: np.ndarray = BASE_MATRIX,
|
| 11 |
+
emission_matrix: np.ndarray = EMISSION_MATRIX,
|
| 12 |
+
states: list[str] = ELEMENTS,
|
| 13 |
+
return_indices: bool = False
|
| 14 |
+
):
|
| 15 |
+
"""
|
| 16 |
+
Restores the true elemental sequence from a withered record.
|
| 17 |
+
obs_sequence: List of indices corresponding to observations (0-7)
|
| 18 |
+
base_matrix: 7x7 transition matrix between elements
|
| 19 |
+
emission_matrix: 7x8 emission matrix for observations
|
| 20 |
+
states: List of possible elemental states (P, H, E, C, A, D, G)
|
| 21 |
+
Returns:
|
| 22 |
+
List of indices corresponding to the true elemental sequence (0-6)
|
| 23 |
+
|
| 24 |
+
This function implements the Viterbi algorithm to find the most likely sequence of states.
|
| 25 |
+
"""
|
| 26 |
+
n_states, n_obs = len(states), len(obs_sequence)
|
| 27 |
+
|
| 28 |
+
# Initialize the Viterbi and Backpointer matrices
|
| 29 |
+
viterbi = np.zeros((n_states, n_obs))
|
| 30 |
+
backpointer = np.zeros((n_states, n_obs), dtype=int)
|
| 31 |
+
|
| 32 |
+
# Initialization (Time step 0)
|
| 33 |
+
# Assume equal probability for the starting element (1/7)
|
| 34 |
+
with np.errstate(divide='ignore'):
|
| 35 |
+
for s in range(n_states):
|
| 36 |
+
viterbi[s, 0] = np.log(1/n_states) + np.log(emission_matrix[s, obs_sequence[0]])
|
| 37 |
+
|
| 38 |
+
# Recursion (Time steps 1 to T)
|
| 39 |
+
with np.errstate(divide='ignore'):
|
| 40 |
+
for t in range(1, n_obs):
|
| 41 |
+
for s in range(n_states):
|
| 42 |
+
# Calculate prob of moving from every 'prev_s' to current 's'
|
| 43 |
+
# using log-space to avoid underflow
|
| 44 |
+
log_probs = viterbi[:, t-1] + np.log(base_matrix[:, s]) + np.log(emission_matrix[s, obs_sequence[t]])
|
| 45 |
+
viterbi[s, t] = np.max(log_probs)
|
| 46 |
+
backpointer[s, t] = np.argmax(log_probs)
|
| 47 |
+
|
| 48 |
+
# Termination & Path Reconstruction
|
| 49 |
+
best_path = np.zeros(n_obs, dtype=int)
|
| 50 |
+
best_path[-1] = np.argmax(viterbi[:, -1])
|
| 51 |
+
|
| 52 |
+
# Backtrack to find the most likely sequence of states
|
| 53 |
+
for t in range(n_obs-2, -1, -1):
|
| 54 |
+
best_path[t] = backpointer[best_path[t+1], t+1]
|
| 55 |
+
|
| 56 |
+
if return_indices:
|
| 57 |
+
return [states[s] for s in best_path], best_path
|
| 58 |
+
return [states[s] for s in best_path]
|
Irminsul/readme.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Phase 1: Deep-Layer Error Correction in the World Tree
|
| 2 |
+
|
| 3 |
+
## Project Overview
|
| 4 |
+
This project treats **Irminsul** (The World Tree) from *Genshin Impact* as a
|
| 5 |
+
biological database of Teyvat's history and genetic blueprints.
|
| 6 |
+
Just as DNA is subject to mutations, Irminsul is vulnerable to "Forbidden Knowledge,"
|
| 7 |
+
a form of high-entropy noise known as *The Withering*.
|
| 8 |
+
|
| 9 |
+
I implemented a **HMM** (Hidden Markov Model) to detect and cleanse this corruption,
|
| 10 |
+
restoring the "True Record" of elemental fluxes using the **Viterbi Algorithm.**
|
| 11 |
+
|
| 12 |
+
## Biological Syntax of Teyvat
|
| 13 |
+
Unlike standard data, elemental records follow a specific mechanistic logic.
|
| 14 |
+
We modeled the transition between elements (Pyro, Hydro, Electro, Cryo, Anemo, Dendro, Geo)
|
| 15 |
+
as a Markovian process where probabilities are weighted by Elemental Gauge Theory.
|
| 16 |
+
Specific features include
|
| 17 |
+
- *Stable Chains:* High transition probabilities for reactive pairs like Dendro x Electro (Quicken) or Hydro x Cryo (Freeze)
|
| 18 |
+
- *Inert Pairs:* Low probabilities for combinations like Anemo x Geo, which do not react with each other
|
| 19 |
+
|
| 20 |
+
The Withering (W) is modeled as an Emission Matrix where the true state is hidden behind a mask of Abyssal corruption.
|
| 21 |
+
|
| 22 |
+
## Technical Details
|
| 23 |
+
1. **The Markov Transition Matrix ($A$):**
|
| 24 |
+
We defined a $7 \times 7$ matrix representing the "Laws of Nature." This ensures that the restoration algorithm "understands" the chemical context of the data it is repairing.
|
| 25 |
+
|
| 26 |
+
2. **The Viterbi "Cleansing" Algorithm:**
|
| 27 |
+
To restore corrupted records, we implemented the Viterbi algorithm in log-probability space for numerical stability.
|
| 28 |
+
> Input: A "Withered" string (e.g., DEWEPWHWG).
|
| 29 |
+
> Process: The algorithm calculates the globally most likely "True" path through the state-space [trellis](#footnote-trellis).
|
| 30 |
+
> Output: A restored elemental sequence.
|
| 31 |
+
|
| 32 |
+

|
| 33 |
+
|
| 34 |
+
*The trellis diagram shows the Viterbi algorithm finding the most likely sequence of hidden elements (green path) that would produce the observed corrupted record. When the original pure record differs from the reconstruction, it is shown as a blue dashed line for comparison.*
|
| 35 |
+
|
| 36 |
+
3. **Numerical Stability:**
|
| 37 |
+
To handle "Forbidden" transitions (zero probability events), we utilized Laplace Smoothing and $\epsilon$-constants, preventing logarithmic underflow while maintaining the strict logic of the elemental system.
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
## Limitations/Quirks
|
| 41 |
+
When the corruption is too high, the algorithm defaults to the "most logical" biological path rather than the "historical truth."
|
| 42 |
+
For example, an original sequence of D-E-E-E (Dendro-Electro-Electro-Electro) might be restored as
|
| 43 |
+
D-E-D-E (Dendro-Electro-Dendro-Electro) because the algorithm favors the Quicken reaction over simple repetition.
|
| 44 |
+
This mirrors the lore-accurate phenomenon of the World Tree "rewriting" history to fit the laws of Teyvat.
|
| 45 |
+
|
| 46 |
+
---
|
| 47 |
+
|
| 48 |
+
<small id="footnote-trellis">A trellis is a graphical diagram that unravels the states of a system over time, showing all possible state transitions as paths, where each path represents a potential sequence of encoded data.</small>
|
Irminsul/trellis.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import matplotlib.pyplot as plt
|
| 3 |
+
try:
|
| 4 |
+
from .constants import ELEMENTS
|
| 5 |
+
except ImportError:
|
| 6 |
+
from constants import ELEMENTS
|
| 7 |
+
|
| 8 |
+
def plot_viterbi_trellis(obs_sequence, states, best_path_indices, output_path=None, pure_record=None):
|
| 9 |
+
"""
|
| 10 |
+
Generates a trellis diagram for the Irminsul reconstruction.
|
| 11 |
+
|
| 12 |
+
Args:
|
| 13 |
+
obs_sequence: String of observed characters (e.g., "DEWEPWHWG")
|
| 14 |
+
states: List of state names (e.g., ['P', 'H', 'E', 'C', 'A', 'D', 'G'])
|
| 15 |
+
best_path_indices: List of state indices for the best path (reconstructed)
|
| 16 |
+
output_path: Optional path to save the figure. If None, displays the figure.
|
| 17 |
+
pure_record: Optional string of the pure/original record to overlay if it differs
|
| 18 |
+
"""
|
| 19 |
+
n_states = len(states)
|
| 20 |
+
n_obs = len(obs_sequence)
|
| 21 |
+
|
| 22 |
+
# Convert pure_record to indices if provided
|
| 23 |
+
pure_path_indices = None
|
| 24 |
+
if pure_record and len(pure_record) == n_obs:
|
| 25 |
+
try:
|
| 26 |
+
pure_path_indices = [states.index(char) for char in pure_record]
|
| 27 |
+
except (ValueError, IndexError):
|
| 28 |
+
pure_path_indices = None
|
| 29 |
+
|
| 30 |
+
plt.figure(figsize=(12, 6))
|
| 31 |
+
|
| 32 |
+
# Create the grid for states and time steps
|
| 33 |
+
for t in range(n_obs):
|
| 34 |
+
for s in range(n_states):
|
| 35 |
+
# Plot each state as a circle
|
| 36 |
+
color = 'lightgrey'
|
| 37 |
+
alpha = 0.3
|
| 38 |
+
|
| 39 |
+
# Check if this state is part of the reconstructed path
|
| 40 |
+
if best_path_indices[t] == s:
|
| 41 |
+
color = '#2ecc71' # Sumeru Green (reconstructed)
|
| 42 |
+
alpha = 1.0
|
| 43 |
+
plt.text(t, s + 0.3, states[s], ha='center', fontweight='bold', color='#27ae60')
|
| 44 |
+
|
| 45 |
+
# Check if this state is part of the pure path (and differs from reconstructed)
|
| 46 |
+
if pure_path_indices and pure_path_indices[t] == s and pure_path_indices[t] != best_path_indices[t]:
|
| 47 |
+
color = '#3498db' # Blue (pure/original)
|
| 48 |
+
alpha = 1.0
|
| 49 |
+
plt.text(t, s - 0.3, states[s], ha='center', fontweight='bold', color='#2980b9')
|
| 50 |
+
|
| 51 |
+
plt.scatter(t, s, color=color, s=500, edgecolors='black', alpha=alpha, zorder=3)
|
| 52 |
+
|
| 53 |
+
# Draw the reconstructed path (The Viterbi Result)
|
| 54 |
+
for t in range(n_obs - 1):
|
| 55 |
+
plt.plot([t, t+1], [best_path_indices[t], best_path_indices[t+1]],
|
| 56 |
+
color='#27ae60', linewidth=3, zorder=2, label='Reconstructed' if t == 0 else '')
|
| 57 |
+
|
| 58 |
+
# Draw the pure path if it differs
|
| 59 |
+
if pure_path_indices:
|
| 60 |
+
paths_differ = any(pure_path_indices[t] != best_path_indices[t] for t in range(n_obs))
|
| 61 |
+
if paths_differ:
|
| 62 |
+
for t in range(n_obs - 1):
|
| 63 |
+
plt.plot([t, t+1], [pure_path_indices[t], pure_path_indices[t+1]],
|
| 64 |
+
color='#3498db', linewidth=3, linestyle='--', zorder=2,
|
| 65 |
+
label='Original' if t == 0 else '')
|
| 66 |
+
|
| 67 |
+
# Formatting
|
| 68 |
+
plt.xticks(range(n_obs), [f"Obs: {char}" for char in obs_sequence])
|
| 69 |
+
plt.yticks(range(n_states), states)
|
| 70 |
+
title = "Project Irminsul: Viterbi Trellis Reconstruction"
|
| 71 |
+
if pure_path_indices and any(pure_path_indices[t] != best_path_indices[t] for t in range(n_obs)):
|
| 72 |
+
title += " (Original vs Reconstructed)"
|
| 73 |
+
plt.title(title, fontsize=14)
|
| 74 |
+
plt.xlabel("Timeline of Withered Observations")
|
| 75 |
+
plt.ylabel("Elemental State Space")
|
| 76 |
+
plt.grid(axis='x', linestyle='--', alpha=0.5)
|
| 77 |
+
if pure_path_indices and any(pure_path_indices[t] != best_path_indices[t] for t in range(n_obs)):
|
| 78 |
+
plt.legend(loc='upper right')
|
| 79 |
+
plt.tight_layout()
|
| 80 |
+
|
| 81 |
+
if output_path:
|
| 82 |
+
plt.savefig(output_path, dpi=150, bbox_inches='tight')
|
| 83 |
+
plt.close()
|
| 84 |
+
return None
|
| 85 |
+
else:
|
| 86 |
+
# Return the figure for use in interactive contexts (e.g., Gradio)
|
| 87 |
+
return plt.gcf()
|
README.md
CHANGED
|
@@ -1,13 +1,101 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
colorTo: blue
|
| 6 |
-
sdk:
|
| 7 |
-
|
| 8 |
-
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
-
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Teyvat Biosystems
|
| 3 |
+
emoji: 🔬
|
| 4 |
+
colorFrom: green
|
| 5 |
colorTo: blue
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
|
|
|
| 8 |
pinned: false
|
| 9 |
+
license: mit
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Teyvat Biosystems
|
| 13 |
+
|
| 14 |
+
A mathematical analysis of biological systems in *Genshin Impact*, focusing on the destructive technologies developed by Il Dottore. This project applies computational methods to model and quantify the effects of Forbidden Knowledge, Eleazar disease, and Delusion technology on human subjects.
|
| 15 |
+
|
| 16 |
+
**⚠️ WARNING: DO NOT EXPERIMENT ON HUMANS, DOTTORE**
|
| 17 |
+
|
| 18 |
+
---
|
| 19 |
+
|
| 20 |
+
## Project Overview
|
| 21 |
+
|
| 22 |
+
This repository contains three phases of mathematical modeling, each addressing a different aspect of biological corruption and system failure in the world of Teyvat:
|
| 23 |
+
|
| 24 |
+
### [Phase 1: Deep-Layer Error Correction in the World Tree](Irminsul/readme.md)
|
| 25 |
+
|
| 26 |
+
**Methodology:** Hidden Markov Model (HMM) with Viterbi Algorithm
|
| 27 |
+
|
| 28 |
+
**Objective:** Restore corrupted elemental records from Irminsul (The World Tree) by treating "The Withering" as high-entropy noise that obscures true biological data.
|
| 29 |
+
|
| 30 |
+
**Key Results:**
|
| 31 |
+
- Successfully implemented a Viterbi-based restoration algorithm that recovers true elemental sequences from withered observations
|
| 32 |
+
- Identified a bifurcation point where corruption becomes too severe for accurate reconstruction
|
| 33 |
+
- Demonstrated how the algorithm favors "biologically logical" paths over historical truth, mirroring Irminsul's tendency to rewrite history
|
| 34 |
+
|
| 35 |
+
**Technologies:** NumPy, Hidden Markov Models, Viterbi Algorithm
|
| 36 |
+
|
| 37 |
+
---
|
| 38 |
+
|
| 39 |
+
### [Phase 2: Eleazar and Biological Reliability](Eleazar/readme.md)
|
| 40 |
+
|
| 41 |
+
**Methodology:** System of Ordinary Differential Equations (ODEs) with Gavrilov Reliability Theory
|
| 42 |
+
|
| 43 |
+
**Objective:** Model the progression of Eleazar disease—a terminal condition caused by Withering manifesting in human hosts—using Reliability Theory of Aging.
|
| 44 |
+
|
| 45 |
+
**Key Results:**
|
| 46 |
+
- Developed a 3-ODE system tracking Vitality, Corruption, and Scales (petrification)
|
| 47 |
+
- Identified three distinct patient outcomes:
|
| 48 |
+
- **Stabilized Chronic** (Vision holders): Reach stable equilibrium via "Aegis Effect"
|
| 49 |
+
- **High-Flux Catalyst** (NPC children): High metabolism feeds corruption ($1.35\gamma$)
|
| 50 |
+
- **Exhausted Terminal** (Elderly NPCs): Rapid collapse due to low redundancy reserves
|
| 51 |
+
- Demonstrated how Vision holders can overcome severe contamination that would be fatal to non-Vision holders
|
| 52 |
+
|
| 53 |
+
**Technologies:** NumPy, SciPy (ODE integration), Reliability Theory of Aging
|
| 54 |
+
|
| 55 |
+
---
|
| 56 |
+
|
| 57 |
+
### [Phase 3: Linear Programming and the "Human Tax" Optimization](Delusion/readme.md)
|
| 58 |
+
|
| 59 |
+
**Methodology:** Linear Programming (Constrained Optimization)
|
| 60 |
+
|
| 61 |
+
**Objective:** Quantify the active destruction caused by Delusion usage, proving mathematically that Delusion technology is a guaranteed death sentence for standard humans.
|
| 62 |
+
|
| 63 |
+
**Key Results:**
|
| 64 |
+
- Identified a brutal bifurcation point: survival time remains effectively zero for subjects with efficiency below 80%
|
| 65 |
+
- Discovered "The Child Paradox": subjects aged 10–14 show slight survival uplift due to high initial redundancy, which Dottore systematically exploits
|
| 66 |
+
- Revealed "The Mortality Cliff": exponential drop in survival window as age increases
|
| 67 |
+
- Mathematically exposed a system designed to treat human souls as disposable high-flux batteries
|
| 68 |
+
|
| 69 |
+
**Technologies:** SciPy (Linear Programming), Constrained Optimization
|
| 70 |
+
|
| 71 |
+
---
|
| 72 |
+
|
| 73 |
+
## Project Structure
|
| 74 |
+
|
| 75 |
+
```
|
| 76 |
+
DottoreHateClub/
|
| 77 |
+
├── Irminsul/ # Phase 1: HMM-based error correction
|
| 78 |
+
├── Eleazar/ # Phase 2: ODE-based disease modeling
|
| 79 |
+
├── Delusion/ # Phase 3: LP-based survival analysis
|
| 80 |
+
└── README.md # This file
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
## Final Summary
|
| 84 |
+
|
| 85 |
+
1. **Irminsul Restoration:** The Viterbi algorithm can recover corrupted records, but favors biological logic over historical accuracy—a phenomenon that mirrors the World Tree's tendency to rewrite history.
|
| 86 |
+
|
| 87 |
+
2. **Eleazar Progression:** Vision holders maintain a "metabolic floor" (Aegis Effect) that prevents terminal collapse, while NPC children's high metabolism paradoxically accelerates corruption.
|
| 88 |
+
|
| 89 |
+
3. **Delusion Lethality:** Only subjects with elite combat mastery (efficiency >80%) can survive Delusion usage, proving that Dottore's technology is designed for disposable human batteries.
|
| 90 |
+
|
| 91 |
+
---
|
| 92 |
+
|
| 93 |
+
## References
|
| 94 |
+
|
| 95 |
+
- Gavrilov, L. A., & Gavrilova, N. S. (2001). The reliability theory of aging and longevity.
|
| 96 |
+
- Viterbi, A. J. (1967). Error bounds for convolutional codes and an asymptotically optimum decoding algorithm.
|
| 97 |
+
- *Genshin Impact* lore and game mechanics
|
| 98 |
+
|
| 99 |
+
---
|
| 100 |
+
|
| 101 |
+
**Disclaimer:** This project is a mathematical analysis of fictional biological systems. All models and conclusions are theoretical and should not be applied to real-world medical scenarios.
|
app.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ui
|
| 2 |
+
|
| 3 |
+
# Import demo for Gradio's reload mechanism to find it
|
| 4 |
+
demo = ui.demo
|
| 5 |
+
|
| 6 |
+
if __name__ == "__main__":
|
| 7 |
+
demo.launch(server_name="0.0.0.0", server_port=7860)
|
handlers.py
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import matplotlib.pyplot as plt
|
| 2 |
+
import numpy as np
|
| 3 |
+
from scipy.integrate import odeint
|
| 4 |
+
from mpl_toolkits.mplot3d import Axes3D
|
| 5 |
+
from Irminsul import trikarma_purification, ELEMENTS, OBS_MAP
|
| 6 |
+
from Irminsul.trellis import plot_viterbi_trellis
|
| 7 |
+
from Eleazar.eleazar import eleazar_model
|
| 8 |
+
from Delusion.delusion import activate_delusion
|
| 9 |
+
|
| 10 |
+
def get_benchmark_stats():
|
| 11 |
+
"""Calculate and return stats for the three benchmark subjects"""
|
| 12 |
+
benchmarks = [
|
| 13 |
+
{"name": "Childe", "age": 23, "vis": True, "eff": 0.65},
|
| 14 |
+
{"name": "Arlecchino", "age": 30, "vis": True, "eff": 0.95},
|
| 15 |
+
{"name": "Foolish NPC", "age": 16, "vis": False, "eff": 0.05}
|
| 16 |
+
]
|
| 17 |
+
|
| 18 |
+
stats_text = "### Benchmark Subject Stats\n\n"
|
| 19 |
+
stats_text += "| Subject | Age | Vision | Efficiency | ER | CD (s) | Q Cost | Budget |\n"
|
| 20 |
+
stats_text += "|---------|-----|--------|------------|----|----|--------|--------|\n"
|
| 21 |
+
|
| 22 |
+
for bench in benchmarks:
|
| 23 |
+
age = bench["age"]
|
| 24 |
+
has_vision = bench["vis"]
|
| 25 |
+
efficiency = bench["eff"]
|
| 26 |
+
|
| 27 |
+
# Calculate stats using same logic as activate_delusion
|
| 28 |
+
cooldown = 12 - (5 * efficiency)
|
| 29 |
+
burst_req = 90 - (10 * efficiency)
|
| 30 |
+
base_energy = 10 + (17 * efficiency) + (8 * efficiency * efficiency) - 0.34 * age
|
| 31 |
+
energy_per_E = base_energy * (1.5 if has_vision else 1.0)
|
| 32 |
+
initial_R = np.exp(-0.012 * age)
|
| 33 |
+
budget = initial_R - 0.15
|
| 34 |
+
|
| 35 |
+
vis_str = "Yes" if has_vision else "No"
|
| 36 |
+
stats_text += f"| {bench['name']} | {age} | {vis_str} | {efficiency:.2f} | {energy_per_E:.1f} | {cooldown:.1f} | {burst_req:.0f} | {budget:.3f} |\n"
|
| 37 |
+
|
| 38 |
+
return stats_text
|
| 39 |
+
|
| 40 |
+
def reconstruct_irminsul(pure_input, withered_input):
|
| 41 |
+
# 1. Validation & Truncation for pure sequence
|
| 42 |
+
valid_elements = ELEMENTS
|
| 43 |
+
clean_pure = "".join([c.upper() for c in pure_input if c.upper() in valid_elements])
|
| 44 |
+
pure_str = clean_pure[:16]
|
| 45 |
+
|
| 46 |
+
# 2. Validation & Truncation for withered sequence
|
| 47 |
+
valid_chars = ELEMENTS + ['W']
|
| 48 |
+
clean_withered = "".join([c.upper() for c in withered_input if c.upper() in valid_chars])
|
| 49 |
+
withered_str = clean_withered[:16]
|
| 50 |
+
|
| 51 |
+
if not withered_str:
|
| 52 |
+
return "Please enter valid Elemental symbols (P, H, E, C, A, D, G) or 'W' for Withering.", None
|
| 53 |
+
|
| 54 |
+
# 3. Convert withered string to observation indices
|
| 55 |
+
try:
|
| 56 |
+
withered_indices = [OBS_MAP[c] for c in withered_str]
|
| 57 |
+
except KeyError:
|
| 58 |
+
return "Invalid character in withered input. Please use only P, H, E, C, A, D, G, or W.", None
|
| 59 |
+
|
| 60 |
+
# 4. Use actual Viterbi algorithm
|
| 61 |
+
reconstructed, path_indices = trikarma_purification(withered_indices, return_indices=True)
|
| 62 |
+
reconstructed_str = "".join(reconstructed)
|
| 63 |
+
|
| 64 |
+
# 5. Calculate accuracy if pure sequence is provided
|
| 65 |
+
accuracy_info = ""
|
| 66 |
+
pure_record_for_plot = None
|
| 67 |
+
if pure_str:
|
| 68 |
+
# Truncate or pad pure_str to match reconstructed length
|
| 69 |
+
if len(pure_str) != len(reconstructed_str):
|
| 70 |
+
if len(pure_str) > len(reconstructed_str):
|
| 71 |
+
pure_str = pure_str[:len(reconstructed_str)]
|
| 72 |
+
else:
|
| 73 |
+
# Pad with empty or use what we have
|
| 74 |
+
pass
|
| 75 |
+
|
| 76 |
+
if len(pure_str) == len(reconstructed_str):
|
| 77 |
+
mismatches = sum(1 for i in range(len(reconstructed_str)) if reconstructed_str[i] != pure_str[i])
|
| 78 |
+
total = len(reconstructed_str)
|
| 79 |
+
accuracy = ((total - mismatches) / total * 100) if total > 0 else 0
|
| 80 |
+
accuracy_info = f"\nAccuracy: {accuracy:.1f}% ({total - mismatches}/{total} correct, {mismatches} mismatches)"
|
| 81 |
+
pure_record_for_plot = pure_str
|
| 82 |
+
|
| 83 |
+
# 6. Use the actual trellis plotting function
|
| 84 |
+
fig = plot_viterbi_trellis(withered_str, ELEMENTS, path_indices, output_path=None, pure_record=pure_record_for_plot)
|
| 85 |
+
|
| 86 |
+
output_text = reconstructed_str + accuracy_info
|
| 87 |
+
return output_text, fig
|
| 88 |
+
|
| 89 |
+
def simulate_triple_comparison(u_name, u_age, u_vision, initial_scenario):
|
| 90 |
+
"""
|
| 91 |
+
Compare custom character against Collei and Dunyarzad using the actual Eleazar model.
|
| 92 |
+
Uses the real eleazar_model function from the Eleazar package.
|
| 93 |
+
"""
|
| 94 |
+
# Initial condition scenarios
|
| 95 |
+
initial_conditions = {
|
| 96 |
+
"Heavy": [84.0, 20.0, 12.0], # V_0, C_0, S_0
|
| 97 |
+
"Medium": [86.0, 12.0, 8.0],
|
| 98 |
+
"Light": [90.0, 5.0, 2.0]
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
y0 = initial_conditions[initial_scenario]
|
| 102 |
+
|
| 103 |
+
# Define benchmark scenarios
|
| 104 |
+
scenarios = [
|
| 105 |
+
{"name": "Collei (Young, Dendro Vision)", "age": 18, "vision": True, "color": "#a6c938"},
|
| 106 |
+
{"name": "Dunyarzad (Elderly, No Vision)", "age": 65, "vision": False, "color": "#ef7a35"},
|
| 107 |
+
{"name": f"{u_name} (Custom)", "age": int(u_age), "vision": bool(u_vision), "color": "#3498db"}
|
| 108 |
+
]
|
| 109 |
+
|
| 110 |
+
# Base parameters from Eleazar solver
|
| 111 |
+
base_params = [0.12, 0.06, 0.22, 0.04, 0.08] # [regen, drain, corruption_rate, scale_drag, ossification]
|
| 112 |
+
t = np.linspace(0, 120, 1200)
|
| 113 |
+
|
| 114 |
+
# Run simulation for each scenario using actual Eleazar model
|
| 115 |
+
results = {}
|
| 116 |
+
for sc in scenarios:
|
| 117 |
+
sol = odeint(eleazar_model, y0, t, args=(sc['age'], sc['vision'], base_params))
|
| 118 |
+
results[sc['name']] = sol
|
| 119 |
+
|
| 120 |
+
# Create visualization
|
| 121 |
+
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
|
| 122 |
+
|
| 123 |
+
for sc in scenarios:
|
| 124 |
+
data = results[sc['name']]
|
| 125 |
+
ax1.plot(t, data[:, 0], label=f"{sc['name']} - Vitality", color=sc['color'], linewidth=2)
|
| 126 |
+
ax2.plot(t, data[:, 2], label=f"{sc['name']} - Scales", color=sc['color'], linewidth=2)
|
| 127 |
+
# Also show corruption for custom character
|
| 128 |
+
if sc['name'] == f"{u_name} (Custom)":
|
| 129 |
+
ax1.plot(t, data[:, 1], label=f"{sc['name']} - Corruption", color=sc['color'], linestyle="--", alpha=0.6)
|
| 130 |
+
|
| 131 |
+
# Aesthetics
|
| 132 |
+
ax1.set_ylabel("Vitality (%)")
|
| 133 |
+
ax1.set_title(f"Eleazar: Vitality Dynamics (Gavrilov Reliability) - Comparison\nInitial: {initial_scenario} (V={y0[0]:.1f}%, C={y0[1]:.1f}%, S={y0[2]:.1f}%)")
|
| 134 |
+
ax1.axhline(15, color='black', linestyle=':', label="Critical Failure Threshold", alpha=0.5)
|
| 135 |
+
ax1.legend()
|
| 136 |
+
ax1.grid(alpha=0.3)
|
| 137 |
+
|
| 138 |
+
ax2.set_ylabel("Petrification (Scales %)")
|
| 139 |
+
ax2.set_xlabel("Days Since Exposure")
|
| 140 |
+
ax2.set_title("Eleazar Physical Progression")
|
| 141 |
+
ax2.legend()
|
| 142 |
+
ax2.grid(alpha=0.3)
|
| 143 |
+
|
| 144 |
+
plt.tight_layout()
|
| 145 |
+
return fig
|
| 146 |
+
|
| 147 |
+
def generate_phase3_plots(name, age, has_vision, efficiency, boss_hp):
|
| 148 |
+
"""
|
| 149 |
+
Generate 2D comparison plot and 3D survival ridge for Phase 3: Delusion Toxicity
|
| 150 |
+
"""
|
| 151 |
+
age = int(age)
|
| 152 |
+
efficiency = float(efficiency)
|
| 153 |
+
boss_hp = float(boss_hp)
|
| 154 |
+
|
| 155 |
+
# --- 1. Generate 2D Comparison Plot ---
|
| 156 |
+
fig2d, ax2d = plt.subplots(figsize=(10, 6))
|
| 157 |
+
hp_range = np.linspace(10000, boss_hp * 1.5, 20)
|
| 158 |
+
|
| 159 |
+
# Benchmark subjects: Childe, Arlecchino, and NPC
|
| 160 |
+
benchmarks = [
|
| 161 |
+
{"name": "Childe", "age": 23, "vis": True, "eff": 0.65, "color": "#e67e22"},
|
| 162 |
+
{"name": "Arlecchino", "age": 30, "vis": True, "eff": 0.95, "color": "#c0392b"},
|
| 163 |
+
{"name": "Foolish NPC", "age": 16, "vis": False, "eff": 0.05, "color": "#7f8c8d"}
|
| 164 |
+
]
|
| 165 |
+
|
| 166 |
+
# Plot benchmarks
|
| 167 |
+
for bench in benchmarks:
|
| 168 |
+
costs = []
|
| 169 |
+
hps = []
|
| 170 |
+
budget = np.exp(-0.012 * bench["age"]) - 0.15
|
| 171 |
+
|
| 172 |
+
for hp in hp_range:
|
| 173 |
+
cost = activate_delusion(bench["name"], bench["age"], bench["vis"], bench["eff"], hp, silent=True)
|
| 174 |
+
if cost and cost <= budget:
|
| 175 |
+
costs.append(cost)
|
| 176 |
+
hps.append(hp)
|
| 177 |
+
else:
|
| 178 |
+
break
|
| 179 |
+
|
| 180 |
+
# Ensure line is visible even if they die instantly
|
| 181 |
+
if len(hps) == 0:
|
| 182 |
+
hps.append(0)
|
| 183 |
+
costs.append(0)
|
| 184 |
+
hps.append(hp_range[0])
|
| 185 |
+
costs.append(budget)
|
| 186 |
+
|
| 187 |
+
if len(hps) > 0:
|
| 188 |
+
ax2d.plot(hps, costs, label=f"{bench['name']} (Budget: {budget:.2f})",
|
| 189 |
+
color=bench["color"], marker='o', linewidth=2)
|
| 190 |
+
# Mark death point with skull
|
| 191 |
+
ax2d.scatter(hps[-1], costs[-1], marker='$\u2620$', color='black', s=250, zorder=5)
|
| 192 |
+
|
| 193 |
+
# Plot custom subject
|
| 194 |
+
costs = []
|
| 195 |
+
hps = []
|
| 196 |
+
budget = np.exp(-0.012 * age) - 0.15
|
| 197 |
+
|
| 198 |
+
for hp in hp_range:
|
| 199 |
+
cost = activate_delusion(name, age, has_vision, efficiency, hp, silent=True)
|
| 200 |
+
if cost and cost <= budget:
|
| 201 |
+
costs.append(cost)
|
| 202 |
+
hps.append(hp)
|
| 203 |
+
else:
|
| 204 |
+
break
|
| 205 |
+
|
| 206 |
+
# Ensure line is visible even if they die instantly
|
| 207 |
+
if len(hps) == 0:
|
| 208 |
+
hps.append(0)
|
| 209 |
+
costs.append(0)
|
| 210 |
+
hps.append(hp_range[0])
|
| 211 |
+
costs.append(budget)
|
| 212 |
+
|
| 213 |
+
ax2d.plot(hps, costs, label=f"{name} (Budget: {budget:.2f})",
|
| 214 |
+
color="#3498db", marker='o', linewidth=2)
|
| 215 |
+
|
| 216 |
+
if len(hps) > 0:
|
| 217 |
+
ax2d.scatter(hps[-1], costs[-1], marker='$\u2620$', color='black', s=250, zorder=5)
|
| 218 |
+
|
| 219 |
+
ax2d.axhline(y=0.15, color='red', linestyle='--', alpha=0.5, label="Critical Instability (15%)")
|
| 220 |
+
ax2d.axhline(y=0, color='red', linestyle='--', alpha=0.5, label="Baseline (0%)")
|
| 221 |
+
ax2d.set_title(f"Forensic Damage Scaling for {name}")
|
| 222 |
+
|
| 223 |
+
# Use appropriate scaling for HP values
|
| 224 |
+
if boss_hp >= 1000000:
|
| 225 |
+
# Scale to millions
|
| 226 |
+
ax2d.set_xlabel("Total Damage Required (Boss HP, millions)")
|
| 227 |
+
ax2d.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{x/1e6:.1f}M'))
|
| 228 |
+
elif boss_hp >= 1000:
|
| 229 |
+
# Scale to thousands
|
| 230 |
+
ax2d.set_xlabel("Total Damage Required (Boss HP, thousands)")
|
| 231 |
+
ax2d.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{x/1e3:.0f}K'))
|
| 232 |
+
else:
|
| 233 |
+
ax2d.set_xlabel("Total Damage Required (Boss HP)")
|
| 234 |
+
|
| 235 |
+
ax2d.set_ylabel("Gavrilov Redundancy Cost (R-Loss)")
|
| 236 |
+
ax2d.set_ylim(bottom=-0.1, top=1.1)
|
| 237 |
+
ax2d.legend()
|
| 238 |
+
ax2d.grid(True, which="both", ls="-", alpha=0.2)
|
| 239 |
+
|
| 240 |
+
# --- 2. Generate 3D Survival Ridge ---
|
| 241 |
+
fig3d = plt.figure(figsize=(10, 7))
|
| 242 |
+
ax3d = fig3d.add_subplot(111, projection='3d')
|
| 243 |
+
|
| 244 |
+
efficiencies = np.linspace(0.05, 0.95, 15)
|
| 245 |
+
hps_3d = np.linspace(100000, int(boss_hp * 1.2), 15)
|
| 246 |
+
X, Y = np.meshgrid(efficiencies, hps_3d)
|
| 247 |
+
Z = np.zeros(X.shape)
|
| 248 |
+
|
| 249 |
+
for i in range(len(hps_3d)):
|
| 250 |
+
for j in range(len(efficiencies)):
|
| 251 |
+
has_vis = X[i, j] > 0.6
|
| 252 |
+
result_cost = activate_delusion("Subject", age=25, has_vision=has_vis,
|
| 253 |
+
efficiency=X[i, j], boss_hp=Y[i, j], silent=True)
|
| 254 |
+
initial_R = np.exp(-0.012 * 25)
|
| 255 |
+
if result_cost is not None:
|
| 256 |
+
remaining = initial_R - result_cost
|
| 257 |
+
Z[i, j] = max(0.15, remaining)
|
| 258 |
+
else:
|
| 259 |
+
Z[i, j] = 0.15
|
| 260 |
+
|
| 261 |
+
surf = ax3d.plot_surface(X, Y, Z, cmap='inferno', edgecolor='none', alpha=0.9)
|
| 262 |
+
ax3d.set_title("Delusions: The 3D Survival Ridge", fontsize=14)
|
| 263 |
+
ax3d.set_xlabel("Mastery Efficiency (η)")
|
| 264 |
+
|
| 265 |
+
# Use appropriate scaling for HP values in 3D plot
|
| 266 |
+
if boss_hp >= 1000000:
|
| 267 |
+
ax3d.set_ylabel("Combat Load (Boss HP, millions)")
|
| 268 |
+
ax3d.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{x/1e6:.1f}M'))
|
| 269 |
+
elif boss_hp >= 1000:
|
| 270 |
+
ax3d.set_ylabel("Combat Load (Boss HP, thousands)")
|
| 271 |
+
ax3d.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{x/1e3:.0f}K'))
|
| 272 |
+
else:
|
| 273 |
+
ax3d.set_ylabel("Combat Load (Boss HP)")
|
| 274 |
+
|
| 275 |
+
ax3d.set_zlabel("Biological Redundancy (R)")
|
| 276 |
+
fig3d.colorbar(surf, ax=ax3d, shrink=0.5, aspect=5, label='Survival Probability')
|
| 277 |
+
|
| 278 |
+
return fig2d, fig3d
|
requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio>=4.0.0
|
| 2 |
+
numpy>=1.24.0
|
| 3 |
+
scipy>=1.10.0
|
| 4 |
+
matplotlib>=3.7.0
|
ui.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr # type: ignore
|
| 2 |
+
from handlers import reconstruct_irminsul, simulate_triple_comparison, generate_phase3_plots, get_benchmark_stats
|
| 3 |
+
|
| 4 |
+
# Use darker Collei green (#6b8a26) for theme
|
| 5 |
+
custom_theme = gr.themes.Soft(
|
| 6 |
+
primary_hue=gr.themes.Color(
|
| 7 |
+
c50="#e8f5e9",
|
| 8 |
+
c100="#c8e6c9",
|
| 9 |
+
c200="#a5d6a7",
|
| 10 |
+
c300="#81c784",
|
| 11 |
+
c400="#66bb6a",
|
| 12 |
+
c500="#6b8a26",
|
| 13 |
+
c600="#5a7a1f",
|
| 14 |
+
c700="#4a6a18",
|
| 15 |
+
c800="#3a5a11",
|
| 16 |
+
c900="#2a4a0a",
|
| 17 |
+
c950="#1a3a03",
|
| 18 |
+
)
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
with gr.Blocks(theme=custom_theme) as demo:
|
| 22 |
+
gr.Markdown("# A mathematical analysis of biological systems in *Genshin Impact*")
|
| 23 |
+
|
| 24 |
+
with gr.Tab("Phase 1: Irminsul Recovery"):
|
| 25 |
+
gr.Markdown("## Project Overview")
|
| 26 |
+
gr.Markdown(
|
| 27 |
+
"This project treats **Irminsul** (The World Tree) from *Genshin Impact* as a biological database of Teyvat's history and genetic blueprints. "
|
| 28 |
+
"Just as DNA is subject to mutations, Irminsul is vulnerable to \"Forbidden Knowledge,\" a form of high-entropy noise known as *The Withering*. "
|
| 29 |
+
"This project utilizes a **HMM** (Hidden Markov Model) to detect and cleanse this corruption, restoring the \"True Record\" of elemental fluxes using the **Viterbi Algorithm.**"
|
| 30 |
+
)
|
| 31 |
+
gr.Markdown("### Forensic Signal Reconstruction")
|
| 32 |
+
gr.Markdown("Input a pure sequence (optional) and a 'Withered' elemental sequence to attempt recovery.")
|
| 33 |
+
|
| 34 |
+
with gr.Row():
|
| 35 |
+
with gr.Column(scale=3):
|
| 36 |
+
txt_pure = gr.Textbox(label="Pure Sequence (Optional, Max 16 chars)", placeholder="e.g. DEEEPAHHG")
|
| 37 |
+
txt_withered = gr.Textbox(label="Withered Sequence (Max 16 chars)", placeholder="e.g. DEWEPWHWG")
|
| 38 |
+
btn_run = gr.Button("Decode Record", variant="primary")
|
| 39 |
+
txt_output = gr.Textbox(label="Reconstructed Pure Record", lines=3)
|
| 40 |
+
|
| 41 |
+
with gr.Column(scale=4):
|
| 42 |
+
plot_output = gr.Plot(label="Viterbi Trellis Visualization")
|
| 43 |
+
plot_caption = gr.Markdown("*The trellis diagram shows the Viterbi algorithm finding the most likely sequence of hidden elements (green path) that would produce the observed corrupted record. When the original pure record differs from the reconstruction, it is shown as a blue dashed line for comparison.*")
|
| 44 |
+
with gr.Accordion("Explain Accuracy", open=False):
|
| 45 |
+
gr.Markdown(
|
| 46 |
+
"When the corruption is too high, the algorithm defaults to the \"most logical\" biological path rather than the \"historical truth.\" "
|
| 47 |
+
"For example, an original sequence of D-E-E-E (Dendro-Electro-Electro-Electro) might be restored as "
|
| 48 |
+
"D-E-D-E (Dendro-Electro-Dendro-Electro) because the algorithm favors the Quicken reaction over simple repetition. "
|
| 49 |
+
"This mirrors the lore-accurate phenomenon of the World Tree \"rewriting\" history to fit the laws of Teyvat."
|
| 50 |
+
)
|
| 51 |
+
btn_run.click(fn=reconstruct_irminsul, inputs=[txt_pure, txt_withered], outputs=[txt_output, plot_output])
|
| 52 |
+
|
| 53 |
+
with gr.Tab("Phase 2: Eleazar Kinetics"):
|
| 54 |
+
gr.Markdown("## Project Overview")
|
| 55 |
+
gr.Markdown(
|
| 56 |
+
"**Eleazar** is a terminal condition caused by the *Withering* manifesting in human hosts. "
|
| 57 |
+
"This project applies a modified version of the **Reliability Theory of Aging** (Gavrilov Model) "
|
| 58 |
+
"to simulate the competition between cellular vitality and Abyssal contamination.\n\n"
|
| 59 |
+
"We treat the human body as a system of redundant components. "
|
| 60 |
+
"Failure (Eleazar) occurs when the \"redundancy reserve\" is exhausted. "
|
| 61 |
+
"The *Gompertz-Makeham Law* is used to define the base mortality and age-dependent decay of a patient. "
|
| 62 |
+
"We also account for the effects of a *Vision*, which we mathematically define as a redundancy buffer, "
|
| 63 |
+
"providing a \"metabolic floor\" that prevents the exponential \"avalanche of failures\" typical in terminal Eleazar cases.\n\n"
|
| 64 |
+
"You can compare your custom character against two canonical Eleazar patients: Collei (young Vision holder) and Dunyarzad "
|
| 65 |
+
"(elderly non-Vision holder) using the Gavrilov Reliability ODE model."
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
with gr.Row():
|
| 69 |
+
with gr.Column():
|
| 70 |
+
char_name = gr.Textbox(label="Character Name", value="Traveler")
|
| 71 |
+
age_slide = gr.Slider(10, 90, value=20, step=1, label="Subject Age")
|
| 72 |
+
vis_check = gr.Checkbox(label="Possesses Vision", value=False)
|
| 73 |
+
initial_scenario = gr.Radio(
|
| 74 |
+
choices=["Heavy", "Medium", "Light"],
|
| 75 |
+
value="Heavy",
|
| 76 |
+
label="Initial Contamination"
|
| 77 |
+
)
|
| 78 |
+
run_btn = gr.Button("Analyze Reliability", variant="primary")
|
| 79 |
+
|
| 80 |
+
with gr.Column():
|
| 81 |
+
plot_out = gr.Plot()
|
| 82 |
+
plot_caption_eleazar = gr.Markdown(
|
| 83 |
+
"*Note: by changing the initial starting parameters, we can get different scenarios, "
|
| 84 |
+
"where all patients recover or non Vision holders failing to recover. By selecting Scenario 1, we demonstrate "
|
| 85 |
+
"the power of having a Vision in providing accelerated regeneration and contamination resistance, "
|
| 86 |
+
"allowing **Collei** to fully recover despite having high initial contamination.*"
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
run_btn.click(simulate_triple_comparison,
|
| 90 |
+
inputs=[char_name, age_slide, vis_check, initial_scenario],
|
| 91 |
+
outputs=plot_out)
|
| 92 |
+
|
| 93 |
+
with gr.Tab("Phase 3: Delusion Toxicity"):
|
| 94 |
+
gr.Markdown("## Project Overview")
|
| 95 |
+
gr.Markdown(
|
| 96 |
+
"We use Constrained Optimization (MILP) to quantify the active destruction caused by Delusion usage. "
|
| 97 |
+
"We treat a subject's biological life force as a non-renewable currency used to \"purchase\" damage output. "
|
| 98 |
+
"The model uses `scipy.optimize.linprog` with integrality constraints to solve for the most bio-efficient combat rotation.\n\n"
|
| 99 |
+
"To reflect lore-accurate combat mastery, the model now maps the Mastery-Efficiency Coefficient (η) to the following mechanical variables:\n\n"
|
| 100 |
+
"- **Skill Cooldown (CD)**: Ranges from 12s (Low Mastery) to 7s (High Mastery).\n"
|
| 101 |
+
"- **Burst Energy Requirement (Q)**: Ranges from 90 to 80 energy.\n"
|
| 102 |
+
"- **Energy Generation (E)**: Scales from 10 to 40 energy per Skill, representing the subject's ability to capture elemental flux.\n"
|
| 103 |
+
"- **Vision-Damping Factor (ζ)**: Acts as a 1.5x Energy Multiplier and provides a 0.05 safety grounding that reduces biological waste."
|
| 104 |
+
)
|
| 105 |
+
gr.Markdown("You can compare your character against benchmark Harbingers (Childe, Arlecchino) and a FoolishNPC to assess survivability under Delusion load.")
|
| 106 |
+
|
| 107 |
+
with gr.Row():
|
| 108 |
+
gr.Markdown(get_benchmark_stats())
|
| 109 |
+
|
| 110 |
+
with gr.Row():
|
| 111 |
+
with gr.Column(scale=1):
|
| 112 |
+
age_in = gr.Slider(15, 70, value=25, step=1, label="Age")
|
| 113 |
+
eff_in = gr.Slider(0.01, 0.8, value=0.5, step=0.01, label="Mastery Efficiency (η)")
|
| 114 |
+
vis_in = gr.Checkbox(label="Vision", value=False)
|
| 115 |
+
hp_in = gr.Slider(0, 1500000, value=500000, step=50000, label="Boss HP")
|
| 116 |
+
btn_phase3 = gr.Button("Run Simulation", variant="primary")
|
| 117 |
+
|
| 118 |
+
with gr.Column(scale=2):
|
| 119 |
+
with gr.Tabs():
|
| 120 |
+
with gr.Tab("2D Analysis"):
|
| 121 |
+
plot_2d = gr.Plot(label="Cumulative Cost vs. Damage")
|
| 122 |
+
gr.Markdown("*The 2D plot shows cumulative biological cost vs. combat output. **Skull markers (☠) indicate biological collapse points** where the subject's redundancy budget is exhausted and the solver returns 'Infeasible', marking immediate biological liquidation. Red dashed lines mark critical thresholds at 0% (baseline) and 15% (critical instability).*")
|
| 123 |
+
with gr.Tab("3D Survival Ridge"):
|
| 124 |
+
plot_3d = gr.Plot(label="Topographic Mortality Mapping")
|
| 125 |
+
gr.Markdown("*The 3D surface shows biological redundancy as a function of mastery efficiency and combat load. The \"Death Valley\" at 0.15 represents the critical failure threshold where Delusion use becomes fatal.*")
|
| 126 |
+
|
| 127 |
+
btn_phase3.click(lambda age, vis, eff, hp: generate_phase3_plots("Traveler", age, vis, eff, hp),
|
| 128 |
+
inputs=[age_in, vis_in, eff_in, hp_in],
|
| 129 |
+
outputs=[plot_2d, plot_3d])
|