Refactor: Rename sustain/last_visited fields for consistency

This commit is contained in:
Michael Winter 2026-03-16 17:35:07 +01:00
parent 861d012a95
commit 482f2b0df5
2 changed files with 33 additions and 31 deletions

View file

@ -23,10 +23,10 @@ class PathStep:
movements: dict[int, int] = field(default_factory=dict)
scores: dict[str, float] = field(default_factory=dict)
weight: float = 0.0 # computed later by _compute_weights
last_visited_count_before: dict | None = None
last_visited_count_after: dict | None = None
sustain_count_before: tuple[int, ...] | None = None
sustain_count_after: tuple[int, ...] | None = None
last_visited_counts_before: dict | None = None
last_visited_counts_after: dict | None = None
sustain_counts_before: tuple[int, ...] | None = None
sustain_counts_after: tuple[int, ...] | None = None
class Path:
@ -60,8 +60,8 @@ class Path:
"""Get last visited counts from the last step, or initialize fresh."""
if self.steps:
last_step = self.steps[-1]
if last_step.last_visited_count_after is not None:
return dict(last_step.last_visited_count_after)
if last_step.last_visited_counts_after is not None:
return dict(last_step.last_visited_counts_after)
# Initialize fresh: all nodes start at 0 (except initial which we set to 0 explicitly)
return {node: 0 for node in self._graph_nodes}
@ -70,8 +70,8 @@ class Path:
"""Get sustain counts from the last step, or initialize fresh."""
if self.steps:
last_step = self.steps[-1]
if last_step.sustain_count_after is not None:
return last_step.sustain_count_after
if last_step.sustain_counts_after is not None:
return last_step.sustain_counts_after
# Initialize fresh: all voices start at 0
return tuple(0 for _ in range(self._num_voices))
@ -114,10 +114,10 @@ class Path:
sustain_after[voice_idx] = 0
# Update step with computed state
step.last_visited_count_before = last_visited_before
step.last_visited_count_after = last_visited_after
step.sustain_count_before = sustain_before
step.sustain_count_after = tuple(sustain_after)
step.last_visited_counts_before = last_visited_before
step.last_visited_counts_after = last_visited_after
step.sustain_counts_before = sustain_before
step.sustain_counts_after = tuple(sustain_after)
self.steps.append(step)
return step

View file

@ -57,22 +57,22 @@ class PathFinder:
# Derive state from last step (or initialize fresh for step 0)
if path_obj.steps:
last_step = path_obj.steps[-1]
voice_stay_count = last_step.sustain_count_after
node_visit_counts = last_step.last_visited_count_after
sustain_counts = last_step.sustain_counts_after
last_visited_counts = last_step.last_visited_counts_after
else:
# First step - derive from path object's current state
voice_stay_count = tuple(0 for _ in range(len(path_obj._voice_map)))
node_visit_counts = {node: 0 for node in set(self.graph.nodes())}
sustain_counts = tuple(0 for _ in range(len(path_obj._voice_map)))
last_visited_counts = {node: 0 for node in set(self.graph.nodes())}
# Build candidates with raw scores
candidates = self._build_candidates(
out_edges,
path_obj.output_chords,
weights_config,
voice_stay_count,
sustain_counts,
path_obj.graph_chords,
path_obj._cumulative_trans,
node_visit_counts,
last_visited_counts,
)
# Compute weights from raw scores
@ -105,10 +105,10 @@ class PathFinder:
out_edges: list,
path: list["Chord"],
config: dict,
voice_stay_count: tuple[int, ...] | None,
sustain_counts: tuple[int, ...] | None,
graph_path: list["Chord"] | None,
cumulative_trans: "Pitch | None",
node_visit_counts: dict | None,
last_visited_counts: dict | None,
) -> list[PathStep]:
"""Build hypothetical path steps with raw factor scores."""
if not out_edges:
@ -151,9 +151,11 @@ class PathFinder:
voice_crossing = self._factor_voice_crossing(edge_data, config)
melodic = self._factor_melodic_threshold(edge_data, config)
contrary = self._factor_contrary_motion(edge_data, config)
hamiltonian = self._factor_dca_hamiltonian(edge, node_visit_counts, config)
hamiltonian = self._factor_dca_hamiltonian(
edge, last_visited_counts, config
)
dca_voice = self._factor_dca_voice_movement(
edge, path, voice_stay_count, config, cumulative_trans
edge, path, sustain_counts, config, cumulative_trans
)
target = self._factor_target_range(edge, path, config, cumulative_trans)
@ -373,7 +375,7 @@ class PathFinder:
return max(0.0, 1.0 - (distance / ideal_up))
def _factor_dca_hamiltonian(
self, edge: tuple, node_visit_counts: dict | None, config: dict
self, edge: tuple, last_visited_counts: dict | None, config: dict
) -> float:
"""Returns score based on how long since node was last visited.
@ -382,11 +384,11 @@ class PathFinder:
if config.get("weight_dca_hamiltonian", 1) == 0:
return 1.0
if node_visit_counts is None:
if last_visited_counts is None:
return 0.0
destination = edge[1]
visit_count = node_visit_counts.get(destination, 0)
visit_count = last_visited_counts.get(destination, 0)
# Return the visit count - higher is better (more steps since last visit)
return float(visit_count)
@ -395,27 +397,27 @@ class PathFinder:
self,
edge: tuple,
path: list,
voice_stay_count: tuple[int, ...] | None,
sustain_counts: tuple[int, ...] | None,
config: dict,
cumulative_trans: "Pitch | None",
) -> float:
"""Returns probability that voices will change.
DCA = Dissonant Counterpoint Algorithm
Probability = (sum of stay_counts for changing voices) / (sum of ALL stay_counts)
Probability = (sum of sustain_counts for changing voices) / (sum of ALL sustain_counts)
Higher probability = more likely to choose edge where long-staying voices change.
"""
if config.get("weight_dca_voice_movement", 1) == 0:
return 1.0
if voice_stay_count is None or len(path) == 0:
if sustain_counts is None or len(path) == 0:
return 1.0
if cumulative_trans is None:
return 1.0
num_voices = len(voice_stay_count)
num_voices = len(sustain_counts)
if num_voices == 0:
return 1.0
@ -434,14 +436,14 @@ class PathFinder:
candidate_cents = [p.to_cents() for p in candidate_transposed.pitches]
sum_changing = 0
sum_all = sum(voice_stay_count)
sum_all = sum(sustain_counts)
if sum_all == 0:
return 1.0
for voice_idx in range(num_voices):
if current_cents[voice_idx] != candidate_cents[voice_idx]:
sum_changing += voice_stay_count[voice_idx]
sum_changing += sustain_counts[voice_idx]
return sum_changing / sum_all