or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

batch-running.mdcore.mddata-collection.mdexperimental.mdindex.mdspatial.md

core.mddocs/

0

# Core Agent-Based Modeling

1

2

The core of Mesa consists of three fundamental classes that form the backbone of any agent-based model: `Agent`, `AgentSet`, and `Model`. These classes provide the essential infrastructure for creating, managing, and running agent-based simulations.

3

4

## Imports

5

6

```python { .api }

7

from mesa import Agent, Model

8

# AgentSet is accessible via Agent.create_agents() or Model.agents

9

from typing import Any, Callable, Iterable, Iterator, Sequence

10

from random import Random

11

import numpy as np

12

13

# Type aliases

14

SeedLike = int | np.integer | Sequence[int] | np.random.SeedSequence

15

RNGLike = np.random.Generator | np.random.BitGenerator

16

```

17

18

## Agent Class

19

20

The `Agent` class serves as the base class for all agents in a Mesa model. It provides essential functionality for agent lifecycle management, random number generation, and integration with the model framework.

21

22

```python { .api }

23

class Agent:

24

"""

25

Base class for model agents with lifecycle management and random number generation.

26

27

Attributes:

28

model: Reference to the model instance containing this agent

29

unique_id: Unique identifier for the agent within the model

30

pos: Position of the agent in space (if applicable)

31

"""

32

33

def __init__(self, model: Model, *args, **kwargs) -> None:

34

"""

35

Initialize a new agent.

36

37

Parameters:

38

model: The model instance this agent belongs to

39

*args: Additional positional arguments

40

**kwargs: Additional keyword arguments

41

"""

42

...

43

44

def step(self) -> None:

45

"""

46

Execute one step of agent behavior.

47

48

This method should be implemented by subclasses to define

49

the agent's behavior during each simulation step.

50

"""

51

...

52

53

def advance(self) -> None:

54

"""

55

Execute the advance phase of agent behavior.

56

57

Used in staged activation where agents first step(),

58

then advance() to update their state based on all

59

agents' step() results.

60

"""

61

...

62

63

def remove(self) -> None:

64

"""

65

Remove this agent from the model.

66

67

This properly deregisters the agent from the model

68

and handles cleanup of spatial positioning if applicable.

69

"""

70

...

71

72

@classmethod

73

def create_agents(cls, model: Model, n: int, *args, **kwargs) -> AgentSet[Agent]:

74

"""

75

Create multiple agents of this class.

76

77

Parameters:

78

model: The model instance

79

n: Number of agents to create

80

*args: Additional positional arguments for agent initialization

81

**kwargs: Additional keyword arguments for agent initialization

82

83

Returns:

84

AgentSet containing the newly created agents

85

"""

86

...

87

88

@property

89

def random(self) -> Random:

90

"""

91

Access to the model's seeded Python random number generator.

92

93

Returns:

94

The model's Random instance for reproducible randomness

95

"""

96

...

97

98

@property

99

def rng(self) -> np.random.Generator:

100

"""

101

Access to the model's seeded NumPy random number generator.

102

103

Returns:

104

The model's numpy.random.Generator instance

105

"""

106

...

107

```

108

109

### Agent Usage Examples

110

111

```python { .api }

112

from mesa import Agent, Model

113

114

class Predator(Agent):

115

"""Example predator agent with energy-based behavior."""

116

117

def __init__(self, model, energy=100):

118

super().__init__(model)

119

self.energy = energy

120

self.max_energy = energy * 2

121

122

def step(self):

123

"""Hunt for prey and consume energy."""

124

# Move randomly

125

self.move_randomly()

126

127

# Hunt for prey

128

prey_in_cell = [agent for agent in self.model.space.get_cell_list_contents([self.pos])

129

if isinstance(agent, Prey)]

130

131

if prey_in_cell and self.energy < self.max_energy:

132

prey = self.random.choice(prey_in_cell)

133

prey.remove()

134

self.energy += 50

135

136

# Consume energy

137

self.energy -= 2

138

139

# Die if energy is depleted

140

if self.energy <= 0:

141

self.remove()

142

143

def move_randomly(self):

144

"""Move to a random neighboring cell."""

145

if hasattr(self.model, 'space'):

146

neighbors = self.model.space.get_neighborhood(self.pos)

147

new_pos = self.random.choice(neighbors)

148

self.model.space.move_agent(self, new_pos)

149

150

# Creating agents

151

model = Model()

152

predator = Predator(model, energy=150)

153

154

# Creating multiple agents

155

predators = Predator.create_agents(model, n=10, energy=100)

156

```

