API Reference

All names below are importable directly from manufacturing_sim_s. Times are seconds, distances are feet, and speeds are feet per second.

AGV

AGV(name: 'str', position: 'tuple[float, float]', width: 'float' = 3.0, depth: 'float' = 5.0, speed: 'float' = 6.0, capacity: 'int' = 1) -> None

An autonomous guided vehicle; no Worker is required.

Example

agv = AGV("AGV 1", position=(5, 5))

AGV.center

Property. Return the center point of the component footprint in feet.

Example

value = aGV.center

Buffer

Buffer(name: 'str', position: 'tuple[float, float]', width: 'float', depth: 'float', capacity: 'int | None' = None) -> None

Intentional intermediate storage; capacity=None means unlimited.

Example

buffer = Buffer("WIP", position=(30, 10), width=8, depth=8, capacity=20)

Buffer.center

Property. Return the center point of the component footprint in feet.

Example

value = buffer.center

ConditionalRoute

ConditionalRoute(attribute: 'str', cases: 'Mapping[Any, PhysicalComponent]', default: 'PhysicalComponent', continuations: 'Mapping[PhysicalComponent, PhysicalComponent] | None' = None) -> None

Choose a destination from a Part or Product attribute without callbacks.

Example: ConditionalRoute("grade", {"A": premium}, default=standard) reads Product(attributes={"grade": "A"}) for each generated Part.

Example

decision = ConditionalRoute("grade", {"A": premium}, default=standard)

ConditionalRoute.choose(self, part: 'Part', rng: 'np.random.Generator') -> 'PhysicalComponent'

Method. Choose the next component, or None to scrap the Part.

Example

destination = decision.choose(part, rng)

ConditionalRoute.destinations(self) -> 'list[PhysicalComponent]'

Method. Return all physical destinations possible during validation.

Example

value = decision.destinations()

Connection

Connection(origin: 'PhysicalComponent', destination: 'PhysicalComponent', worker: 'Worker | None' = None, transporter: 'Forklift | AGV | None' = None, name: 'str | None' = None) -> None

The assigned movement resources between two physical locations.

Example

connection = plant.connect(source, machine, worker=worker)

Constant

Constant(value: 'float') -> None

A deterministic value, such as Constant(60) seconds.

Example

distribution = Constant(60)

Constant.sample(self, rng: 'np.random.Generator') -> 'float'

Method. Return one nonnegative sample.

Example

value = distribution.sample()

Constant.to_config(self) -> 'dict[str, Any]'

Method. Return a JSON-serializable description.

Example

value = distribution.to_config()

Distribution

Distribution()

Base class for a time distribution.

Call :meth:sample with a NumPy generator to obtain one value in seconds.

Example

distribution = Constant(60)  # Concrete Distribution

Distribution.sample(self, rng: 'np.random.Generator') -> 'float'

Method. Return one nonnegative sample.

Example

seconds = distribution.sample(rng)

Distribution.to_config(self) -> 'dict[str, Any]'

Method. Return a JSON-serializable description.

Example

value = distribution.to_config()

DistributionError

DistributionError

Raised when a probability distribution has invalid parameters.

Example

try:
    plant.validate()
except DistributionError as error:
    print(error)

Exponential

Exponential(mean: 'float') -> None

An exponential distribution parameterized by its mean.

Example

distribution = Exponential(mean=60)

Exponential.sample(self, rng: 'np.random.Generator') -> 'float'

Method. Return one nonnegative sample.

Example

value = distribution.sample()

Exponential.to_config(self) -> 'dict[str, Any]'

Method. Return a JSON-serializable description.

Example

value = distribution.to_config()

Forklift

Forklift(name: 'str', position: 'tuple[float, float]', width: 'float' = 4.0, depth: 'float' = 8.0, speed: 'float' = 8.0, capacity: 'int' = 1) -> None

Worker-operated transport equipment with one-unit carrying capacity.

Example

forklift = Forklift("Forklift 1", position=(5, 5))

Forklift.center

Property. Return the center point of the component footprint in feet.

Example

value = forklift.center

LayoutError

LayoutError

Raised when a component is outside the plant or violates clearance.

Example

try:
    plant.validate()
except LayoutError as error:
    print(error)

Machine

