stochastic-flock 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stochastic_flock-0.1.0/.github/workflows/publish.yml +69 -0
- stochastic_flock-0.1.0/.gitignore +34 -0
- stochastic_flock-0.1.0/CMakeLists.txt +92 -0
- stochastic_flock-0.1.0/Makefile +41 -0
- stochastic_flock-0.1.0/PKG-INFO +88 -0
- stochastic_flock-0.1.0/README.md +79 -0
- stochastic_flock-0.1.0/pyproject.toml +23 -0
- stochastic_flock-0.1.0/requirements.txt +11 -0
- stochastic_flock-0.1.0/src/bird_solver.cpp +47 -0
- stochastic_flock-0.1.0/src/constants.hpp +9 -0
- stochastic_flock-0.1.0/src/python_bindings.cpp +74 -0
- stochastic_flock-0.1.0/src/simulation.hpp +743 -0
- stochastic_flock-0.1.0/src/visual.hpp +248 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: Build and Upload to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
branches: [ main ]
|
|
7
|
+
release:
|
|
8
|
+
types: [published, created, released] # Added more types for safety
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build_wheels:
|
|
12
|
+
name: Build wheels on ${{ matrix.os }}
|
|
13
|
+
runs-on: ${{ matrix.os }}
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
|
|
18
|
+
os: [ubuntu-latest, windows-latest, macos-14]
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
with:
|
|
23
|
+
submodules: recursive
|
|
24
|
+
|
|
25
|
+
- name: Build wheels
|
|
26
|
+
uses: pypa/cibuildwheel@v2.21.3
|
|
27
|
+
env:
|
|
28
|
+
# Only CPython 3.10+, No PyPy (fixes your previous error)
|
|
29
|
+
CIBW_SKIP: pp* cp36-* cp37-* cp38-* cp39-* *-win32 *-manylinux_i686
|
|
30
|
+
# manylinux_2_28 provides GCC 11/12 for C++20 support
|
|
31
|
+
CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
|
|
32
|
+
CIBW_BUILD_VERBOSITY: 1
|
|
33
|
+
|
|
34
|
+
- uses: actions/upload-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
|
|
37
|
+
path: ./wheelhouse/*.whl
|
|
38
|
+
|
|
39
|
+
build_sdist:
|
|
40
|
+
name: Build source distribution
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v4
|
|
44
|
+
with:
|
|
45
|
+
submodules: recursive
|
|
46
|
+
- name: Build sdist
|
|
47
|
+
run: pipx run build --sdist
|
|
48
|
+
- uses: actions/upload-artifact@v4
|
|
49
|
+
with:
|
|
50
|
+
name: cibw-sdist
|
|
51
|
+
path: dist/*.tar.gz
|
|
52
|
+
|
|
53
|
+
upload_pypi:
|
|
54
|
+
needs: [build_wheels, build_sdist]
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
# This job only runs when you actually publish a "Release" on GitHub
|
|
57
|
+
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
|
|
58
|
+
permissions:
|
|
59
|
+
id-token: write # Mandatory for Trusted Publishing
|
|
60
|
+
contents: read
|
|
61
|
+
steps:
|
|
62
|
+
- uses: actions/download-artifact@v4
|
|
63
|
+
with:
|
|
64
|
+
pattern: cibw-*
|
|
65
|
+
path: dist
|
|
66
|
+
merge-multiple: true
|
|
67
|
+
|
|
68
|
+
- name: Publish to PyPI
|
|
69
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 1. Ignore everything by default
|
|
2
|
+
*
|
|
3
|
+
|
|
4
|
+
# 2. Allow all directories so Git can search them
|
|
5
|
+
!*/
|
|
6
|
+
|
|
7
|
+
# 3. Un-ignore C++ and Project Metadata files (anywhere)
|
|
8
|
+
!*.cpp
|
|
9
|
+
!*.hpp
|
|
10
|
+
!*.h
|
|
11
|
+
!*.gitignore
|
|
12
|
+
!*.txt
|
|
13
|
+
!*.toml
|
|
14
|
+
!*.md
|
|
15
|
+
!Makefile
|
|
16
|
+
!.github/
|
|
17
|
+
!.github/workflows/*.yml
|
|
18
|
+
|
|
19
|
+
# 4. Handle Python files:
|
|
20
|
+
# We DON'T un-ignore *.py globally (this keeps root .py files ignored).
|
|
21
|
+
# Instead, we only un-ignore the specific folder you want:
|
|
22
|
+
!src/stochastic_flock/
|
|
23
|
+
!src/stochastic_flock/*.py
|
|
24
|
+
|
|
25
|
+
# 5. Standard cleanup (Re-ignore build artifacts)
|
|
26
|
+
build/
|
|
27
|
+
build_pgo/
|
|
28
|
+
build_native/
|
|
29
|
+
dist/
|
|
30
|
+
__pycache__/
|
|
31
|
+
*.egg-info/
|
|
32
|
+
*.so
|
|
33
|
+
.venv/
|
|
34
|
+
src/stochastic_flock/__init__.py
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.18)
|
|
2
|
+
project(stochastic_flock LANGUAGES CXX)
|
|
3
|
+
|
|
4
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
5
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
6
|
+
|
|
7
|
+
# 1. Dependencies (Eigen)
|
|
8
|
+
include(FetchContent)
|
|
9
|
+
set(EIGEN_BUILD_PKGCONFIG OFF CACHE BOOL "" FORCE)
|
|
10
|
+
set(EIGEN_BUILD_DOC OFF CACHE BOOL "" FORCE)
|
|
11
|
+
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
|
12
|
+
set(EIGEN_LEAVE_TEST_IN_ALL_TARGET OFF CACHE BOOL "" FORCE)
|
|
13
|
+
set(EIGEN_BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
|
14
|
+
|
|
15
|
+
FetchContent_Declare(
|
|
16
|
+
eigen
|
|
17
|
+
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
|
|
18
|
+
GIT_TAG 3.4.0
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Use the "manual" population instead of MakeAvailable
|
|
22
|
+
# so we can use EXCLUDE_FROM_ALL
|
|
23
|
+
FetchContent_GetProperties(eigen)
|
|
24
|
+
if(NOT eigen_POPULATED)
|
|
25
|
+
FetchContent_Populate(eigen)
|
|
26
|
+
# The EXCLUDE_FROM_ALL flag here is the magic bit.
|
|
27
|
+
# It tells CMake: "Build this, but don't install its files."
|
|
28
|
+
add_subdirectory(${eigen_SOURCE_DIR} ${eigen_BINARY_DIR} EXCLUDE_FROM_ALL)
|
|
29
|
+
endif()
|
|
30
|
+
|
|
31
|
+
find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED) #added .Module
|
|
32
|
+
|
|
33
|
+
# if(NOT pybind11_FOUND)
|
|
34
|
+
# execute_process(
|
|
35
|
+
# COMMAND "${Python3_EXECUTABLE}" -m pybind11 --cmakedir
|
|
36
|
+
# OUTPUT_VARIABLE pybind11_DIR
|
|
37
|
+
# OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
38
|
+
# ERROR_QUIET
|
|
39
|
+
# )
|
|
40
|
+
# endif()
|
|
41
|
+
|
|
42
|
+
# # Now find it (using the path discovered above if necessary)
|
|
43
|
+
# find_package(pybind11 REQUIRED)
|
|
44
|
+
|
|
45
|
+
find_package(pybind11 QUIET)
|
|
46
|
+
|
|
47
|
+
# If not found, fall back to your manual search (works for your local build)
|
|
48
|
+
if(NOT pybind11_FOUND)
|
|
49
|
+
execute_process(
|
|
50
|
+
COMMAND "${Python3_EXECUTABLE}" -m pybind11 --cmakedir
|
|
51
|
+
OUTPUT_VARIABLE pybind11_DIR
|
|
52
|
+
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
53
|
+
ERROR_QUIET
|
|
54
|
+
)
|
|
55
|
+
find_package(pybind11 REQUIRED PATHS ${pybind11_DIR} NO_DEFAULT_PATH)
|
|
56
|
+
endif()
|
|
57
|
+
|
|
58
|
+
# 3. Define Optimization Settings (Interface Library)
|
|
59
|
+
# This replaces your 'foreach' loop logic
|
|
60
|
+
add_library(sim_opts INTERFACE)
|
|
61
|
+
target_compile_definitions(sim_opts INTERFACE EIGEN_RUNTIME_NO_MALLOC)
|
|
62
|
+
|
|
63
|
+
if(NOT MSVC)
|
|
64
|
+
target_compile_options(sim_opts INTERFACE -O3 -ffast-math -Wall)
|
|
65
|
+
if(NATIVE_OPTIM)
|
|
66
|
+
target_compile_options(sim_opts INTERFACE -march=native)
|
|
67
|
+
include(CheckIPOSupported)
|
|
68
|
+
check_ipo_supported(RESULT lto_supported)
|
|
69
|
+
if(lto_supported)
|
|
70
|
+
set_property(TARGET sim_opts PROPERTY INTERFACE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
|
71
|
+
endif()
|
|
72
|
+
endif()
|
|
73
|
+
endif()
|
|
74
|
+
|
|
75
|
+
pybind11_add_module(stochastic_flock src/python_bindings.cpp)
|
|
76
|
+
target_include_directories(stochastic_flock PRIVATE src)
|
|
77
|
+
target_link_libraries(stochastic_flock PRIVATE Eigen3::Eigen sim_opts)
|
|
78
|
+
|
|
79
|
+
install(TARGETS stochastic_flock DESTINATION stochastic_flock)
|
|
80
|
+
|
|
81
|
+
#TODO : ^^^ doesnt install to stochastic_flock folder. perhaps completely remove coupled makefile with bird_solver and python?
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# 5. Target: Optional SFML (Skipped during Python build)
|
|
85
|
+
if(NOT SKBUILD)
|
|
86
|
+
find_package(SFML 2.5 COMPONENTS graphics window system QUIET)
|
|
87
|
+
if(SFML_FOUND)
|
|
88
|
+
add_executable(bird_solver src/bird_solver.cpp)
|
|
89
|
+
target_include_directories(bird_solver PRIVATE src)
|
|
90
|
+
target_link_libraries(bird_solver PRIVATE Eigen3::Eigen sfml-graphics sfml-window sfml-system sim_opts)
|
|
91
|
+
endif()
|
|
92
|
+
endif()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 1. Path to your virtual environment's python
|
|
2
|
+
# This ensures we use your .venv even if it isn't "activated" in the terminal
|
|
3
|
+
PYTHON = $(shell pwd)/.venv/bin/python3
|
|
4
|
+
THREADS = $(shell nproc)
|
|
5
|
+
|
|
6
|
+
init:
|
|
7
|
+
$(PYTHON) -m pip install -e .
|
|
8
|
+
all:
|
|
9
|
+
# Only configure if the build directory doesn't exist
|
|
10
|
+
@if [ ! -d "build" ]; then \
|
|
11
|
+
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release -DPython3_EXECUTABLE=$(PYTHON); \
|
|
12
|
+
fi
|
|
13
|
+
# Use -j to use all CPU cores
|
|
14
|
+
cmake --build build -j $(THREADS)
|
|
15
|
+
cp build/stochastic_flock*.so src/stochastic_flock
|
|
16
|
+
|
|
17
|
+
native:
|
|
18
|
+
cmake -B build_native -S . -DCMAKE_BUILD_TYPE=Release -DNATIVE_OPTIM=ON -DPython3_EXECUTABLE=$(PYTHON)
|
|
19
|
+
cmake --build build_native -j $(THREADS)
|
|
20
|
+
|
|
21
|
+
pgo: #only does bird_solver PGO
|
|
22
|
+
|
|
23
|
+
cmake -B build_pgo -S . -DCMAKE_BUILD_TYPE=Release -DNATIVE_OPTIM=ON -DCMAKE_CXX_FLAGS="-fprofile-generate" -DPython3_EXECUTABLE=$(PYTHON)
|
|
24
|
+
cmake --build build_pgo --target bird_solver -j $(THREADS)
|
|
25
|
+
|
|
26
|
+
./build_pgo/bird_solver
|
|
27
|
+
|
|
28
|
+
cmake -B build_pgo -S . -DCMAKE_BUILD_TYPE=Release -DNATIVE_OPTIM=ON -DCMAKE_CXX_FLAGS="-fprofile-use" -DPython3_EXECUTABLE=$(PYTHON)
|
|
29
|
+
cmake --build build_pgo --target bird_solver -j $(THREADS)
|
|
30
|
+
|
|
31
|
+
debug:
|
|
32
|
+
cmake -B build_debug -S . -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined" -DPython3_EXECUTABLE=$(PYTHON)
|
|
33
|
+
cmake --build build_debug -j $(THREADS)
|
|
34
|
+
|
|
35
|
+
clean:
|
|
36
|
+
rm -rf build build_native build_debug build_pgo *.so *.gcda dist
|
|
37
|
+
|
|
38
|
+
help:
|
|
39
|
+
@echo "all: Standard build"
|
|
40
|
+
@echo "native: Fast build with native hardware optimizations"
|
|
41
|
+
@echo "pgo: Profile guided optimization + native build, max performance"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: stochastic_flock
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unified Bird Flocking Simulation (1D & 2D)
|
|
5
|
+
Author-Email: Michael Stavreff <Mstavreff@outlook.com>
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Requires-Dist: numpy
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# High Performance C++ Flocking Simulation for Stochastic Modelling
|
|
13
|
+
> *Michael Stavreff,*
|
|
14
|
+
> *December 17, 2025*
|
|
15
|
+
## Development & Compilation
|
|
16
|
+
|
|
17
|
+
This project uses **CMake** and a **Makefile** to manage the C++ build process, dependencies (Eigen, pybind11), and performance optimizations.
|
|
18
|
+
|
|
19
|
+
### Prerequisites
|
|
20
|
+
|
|
21
|
+
To build the project from source, you will need:
|
|
22
|
+
* **C++20 Compiler** (GCC 10+ or Clang 11+)
|
|
23
|
+
* **CMake** (3.18+)
|
|
24
|
+
* **Python 3.8+** (with `python3-venv` and `python3-dev`)
|
|
25
|
+
* **SFML 2.5** (Optional: only required for the visual standalone solver)
|
|
26
|
+
```bash
|
|
27
|
+
sudo apt install libsfml-dev
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Developer Setup
|
|
31
|
+
1. Clone and create a virtual environment:
|
|
32
|
+
|
|
33
|
+
```Bash
|
|
34
|
+
git clone https://github.com/Mstavreff/stochastic_flock.git
|
|
35
|
+
cd stochastic_flock
|
|
36
|
+
python3 -m venv .venv
|
|
37
|
+
source .venv/bin/activate
|
|
38
|
+
```
|
|
39
|
+
2. Install build dependencies:
|
|
40
|
+
```Bash
|
|
41
|
+
pip install -r requirements.txt
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Building the Project
|
|
45
|
+
The provided Makefile contains shortcuts for common build scenarios.
|
|
46
|
+
1. Standard Build (Python + C++ Solver)
|
|
47
|
+
Compiles the Python module into the root directory and the standalone solver into build/.
|
|
48
|
+
|
|
49
|
+
```Bash
|
|
50
|
+
make
|
|
51
|
+
```
|
|
52
|
+
2. Native Hardware Optimization
|
|
53
|
+
Compiles using -march=native and -ffast-math. This produces the fastest possible binary for your specific CPU but is not portable to other hardware.
|
|
54
|
+
|
|
55
|
+
```Bash
|
|
56
|
+
make native
|
|
57
|
+
```
|
|
58
|
+
3. Profile-Guided Optimization (PGO) + Native
|
|
59
|
+
For maximum performance, use PGO to optimize code paths based on simulation data. Uses ```tuning.py``` to instrument and recompiles using native flags.
|
|
60
|
+
```Bash
|
|
61
|
+
make pgo
|
|
62
|
+
```
|
|
63
|
+
4. Debug Mode
|
|
64
|
+
Compiles with debug symbols (-g) and Undefined Behavior Sanitizers for use with GDB/LLDB.
|
|
65
|
+
|
|
66
|
+
```Bash
|
|
67
|
+
make debug
|
|
68
|
+
```
|
|
69
|
+
### Python Usage
|
|
70
|
+
|
|
71
|
+
If you simply wish to use the simulation in a Python environment without modifying the C++ source:
|
|
72
|
+
|
|
73
|
+
```Bash
|
|
74
|
+
pip install stochastic_flock
|
|
75
|
+
```
|
|
76
|
+
For local development, after running make, you can import the module directly in the root directory:
|
|
77
|
+
|
|
78
|
+
```Python
|
|
79
|
+
>>> import stochastic_flock
|
|
80
|
+
>>> sim = stochastic_flock.Simulation2d(params, seed)
|
|
81
|
+
```
|
|
82
|
+
## Introduction
|
|
83
|
+
Financial markets have famously exhibited flocking or herding behavior, most famously during crises and impending crashes. Such movements typically are completely unpredictable; the aim of this paper is to explore whether these movements are compltely unable to be modelled or are instead the product of some highly non-linear behavior requiring a novel approach. Naturally, birds in large flocks are an interesting candidate to model such emergent behavior in financial markets. Large flocks exhibit features which must be re-interpreted to a financial context, particularly in attraction, repulsion, turning behavior, and in the context of the particular paper, leader/follower dynamics:
|
|
84
|
+
|
|
85
|
+
### Reference Paper Overview
|
|
86
|
+
*The original paper is given here: https://arxiv.org/abs/2010.01990.* While the paper is short and concise and absolutely worth a read, some important details will be repeated.
|
|
87
|
+
|
|
88
|
+
Cristiani et al.'s paper puts forward a second-order, delayed, stochastic differential equation to describe accelerations of bird agents. The stochastic element stems from birds having an exponential process (geometric in approximation) describing a follower -> leader transition where any attractive forces are dropped in their acceleration calculation and causing only repulsive-force trajectories. Additionally, birds react to the positions of others in a rank-ordered system of the nearest M birds, irregardless of distance; they also react to the delayed positions rather than the most instant information, something which creates more heavy movements and drifting of flocks in practice. These behaviors underline various interpretations worth discussing in the paper, mostly regarding trader behaviors or modelling portfolios of correlated equities in a sector which may be driven by such "social" forces and similarly experience shocks or new information in the form of a leader bird.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
# High Performance C++ Flocking Simulation for Stochastic Modelling
|
|
4
|
+
> *Michael Stavreff,*
|
|
5
|
+
> *December 17, 2025*
|
|
6
|
+
## Development & Compilation
|
|
7
|
+
|
|
8
|
+
This project uses **CMake** and a **Makefile** to manage the C++ build process, dependencies (Eigen, pybind11), and performance optimizations.
|
|
9
|
+
|
|
10
|
+
### Prerequisites
|
|
11
|
+
|
|
12
|
+
To build the project from source, you will need:
|
|
13
|
+
* **C++20 Compiler** (GCC 10+ or Clang 11+)
|
|
14
|
+
* **CMake** (3.18+)
|
|
15
|
+
* **Python 3.8+** (with `python3-venv` and `python3-dev`)
|
|
16
|
+
* **SFML 2.5** (Optional: only required for the visual standalone solver)
|
|
17
|
+
```bash
|
|
18
|
+
sudo apt install libsfml-dev
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Developer Setup
|
|
22
|
+
1. Clone and create a virtual environment:
|
|
23
|
+
|
|
24
|
+
```Bash
|
|
25
|
+
git clone https://github.com/Mstavreff/stochastic_flock.git
|
|
26
|
+
cd stochastic_flock
|
|
27
|
+
python3 -m venv .venv
|
|
28
|
+
source .venv/bin/activate
|
|
29
|
+
```
|
|
30
|
+
2. Install build dependencies:
|
|
31
|
+
```Bash
|
|
32
|
+
pip install -r requirements.txt
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Building the Project
|
|
36
|
+
The provided Makefile contains shortcuts for common build scenarios.
|
|
37
|
+
1. Standard Build (Python + C++ Solver)
|
|
38
|
+
Compiles the Python module into the root directory and the standalone solver into build/.
|
|
39
|
+
|
|
40
|
+
```Bash
|
|
41
|
+
make
|
|
42
|
+
```
|
|
43
|
+
2. Native Hardware Optimization
|
|
44
|
+
Compiles using -march=native and -ffast-math. This produces the fastest possible binary for your specific CPU but is not portable to other hardware.
|
|
45
|
+
|
|
46
|
+
```Bash
|
|
47
|
+
make native
|
|
48
|
+
```
|
|
49
|
+
3. Profile-Guided Optimization (PGO) + Native
|
|
50
|
+
For maximum performance, use PGO to optimize code paths based on simulation data. Uses ```tuning.py``` to instrument and recompiles using native flags.
|
|
51
|
+
```Bash
|
|
52
|
+
make pgo
|
|
53
|
+
```
|
|
54
|
+
4. Debug Mode
|
|
55
|
+
Compiles with debug symbols (-g) and Undefined Behavior Sanitizers for use with GDB/LLDB.
|
|
56
|
+
|
|
57
|
+
```Bash
|
|
58
|
+
make debug
|
|
59
|
+
```
|
|
60
|
+
### Python Usage
|
|
61
|
+
|
|
62
|
+
If you simply wish to use the simulation in a Python environment without modifying the C++ source:
|
|
63
|
+
|
|
64
|
+
```Bash
|
|
65
|
+
pip install stochastic_flock
|
|
66
|
+
```
|
|
67
|
+
For local development, after running make, you can import the module directly in the root directory:
|
|
68
|
+
|
|
69
|
+
```Python
|
|
70
|
+
>>> import stochastic_flock
|
|
71
|
+
>>> sim = stochastic_flock.Simulation2d(params, seed)
|
|
72
|
+
```
|
|
73
|
+
## Introduction
|
|
74
|
+
Financial markets have famously exhibited flocking or herding behavior, most famously during crises and impending crashes. Such movements typically are completely unpredictable; the aim of this paper is to explore whether these movements are compltely unable to be modelled or are instead the product of some highly non-linear behavior requiring a novel approach. Naturally, birds in large flocks are an interesting candidate to model such emergent behavior in financial markets. Large flocks exhibit features which must be re-interpreted to a financial context, particularly in attraction, repulsion, turning behavior, and in the context of the particular paper, leader/follower dynamics:
|
|
75
|
+
|
|
76
|
+
### Reference Paper Overview
|
|
77
|
+
*The original paper is given here: https://arxiv.org/abs/2010.01990.* While the paper is short and concise and absolutely worth a read, some important details will be repeated.
|
|
78
|
+
|
|
79
|
+
Cristiani et al.'s paper puts forward a second-order, delayed, stochastic differential equation to describe accelerations of bird agents. The stochastic element stems from birds having an exponential process (geometric in approximation) describing a follower -> leader transition where any attractive forces are dropped in their acceleration calculation and causing only repulsive-force trajectories. Additionally, birds react to the positions of others in a rank-ordered system of the nearest M birds, irregardless of distance; they also react to the delayed positions rather than the most instant information, something which creates more heavy movements and drifting of flocks in practice. These behaviors underline various interpretations worth discussing in the paper, mostly regarding trader behaviors or modelling portfolios of correlated equities in a sector which may be driven by such "social" forces and similarly experience shocks or new information in the form of a leader bird.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["scikit-build-core>=0.8", "pybind11"]
|
|
3
|
+
build-backend = "scikit_build_core.build"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "stochastic_flock"
|
|
8
|
+
version = "0.1.0"
|
|
9
|
+
description = "Unified Bird Flocking Simulation (1D & 2D)"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Michael Stavreff", email = "Mstavreff@outlook.com"},
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"numpy",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[tool.scikit-build]
|
|
20
|
+
wheel.packages = ["src/stochastic_flock"]
|
|
21
|
+
editable.mode = "redirect"
|
|
22
|
+
cmake.args = ["-DSKBUILD=ON"]
|
|
23
|
+
build-dir = "build/{wheel_tag}"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#include "constants.hpp"
|
|
2
|
+
#include "simulation.hpp"
|
|
3
|
+
#include "visual.hpp"
|
|
4
|
+
|
|
5
|
+
#include <Eigen/Dense>
|
|
6
|
+
#include <SFML/Graphics.hpp>
|
|
7
|
+
#include <format>
|
|
8
|
+
#include <random>
|
|
9
|
+
#include <stdexcept>
|
|
10
|
+
#include <string>
|
|
11
|
+
#include <vector>
|
|
12
|
+
|
|
13
|
+
int main()
|
|
14
|
+
{
|
|
15
|
+
|
|
16
|
+
Parameters p;
|
|
17
|
+
int n_birds = 500;
|
|
18
|
+
double att = 0.03;
|
|
19
|
+
double rep = 2.5;
|
|
20
|
+
std::cout << "birds: ";
|
|
21
|
+
std::cin >> n_birds;
|
|
22
|
+
std::cout << "\n";
|
|
23
|
+
std::cout << "attraction: ";
|
|
24
|
+
std::cin >> att;
|
|
25
|
+
std::cout << "\n";
|
|
26
|
+
std::cout << "repulsion: ";
|
|
27
|
+
std::cin >> rep;
|
|
28
|
+
std::cout << "\n";
|
|
29
|
+
|
|
30
|
+
p.kWIDTH_2D = 2100;
|
|
31
|
+
p.kHEIGHT_2D = 1300;
|
|
32
|
+
p.kREP = rep;
|
|
33
|
+
p.kATT = att;
|
|
34
|
+
p.kFRAMERATE = 1000;
|
|
35
|
+
p.kN_BIRDS = n_birds;
|
|
36
|
+
p.kROUNDS = 1000000;
|
|
37
|
+
std::mt19937 mt;
|
|
38
|
+
mt.seed(std::random_device{}());
|
|
39
|
+
// mt.seed(50);
|
|
40
|
+
|
|
41
|
+
Eigen::Matrix<double, Eigen::Dynamic, 4> positions;
|
|
42
|
+
positions.resize(p.kN_BIRDS, 4);
|
|
43
|
+
positions = positions.setRandom() * 100;
|
|
44
|
+
|
|
45
|
+
Simulation2d<> Sim(p, mt, positions);
|
|
46
|
+
init_simulation(Sim);
|
|
47
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
inline constexpr int kFRAMERATE{60};
|
|
4
|
+
inline constexpr int kROUNDS{10000};
|
|
5
|
+
// Higher dimensional parameters
|
|
6
|
+
inline constexpr int kTREE_MEDIAN_SAMPLE{30}; // could profile
|
|
7
|
+
inline constexpr int kLEAF_SIZE{16}; // double once using floats to fit SIMD registers better, could profile
|
|
8
|
+
inline constexpr double kPRUNE_EPS{0.01}; // for approximate KD tree pruning
|
|
9
|
+
inline constexpr double kAPPROX_PRUNE_FACTOR{1.0 / ((1.0 + kPRUNE_EPS) * (1.0 + kPRUNE_EPS))};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#include "simulation.hpp"
|
|
2
|
+
// #include "visual.hpp"
|
|
3
|
+
#include <pybind11/eigen.h>
|
|
4
|
+
#include <pybind11/pybind11.h>
|
|
5
|
+
#include <pybind11/stl.h>
|
|
6
|
+
|
|
7
|
+
namespace py = pybind11;
|
|
8
|
+
using Sim1d = Simulation1d<Eigen::Dynamic>;
|
|
9
|
+
using Sim2d = Simulation2d<Eigen::Dynamic>;
|
|
10
|
+
void init_simulation(Sim2d &sim);
|
|
11
|
+
|
|
12
|
+
void bind_parameters(py::module &m)
|
|
13
|
+
{
|
|
14
|
+
py::class_<Parameters>(m, "Parameters")
|
|
15
|
+
.def(py::init<>())
|
|
16
|
+
.def_readwrite("kN_BIRDS", &Parameters::kN_BIRDS)
|
|
17
|
+
.def_readwrite("kM", &Parameters::kM)
|
|
18
|
+
.def_readwrite("kDELAY", &Parameters::kDELAY)
|
|
19
|
+
.def_readwrite("kPT", &Parameters::kPT)
|
|
20
|
+
.def_readwrite("kPD", &Parameters::kPD)
|
|
21
|
+
.def_readwrite("kRT", &Parameters::kRT)
|
|
22
|
+
.def_readwrite("kREP", &Parameters::kREP)
|
|
23
|
+
.def_readwrite("kALI", &Parameters::kALI)
|
|
24
|
+
.def_readwrite("kATT", &Parameters::kATT)
|
|
25
|
+
.def_readwrite("kTIMESTEP", &Parameters::kTIMESTEP)
|
|
26
|
+
.def_readwrite("kROUNDS", &Parameters::kROUNDS)
|
|
27
|
+
.def_readwrite("kPROBABILITY", &Parameters::kPROBABILITY)
|
|
28
|
+
.def_readwrite("kBOX_SIZE", &Parameters::kBOX_SIZE)
|
|
29
|
+
.def_readwrite("kEPSILON", &Parameters::kEPSILON)
|
|
30
|
+
.def_readwrite("kBUFFER_CYCLES", &Parameters::kBUFFER_CYCLES); // must be calculated manually in python
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
PYBIND11_MODULE(stochastic_flock, m)
|
|
34
|
+
{
|
|
35
|
+
m.doc() = "Agent-Based Bird Flocking Simulation";
|
|
36
|
+
|
|
37
|
+
bind_parameters(m);
|
|
38
|
+
|
|
39
|
+
py::class_<std::mt19937>(m, "MT19937").def(py::init<uint32_t>());
|
|
40
|
+
|
|
41
|
+
// py::class_<Sim1d>(m, "Simulation1d")
|
|
42
|
+
// .def(py::init<Parameters &, std::mt19937 &>())
|
|
43
|
+
// .def("update",
|
|
44
|
+
// [](Sim1d &self) {
|
|
45
|
+
// self.update_state();
|
|
46
|
+
// self.shift_back();
|
|
47
|
+
// })
|
|
48
|
+
// .def_property_readonly("states", [](Sim1d &self) { return self.states; })
|
|
49
|
+
// .def_property_readonly("positions", [](Sim1d &self) { return self.states.col(0); })
|
|
50
|
+
// .def_property_readonly("velocities", [](Sim1d &self) { return self.states.col(1); })
|
|
51
|
+
// .def_property_readonly("status", [](Sim1d &self) { return self.states.col(2); })
|
|
52
|
+
// .def_property_readonly("timers", [](Sim1d &self) { return self.timer_states; });
|
|
53
|
+
|
|
54
|
+
py::class_<Sim2d>(m, "Simulation2d")
|
|
55
|
+
.def(py::init<Parameters &, std::mt19937 &, const std::optional<Eigen::Matrix<double, Eigen::Dynamic, 4>> &>(),
|
|
56
|
+
py::arg("params"), py::arg("seed"), py::arg("start_conditions") = std::nullopt)
|
|
57
|
+
.def("update",
|
|
58
|
+
[](Sim2d &self) {
|
|
59
|
+
self.update_state();
|
|
60
|
+
self.shift_back();
|
|
61
|
+
})
|
|
62
|
+
.def("debug_tree", &Sim2d::debug_print_tree, py::arg("i") = 0, py::arg("indent") = 0)
|
|
63
|
+
// .def("show",
|
|
64
|
+
// [](Sim2d &self) {
|
|
65
|
+
// py::gil_scoped_release release; // Allows other Python threads to run while window is open
|
|
66
|
+
// init_simulation_fontless(self);
|
|
67
|
+
// })
|
|
68
|
+
|
|
69
|
+
.def_property_readonly("states", [](Sim2d &self) { return self.states; })
|
|
70
|
+
.def_property_readonly("positions", [](Sim2d &self) { return self.states.leftCols(2); })
|
|
71
|
+
.def_property_readonly("velocities", [](Sim2d &self) { return self.states.middleCols(2, 2); })
|
|
72
|
+
.def_property_readonly("status", [](Sim2d &self) { return self.states.col(4); })
|
|
73
|
+
.def_property_readonly("timers", [](Sim2d &self) { return self.timer_states; });
|
|
74
|
+
}
|