157

158

## AgentSet Class

159

160

`AgentSet` is a powerful collection class for managing groups of agents. It provides efficient operations for filtering, sorting, and executing methods across multiple agents.

161

162

```python { .api }

163

class AgentSet(MutableSet, Sequence):

164

"""

165

Collection class for managing ordered sets of agents with advanced operations.

166

167

AgentSet implements both MutableSet and Sequence interfaces, providing

168

set-like operations while maintaining agent ordering.

169

"""

170

171

def __init__(self, agents: Iterable[Agent], random: Random | None = None):

172

"""

173

Initialize an AgentSet with agents.

174

175

Parameters:

176

agents: Iterable of agents to include in the set

177

random: Random number generator for shuffle operations

178

"""

179

...

180

181

def __len__(self) -> int:

182

"""Return the number of agents in the set."""

183

...

184

185

def __iter__(self) -> Iterator[Agent]:

186

"""Iterate over agents in the set."""

187

...

188

189

def __contains__(self, agent: Agent) -> bool:

190

"""Check if an agent is in the set."""

191

...

192

193

def __getitem__(self, item: int | slice) -> Agent:

194

"""Get agent by index or slice."""

195

...

196

197

def select(self,

198

filter_func: Callable[[Agent], bool] | None = None,

199

at_most: int | float = float("inf"),

200

inplace: bool = False,

201

agent_type: type[Agent] | None = None) -> AgentSet:

202

"""

203

Select agents based on criteria.

204

205

Parameters:

206

filter_func: Function that returns True for agents to include

207

at_most: Maximum number of agents to select

208

inplace: Whether to modify this AgentSet or return a new one

209

agent_type: Filter by agent type/class

210

211

Returns:

212

AgentSet containing selected agents (or self if inplace=True)

213

"""

214

...

215

216

def shuffle(self, inplace: bool = False) -> AgentSet:

217

"""

218

Shuffle the order of agents.

219

220

Parameters:

221

inplace: Whether to modify this AgentSet or return a new one

222

223

Returns:

224

Shuffled AgentSet (or self if inplace=True)

225

"""

226

...

227

228

def sort(self,

229

key: Callable[[Agent], Any] | str,

230

ascending: bool = False,

231

inplace: bool = False) -> AgentSet:

232

"""

233

Sort agents by a key function or attribute name.

234

235

Parameters:

236

key: Function to generate sort key or attribute name

237

ascending: Whether to sort in ascending order

238

inplace: Whether to modify this AgentSet or return a new one

239

240

Returns:

241

Sorted AgentSet (or self if inplace=True)

242

"""

243

...

244

245

def do(self, method: str | Callable, *args, **kwargs) -> AgentSet:

246

"""

247

Execute a method on all agents in the set.

248

249

Parameters:

250

method: Method name (string) or callable to execute

251

*args: Arguments to pass to the method

252

**kwargs: Keyword arguments to pass to the method

253

254

Returns:

255

This AgentSet for method chaining

256

"""

257

...

258

259

def shuffle_do(self, method: str | Callable, *args, **kwargs) -> AgentSet:

260

"""

261

Shuffle agents and then execute a method on all agents.

262

263

Parameters:

264

method: Method name (string) or callable to execute

265

*args: Arguments to pass to the method

266

**kwargs: Keyword arguments to pass to the method

267

268

Returns:

269

This AgentSet for method chaining

270

"""

271

...

272

273

def map(self, method: str | Callable, *args, **kwargs) -> list[Any]:

274

"""

275

Apply a method to all agents and return results.

276

277

Parameters:

278

method: Method name (string) or callable to apply

279

*args: Arguments to pass to the method

280

**kwargs: Keyword arguments to pass to the method

281

282

Returns:

283

List of results from applying method to each agent

284

"""

285

...

286

287

def agg(self, attribute: str, func: Callable | Iterable[Callable]) -> Any | list[Any]:

288

"""

289

Aggregate an attribute across all agents using one or more functions.

290

291

Parameters:

292

attribute: Name of the attribute to aggregate

293

func: Aggregation function(s) like sum, mean, max, etc.

294

295

Returns:

296

Aggregated value(s)

297

"""

298

...

299

300

def get(self,

301

attr_names: str | list[str],

302

handle_missing: str = "error",

303

default_value: Any = None) -> list[Any] | list[list[Any]]:

304

"""

305

Get attribute values from all agents.

306

307

Parameters:

308

attr_names: Attribute name(s) to retrieve

309

handle_missing: How to handle missing attributes ("error", "default", "ignore")

310

default_value: Default value when handle_missing="default"

311

312

Returns:

313

List of attribute values (or list of lists for multiple attributes)

314

"""

315

...

316

317

def set(self, attr_name: str, value: Any) -> AgentSet:

318

"""

319

Set an attribute value on all agents.

320

321

Parameters:

322

attr_name: Name of the attribute to set

323

value: Value to set (can be callable for per-agent values)

324

325

Returns:

326

This AgentSet for method chaining

327

"""

328

...

329

330

def add(self, agent: Agent):

331

"""Add an agent to the set."""

332

...

333

334

def discard(self, agent: Agent):

335

"""Remove an agent from the set if present."""

336

...

337

338

def remove(self, agent: Agent):

339

"""Remove an agent from the set (raises error if not present)."""

340

...

341

342

def groupby(self, by: Callable | str, result_type: str = "agentset") -> GroupBy:

343

"""

344

Group agents by a key function or attribute.

345

346

Parameters:

347

by: Grouping key function or attribute name

348

result_type: Type of result collections ("agentset" or "list")

349

350

Returns:

351

GroupBy object for grouped operations

352

"""

353

...

354

```