Machine(name: 'str', position: 'tuple[float, float]', width: 'float', depth: 'float', processing_time: 'Distribution | float | None' = None, processing_times: 'Mapping[str, Distribution | float] | None' = None, worker: 'Worker | Sequence[Worker] | None' = None, required_skill: 'str | None' = None, capacity: 'int' = 1) -> None

A processing resource with an automatically managed input queue.

Example

machine = Machine("Cutting", (30, 10), 10, 8, processing_time=60)

Machine.center

Property. Return the center point of the component footprint in feet.

Example

value = machine.center

Machine.time_for(self, product_name: 'str') -> 'Distribution'

Method. Return the processing-time distribution for a Product name.

Example

distribution = machine.time_for("Product A")

Machine.workers

Property. Return assigned operators as a list.

Example

value = machine.workers

ManufacturingSimError

ManufacturingSimError

Base class for all framework errors.

Example

try:
    plant.validate()
except ManufacturingSimError as error:
    print(error)

Normal

Normal(mean: 'float', std: 'float') -> None

A normal distribution that resamples, rather than clamps, negatives.

Example

distribution = Normal(mean=60, std=8)

Normal.sample(self, rng: 'np.random.Generator') -> 'float'

Method. Return one nonnegative sample.

Example

value = distribution.sample()

Normal.to_config(self) -> 'dict[str, Any]'

Method. Return a JSON-serializable description.

Example

value = distribution.to_config()

Part

Part(product: 'Product', created_time: 'float', current_location: 'PhysicalComponent', part_id: 'str' = <factory>, travel_distance: 'float' = 0.0, waiting_time: 'float' = 0.0, processing_time: 'float' = 0.0, transport_time: 'float' = 0.0, completion_time: 'float | None' = None, scrapped_time: 'float | None' = None, scrap_reason: 'str | None' = None, history: 'list[dict[str, Any]]' = <factory>, attributes: 'dict[str, Any]' = <factory>, route_index: 'int' = 0, waiting_by_category: 'dict[str, float]' = <factory>, rework_counts: 'dict[str, int]' = <factory>) -> None

One simulation entity with a complete event history.

Example

part = result.parts[0]

Part.lead_time

Property. Return creation-to-Sink time for a completed Part.

Example

value = part.lead_time

Part.product_type

Property. Return the Product name for convenient inspection.

Example

value = part.product_type

Part.record(self, timestamp: 'float', event_type: 'str', **details: 'Any') -> 'None'

Method. Append an event to this Part's inspectable history.

Example

part.record(120, "inspection", resource="Inspection")

Part.scrap_system_time

Property. Return creation-to-scrap time, or None for a nonscrapped Part.

Example: part.scrap_system_time returns seconds spent in the system before a terminal quality decision.

Example

value = part.scrap_system_time

Plant

Plant(name: 'str', width: 'float', height: 'float', distance_method: 'str' = 'manhattan', clearance: 'float' = 6.0, output_dir: 'str | Path' = 'outputs') -> 'None'

A physical manufacturing system and its simulation configuration.

Parameters use feet for dimensions and seconds for simulation time. The default distance is Manhattan and the default clearance is six feet.

Example

plant = Plant("Teaching Plant", width=100, height=60)

Plant.add(self, *objects: 'Any') -> 'Plant'

Method. Add components or Products and return this Plant for convenient chaining.

Example

plant.add(source, machine, sink, product)

Plant.animate(self, **kwargs: 'Any') -> 'Any'

Method. Display and export an MP4 and GIF animation of the latest run.

Example

value = plant.animate()

Plant.connect(self, origin: 'PhysicalComponent', destination: 'PhysicalComponent', *, worker: 'Worker | None' = None, transporter: 'Forklift | AGV | None' = None, name: 'str | None' = None) -> 'Connection'

Method. Assign how material moves from origin to destination.

Example

plant.connect(source, machine, worker=worker)

Plant.connection(self, origin: 'PhysicalComponent', destination: 'PhysicalComponent') -> 'Connection | None'

Method. Return the configured directed transport connection, if one exists.

Example

connection = plant.connection(source, machine)

Plant.copy(self) -> 'Plant'

Method. Return an independent scenario copy without transient run state.

Example

value = plant.copy()

Plant.distance(self, a: 'PhysicalComponent | tuple[float, float]', b: 'PhysicalComponent | tuple[float, float]') -> 'float'

Method. Calculate center-to-center distance using the configured model.

Example

feet = plant.distance(source, machine)

