Skip to content

main

qemcmc.main

ProgressProposal

ProgressProposal(proposer, progress_file)

Wraps a proposal so each chain records its hop count to its own file.

MCMCRunner.run only ever calls proposer.update(), so this needs no cooperation from the runner. Chains run in separate processes, so a file is the simplest thing they can all write to without the parent having to coordinate them.

Source code in src/qemcmc/main.py
def __init__(self, proposer, progress_file):
    self._proposer = proposer
    self._progress_file = Path(progress_file)
    self._hops = 0

ChainProgress

ChainProgress(progress_dir, *args, **kwargs)

Bases: Progress

One bar per chain, re-read from the workers' files on every refresh.

Source code in src/qemcmc/main.py
def __init__(self, progress_dir, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.progress_dir = Path(progress_dir)

run_arm

run_arm(
    label, color, proposer, runner, initial_states, seeds
)

Run REPS independent chains for one proposal method and add them to the current plot.

Source code in src/qemcmc/main.py
def run_arm(label, color, proposer, runner, initial_states, seeds):
    """Run REPS independent chains for one proposal method and add them to the current plot."""
    console.print(f"[bold]{label}[/bold]")
    start = time.time()

    with tempfile.TemporaryDirectory() as progress_dir:
        columns = (
            TextColumn("  {task.description}"),
            BarColumn(),
            MofNCompleteColumn(),
            TextColumn("hops"),
            TimeElapsedColumn(),
            TimeRemainingColumn(),
        )
        with ChainProgress(progress_dir, *columns) as progress:
            task_ids = [progress.add_task(f"chain {i}", total=STEPS) for i in range(len(seeds))]
            chains = Parallel(n_jobs=-1)(
                delayed(run_chain_with_seed)(
                    seed,
                    runner,
                    proposer=ProgressProposal(proposer, Path(progress_dir) / str(task_ids[i])),
                    n_hops=STEPS,
                    initial_state=initial_states[i],
                    verbose=False,
                )
                for i, seed in enumerate(seeds)
            )

    console.print(f"  [dim]{label}: {time.time() - start:.1f} s[/dim]")
    plot_chains(chains, color, label=label, plot_individual_chains=True)
    return chains

annotate_below_legend

annotate_below_legend(ax, legend, text)

Place text directly under the legend box, in axes coordinates.

Source code in src/qemcmc/main.py
def annotate_below_legend(ax, legend, text):
    """Place text directly under the legend box, in axes coordinates."""
    ax.figure.canvas.draw()  # the legend has no extent until the figure is drawn
    bbox = legend.get_window_extent().transformed(ax.transAxes.inverted())
    ax.text(bbox.x0, bbox.y0 - 0.03, text, transform=ax.transAxes, ha="left", va="top", fontsize=9)