355

356

### AgentSet Usage Examples

357

358

```python { .api }

359

from mesa import Agent, Model

360

# AgentSet is accessible via Agent.create_agents() or Model.agents

361

362

class WealthAgent(Agent):

363

def __init__(self, model, wealth=100):

364

super().__init__(model)

365

self.wealth = wealth

366

self.age = 0

367

368

def step(self):

369

self.age += 1

370

# Simple wealth dynamics

371

if self.wealth > 0:

372

self.wealth += self.random.randint(-5, 10)

373

374

# Create model with agents

375

model = Model()

376

agents = WealthAgent.create_agents(model, n=100)

377

378

# Selection operations

379

wealthy_agents = model.agents.select(lambda a: a.wealth > 200)

380

young_agents = model.agents.select(lambda a: a.age < 10, at_most=20)

381

382

# Sorting operations

383

by_wealth = model.agents.sort(key="wealth", ascending=False)

384

by_age = model.agents.sort(key=lambda a: a.age)

385

386

# Bulk operations

387

model.agents.shuffle_do("step") # Randomly order, then call step() on each

388

model.agents.set("wealth", lambda a: max(0, a.wealth)) # Ensure non-negative wealth

389

390

# Aggregation operations

391

total_wealth = model.agents.agg("wealth", sum)

392

wealth_stats = model.agents.agg("wealth", [sum, len, max, min])

393

394

# Get attribute values

395

all_wealth = model.agents.get("wealth")

396

wealth_and_age = model.agents.get(["wealth", "age"])

397

398

# Grouping operations

399

by_wealth_class = model.agents.groupby(lambda a: "rich" if a.wealth > 100 else "poor")

400

rich_agents = by_wealth_class["rich"]

401

```

402

403

## GroupBy Class

404

405

The `GroupBy` class enables grouped operations on agents, similar to SQL GROUP BY or pandas groupby functionality.

406

407

