sktopt.tools

class sktopt.tools.HistoryCollection(dst_path: str)

Bases: object

Manager for multiple HistorySeries instances.

This class provides a convenient interface to:

  • Register multiple named histories

  • Append new data to any history

  • Print the latest values for all histories

  • Export progress plots to image files

  • Export/import histories to/from a .npz file

  • Convert all histories to NumPy arrays or attribute-style objects

Parameters:

dst_path (str) – Destination directory where exported figures and .npz files will be written.

add(name: str, constants: list[float] | None = None, constant_names: list[str] | None = None, plot_type: Literal['value', 'min-max-mean', 'min-max-mean-std'] = 'value', ylog: bool = False, data: list | None = None)

Register a new history under the given name.

Parameters:
  • name (str) – Name of the history to create.

  • constants (list of float, optional) – Optional constant values associated with this history (e.g. target volume fraction, penalty parameters). Currently stored but not used in the internal logic.

  • constant_names (list of str, optional) – Names corresponding to constants.

  • plot_type ({"value", "min-max-mean", "min-max-mean-std"}, optional) –

    Type of aggregation for array inputs:

    • "value": store scalar values directly. Array inputs are aggregated as in HistorySeries.add() for the chosen plot_type in HistorySeries.

    • "min-max-mean": see HistorySeries.

    • "min-max-mean-std": see HistorySeries.

    Default is "value".

  • ylog (bool, optional) – If True, the history is intended to be plotted on a logarithmic y-axis in export_progress().

  • data (list, optional) – Initial data for the history. If provided, it is passed directly to HistorySeries and stored as a list.

as_object()

Return all histories as an attribute-style object.

Each history is exposed as an attribute whose value is the full NumPy array returned by HistorySeries.data_np_array.

Returns:

obj – An anonymous object such that obj.<name> is the array corresponding to history <name>.

Return type:

object

as_object_latest()

Return the latest value of all histories as an attribute-style object.

Each attribute corresponds to a history name and stores the last entry of HistorySeries.data_np_array.

Returns:

obj – An anonymous object such that obj.<name> is the latest value of history <name>.

Return type:

object

export_histories(fname: str | None = None)

Save all histories to a .npz file and reload them.

This method:

  1. Collects all histories via histories_to_array()

  2. Saves them to dst_path / fname using numpy.savez()

  3. Calls import_histories() to reload the data and reconstruct HistorySeries instances

Parameters:

fname (str, optional) – Output file name (without path). Defaults to "histories.npz".

export_progress(fname: str | None = None)

Generate and save progress plots for all histories.

Histories are plotted in a grid of subplots, with up to eight graphs per page (2 rows × 4 columns). If there are more than eight histories, multiple pages are created.

For aggregated histories (min/mean/max[/std]), the following are plotted against iteration index:

  • min (line + markers)

  • mean (line + markers)

  • max (line + markers)

  • optional shaded region mean ± std if plot_type == "min-max-mean-std"

For scalar histories, a single curve is plotted.

The y-axis is logarithmic if ylog=True for that history.

Parameters:

fname (str, optional) – Base file name of the output image(s). If multiple pages are required, an index is prepended (e.g. "0progress.jpg"). Default is "progress.jpg".

feed_data(name: str, data: ndarray | float)

Append a new data point to an existing history.

Parameters:
  • name (str) – Name of the history (must already exist in histories).

  • data (float or numpy.ndarray) – Data to be passed to HistorySeries.add().

histories_to_array() dict[str, ndarray]

Convert all histories into a dictionary of NumPy arrays.

For each history name, two entries may be created:

  • name: main data array returned by HistorySeries.data_to_array()

  • f"{name}_header": header array containing metadata such as name and plot_type

Histories with no data are skipped.

Returns:

Mapping from keys to data/header arrays, suitable for saving via numpy.savez().

Return type:

dict[str, numpy.ndarray]

import_histories(fname: str | None = None)