Plant.load_config(path: 'str | Path') -> 'Plant'

Method. Load and validate a Plant saved by :meth:save_config.

Example

plant = Plant.load_config("outputs/configs/layout.json")

Plant.move(self, component: 'PhysicalComponent', position: 'tuple[float, float]') -> 'PhysicalComponent'

Method. Move a component and return the corresponding object in this Plant.

A component from the original Plant may be passed to a copied scenario; its same-name, same-type counterpart is selected automatically.

Example

plant.move(machine, position=(40, 20))

Plant.report(self) -> 'Any'

Method. Print and return the latest run's headline KPI DataFrame.

Example

value = plant.report()

Plant.run(self, duration: 'float' = 28800, *, seed: 'int | None' = None, event_log: 'bool' = False) -> 'Any'

Method. Run one experiment and drain all WIP after the arrival cutoff.

Example

result = plant.run(duration=3600, seed=42)

Plant.run_replications(self, replications: 'int' = 3, *, duration: 'float' = 28800, seed: 'int | None' = None, event_log: 'bool' = False) -> 'Any'

Method. Run independent replications with deterministic derived seeds.

Example

replications = plant.run_replications(10, seed=42)

Plant.save_config(self, path: 'str | Path') -> 'Path'

Method. Save the complete reusable Plant configuration as JSON.

Example

plant.save_config("outputs/configs/layout.json")

Plant.validate(self) -> 'str'

Method. Validate layout, routes, assignments, and skills; return a summary.

Example

value = plant.validate()

Plant.visualize(self, product: 'str | Product | None' = None, **kwargs: 'Any') -> 'Any'

Method. Draw the static plant layout and process-routing arrows.

Example

value = plant.visualize()

PlantConfigurationError

PlantConfigurationError

Raised when a plant configuration is incomplete or inconsistent.

Example

try:
    plant.validate()
except PlantConfigurationError as error:
    print(error)

ProbabilisticRoute

ProbabilisticRoute(probabilities: 'Mapping[PhysicalComponent, float]', continuations: 'Mapping[PhysicalComponent, PhysicalComponent] | None' = None) -> None

Choose among destinations using explicit probabilities that sum to one.

Example

decision = ProbabilisticRoute({machine_a: 0.5, machine_b: 0.5})

ProbabilisticRoute.choose(self, part: 'Part', rng: 'np.random.Generator') -> 'PhysicalComponent'

Method. Choose the next component, or None to scrap the Part.

Example

destination = decision.choose(part, rng)

ProbabilisticRoute.destinations(self) -> 'list[PhysicalComponent]'

Method. Return all physical destinations possible during validation.

Example

value = decision.destinations()

Product

Product(name: 'str', route: 'list[Any]', attributes: 'Mapping[str, Any]' = <factory>) -> None

A product definition containing its process route and Part attributes.

attributes are copied to every generated Part. They provide a callback-free way to drive :class:ConditionalRoute decisions.

Example: Product("Priority", [source, decision, sink], {"grade": "A"}).

Example

product = Product("A", [source, machine, sink])

ReplicationResult

ReplicationResult(results: 'Sequence[SimulationResult]') -> 'None'

Statistics across independent :class:SimulationResult runs.

Example

replications = plant.run_replications(3, seed=42)

ReplicationResult.export_csv(self, path: 'str | Path' = 'outputs/csv/replications.csv') -> 'Path'

Method. Export the replication summary to CSV.

Example

replications.export_csv("outputs/csv/replications.csv")

ReplicationResult.plot(self, metric: 'str' = 'units_produced', **kwargs: 'Any') -> 'Any'

Method. Plot a replication mean with its 95% confidence interval.

Example

value = replications.plot()

ReplicationResult.raw

Property. Return one row of headline values per replication.

Example

value = replications.raw

ReplicationResult.summary

Property. Return mean, sample standard deviation, and 95% confidence interval.

Example

value = replications.summary

ResourceAssignmentError

ResourceAssignmentError

Raised when a required worker or transporter is missing or invalid.

Example

try:
    plant.validate()
except ResourceAssignmentError as error:
    print(error)

ReworkRoute

ReworkRoute(target: 'PhysicalComponent', probability: 'float', next_component: 'PhysicalComponent', max_reworks: 'int' = 1, key: 'str | None' = None) -> None

Probabilistically revisit target up to max_reworks times.

