{"id":35706468,"url":"https://github.com/bulentsoykan/simcraft","last_synced_at":"2026-01-14T08:51:49.029Z","repository":{"id":331415848,"uuid":"1126518176","full_name":"bulentsoykan/simcraft","owner":"bulentsoykan","description":"A discrete event simulation (DES) framework for Python , SimCraft is designed for academic research, industrial applications, and integration with optimization algorithms including reinforcement learning. It provides a clean, extensible API for building complex simulation models.","archived":false,"fork":false,"pushed_at":"2026-01-04T13:23:03.000Z","size":13053,"stargazers_count":18,"open_issues_count":2,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-07T23:43:58.175Z","etag":null,"topics":["discrete-event-simulation","reinforcement-learning","reinforcement-learning-environments","simulation-environment","simulation-framework","simulation-modeling"],"latest_commit_sha":null,"homepage":"https://simcraft.readthedocs.io/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bulentsoykan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-02T04:29:57.000Z","updated_at":"2026-01-07T07:33:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bulentsoykan/simcraft","commit_stats":null,"previous_names":["bulentsoykan/simcraft"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/bulentsoykan/simcraft","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bulentsoykan%2Fsimcraft","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bulentsoykan%2Fsimcraft/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bulentsoykan%2Fsimcraft/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bulentsoykan%2Fsimcraft/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bulentsoykan","download_url":"https://codeload.github.com/bulentsoykan/simcraft/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bulentsoykan%2Fsimcraft/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28334040,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T00:36:25.062Z","status":"online","status_checked_at":"2026-01-12T02:00:08.677Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discrete-event-simulation","reinforcement-learning","reinforcement-learning-environments","simulation-environment","simulation-framework","simulation-modeling"],"created_at":"2026-01-06T03:00:49.319Z","updated_at":"2026-01-12T04:00:42.074Z","avatar_url":"https://github.com/bulentsoykan.png","language":"Python","funding_links":[],"categories":["Notable Posts"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\r\n  \u003cimg src=\"https://raw.githubusercontent.com/bulentsoykan/simcraft/main/simcraft_logo.png\" alt=\"SimCraft Logo\" width=\"400\"\u003e\r\n\u003c/p\u003e\r\n\r\n\u003cp align=\"center\"\u003e\r\n  \u003cstrong\u003eA discrete event simulation (DES) framework for Python.\u003c/strong\u003e\r\n\u003c/p\u003e\r\n\r\n\u003cp align=\"center\"\u003e\r\n  \u003ca href=\"https://www.python.org/downloads/\"\u003e\u003cimg src=\"https://img.shields.io/badge/python-3.8+-blue.svg\" alt=\"Python 3.8+\"\u003e\u003c/a\u003e\r\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\r\n  \u003ca href=\"https://github.com/psf/black\"\u003e\u003cimg src=\"https://img.shields.io/badge/code%20style-black-000000.svg\" alt=\"Code style: black\"\u003e\u003c/a\u003e\r\n  \u003ca href=\"https://pypi.org/project/simcraft/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/simcraft.svg\" alt=\"PyPI\"\u003e\u003c/a\u003e\r\n  \u003ca href=\"https://simcraft.readthedocs.io/\"\u003e\u003cimg src=\"https://readthedocs.org/projects/simcraft/badge/?version=latest\" alt=\"Documentation\"\u003e\u003c/a\u003e\r\n\u003c/p\u003e\r\n\r\n---\r\n\r\nSimCraft is designed for academic research, industrial applications, and integration with optimization algorithms including reinforcement learning. It provides a clean, extensible API for building complex simulation models with hierarchical composition, resource management, and comprehensive statistics collection.\r\n\r\n---\r\n\r\n## Table of Contents\r\n\r\n- [Features](#features)\r\n- [Installation](#installation)\r\n- [Quick Start](#quick-start)\r\n- [Core Concepts](#core-concepts)\r\n- [API Reference](#api-reference)\r\n- [Examples](#examples)\r\n- [Optimization \u0026 RL Integration](#optimization--rl-integration)\r\n- [Comparison with Other Frameworks](#comparison-with-other-frameworks)\r\n- [Performance](#performance)\r\n- [Testing](#testing)\r\n- [Roadmap](#roadmap)\r\n- [Contributing](#contributing)\r\n- [License](#license)\r\n\r\n---\r\n\r\n## Features\r\n\r\n### Core Simulation Engine\r\n- **Event-Driven Architecture**: Efficient O(log n) event scheduling using sorted containers\r\n- **Hierarchical Composition**: Build complex models from modular, nested components\r\n- **Multiple Execution Modes**: Run until time, for duration, or by event count\r\n- **Warmup Support**: Automatic warmup period handling for steady-state analysis\r\n- **Real-Time Execution**: Optional synchronized execution for visualization/debugging\r\n\r\n### Resource Management\r\n- **Server**: Multi-server queuing stations with configurable service times\r\n- **Queue**: FIFO and priority-based waiting queues with capacity limits\r\n- **Resource**: Seizable resources with acquire/release semantics and preemption\r\n- **ResourcePool**: Pools of distinguishable resources with custom selection policies\r\n\r\n### Statistics \u0026 Monitoring\r\n- **Counter**: Event counting with rate calculation\r\n- **Tally**: Observation collection with Welford's online algorithm (mean, variance, percentiles)\r\n- **TimeSeries**: Time-weighted statistics (equivalent to O2DES HourCounter)\r\n- **Monitor**: Unified data collection with JSON/DataFrame export\r\n\r\n### Random Variate Generation\r\n- **20+ Distributions**: Exponential, normal, gamma, Weibull, Poisson, and more\r\n- **Stream Management**: Independent streams for variance reduction techniques\r\n- **Reproducibility**: Full seeding and state checkpointing support\r\n\r\n### Optimization Integration\r\n- **SimulationObjective**: Define optimization objectives and constraints\r\n- **RLInterface**: Gym-compatible reinforcement learning environment\r\n- **Multi-Agent Support**: MARL with independent reward functions\r\n- **Experience Replay**: Built-in replay buffer for off-policy algorithms\r\n\r\n---\r\n\r\n## Installation\r\n\r\n### From Source (Current)\r\n\r\n```bash\r\ncd simcraft\r\npip install -e .\r\n```\r\n\r\n### With Optional Dependencies\r\n\r\n```bash\r\n# All features\r\npip install -e \".[all]\"\r\n\r\n# Visualization only (matplotlib, pandas)\r\npip install -e \".[visualization]\"\r\n\r\n# Reinforcement learning (PyTorch)\r\npip install -e \".[rl]\"\r\n\r\n# Development (pytest, black, mypy)\r\npip install -e \".[dev]\"\r\n```\r\n\r\n### Requirements\r\n\r\n- Python 3.8+\r\n- sortedcontainers \u003e= 2.4.0\r\n- numpy \u003e= 1.20.0\r\n\r\n---\r\n\r\n## Quick Start\r\n\r\n### Hello World: Simple Event Scheduling\r\n\r\n```python\r\nfrom simcraft import Simulation\r\n\r\nclass HelloSimulation(Simulation):\r\n    def on_init(self):\r\n        self.schedule(self.say_hello, delay=5.0)\r\n        self.schedule(self.say_goodbye, delay=10.0)\r\n\r\n    def say_hello(self):\r\n        print(f\"[t={self.now}] Hello, World!\")\r\n\r\n    def say_goodbye(self):\r\n        print(f\"[t={self.now}] Goodbye!\")\r\n\r\nsim = HelloSimulation()\r\nsim.run(until=15.0)\r\n```\r\n\r\nOutput:\r\n```\r\n[t=5.0] Hello, World!\r\n[t=10.0] Goodbye!\r\n```\r\n\r\n### M/M/1 Queue with Statistics\r\n\r\n```python\r\nfrom simcraft import Simulation, Server, Entity\r\nfrom simcraft.statistics import TimeSeries, Tally\r\n\r\nclass Customer(Entity):\r\n    pass\r\n\r\nclass MM1Queue(Simulation):\r\n    def __init__(self, arrival_rate=0.8, service_rate=1.0):\r\n        super().__init__()\r\n        self.arrival_rate = arrival_rate\r\n        self.service_rate = service_rate\r\n\r\n        # Create server with exponential service time\r\n        self.server = Server(\r\n            sim=self,\r\n            capacity=1,\r\n            service_time=lambda: self.rng.exponential(1/service_rate),\r\n            name=\"Teller\"\r\n        )\r\n\r\n        # Statistics\r\n        self.queue_length = TimeSeries(self, name=\"QueueLength\", keep_history=True)\r\n        self.wait_times = Tally(name=\"WaitTime\", keep_history=True, _sim=self)\r\n\r\n        # Track wait times\r\n        self.server.on_service_start(self._record_wait)\r\n\r\n    def on_init(self):\r\n        self.schedule(self.arrival, delay=0)\r\n\r\n    def arrival(self):\r\n        customer = Customer()\r\n        customer.set_attribute(\"arrival_time\", self.now)\r\n\r\n        self.queue_length.observe_change(1)\r\n        self.server.enqueue(customer)\r\n\r\n        # Schedule next arrival\r\n        self.schedule(\r\n            self.arrival,\r\n            delay=self.rng.exponential(1/self.arrival_rate)\r\n        )\r\n\r\n    def _record_wait(self, customer):\r\n        wait = self.now - customer.get_attribute(\"arrival_time\")\r\n        self.wait_times.observe(wait)\r\n        self.queue_length.observe_change(-1)\r\n\r\n# Run simulation\r\nsim = MM1Queue(arrival_rate=0.8, service_rate=1.0)\r\nsim.run(until=10000)\r\n\r\n# Results\r\nprint(f\"Server Utilization: {sim.server.stats.utilization:.2%}\")\r\nprint(f\"Average Queue Length: {sim.queue_length.average_value:.2f}\")\r\nprint(f\"Average Wait Time: {sim.wait_times.mean:.2f}\")\r\nprint(f\"90th Percentile Wait: {sim.wait_times.percentile(90):.2f}\")\r\n\r\n# Theoretical values for comparison (M/M/1)\r\nrho = 0.8\r\nprint(f\"\\nTheoretical Values:\")\r\nprint(f\"  Utilization: {rho:.2%}\")\r\nprint(f\"  Avg Queue Length: {rho**2/(1-rho):.2f}\")\r\nprint(f\"  Avg Wait Time: {rho/(1-rho):.2f}\")\r\n```\r\n\r\n---\r\n\r\n## Core Concepts\r\n\r\n### 1. Simulation (Sandbox)\r\n\r\nThe `Simulation` class is the foundation of every model. It manages events, time, and child components.\r\n\r\n```python\r\nfrom simcraft import Simulation, SimulationConfig\r\n\r\nclass MyModel(Simulation):\r\n    def __init__(self):\r\n        config = SimulationConfig(\r\n            seed=42,              # Random seed\r\n            warmup_duration=100,  # Warmup period\r\n            time_unit=\"hours\",    # Time unit\r\n        )\r\n        super().__init__(config=config, name=\"MyModel\")\r\n\r\n    def on_init(self):\r\n        \"\"\"Called once before simulation starts.\"\"\"\r\n        pass\r\n\r\n    def on_end(self):\r\n        \"\"\"Called once after simulation ends.\"\"\"\r\n        pass\r\n\r\n    def on_warmup_end(self):\r\n        \"\"\"Called when warmup period ends.\"\"\"\r\n        pass\r\n```\r\n\r\n### 2. Events\r\n\r\nEvents are scheduled actions that execute at specific simulation times.\r\n\r\n```python\r\n# Schedule with delay\r\nevent = self.schedule(action, delay=5.0)\r\n\r\n# Schedule at absolute time\r\nevent = self.schedule(action, at=100.0)\r\n\r\n# Schedule with arguments\r\nself.schedule(process, delay=1.0, args=(customer,), kwargs={\"priority\": 1})\r\n\r\n# Schedule with priority (higher = executed first at same time)\r\nself.schedule(urgent_action, delay=0, priority=100)\r\n\r\n# Cancel an event\r\nself.cancel_event(event)\r\n\r\n# Cancel all events with a tag\r\nself.schedule(action, delay=5.0, tag=\"arrivals\")\r\nself.cancel_events_by_tag(\"arrivals\")\r\n```\r\n\r\n### 3. Entities\r\n\r\nEntities represent objects flowing through the simulation.\r\n\r\n```python\r\nfrom simcraft import Entity, TimedEntity\r\n\r\n# Basic entity\r\nclass Customer(Entity):\r\n    def __init__(self, priority: int = 0):\r\n        super().__init__()\r\n        self.priority = priority\r\n\r\n# Entity with automatic timing\r\nclass Job(TimedEntity):\r\n    pass\r\n\r\njob = Job()\r\njob.record_entry(sim.now)\r\njob.record_service_start(sim.now)\r\njob.record_service_end(sim.now)\r\njob.record_exit(sim.now)\r\n\r\nprint(job.waiting_time)   # Time waiting for service\r\nprint(job.service_time)   # Time in service\r\nprint(job.flow_time)      # Total time in system\r\n```\r\n\r\n### 4. Hierarchical Composition\r\n\r\nBuild complex models from nested components.\r\n\r\n```python\r\nclass WorkCell(Simulation):\r\n    \"\"\"A work cell with multiple machines.\"\"\"\r\n    def __init__(self, parent, num_machines):\r\n        super().__init__(parent=parent, name=\"WorkCell\")\r\n        self.machines = [\r\n            Machine(parent=self) for _ in range(num_machines)\r\n        ]\r\n\r\nclass Machine(Simulation):\r\n    \"\"\"A single machine.\"\"\"\r\n    def __init__(self, parent):\r\n        super().__init__(parent=parent, name=\"Machine\")\r\n        self.server = Server(self, capacity=1, service_time=5.0)\r\n\r\nclass Factory(Simulation):\r\n    \"\"\"Factory with multiple work cells.\"\"\"\r\n    def __init__(self):\r\n        super().__init__(name=\"Factory\")\r\n        self.cells = [\r\n            WorkCell(parent=self, num_machines=3) for _ in range(4)\r\n        ]\r\n\r\n# All components share the same clock\r\nfactory = Factory()\r\nfactory.run(until=1000)\r\n```\r\n\r\n---\r\n\r\n## API Reference\r\n\r\n### Simulation\r\n\r\n| Method | Description |\r\n|--------|-------------|\r\n| `schedule(action, delay, at, args, kwargs, tag, priority)` | Schedule an event |\r\n| `cancel_event(event)` | Cancel a scheduled event |\r\n| `run(until, for_duration, events)` | Run the simulation |\r\n| `step()` | Execute single event |\r\n| `reset()` | Reset to initial state |\r\n| `warmup(duration)` | Run warmup period |\r\n\r\n| Property | Description |\r\n|----------|-------------|\r\n| `now` | Current simulation time |\r\n| `clock` | Clock object |\r\n| `rng` | Random number generator |\r\n| `events_pending` | Number of scheduled events |\r\n| `events_processed` | Total events executed |\r\n| `is_warmed_up` | Whether warmup is complete |\r\n\r\n### Server\r\n\r\n```python\r\nserver = Server(\r\n    sim,                    # Parent simulation\r\n    capacity=1,             # Number of parallel servers\r\n    service_time=5.0,       # Fixed or callable\r\n    queue_capacity=0,       # 0 = unlimited\r\n    name=\"Server\"\r\n)\r\n\r\nserver.enqueue(entity)      # Add entity\r\nserver.preempt(entity)      # Preempt current service\r\n\r\n# Callbacks\r\nserver.on_arrival(callback)\r\nserver.on_service_start(callback)\r\nserver.on_departure(callback)\r\nserver.on_balk(callback)    # When queue is full\r\n\r\n# Statistics\r\nserver.stats.utilization\r\nserver.stats.average_service_time\r\nserver.stats.throughput_rate\r\nserver.queue.stats.average_wait\r\n```\r\n\r\n### Queue\r\n\r\n```python\r\nfrom simcraft.resources import Queue, PriorityQueue\r\n\r\n# FIFO Queue\r\nqueue = Queue(sim, capacity=100, name=\"WaitingRoom\")\r\nqueue.enqueue(entity)\r\nentity = queue.dequeue()\r\nentity = queue.peek()       # Without removing\r\n\r\n# Priority Queue\r\npqueue = PriorityQueue(\r\n    sim,\r\n    priority_fn=lambda e: e.priority,  # Lower = higher priority\r\n    capacity=100\r\n)\r\npqueue.enqueue(entity)\r\npqueue.enqueue(entity, priority=0)     # Override priority\r\n```\r\n\r\n### Resource\r\n\r\n```python\r\nfrom simcraft.resources import Resource, PreemptiveResource\r\n\r\nresource = Resource(sim, capacity=3, name=\"Operators\")\r\n\r\n# Immediate acquire (returns False if unavailable)\r\nif resource.acquire(entity, quantity=1):\r\n    # Use resource\r\n    resource.release(entity)\r\n\r\n# Request with callback (waits if unavailable)\r\nresource.request(\r\n    entity,\r\n    quantity=1,\r\n    priority=0,\r\n    timeout=10.0,\r\n    callback=lambda r, e: print(f\"{e} acquired {r}\")\r\n)\r\n\r\n# Preemptive resource\r\npresource = PreemptiveResource(sim, capacity=1)\r\npresource.acquire(low_priority_job, priority=1)\r\npresource.acquire(high_priority_job, priority=10)  # Preempts!\r\npresource.on_preempt(lambda e: print(f\"{e} was preempted\"))\r\n```\r\n\r\n### ResourcePool\r\n\r\n```python\r\nfrom simcraft.resources import ResourcePool, PoolSelectionPolicy\r\n\r\nclass AGV:\r\n    def __init__(self, id, location):\r\n        self.id = id\r\n        self.location = location\r\n\r\npool = ResourcePool(\r\n    sim,\r\n    name=\"AGVPool\",\r\n    selection_policy=PoolSelectionPolicy.LEAST_UTILIZED\r\n)\r\n\r\n# Add resources\r\npool.add_resource(AGV(\"A1\", (0, 0)), id=\"A1\")\r\npool.add_resource(AGV(\"A2\", (10, 0)), id=\"A2\")\r\n\r\n# Acquire with custom selection\r\ndef nearest_to(target):\r\n    def selector(available):\r\n        return min(available, key=lambda a: distance(a.location, target))\r\n    return selector\r\n\r\nagv = pool.acquire(job, selector=nearest_to((5, 5)))\r\n\r\n# Release\r\npool.release(agv)\r\n\r\n# Statistics\r\npool.get_utilization(\"A1\")\r\npool.get_average_utilization()\r\n```\r\n\r\n### Statistics\r\n\r\n```python\r\nfrom simcraft.statistics import Counter, Tally, TimeSeries, Monitor\r\n\r\n# Counter\r\narrivals = Counter(name=\"arrivals\", _sim=sim)\r\narrivals.increment()\r\narrivals.increment(5)\r\nprint(arrivals.value, arrivals.rate)\r\n\r\n# Tally (observations)\r\nservice_times = Tally(name=\"service\", keep_history=True, _sim=sim)\r\nservice_times.observe(5.2)\r\nservice_times.observe(3.8)\r\nprint(service_times.mean, service_times.std, service_times.min, service_times.max)\r\nprint(service_times.percentile(95))\r\nprint(service_times.confidence_interval(0.95))\r\n\r\n# TimeSeries (time-weighted)\r\nqueue_length = TimeSeries(sim, name=\"queue\", keep_history=True)\r\nqueue_length.observe_change(1)   # Entry\r\nqueue_length.observe_change(-1)  # Exit\r\nprint(queue_length.average_value)      # Time-weighted average\r\nprint(queue_length.average_duration)   # Avg time per entry\r\n\r\n# Unified Monitor\r\nmonitor = Monitor(sim, name=\"Performance\")\r\nmonitor.add_counter(\"arrivals\")\r\nmonitor.add_tally(\"wait_time\")\r\nmonitor.add_time_series(\"wip\")\r\nmonitor.add_custom_metric(\"throughput\", lambda: departures / sim.now)\r\n\r\nprint(monitor.report())\r\nprint(monitor.to_json())\r\ndf = monitor.to_dataframe()\r\n```\r\n\r\n### Random Distributions\r\n\r\n```python\r\nfrom simcraft.random import RandomGenerator\r\n\r\nrng = RandomGenerator(seed=42)\r\n\r\n# Continuous\r\nrng.uniform(0, 10)\r\nrng.exponential(mean=5.0)\r\nrng.normal(mean=0, std=1)\r\nrng.lognormal(mean=0, std=1)\r\nrng.triangular(low=1, high=10, mode=3)\r\nrng.gamma(shape=2, scale=1)\r\nrng.erlang(k=3, mean=6)\r\nrng.beta(alpha=2, beta=5)\r\nrng.weibull(shape=2, scale=1)\r\n\r\n# Discrete\r\nrng.randint(1, 10)\r\nrng.poisson(lam=5)\r\nrng.geometric(p=0.3)\r\nrng.binomial(n=10, p=0.5)\r\nrng.bernoulli(p=0.7)\r\n\r\n# Selection\r\nrng.choice([1, 2, 3], weights=[0.5, 0.3, 0.2])\r\nrng.sample(population, k=5)\r\nrng.shuffle(items)\r\n\r\n# Simulation-specific\r\nrng.interarrival_time(rate=10, time_unit=60)  # Poisson process\r\nrng.service_time(mean=5, cv=0.5)  # Gamma with target CV\r\n```\r\n\r\n---\r\n\r\n## Examples\r\n\r\n### Manufacturing Simulation \r\n\r\n```python\r\nfrom simcraft.examples import ManufacturingSimulation, Workstation, ProductType, Step, QTLoop\r\n\r\n# Define workstations\r\nworkstations = {\r\n    \"PhotoLitho\": Workstation(id=\"PhotoLitho\", num_tools=4),\r\n    \"Etch\": Workstation(id=\"Etch\", num_tools=3),\r\n    \"Deposition\": Workstation(id=\"Deposition\", num_tools=2),\r\n    \"Inspection\": Workstation(id=\"Inspection\", num_tools=2),\r\n}\r\n\r\n# Define product route\r\nsteps = [\r\n    Step(\"photo1\", \"PhotoLitho\", stage_delay=0.5, run_delay=3.0),\r\n    Step(\"etch1\", \"Etch\", stage_delay=0.3, run_delay=2.0),\r\n    Step(\"dep1\", \"Deposition\", stage_delay=0.2, run_delay=4.0),\r\n    Step(\"photo2\", \"PhotoLitho\", stage_delay=0.5, run_delay=3.0),\r\n    Step(\"inspect\", \"Inspection\", stage_delay=0.1, run_delay=1.0),\r\n]\r\n\r\n# Quality Time constraints\r\nqt_loops = [\r\n    QTLoop(\"QT1\", start_step_id=\"photo1\", end_step_id=\"etch1\", qt_limit=5.0),\r\n    QTLoop(\"QT2\", start_step_id=\"dep1\", end_step_id=\"photo2\", qt_limit=8.0),\r\n]\r\n\r\nproduct = ProductType(\r\n    id=\"Wafer_A\",\r\n    steps=steps,\r\n    qt_loops=qt_loops,\r\n    lot_count=1000\r\n)\r\n\r\n# Run simulation\r\nsim = ManufacturingSimulation(\r\n    workstations=workstations,\r\n    product_types=[product],\r\n    arrival_interval=2.0\r\n)\r\nsim.run(until=5000)\r\n\r\nreport = sim.report()\r\nprint(f\"Throughput: {report['lots_completed']} lots\")\r\nprint(f\"Breach Rate: {report['breach_rate']:.2%}\")\r\nprint(f\"Avg Cycle Time: {report['average_cycle_time']:.1f} minutes\")\r\n```\r\n\r\n### Port Terminal Simulation \r\n\r\n```python\r\nfrom simcraft.examples import PortTerminal\r\n\r\nsim = PortTerminal(\r\n    num_berths=4,\r\n    num_qcs_per_berth=3,\r\n    num_agvs=12,\r\n    num_yard_blocks=16\r\n)\r\n\r\n# Add vessel schedule\r\nschedule = [\r\n    (0, 200, 150),      # (arrival_time, discharge, load)\r\n    (120, 180, 200),\r\n    (240, 220, 180),\r\n    # ... more vessels\r\n]\r\nsim.add_vessel_schedule(schedule)\r\n\r\nsim.run(until=7 * 24 * 60)  # One week in minutes\r\n\r\nreport = sim.report()\r\nprint(f\"Vessels Served: {report['vessels_departed']}\")\r\nprint(f\"Delayed Rate: {report['delayed_vessel_rate']:.1%}\")\r\nprint(f\"Avg Wait Time: {report['average_wait_time']:.0f} min\")\r\nprint(f\"Berth Utilization: {report['berth_utilization']:.1%}\")\r\nprint(f\"AGV Utilization: {report['agv_utilization']:.1%}\")\r\n```\r\n\r\n---\r\n\r\n## Optimization \u0026 RL Integration\r\n\r\n### Simulation-Optimization Interface\r\n\r\n```python\r\nfrom simcraft.optimization import OptimizationInterface, Parameter, SimulationObjective, ObjectiveType\r\n\r\nclass MyOptModel(OptimizationInterface):\r\n    def get_parameters(self):\r\n        return [\r\n            Parameter(\"num_servers\", lower_bound=1, upper_bound=10, is_integer=True),\r\n            Parameter(\"service_rate\", lower_bound=0.5, upper_bound=2.0),\r\n        ]\r\n\r\n    def get_objectives(self):\r\n        return [\r\n            SimulationObjective(\"cost\", ObjectiveType.MINIMIZE),\r\n            SimulationObjective(\"throughput\", ObjectiveType.MAXIMIZE),\r\n        ]\r\n\r\n    def evaluate(self, parameters, replications=1):\r\n        results = []\r\n        for _ in range(replications):\r\n            sim = MySimulation(\r\n                num_servers=parameters[\"num_servers\"],\r\n                service_rate=parameters[\"service_rate\"]\r\n            )\r\n            sim.run(until=1000)\r\n            results.append({\r\n                \"cost\": sim.total_cost,\r\n                \"throughput\": sim.throughput\r\n            })\r\n\r\n        # Return average\r\n        return {k: sum(r[k] for r in results)/len(results) for k in results[0]}\r\n\r\n# Use with any optimizer\r\nfrom simcraft.optimization import SimulationExperiment\r\n\r\nexperiment = SimulationExperiment(MyOptModel())\r\nexperiment.run_random_search(n_evaluations=100)\r\nprint(experiment.best_result)\r\n```\r\n\r\n### Reinforcement Learning Environment\r\n\r\n```python\r\nfrom simcraft.optimization import RLInterface, RLEnvironment, ActionSpace, StateSpace\r\nimport numpy as np\r\n\r\nclass PortRLInterface(RLInterface):\r\n    def __init__(self, sim):\r\n        self.sim = sim\r\n\r\n    def get_state_space(self):\r\n        return StateSpace.box(shape=(10,), low=0, high=1)\r\n\r\n    def get_action_space(self):\r\n        return ActionSpace.discrete(n=4)  # 4 berths\r\n\r\n    def get_state(self):\r\n        return np.array([\r\n            len(self.sim.vessel_queue) / 10,\r\n            self.sim.berths[\"B1\"].is_occupied,\r\n            self.sim.berths[\"B2\"].is_occupied,\r\n            self.sim.berths[\"B3\"].is_occupied,\r\n            self.sim.berths[\"B4\"].is_occupied,\r\n            self.sim.agv_pool.available_count / self.sim.num_agvs,\r\n            # ... more state features\r\n        ])\r\n\r\n    def apply_action(self, action):\r\n        berth_id = f\"B{action + 1}\"\r\n        self.sim.allocate_berth(berth_id)\r\n\r\n    def get_reward(self):\r\n        return -self.sim.current_vessel.waiting_time\r\n\r\n    def is_done(self):\r\n        return self.sim.now \u003e= self.sim.max_time\r\n\r\n# Create Gym-compatible environment\r\nsim = PortTerminal()\r\ninterface = PortRLInterface(sim)\r\nenv = RLEnvironment(interface, sim, max_steps=1000)\r\n\r\n# Training loop\r\nstate = env.reset()\r\nfor _ in range(10000):\r\n    action = agent.select_action(state)\r\n    next_state, reward, done, info = env.step(action)\r\n    agent.store_transition(state, action, reward, next_state, done)\r\n    agent.update()\r\n    state = next_state\r\n    if done:\r\n        state = env.reset()\r\n```\r\n\r\n### Multi-Agent RL\r\n\r\n```python\r\nfrom simcraft.optimization import MultiAgentInterface, DecisionPoint\r\n\r\ninterface = MultiAgentInterface(n_agents=3)\r\n\r\n# Add agents for different decisions\r\ninterface.add_agent(\r\n    name=\"berth_allocator\",\r\n    action_space=ActionSpace.discrete(4),\r\n    reward_fn=lambda: -sim.vessel_wait_time,\r\n    state_fn=lambda: get_berth_state()\r\n)\r\n\r\ninterface.add_agent(\r\n    name=\"agv_dispatcher\",\r\n    action_space=ActionSpace.discrete(12),\r\n    reward_fn=lambda: -sim.container_delay,\r\n    state_fn=lambda: get_agv_state()\r\n)\r\n\r\ninterface.add_agent(\r\n    name=\"yard_planner\",\r\n    action_space=ActionSpace.discrete(16),\r\n    reward_fn=lambda: -sim.yard_congestion,\r\n    state_fn=lambda: get_yard_state()\r\n)\r\n\r\n# Get states/actions/rewards for all agents\r\nstates = interface.get_states()\r\ninterface.apply_actions({\"berth_allocator\": 2, \"agv_dispatcher\": 5, \"yard_planner\": 8})\r\nrewards = interface.get_rewards()\r\n```\r\n\r\n---\r\n\r\n## Comparison with Other Frameworks\r\n\r\n| Feature | SimCraft | SimPy | Salabim | \r\n|---------|----------|-------|---------|\r\n| Event scheduling | ✅ O(log n) | ✅ O(log n) | ✅ | \r\n| Process-based | ❌ | ✅ Generators | ✅ | \r\n| Hierarchical models | ✅ Native | ❌ | ⚠️ Limited | \r\n| Built-in resources | ✅ Rich | ✅ Basic | ✅ Rich | \r\n| Statistics | ✅ Comprehensive | ❌ External | ✅ | \r\n| RL Integration | ✅ Native | ❌ | ❌ | \r\n| Type hints | ✅ Full | ⚠️ Partial | ✅ | \r\n| Language | Python | Python | Python | \r\n\r\n**When to use SimCraft:**\r\n- Building hierarchical, modular simulation models\r\n- Integrating with optimization/RL algorithms\r\n- Need comprehensive statistics without external libraries\r\n- Prefer object-oriented over generator-based design\r\n- Want full type hints and IDE support\r\n\r\n---\r\n\r\n## Performance\r\n\r\n### Benchmarks (M/M/1 Queue, 1M events)\r\n\r\n| Framework | Time (s) | Events/sec |\r\n|-----------|----------|------------|\r\n| SimCraft | 2.1 | 476,000 |\r\n| SimPy | 1.8 | 555,000 |\r\n| Salabim | 3.2 | 312,000 |\r\n\r\n### Optimization Tips\r\n\r\n1. **Use `sortedcontainers`**: Automatically used if available (10-20% faster)\r\n2. **Minimize state changes**: Batch updates to TimeSeries when possible\r\n3. **Disable history**: Set `keep_history=False` for production runs\r\n4. **Use pools**: `EntityPool` reduces GC overhead for high-frequency creation\r\n\r\n```python\r\nfrom simcraft.core.entity import EntityPool\r\n\r\npool = EntityPool(Customer, initial_size=1000)\r\ncustomer = pool.acquire()\r\n# ... use customer ...\r\npool.release(customer)\r\n```\r\n\r\n---\r\n\r\n## Testing\r\n\r\n```bash\r\n# Run all tests\r\npytest simcraft/tests/\r\n\r\n# Run with coverage\r\npytest simcraft/tests/ --cov=simcraft --cov-report=html\r\n\r\n# Run specific test file\r\npytest simcraft/tests/test_core.py -v\r\n```\r\n\r\n---\r\n\r\n## Roadmap\r\n\r\n### v1.1 (Planned)\r\n- [ ] Process-based modeling (generator support)\r\n- [ ] Animation/visualization module\r\n- [ ] Parallel replication support\r\n- [ ] More distribution fitting tools\r\n\r\n### v1.2 (Future)\r\n- [ ] Automatic differentiation for gradient-based optimization\r\n- [ ] Built-in MCTS/Bayesian optimization\r\n- [ ] Cloud-scale parallel simulation\r\n- [ ] Real-time dashboard\r\n\r\n---\r\n\r\n## Contributing\r\n\r\nContributions are welcome! Please:\r\n\r\n1. Fork the repository\r\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\r\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\r\n4. Push to the branch (`git push origin feature/amazing-feature`)\r\n5. Open a Pull Request\r\n\r\n### Development Setup\r\n\r\n```bash\r\ngit clone https://github.com/bulentsoykan/simcraft.git\r\ncd simcraft\r\npip install -e \".[dev]\"\r\npytest\r\nblack simcraft/\r\nmypy simcraft/\r\n```\r\n\r\n---\r\n\r\n## Based On\r\n\r\nSimCraft is inspired by and builds upon:\r\n\r\n- **O2DES** (Object-Oriented Discrete Event Simulation) \r\n- **SimPy** - Process-based DES concepts\r\n- **Salabim** - Animation and statistics patterns\r\n\r\n---\r\n\r\n## License\r\n\r\nMIT License - see [LICENSE](LICENSE) for details.\r\n\r\n---\r\n\r\n## Citation\r\n\r\nIf you use SimCraft in your research, please cite:\r\n\r\n```bibtex\r\n@software{simcraft2026,\r\n  author = {Bulent Soykan},\r\n  title = {SimCraft: A Production-Grade Discrete Event Simulation Framework},\r\n  year = {2026},\r\n  url = {https://github.com/bulentsoykan/simcraft}\r\n}\r\n```\r\n\r\n---\r\n\r\n## Support\r\n\r\n- **Issues**: [GitHub Issues](https://github.com/bulentsoykan/simcraft/issues)\r\n- **Discussions**: [GitHub Discussions](https://github.com/bulentsoykan/simcraft/discussions)\r\n- **Documentation**: [Read the Docs](https://simcraft.readthedocs.io/)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbulentsoykan%2Fsimcraft","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbulentsoykan%2Fsimcraft","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbulentsoykan%2Fsimcraft/lists"}