```python { .api }

408

class GroupBy:

409

"""

410

Helper class for grouped operations on agents.

411

412

Provides methods to apply operations to groups of agents

413

created by AgentSet.groupby().

414

"""

415

416

def __init__(self, groups: dict[Any, list | AgentSet]):

417

"""

418

Initialize GroupBy with groups.

419

420

Parameters:

421

groups: Dictionary mapping group keys to agent collections

422

"""

423

...

424

425

def map(self, method: Callable | str, *args, **kwargs) -> dict[Any, Any]:

426

"""

427

Apply a method to each group and return results.

428

429

Parameters:

430

method: Method name or callable to apply

431

*args: Arguments to pass to the method

432

**kwargs: Keyword arguments to pass to the method

433

434

Returns:

435

Dictionary mapping group keys to results

436

"""

437

...

438

439

def do(self, method: Callable | str, *args, **kwargs) -> GroupBy:

440

"""

441

Execute a method on each group.

442

443

Parameters:

444

method: Method name or callable to execute

445

*args: Arguments to pass to the method

446

**kwargs: Keyword arguments to pass to the method

447

448

Returns:

449

This GroupBy object for method chaining

450

"""

451

...

452

453

def count(self) -> dict[Any, int]:

454

"""

455

Count agents in each group.

456

457

Returns:

458

Dictionary mapping group keys to agent counts

459

"""

460

...

461

462

def agg(self, attr_name: str, func: Callable) -> dict[Hashable, Any]:

463

"""

464

Aggregate an attribute within each group.

465

466

Parameters:

467

attr_name: Name of the attribute to aggregate

468

func: Aggregation function (sum, mean, max, etc.)

469

470

Returns:

471

Dictionary mapping group keys to aggregated values

472

"""

473

...

474

```

475

476

## Model Class

477

478

The `Model` class serves as the container and coordinator for the entire simulation. It manages agents, handles random number generation, and orchestrates the simulation loop.

479

480

```python { .api }

481

class Model:

482

"""

483

Base class for agent-based models with simulation management.

484

485

The Model class provides infrastructure for managing agents,

486

coordinating simulation steps, and handling random number generation.

487

488

Attributes:

489

running: Boolean indicating if model should continue running

490

steps: Number of times model.step() has been called

491

random: Seeded Python random number generator

492

rng: Seeded NumPy random number generator

493

"""

494

495

def __init__(self,

496

*args: Any,

497

seed: float | None = None,

498

rng: RNGLike | SeedLike | None = None,

499

**kwargs: Any) -> None:

500

"""

501

Initialize a new model.

502

503

Parameters:

504

*args: Additional positional arguments

505

seed: Random seed for reproducible results

506

rng: Random number generator or seed

507

**kwargs: Additional keyword arguments

508

"""

509

...

510

511

def step(self) -> None:

512

"""

513

Execute one step of the model.

514

515

This method should be implemented by subclasses to define

516

the model's behavior during each simulation step.

517

"""

518

...

519

520

def run_model(self) -> None:

521

"""

522

Run the model until completion.

523

524

Repeatedly calls step() while self.running is True.

525

"""

526

...

527

528

def register_agent(self, agent):

529

"""

530

Register an agent with the model.

531

532

Parameters:

533

agent: Agent to register

534

"""

535

...

536

537

def deregister_agent(self, agent):

538

"""

539

Deregister an agent from the model.

540

541

Parameters:

542

agent: Agent to deregister

543

"""

544

...

545

546

def reset_randomizer(self, seed: int | None = None) -> None:

547

"""

548

Reset the random number generators with a new seed.

549

550

Parameters:

551

seed: New random seed

552

"""

553

...

554

555

def reset_rng(self, rng: RNGLike | SeedLike | None = None) -> None:

556

"""

557

Reset the NumPy random number generator.

558

559

Parameters:

560

rng: New random number generator or seed

561

"""

562

...

563

564

def remove_all_agents(self):

565

"""Remove all agents from the model."""

566

...

567

568

@property

569

def agents(self) -> AgentSet:

570

"""

571

Get all agents in the model.

572

573

Returns:

574

AgentSet containing all registered agents

575

"""

576

...

577

578

@property

579

def agent_types(self) -> list[type]:

580

"""

581

Get all agent types present in the model.

582

583

Returns:

584

List of agent classes represented in the model

585

"""

586

...

587

588

@property

589

def agents_by_type(self) -> dict[type[Agent], AgentSet]:

590

"""

591

Get agents organized by type.

592

593

Returns:

594

Dictionary mapping agent types to AgentSets

595

"""

596

...

597

```

598

599

### Model Usage Examples

600

601