Load histories from a .npz file and rebuild the loggers.

For each data array stored under key name, this method:

  • Looks for a corresponding f"{name}_header" entry to recover the original history name and plot_type

  • Converts the array back into the internal list format used by HistorySeries

  • Reuses constants, constant_names and ylog from any existing logger with the same name (if present)

  • Populates a new HistorySeries and replaces histories with the reconstructed dictionary

Parameters:

fname (str, optional) – Input file name (without path). Defaults to "histories.npz".

latest(name: str)

Return the latest value of a specific history.

Parameters:

name (str) – Name of the history to query.

Returns:

Latest value stored in the specified history.

Return type:

float or numpy.ndarray

Raises:
  • KeyError – If the history name does not exist.

  • ValueError – If the history exists but has no data.

print()

Print the latest value for all histories that contain data.

Uses each HistorySeries’s print() method and the global logger to emit messages.

class sktopt.tools.SchedulerConfig(name: str | None = None, init_value: float | None = None, target_value: float | None = None, num_steps: int | None = None, iters_max: int | None = None, curvature: float | None = None, scheduler_type: Literal['Constant', 'ConstantOne', 'Step', 'StepAccelerating', 'StepDecelerating', 'SawtoothDecay', 'StepToOne', 'StepAcceleratingToOne', 'StepDeceleratingToOne', 'None'] = 'Constant')

Bases: object

Configuration for continuation and parameter scheduling.

Defines how a scalar parameter (e.g., penalization p, projection sharpness beta, or volume fraction vol_frac) evolves across optimization iterations. Supports several scheduling strategies.

name

Identifier for the schedule (e.g., “p”, “vol_frac”).

Type:

str, optional

init_value

Starting value of the parameter. - Required for Step, StepAccelerating, StepDecelerating, SawtoothDecay. - Automatically inferred for StepToOne. - Ignored if Constant.

Type:

float, optional

target_value

Final value of the parameter. - Required for Step, StepAccelerating, StepDecelerating, SawtoothDecay. - Fixed to 1.0 for StepToOne. - Used as fixed value if Constant.

Type:

float, optional

num_steps

Number of continuation steps or cycles. - Step / StepAccelerating / StepDecelerating / StepToOne: number of increments between init and target. - SawtoothDecay: number of sawtooth cycles (restarts). - Ignored for Constant.

Type:

int, optional

iters_max

Maximum total number of iterations for which the schedule is defined. - Used in SawtoothDecay to partition iterations into cycles. - Typically equals the outer optimizer’s max_iters.

Type:

int, optional

curvature

Shape parameter used in StepAccelerating / StepDecelerating. - Example: curvature=2.0 accelerates change near the end. - Ignored in other schedulers.

Type:

float, optional

scheduler_type
Scheduling strategy:
  • Constant: fixed at target_value.

  • ConstantOne: fixed at 1.0 (alias of Constant with target 1).

  • Step: discrete continuation from init_valuetarget_value in num_steps increments.

  • StepAccelerating: like Step but transition rate controlled by curvature.

  • StepDecelerating: mirror of StepAccelerating (fast early changes, slows later).

  • SawtoothDecay: parameter decays linearly from init_valuetarget_value within each cycle (cycle length = iters_max/num_steps), then resets to init_value at the start of the next cycle.

  • StepToOne: like Step but automatically fixes target_value to 1.0 and infers init_value from num_steps (1.0 / num_steps).

  • StepAcceleratingToOne: accelerating variant with fixed target 1.0 and inferred init_value (1.0 / num_steps).

  • StepDeceleratingToOne: decelerating variant with fixed target 1.0 and inferred init_value (1.0 / num_steps).

Type:

{“Constant”, “ConstantOne”, “Step”, “StepAccelerating”, “StepDecelerating”, “SawtoothDecay”, “StepToOne”, “StepAcceleratingToOne”, “StepDeceleratingToOne”}