Example

decision = ReworkRoute(machine, 0.1, sink, max_reworks=1)

ReworkRoute.choose(self, part: 'Part', rng: 'np.random.Generator') -> 'PhysicalComponent'

Method. Choose the next component, or None to scrap the Part.

Example

destination = decision.choose(part, rng)

ReworkRoute.destinations(self) -> 'list[PhysicalComponent]'

Method. Return all physical destinations possible during validation.

Example

value = decision.destinations()

Route

Route(origin: 'PhysicalComponent', destination: 'PhysicalComponent', label: 'str | None' = None) -> None

One connected edge in an alternative Product route declaration.

Example: Product("A", [Route(source, machine), Route(machine, sink)]).

Example

product = Product("A", [Route(source, machine), Route(machine, sink)])

RoutingError

RoutingError

Raised when a product route cannot be transported as configured.

Example

try:
    plant.validate()
except RoutingError as error:
    print(error)

ScenarioComparison

ScenarioComparison(results: 'Sequence[SimulationResult]', metrics: 'Sequence[str] | None' = None) -> 'None'

Structured baseline-relative KPI comparison across scenarios.

Example

comparison = compare(baseline, redesign)

ScenarioComparison.export_csv(self, path: 'str | Path' = 'outputs/csv/scenario_comparison.csv') -> 'Path'

Method. Export the structured comparison table.

Example

comparison.export_csv("outputs/csv/comparison.csv")

ScenarioComparison.plot(self, metric: 'str' = 'units_produced', **kwargs: 'Any') -> 'Any'

Method. Plot values for one KPI across all compared scenarios.

Example

value = comparison.plot()

ScrapRoute

ScrapRoute(probability: 'float', next_component: 'PhysicalComponent', reason: 'str' = 'quality rejection') -> None

Scrap with a probability, otherwise continue to next_component.

Example

decision = ScrapRoute(0.05, sink, reason="inspection")

ScrapRoute.choose(self, part: 'Part', rng: 'np.random.Generator') -> 'PhysicalComponent | None'

Method. Choose the next component, or None to scrap the Part.

Example

destination = decision.choose(part, rng)

ScrapRoute.destinations(self) -> 'list[PhysicalComponent]'

Method. Return all physical destinations possible during validation.

Example

value = decision.destinations()

SimulationError

SimulationError

Raised when a valid plant cannot complete a simulation.

Example

try:
    plant.validate()
except SimulationError as error:
    print(error)

SimulationResult

SimulationResult(*, plant: 'Any', scheduled_duration: 'float', elapsed_time: 'float', seed: 'int | None', parts: 'list[Any]', completed_parts: 'list[Any]', scrapped_parts: 'list[Any]', metrics: 'Any', event_log_enabled: 'bool', simpy_environment: 'Any', simpy_resources: 'dict[str, Any]') -> 'None'

The structured output from one :meth:Plant.run call.

Example

result = plant.run(duration=3600, seed=42)

SimulationResult.animate(self, **kwargs: 'Any') -> 'Any'

Method. Create a continuous Matplotlib animation and export GIF and MP4.

Example

value = result.animate()

SimulationResult.average_lead_time

Property. Mean Source creation-to-Sink arrival time for good units.

Example

value = result.average_lead_time

SimulationResult.average_processing_time

Property. Mean processing time per completed Part.

Example

value = result.average_processing_time

SimulationResult.average_scrap_system_time

Property. Mean creation-to-scrap time for scrapped Parts, in seconds.

Example: result.average_scrap_system_time reports quality-loss exposure separately from good-unit lead time.

Example

value = result.average_scrap_system_time

SimulationResult.average_transport_time

Property. Mean loaded transport time per completed Part.

Example

value = result.average_transport_time

SimulationResult.average_waiting_time

Property. Mean wait for Machines, labor, transport, and downstream space.

Example

value = result.average_waiting_time

SimulationResult.average_wip

Property. Exact time-weighted average work in process.

Example

value = result.average_wip

SimulationResult.bottleneck_analysis(self) -> 'pd.DataFrame'

Method. Return instructor-facing multi-signal bottleneck scores.

This table is intentionally excluded from :meth:report.

Example

value = result.bottleneck_analysis()

SimulationResult.buffer_metrics

Property. Return time-weighted occupancy and full-time metrics for Buffers.

Example

value = result.buffer_metrics