```python { .api }

602

from mesa import Agent, Model, DataCollector

603

import numpy as np

604

605

class EcosystemModel(Model):

606

"""Example ecosystem model with predators and prey."""

607

608

def __init__(self, n_predators=20, n_prey=100, width=50, height=50):

609

super().__init__()

610

self.width = width

611

self.height = height

612

613

# Create spatial environment (would typically use mesa.space or mesa.discrete_space)

614

# self.space = MultiGrid(width, height, True)

615

616

# Data collection

617

self.datacollector = DataCollector(

618

model_reporters={

619

"Predators": lambda m: len(m.agents.select(agent_type=Predator)),

620

"Prey": lambda m: len(m.agents.select(agent_type=Prey)),

621

"Total Population": lambda m: len(m.agents)

622

},

623

agent_reporters={

624

"Energy": "energy",

625

"Position": "pos"

626

}

627

)

628

629

# Create agents

630

for i in range(n_predators):

631

predator = Predator(self, energy=100)

632

633

for i in range(n_prey):

634

prey = Prey(self, energy=50)

635

636

self.running = True

637

638

def step(self):

639

"""Execute one step of the ecosystem simulation."""

640

# Collect data before step

641

self.datacollector.collect(self)

642

643

# Execute agent behaviors in random order

644

self.agents.shuffle_do("step")

645

646

# Check if simulation should continue

647

predator_count = len(self.agents.select(agent_type=Predator))

648

prey_count = len(self.agents.select(agent_type=Prey))

649

650

if predator_count == 0 or prey_count == 0:

651

self.running = False

652

653

# Running the model

654

model = EcosystemModel(n_predators=10, n_prey=50)

655

656

# Run for specific number of steps

657

for step in range(100):

658

model.step()

659

if not model.running:

660

print(f"Simulation ended at step {step}")

661

break

662

663

# Or run until completion

664

model = EcosystemModel(n_predators=10, n_prey=50)

665

model.run_model()

666

667

# Access agents by type

668

predators = model.agents_by_type[Predator]

669

prey = model.agents_by_type[Prey]

670

671

# Get model statistics

672

print(f"Final population: {len(model.agents)} agents")

673

print(f"Agent types: {model.agent_types}")

674

```

675

676

## Advanced Usage Patterns

677

678

### Custom Agent Behaviors

679

680

```python { .api }

681

class SocialAgent(Agent):

682

"""Agent with social network capabilities."""

683

684

def __init__(self, model, cooperation_probability=0.5):

685

super().__init__(model)

686

self.cooperation_prob = cooperation_probability

687

self.social_network = set()

688

self.reputation = 0.5

689

690

def add_connection(self, other_agent):

691

"""Add a social connection."""

692

self.social_network.add(other_agent)

693

other_agent.social_network.add(self)

694

695

def interact_with_neighbors(self):

696

"""Interact with agents in social network."""

697

for neighbor in self.social_network:

698

if self.random.random() < self.cooperation_prob:

699

# Cooperate

700

neighbor.reputation += 0.1

701

self.reputation += 0.05

702

else:

703

# Defect

704

neighbor.reputation -= 0.05

705

706

def update_cooperation(self):

707

"""Update cooperation probability based on reputation."""

708

self.cooperation_prob = min(1.0, max(0.0, self.reputation))

709

710

def step(self):

711

self.interact_with_neighbors()

712

self.update_cooperation()

713

```

714

715

### Staged Activation Pattern

716

717

```python { .api }

718

class StagedModel(Model):

719

"""Model using staged activation for simultaneous updates."""

720

721

def __init__(self, n_agents=100):

722

super().__init__()

723

724

# Create agents

725

for i in range(n_agents):

726

agent = SocialAgent(self)

727

728

self.running = True

729

730

def step(self):

731

"""Execute staged activation: step, then advance."""

732

# Stage 1: All agents observe and plan

733

self.agents.do("step")

734

735

# Stage 2: All agents update their state simultaneously

736

self.agents.do("advance")

737

```

738

739

## Type Definitions

740

741

```python { .api }

742

# Type aliases used in Mesa core modules

743

from typing import Any, Callable, Hashable, Iterable, Iterator, MutableSet, Sequence

744

from random import Random

745

import numpy as np

746

747

# Random number generation types

748

SeedLike = int | np.integer | Sequence[int] | np.random.SeedSequence

749

RNGLike = np.random.Generator | np.random.BitGenerator

750

751

# Agent and model types (forward references for documentation)

752

Agent = Agent

753

AgentSet = AgentSet[Agent]

754

Model = Model

755

GroupBy = GroupBy

756

```