classmethod constant(name: str | None = None, target_value: float = 1.0) SchedulerConfig

Factory for a Constant scheduler (always returns the same value).

classmethod constant_one(name: str | None = None) SchedulerConfig

Factory for a Constant scheduler fixed at 1.0.

classmethod from_defaults(name: str | None = None, init_value: float | None = None, target_value: float | None = None, num_steps: int | None = None, iters_max: int | None = None, curvature: float | None = None, scheduler_type: Literal['Constant', 'ConstantOne', 'Step', 'StepAccelerating', 'StepDecelerating', 'SawtoothDecay', 'StepToOne', 'StepAcceleratingToOne', 'StepDeceleratingToOne', 'None'] = 'Constant') SchedulerConfig

Construct a SchedulerConfig with validated defaults.

This helper ensures that each scheduler type receives the proper parameters and fills in sensible defaults where possible.

Parameters:
  • name (str, optional) – Identifier for the schedule (e.g., “p”, “vol_frac”).

  • init_value (float, optional) – Starting value of the parameter. - Required for Step, StepAccelerating, StepDecelerating, SawtoothDecay. - Computed automatically for StepToOne. - Ignored if Constant.

  • target_value (float, optional) – Final value of the parameter. - Required for Step, StepAccelerating, StepDecelerating, SawtoothDecay. - Forced to 1.0 for StepToOne. - Used as fixed value if Constant.

  • num_steps (int, optional) –

    Number of continuation steps or cycles. - Step / StepAccelerating / StepDecelerating / StepToOne:

    number of increments from init → target.

    • SawtoothDecay: number of sawtooth cycles.

    • Ignored if Constant.

  • iters_max (int, optional) – Maximum number of iterations over which the schedule is defined. - Used in SawtoothDecay to split iterations into cycles. - Ignored otherwise.

  • curvature (float, optional) – Shape parameter for StepAccelerating (default ≈ 2.0). Controls acceleration of the step transition. Ignored in other schedulers.

  • scheduler_type ({"Constant", "ConstantOne", "Step", "StepAccelerating", "StepDecelerating", "SawtoothDecay", "StepToOne", "StepAcceleratingToOne", "StepDeceleratingToOne"}, default="Constant") –

    Which scheduling strategy to use:
    • Constant: fixed value at target_value.

    • ConstantOne: fixed to 1.0 regardless of provided values.

    • Step: discrete continuation from init_valuetarget_value over num_steps stages.

    • StepAccelerating: like Step, but interpolation biased by curvature.

    • StepDecelerating: front-loaded change that slows down over time.

    • SawtoothDecay: linear decay from init_valuetarget_value within each cycle, resetting each time; iters_max defines total length.

    • StepToOne: fixed target of 1.0 with the starting point inferred from the number of steps (1.0 / num_steps).

    • StepAcceleratingToOne / StepDeceleratingToOne: accelerating / decelerating variants with fixed target 1.0.

Returns:

A validated configuration object ready to be used by the scheduler functions.

Return type:

SchedulerConfig

Raises:

ValueError – If required parameters are missing or inconsistent with the chosen scheduler_type.

Notes

  • Iteration indices are assumed to be 1-based (it=1 is the first).

  • For Constant, init_value is overridden by target_value.

  • Defaults may be auto-filled (e.g., curvature=2.0 if omitted).

classmethod sawtooth_decay(name: str | None = None, init_value: float = 0.1, target_value: float = 0.05, iters_max: int = 100, num_steps: int = 6) SchedulerConfig

Factory for a SawtoothDecay scheduler.

Parameter decays linearly from init_value to target_value within each cycle, then resets. Total iterations = iters_max, cycles = num_steps.

classmethod step(name: str | None = None, init_value: float | None = None, target_value: float | None = None, num_steps: int | None = None, iters_max: int | None = None) SchedulerConfig

Factory for a Step scheduler (discrete continuation).