SimulationResult.dataframes(self) -> 'dict[str, pd.DataFrame]'

Method. Return every standard table using stable export names.

Example

value = result.dataframes()

SimulationResult.event_log

Property. Return event-level data when event_log=True was used.

Example

value = result.event_log

SimulationResult.export_csv(self, path: 'str | Path' = 'outputs/csv') -> 'dict[str, Path]'

Method. Export standard result tables to a directory of CSV files.

Example

result.export_csv("outputs/csv")

SimulationResult.export_instructor_results(self, path: 'str | Path') -> 'Path'

Method. Save expected KPIs and bottleneck evidence as machine-readable JSON.

Example

result.export_instructor_results("expected.json")

SimulationResult.from_to_matrix

Property. Return From, To, Product, Trips, and distance movement data.

Example

value = result.from_to_matrix

SimulationResult.headline_metrics

Property. Return headline KPIs as a two-column DataFrame.

Example

value = result.headline_metrics

SimulationResult.likely_bottleneck

Property. Return the instructor-facing likely bottleneck Machine name.

Example

value = result.likely_bottleneck

SimulationResult.machine_metrics

Property. Return utilization, queue, and state accounting for every Machine.

Example

value = result.machine_metrics

SimulationResult.maximum_wip

Property. Largest instantaneous WIP observed.

Example

value = result.maximum_wip

SimulationResult.part_history(self, part_id: 'str') -> 'pd.DataFrame'

Method. Return the complete ordered history for one Part identifier.

Example

history = result.part_history("Part-000001")

SimulationResult.part_metrics

Property. Return one row per Part with terminal and accumulated values.

Example

value = result.part_metrics

SimulationResult.plot_cumulative_production(self, **kwargs: 'Any') -> 'Any'

Method. Plot cumulative Sink arrivals over time.

Example

value = result.plot_cumulative_production()

SimulationResult.plot_lead_times(self, **kwargs: 'Any') -> 'Any'

Method. Draw the default Product lead-time box plot.

Example

value = result.plot_lead_times()

SimulationResult.plot_machine_states(self, **kwargs: 'Any') -> 'Any'

Method. Plot Machine time by PROCESSING/BLOCKED/STARVED/WAITING/IDLE state.

Example

value = result.plot_machine_states()

SimulationResult.plot_queue_lengths(self, **kwargs: 'Any') -> 'Any'

Method. Plot automatic Machine queue lengths over time.

Example

value = result.plot_queue_lengths()

SimulationResult.plot_travel(self, **kwargs: 'Any') -> 'Any'

Method. Plot material travel by Product.

Example

value = result.plot_travel()

SimulationResult.plot_utilization(self, **kwargs: 'Any') -> 'Any'

Method. Plot resource utilization.

Example

value = result.plot_utilization()

SimulationResult.plot_wip(self, **kwargs: 'Any') -> 'Any'

Method. Plot time-weighted WIP changes over time.

Example

value = result.plot_wip()

SimulationResult.product_metrics

Property. Return major KPIs grouped by Product.

Example

value = result.product_metrics

SimulationResult.report(self) -> 'pd.DataFrame'

Method. Print a beginner-friendly KPI table and return its DataFrame.

Example

value = result.report()

SimulationResult.scrap_rate

Property. Scrapped Parts divided by all terminal Parts.

Example

value = result.scrap_rate

SimulationResult.simpy_environment

Property. Return the completed underlying SimPy Environment for advanced inspection.

Example

value = result.simpy_environment

SimulationResult.simpy_resources

Property. Return categorized underlying SimPy resources for advanced inspection.

Example

value = result.simpy_resources

SimulationResult.snapshot(self, at: 'float', **kwargs: 'Any') -> 'Any'

Method. Draw a static reconstructed plant state at at seconds.

Example

result.snapshot(at=7200)

SimulationResult.source_metrics

Property. Return batch, release, and actual product-mix counts by Source.

Example

value = result.source_metrics

SimulationResult.spaghetti_diagram(self, product: 'str | None' = None, **kwargs: 'Any') -> 'Any'

Method. Draw material flows, optionally filtered to one Product.

Example

value = result.spaghetti_diagram()

SimulationResult.throughput

Property. Alias for scheduled throughput in units/hour.

Example

value = result.throughput

SimulationResult.throughput_elapsed

Property. Good units per elapsed hour, including WIP drain time.

