Files

139 lines
4.0 KiB
Python

"""
Generate parameter combinations from parsed parameter lists.
Two modes:
- cartesian: All combinations (every permutation)
- linear_zip: Paired values, cycling shorter lists to match the longest
Each combination is a list of tuples:
[(param_name, param_value, target_info), ...]
where target_info is a dict with keys:
target_node_title, target_widget_name
"""
import itertools
def cartesian(parsed_params: list[dict]) -> list[list[tuple]]:
"""
Cartesian product of all parameter value lists.
Args:
parsed_params: List of dicts, each with keys:
- name: str (parameter display name)
- parsed_values: list (the values to iterate)
- target_node_title: str
- target_widget_name: str
Returns:
List of combinations. Each combination is a list of
(param_name, param_value, target_info) tuples.
Example:
params = [
{"name": "steps", "parsed_values": [10, 20],
"target_node_title": "KSampler", "target_widget_name": "steps"},
{"name": "cfg", "parsed_values": [5, 7, 9],
"target_node_title": "KSampler", "target_widget_name": "cfg"},
]
Result: 6 combinations (2 x 3)
"""
if not parsed_params:
return []
# Filter out params with empty value lists
active_params = [p for p in parsed_params if p.get("parsed_values")]
if not active_params:
return []
value_lists = [p["parsed_values"] for p in active_params]
target_infos = [
{
"target_node_title": p["target_node_title"],
"target_widget_name": p["target_widget_name"],
}
for p in active_params
]
names = [p["name"] for p in active_params]
combinations = []
for combo_values in itertools.product(*value_lists):
combination = [
(names[i], combo_values[i], target_infos[i])
for i in range(len(active_params))
]
combinations.append(combination)
return combinations
def linear_zip(parsed_params: list[dict]) -> list[list[tuple]]:
"""
Zip parameters together, cycling shorter lists to match the longest.
Args:
parsed_params: Same format as cartesian()
Returns:
List of combinations (same format as cartesian).
Length equals the longest parameter value list.
Shorter lists are cycled.
Example:
steps: [10, 20, 30]
cfg: [5, 7]
Result: 3 combinations: (10,5), (20,7), (30,5)
"""
if not parsed_params:
return []
active_params = [p for p in parsed_params if p.get("parsed_values")]
if not active_params:
return []
max_len = max(len(p["parsed_values"]) for p in active_params)
if max_len == 0:
return []
target_infos = [
{
"target_node_title": p["target_node_title"],
"target_widget_name": p["target_widget_name"],
}
for p in active_params
]
names = [p["name"] for p in active_params]
combinations = []
for i in range(max_len):
combination = []
for j, param in enumerate(active_params):
values = param["parsed_values"]
# Cycle: use modulo to wrap around
value = values[i % len(values)]
combination.append((names[j], value, target_infos[j]))
combinations.append(combination)
return combinations
def get_axis_labels(combinations: list[list[tuple]], param_names: list[str]) -> dict:
"""
Extract unique values for each parameter from the combinations.
Useful for grid labeling.
Returns:
Dict mapping param_name -> list of unique values in order.
"""
labels = {name: [] for name in param_names}
seen = {name: set() for name in param_names}
for combo in combinations:
for name, value, _ in combo:
if name in labels and value not in seen[name]:
seen[name].add(value)
labels[name].append(value)
return labels