classmethod step_accelerating(name: str | None = None, init_value: float | None = None, target_value: float | None = None, num_steps: int | None = None, iters_max: int | None = None, curvature=None) SchedulerConfig

Factory for a StepAccelerating scheduler (nonlinear continuation with curvature).

classmethod step_accelerating_to_one(name: str | None = None, num_steps: int | None = None, iters_max: int | None = None, curvature=None) SchedulerConfig

Factory for an accelerating Step scheduler with fixed target 1.0.

classmethod step_decelerating(name: str | None = None, init_value: float | None = None, target_value: float | None = None, num_steps: int | None = None, iters_max: int | None = None, curvature=None) SchedulerConfig

Factory for a StepDecelerating scheduler (nonlinear continuation that slows down).

classmethod step_decelerating_to_one(name: str | None = None, num_steps: int | None = None, iters_max: int | None = None, curvature=None) SchedulerConfig

Factory for a decelerating Step scheduler with fixed target 1.0.

classmethod step_to_one(name: str | None = None, num_steps: int | None = None, iters_max: int | None = None) SchedulerConfig

Factory for a Step scheduler that always targets 1.0.

class sktopt.tools.SchedulerSawtoothDecay(name: str, init_value: float, target_value: float, num_steps: float, iters_max: int | None = None)

Bases: Scheduler

Sawtooth-style cyclic decay scheduler.

This scheduler repeatedly decays a parameter from init_value to target_value over each cycle, then resets sharply to init_value. The full optimization window of iters_max iterations is divided into num_steps cycles.

This pattern is useful for: - oscillatory move-limit control, - alternating aggressive and conservative update phases, - maintaining exploration ability in early cycles while enforcing

stability in later cycles.

Parameters:
  • name (str) – Name of the scheduled parameter (e.g., "move_limit").

  • init_value (float) – Starting value at the beginning of each cycle.

  • target_value (float) – Final (lowest) value reached at the end of each cycle.

  • num_steps (int) – Number of decay cycles (sawtooth teeth).

  • iters_max (int, optional) – Total iterations across which cycles are distributed.

Notes

  • Scheduling logic is delegated to schedule_sawtooth_decay().

  • Commonly used for move-limit modulation in OC/MOC updates.

  • The value evolves linearly within each cycle.

Examples

>>> cfg = SchedulerConfig.sawtooth_decay(
...     name="move", init_value=0.3, target_value=0.1,
...     iters_max=120, num_steps=4
... )
>>> sched = Scheduler.from_config(cfg)
>>> sched.value(1)
0.3
>>> sched.value(30)
0.2
>>> sched.value(60)  # end of second cycle
0.1
>>> sched.value(61)  # reset at cycle 3
0.3
class sktopt.tools.SchedulerStep(name: str, init_value: float, target_value: float, num_steps: float, iters_max: int)

Bases: Scheduler

Step-based continuation scheduler.

This scheduler implements a discrete continuation strategy in which the parameter value (e.g., SIMP exponent p or projection sharpness beta) transitions from init_value to target_value across num_steps equally sized stages. Each stage is active for approximately iters_max / num_steps iterations.

Unlike gradual exponential schedules, this method produces distinct “plateaus” in which the parameter remains constant for a block of iterations before jumping to the next value. This is one of the common continuation techniques used in density-based topology optimization.

Parameters:
  • name (str) – Identifier for the parameter being scheduled (e.g., "p" or "vol_frac").

  • init_value (float) – Starting value of the scheduled parameter.

  • target_value (float) – Final value of the scheduled parameter.

  • num_steps (int) – Number of continuation steps (including both endpoints).

  • iters_max (int) – Total number of iterations for the optimization process.

Notes

  • The actual scheduling logic is delegated to schedule_step().

  • The value transitions linearly in num_steps discrete increments.

Examples