Example

value = result.throughput_elapsed

SimulationResult.throughput_scheduled

Property. Good units per scheduled hour, using the arrival window.

Example

value = result.throughput_scheduled

SimulationResult.total_material_travel_distance

Property. Total loaded travel distance of all Parts, in feet.

Example

value = result.total_material_travel_distance

SimulationResult.transporter_metrics

Property. Return Forklift and AGV motion and reservation utilization.

Example

value = result.transporter_metrics

SimulationResult.travel_distance_per_unit

Property. Total material travel divided by good Units Produced.

Example

value = result.travel_distance_per_unit

SimulationResult.units_by_product

Property. Units Produced grouped by Product.

Example

value = result.units_by_product

SimulationResult.units_by_sink

Property. Units Produced grouped by Sink.

Example

value = result.units_by_sink

SimulationResult.units_produced

Property. Number of good units that physically reached a Sink.

Example

value = result.units_produced

SimulationResult.units_scrapped

Property. Number of Parts removed by ScrapRoute decisions.

Example

value = result.units_scrapped

SimulationResult.worker_metrics

Property. Return distance, time, utilization, and idle time for Workers.

Example

value = result.worker_metrics

SimulationResult.worker_spaghetti_diagram(self, worker: 'str | None' = None, **kwargs: 'Any') -> 'Any'

Method. Draw recorded Worker movement paths.

Example

value = result.worker_spaghetti_diagram()

Sink

Sink(name: 'str', position: 'tuple[float, float]', width: 'float', depth: 'float') -> None

A finished-goods location; a unit is produced only on arrival here.

Example

sink = Sink("Shipping", (80, 20), 8, 8)

Sink.center

Property. Return the center point of the component footprint in feet.

Example

value = sink.center

SkillError

SkillError

Raised when an assigned worker lacks a required skill.

Example

try:
    plant.validate()
except SkillError as error:
    print(error)

Source

Source(name: 'str', position: 'tuple[float, float]', width: 'float', depth: 'float', arrivals: 'Distribution | float' = <factory>, batch_size: 'int' = 1, products: 'Any' = None, product_mix: 'Mapping[Any, float] | None' = None) -> None

A physical input area that generates Parts.

arrivals is the time between batches in seconds. Products can be assigned directly or inferred from Product routes that begin at this Source.

Example

source = Source("Receiving", (5, 20), 8, 8, arrivals=60)

Source.center

Property. Return the center point of the component footprint in feet.

Example

value = source.center

Triangular

Triangular(low: 'float', mode: 'float', high: 'float') -> None

A triangular distribution with low, most-likely mode, and high.

Example

distribution = Triangular(low=40, mode=60, high=90)

Triangular.sample(self, rng: 'np.random.Generator') -> 'float'

Method. Return one nonnegative sample.

Example

value = distribution.sample()

Triangular.to_config(self) -> 'dict[str, Any]'

Method. Return a JSON-serializable description.

Example

value = distribution.to_config()

Uniform

Uniform(low: 'float', high: 'float') -> None

A continuous uniform distribution between low and high.

Example

distribution = Uniform(low=50, high=70)

Uniform.sample(self, rng: 'np.random.Generator') -> 'float'

Method. Return one nonnegative sample.

Example

value = distribution.sample()

Uniform.to_config(self) -> 'dict[str, Any]'

Method. Return a JSON-serializable description.

Example

value = distribution.to_config()

Worker

Worker(name: 'str', position: 'tuple[float, float]', width: 'float' = 1.5, depth: 'float' = 1.5, speed: 'float' = 4.0, skills: 'list[str] | str' = 'all') -> None

An individual who can move material and/or operate Machines.

Example: Worker('Alex', (5, 5), skills=['transport', 'cutting']).

Example

worker = Worker("Alex", position=(5, 5), skills="all")

Worker.center

Property. Return the center point of the component footprint in feet.

Example

value = worker.center

Worker.has_skill(self, skill: 'str | None') -> 'bool'

Method. Return whether this Worker has skill; skills='all' is universal.

Example

can_transport = worker.has_skill("transport")

compare(baseline: 'SimulationResult', *scenarios: 'SimulationResult', metrics: 'Sequence[str] | None' = None) -> 'ScenarioComparison'

Compare scenarios to the first (baseline) result.

Example

comparison = compare(baseline, redesign)