Files
Artificial-Sweetener-Simple…/tools/anima_lora_characterization/matrix.py
T

103 lines
2.9 KiB
Python

# SimpleSyrup - workflow-focused ComfyUI extensions for image generation
# Copyright (C) 2026 Artificial Sweetener and contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Own the immutable global LoRA characterization matrix."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Literal
LoraMode = Literal["static", "scheduled"]
MEASUREMENT_SEEDS = (1_029_384_756, 3_141_592_653, 2_718_281_828)
CAPTURE_SEED = MEASUREMENT_SEEDS[0]
SCHEDULE = ((0.0, 0.0), (0.25, 1.0), (0.5, 0.5), (0.75, 0.0))
@dataclass(frozen=True)
class AdapterDefinition:
"""Define one ordered identity applied from the selected adapter artifact."""
identity: str
strength: float
schedule: tuple[tuple[float, float], ...] = ()
@dataclass(frozen=True)
class LoraProfile:
"""Define one zero, static, or scheduled adapter-stack profile."""
profile_id: str
mode: LoraMode
adapters: tuple[AdapterDefinition, ...]
@dataclass(frozen=True)
class LoraRun:
"""Identify one measurement or denoiser-digest capture execution."""
profile: LoraProfile
seed: int
capture_outputs: bool
@property
def artifact_id(self) -> str:
"""Return the stable result and image identity."""
evidence_kind = "outputs" if self.capture_outputs else "measurement"
return (
f"adapter-global__{self.profile.profile_id}__"
f"{evidence_kind}__seed-{self.seed}"
)
def profiles() -> tuple[LoraProfile, ...]:
"""Return the fixed additive-strength and scheduling profiles."""
static_strengths = {
0: (),
1: (1.0,),
2: (0.4, 0.6),
4: (0.1, 0.2, 0.3, 0.4),
}
static = tuple(
LoraProfile(
profile_id=f"static-{count}",
mode="static",
adapters=tuple(
AdapterDefinition(f"static-{count}-adapter-{index + 1}", strength)
for index, strength in enumerate(strengths)
),
)
for count, strengths in static_strengths.items()
)
scheduled = tuple(
LoraProfile(
profile_id=f"scheduled-{count}",
mode="scheduled",
adapters=tuple(
AdapterDefinition(
f"scheduled-{count}-adapter-{index + 1}", strength, SCHEDULE
)
for index, strength in enumerate(strengths)
),
)
for count, strengths in static_strengths.items()
if count > 0
)
return (*static, *scheduled)
def runs() -> tuple[LoraRun, ...]:
"""Expand three clean timing seeds plus one output-evidence pass per profile."""
expanded: list[LoraRun] = []
for profile in profiles():
expanded.extend(
LoraRun(profile, seed, capture_outputs=False) for seed in MEASUREMENT_SEEDS
)
expanded.append(LoraRun(profile, CAPTURE_SEED, capture_outputs=True))
return tuple(expanded)