>>> cfg = SchedulerConfig.step(
...     name="p", init_value=1.0, target_value=3.0, num_steps=5, iters_max=100
... )
>>> sched = Scheduler.from_config(cfg)
>>> sched.value(1)
1.0
>>> sched.value(50)
2.0
>>> sched.value(100)
3.0
class sktopt.tools.SchedulerStepAccelerating(name: str, init_value: float, target_value: float, num_steps: float, iters_max: int | None = None, curvature: float | None = None)

Bases: Scheduler

Nonlinear step-based continuation scheduler with acceleration.

This scheduler extends SchedulerStep by introducing a curvature-controlled nonlinear interpolation. Earlier stages change slowly, while later stages accelerate more aggressively toward target_value as determined by the curvature parameter.

Compared to the uniform Step schedule, this variant is useful when early iterations require stability (small changes) and later iterations benefit from rapid parameter adjustments.

Parameters:
  • name (str) – Identifier for the parameter being scheduled.

  • init_value (float) – Starting value of the scheduled parameter.

  • target_value (float) – Final value of the scheduled parameter.

  • num_steps (int) – Number of discrete continuation steps.

  • iters_max (int, optional) – Total number of optimization iterations.

  • curvature (float, optional) – Nonlinearity exponent controlling acceleration. Higher values → stronger acceleration near the final iterations.

Notes

  • Scheduling logic is delegated to schedule_step_accelerating().

  • Behaves similarly to a “power-law continuation”.

  • Typically configured via SchedulerConfig.step_accelerating().

Examples

>>> cfg = SchedulerConfig.step_accelerating(
...     name="beta", init_value=1.0, target_value=8.0,
...     num_steps=6, iters_max=120, curvature=3.0
... )
>>> sched = Scheduler.from_config(cfg)
>>> sched.value(1)
1.0
>>> sched.value(100)  # accelerated toward the target
7.2
class sktopt.tools.SchedulerStepAcceleratingToOne(name: str, num_steps: float, iters_max: int | None = None, curvature: float | None = None)

Bases: Scheduler

Accelerating Step scheduler with fixed target 1.0.

class sktopt.tools.SchedulerStepDecelerating(name: str, init_value: float, target_value: float, num_steps: float, iters_max: int | None = None, curvature: float | None = None)

Bases: Scheduler

Nonlinear step-based continuation scheduler with deceleration.

This is the mirror of SchedulerStepAccelerating: the schedule changes quickly at the beginning and gradually flattens as iterations progress. Useful when you want aggressive early updates that stabilize over time.

class sktopt.tools.SchedulerStepDeceleratingToOne(name: str, num_steps: float, iters_max: int | None = None, curvature: float | None = None)

Bases: Scheduler

Decelerating Step scheduler with fixed target 1.0.

class sktopt.tools.SchedulerStepToOne(name: str, num_steps: float, iters_max: int)

Bases: Scheduler

Step-based scheduler with a fixed target of 1.0.

The schedule mirrors SchedulerStep but automatically sets target_value=1.0 and infers init_value from num_steps (1.0 / num_steps). This is handy for ratios or blending factors that should eventually reach one without explicitly specifying both endpoints.

class sktopt.tools.SectionTimer(clock: Callable[[], float] | None = None, hierarchical: bool = False, sep: str = '>')

Bases: object

Lightweight helper to measure how long named sections take.

Examples

>>> timer = SectionTimer()
>>> with timer.section("assemble"):
...     ...
>>> with timer.section("solve"):
...     ...
>>> timer.report()

To track nested calls, enable hierarchical so section names are recorded with their call stack (e.g., outer>inner):

timer = SectionTimer(hierarchical=True)
with timer.section("outer"):
    with timer.section("inner"):
        ...
plot(ax=None, sort_by: str = 'total', value: str = 'total', descending: bool = True, color: str = 'C0', format_nested: bool | None = None, stacked_nested: bool = False, kind: str = 'pie', moving_average: bool = False, use_self_time: bool = False, **kwargs)

Plot timing results choosing between pie (default) or bar chart.

Parameters:
  • kind ({"pie", "bar"}) – Chart type. "pie" uses plot_pie() and is the default, "bar" uses plot_bar().

  • parameters (Other) – Passed through to the selected plotting function.

plot_bar(ax=None, sort_by: str = 'total', value: str = 'total', descending: bool = True, color: str = 'C0', format_nested: bool | None = None, stacked_nested: bool = False, moving_average: bool = False, use_self_time: bool = False)

Plot timing results as a horizontal bar chart without relying on pyplot state.

Parameters:
  • ax (matplotlib.axes.Axes, optional) – Target axes. If omitted, a new Figure/Axes is created.

  • sort_by ({"total", "avg", "max", "count", "name"}) – Sorting key used before plotting.

  • value ({"total", "avg", "max", "count"}) – Metric plotted on the x-axis.

  • descending (bool) – Sort order for sort_by.

  • color (str) – Bar color passed to Matplotlib.

  • format_nested (bool, optional) – If True and the timer is hierarchical, indent nested section labels using sep for readability. Defaults to hierarchical flag used at construction time (ignored when stacked_nested is True).

  • stacked_nested (bool) – If True and hierarchical data are present, render a stacked bar for every section that has children: self-time (parent minus sum(children)) plus one segment per direct child. Sections without children are drawn as regular bars alongside the stacked groups.

  • moving_average (bool) – If True, plot exponential-free running averages using the incremental mean update (no full history stored).

Returns:

Figure/Axes containing the plot. If ax was provided, its parent figure is returned.

Return type:

(matplotlib.figure.Figure, matplotlib.axes.Axes)

plot_pie(ax=None, sort_by: str = 'total', value: str = 'total', descending: bool = True, colors: List[str] | None = None, autopct: str = '%.1f%%', label_threshold: float = 0.05, min_pct_to_label: float = 1.0, show_legend: bool = True, legend_kwargs: dict | None = None, show_total: bool = True, moving_average: bool = False, use_self_time: bool = False)

Plot timing results as a pie chart to show relative time share.

Parameters:
  • ax (matplotlib.axes.Axes, optional) – Target axes. If omitted, a new Figure/Axes is created.

  • sort_by ({"total", "avg", "max", "count", "name"}) – Sorting key used before plotting.

  • value ({"total", "avg", "max", "count"}) – Metric used to size the wedges.

  • descending (bool) – Sort order for sort_by.

  • colors (list of str, optional) – Colors passed to Matplotlib pie.

  • autopct (str) – autopct string passed to Matplotlib pie.

  • label_threshold (float) – Minimum fraction (0-1) required to draw a text label on the wedge. Smaller slices omit the label to reduce clutter.

  • min_pct_to_label (float) – Minimum percent value to render autopct text. Use None to always show.

  • show_legend (bool) – If True, draw a legend with all section names.

  • legend_kwargs (dict, optional) – Extra kwargs forwarded to Axes.legend when show_legend is True.

  • show_total (bool) – If True, append total runtime text to the title.

  • moving_average (bool) – If True, plot exponential-free running averages using the incremental mean update (no full history stored).

Returns:

Figure/Axes containing the plot. If ax was provided, its parent figure is returned.

Return type:

(matplotlib.figure.Figure, matplotlib.axes.Axes)

save_plot(filepath: str, sort_by: str = 'total', value: str = 'total', descending: bool = True, color: str = 'C0', dpi: int = 150, format_nested: bool | None = None, stacked_nested: bool = False, kind: str = 'pie', use_self_time: bool = False, moving_average: bool = False, **kwargs) None

Render and save the timing plot to filepath.

This helper builds its own Figure/Axes (no pyplot state), so it can be used safely inside loops.

wrap(name: str)

Decorator form of section().

This is convenient for quickly instrumenting functions without rewriting call sites:

@timer.wrap("my_step")
def my_step(...):
    ...