Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d34e483
chore: remove duplicated and internal files
HadenSmith Apr 23, 2026
0bc345c
feat: auto-discover Numerics DLL via resolve_numerics_dll() helper
HadenSmith Apr 23, 2026
9642b47
fix(nb00): typos, kurtosis convention note, cleared leaked path
HadenSmith Apr 23, 2026
311b263
fix(nb01): GEV Hosking labels, Pearson kurtosis note, Triangular typos
HadenSmith Apr 23, 2026
c7332c2
fix(nb02): correct comparison labels; log-likelihood direction; title…
HadenSmith Apr 23, 2026
160be57
fix(nb10): Quarterly spelling; missing-value count uses gap series
HadenSmith Apr 23, 2026
270066d
fix(nb11): KMeans matrix shape; benchmark caveat; regressor max_featu…
HadenSmith Apr 23, 2026
8f87c90
fix(nb03): remove dead ThreadPool.SetMaxThreads workaround (H14)
HadenSmith Apr 23, 2026
4ca962a
fix(nb04): Normal-fit header label; linear-models cross-ref; ThreadPo…
HadenSmith Apr 23, 2026
4e36b11
chore(nb07,nb09,nb12): re-execute to regenerate outputs
HadenSmith Apr 23, 2026
c999c54
fix(nb05): retool HMC/NUTS example to Gumbel; Weibull label swap; cit…
HadenSmith Apr 23, 2026
0f01387
fix(nb06): DEMCz property names; title typo; ThreadPool cleanup
HadenSmith Apr 23, 2026
c9962d0
feat(nb08): global-optimizer convergence + path plots; strip anim HTML
HadenSmith Apr 23, 2026
a57ce62
fix(examples): remove dead ThreadPool workaround; docstring typo
HadenSmith Apr 23, 2026
03f8100
docs: CITATION.cff (version, repo-code, ORCIDs) and CONTRIBUTING.md p…
HadenSmith Apr 23, 2026
6dc23e8
fix(nb08): Eggholder MLSL/SCE settings; Func import; convergence plot…
HadenSmith Apr 23, 2026
720c500
fix(nb03): replace non-existent SampleSize/BurnInSamples in commented…
HadenSmith Apr 23, 2026
a0ddf5e
fix(notebooks): MCMC note cells as markdown; drop nb08 animations
HadenSmith Apr 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -398,12 +398,23 @@ FodyWeavers.xsd

# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets

# Claude Code session state
.claude/

# Local NuGet package install location (populated by `nuget install -OutputDirectory packages`)
packages/

# Python virtual environments
.venv/
venv/

# Jupyter checkpoint snapshots
**/.ipynb_checkpoints/

# Local History for Visual Studio Code
.history/

Expand Down
6 changes: 0 additions & 6 deletions .vscode/extensions.json

This file was deleted.

5 changes: 0 additions & 5 deletions .vscode/settings.json

This file was deleted.

9 changes: 5 additions & 4 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ cff-version: 1.2.0
message: "If you use this software, please cite it using the information below."
type: software
title: "Numerics-Python-Examples"
version: 0.0.0
repository-code:
date-released: "2026-03-30"
version: "1.0.0"
repository-code: "https://github.com/USACE-RMC/Numerics-Python-Examples"
date-released: "2026-04-23"
license: BSD-3-Clause
url: "https://github.com/USACE-RMC/Numerics-Python-Examples.git"
abstract: >-
Expand All @@ -26,9 +26,10 @@ authors:
affiliation: "U.S. Army Corps of Engineers, Risk Management Center"
orcid: "https://orcid.org/0009-0008-8588-4816"
- family-names: "Gonzalez"
given-names: "Tiki"
given-names: "Julian"
email: "julian.t.gonzalez@usace.army.mil"
affiliation: "U.S. Army Corps of Engineers, Risk Management Center"
orcid: "https://orcid.org/0009-0009-9058-7653"
- family-names: "Smith"
given-names: "C. Haden"
email: "cole.h.smith@usace.army.mil"
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ Given the life-safety applications of Numerics, which this demo is an extension
Pull requests may take several weeks or longer to review. Before submitting code:

1. **Open an issue first** to discuss the proposed change
2. **Follow the coding standards**, including XML documentation on all public types and members
3. **Include unit tests** that validate against known results (R, SciPy, Mathematica, or published tables)
5. **Ensure a clean build** with zero errors and zero warnings
2. **Follow PEP 8** and add docstrings to new functions and modules; clear notebook outputs before submitting (`jupyter nbconvert --clear-output --inplace notebooks/*.ipynb`)
3. **Include validation** against known results (R, SciPy, Mathematica, or published tables) where applicable
4. **Ensure notebooks run end to end** without errors in a fresh virtual environment

## Developer Certificate of Origin

Expand Down
98 changes: 62 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Numerics Python Examples
# Numerics Python Examples

This repository contains Python notebooks that demonstrate the Numerics .NET library through pythonnet. The notebooks provide practical, reproducible examples of Numerics applications, including distribution fitting, MCMC, optimization, statistical analysis, time series analysis, machine learning, and linear model fitting.

Expand All @@ -22,60 +22,86 @@ This repository contains Python notebooks that demonstrate the Numerics .NET lib
- `12_linear_models.ipynb` Linear/GLM workflows

## Prerequisites
- Windows with .NET installed (or .NET 6+ runtime on Linux/macOS)
- Python with [pythonnet](https://github.com/pythonnet/pythonnet)
- Numerics built and compiled locally. The resulting DLL path must match the path referenced in the notebooks — see Quick Start and/or notebook 00 for setup instructions.
- Python **3.10–3.13** recommended. pythonnet does not yet support Python 3.14.
- .NET 6+ runtime (or .NET Framework 4.8.1 on Windows). Install the [.NET SDK](https://dotnet.microsoft.com/download) if you don't already have it.
- The [RMC.Numerics](https://www.nuget.org/packages/RMC.Numerics) NuGet package (see Quick Start).

## Quick Start
The quick start will step through the creation of an active python environment, installing the notebook requirements & RMC-Numerics, and getting the methods ready to be used. For a more in depth walk through see notebook 00.
**NOTE:** This set up is geared towards Windows users. For other operating systems see notebook 00.
The quick start will walk you through creating a virtual Python environment, installing the notebook requirements, and pulling in the `RMC.Numerics` NuGet package. For a more in-depth walkthrough see notebook [`00_getting_started.ipynb`](notebooks/00_getting_started.ipynb).
**NOTE:** The commands below assume Windows. See notebook `00` for macOS/Linux equivalents.

1. Create and activate a virtual Python environment
```bash
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install ipykernel
python -m ipykernel install --user --name=.venv --display-name "Python (.venv)"
```

2. Install notebook requirements
```bash
pip install -r notebook-requirements.txt
```
```bash
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install ipykernel
python -m ipykernel install --user --name=.venv --display-name "Python (.venv)"
```

2. Install the Python requirements

```bash
pip install -r notebook-requirements.txt
```

3. Install the `RMC.Numerics` NuGet package

```bash
# Option A — global NuGet cache (recommended; requires the .NET SDK):
dotnet add package RMC.Numerics

# Option B — local packages/ folder (requires nuget.exe on PATH):
nuget install RMC.Numerics -OutputDirectory packages
```

Both commands pull the **latest** published version by default. This demo was built against version `2.0.1`; to pin that version, append `--version 2.0.1` (Option A) or `-Version 2.0.1` (Option B).

The notebooks auto-discover the DLL in either location via `resolve_numerics_dll()` in [`notebooks/helper_functions.py`](notebooks/helper_functions.py).

4. Load Numerics in a notebook or script

```python
import pythonnet
pythonnet.load("coreclr")

import clr
from helper_functions import resolve_numerics_dll
clr.AddReference(str(resolve_numerics_dll()))
```

5. Create a Normal distribution

```python
from Numerics.Distributions import Normal
dist = Normal(100, 15)
```

## Using a local Numerics build instead of NuGet

If you prefer to build Numerics from source — for example, to develop against the latest `main` branch — clone the [Numerics](https://github.com/USACE-RMC/Numerics) repo and build it:

3. Install and build Numerics
```bash
git clone https://github.com/USACE-RMC/Numerics.git
cd Numerics
dotnet build Numerics.sln --configuration Release
```

4. Load and confirm the DLL path
```bash
import pythonnet
pythonnet.load("coreclr")
Then point the notebooks at your build by setting the `NUMERICS_DLL` environment variable before launching Jupyter:

import clr
from pathlib import Path
```powershell
# PowerShell
$env:NUMERICS_DLL = "C:\path\to\Numerics\Numerics\bin\Release\net8.0\Numerics.dll"

# Path to your Numerics.dll
# MODIFY THIS PATH to make your installation
dll_path = Path(r"C:\GIT\Numerics\Numerics\bin\Debug\net8.0\Numerics.dll")
clr.AddReference(str(dll_path))
# bash / zsh
export NUMERICS_DLL=/path/to/Numerics/Numerics/bin/Release/net8.0/Numerics.dll
```

5. Create a Normal Distribution
```bash
from Numerics.Distributions import Normal
dist = Normal(100,15)
```
`resolve_numerics_dll()` uses this variable first, then falls back to the NuGet cache and finally a local `packages/` folder.

## Notes
- These notebooks compare Numerics to common Python libraries where relevant. When comparing MCMC chains, align warmup/thinning settings.
- Many examples use synthetic data to keep results consistent and easy to interpret.

## How To Update DLL Path
If your Numerics build output is in a different location, update the DLL path in the setup cell of each notebook. Search for `Numerics.dll` and replace the path with your local build output.

## License
See the Numerics project license for usage and distribution terms.
This project is released under the [USACE-RMC license](LICENSE). It is compatible with the parent [Numerics project license](https://github.com/USACE-RMC/Numerics/blob/main/LICENSE).
50 changes: 30 additions & 20 deletions examples/bayesian_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
and tables will be output to the terminal.
"""

import os
from pathlib import Path

import matplotlib.pyplot as plt
Expand All @@ -14,12 +15,29 @@
import clr


def _resolve_numerics_dll():
"""Resolve Numerics.dll from NUMERICS_DLL env var, the NuGet cache, or a local packages/ folder."""
env = os.environ.get("NUMERICS_DLL")
if env:
return Path(env)
cache = Path.home() / ".nuget" / "packages" / "rmc.numerics"
if cache.exists():
hits = sorted(cache.glob("*/lib/net8.0/Numerics.dll"), reverse=True)
if hits:
return hits[0]
for root in (Path.cwd(), Path(__file__).parent.parent):
local = sorted((root / "packages").glob("RMC.Numerics.*/lib/net8.0/Numerics.dll"), reverse=True)
if local:
return local[0]
raise FileNotFoundError(
"Numerics DLL not found. Install via `dotnet add package RMC.Numerics` "
"(pulls latest; append `--version 2.0.1` to pin) or set the NUMERICS_DLL "
"environment variable."
)


def load_numerics():
dll_path = Path(r"C:\GIT\Numerics\Numerics\bin\Debug\net8.0\Numerics.dll")
if not dll_path.exists():
raise FileNotFoundError(
f"Numerics DLL not found at {dll_path}. Update `dll_path` in this script."
)
dll_path = _resolve_numerics_dll()
clr.AddReference(str(dll_path))


Expand All @@ -29,21 +47,13 @@ def main(seed=123):
from Numerics.Distributions import IUnivariateDistribution, Normal, Uniform
from Numerics.Sampling.MCMC import DEMCzs, LogLikelihood, MCMCResults
from System.Collections.Generic import List
from System.Threading import ThreadPool
import os

''' NOTE FOR DEMO USERS:
When calling Numerics MCMC samplers from Python via pythonnet, the samplers'
internal parallel chains (Parallel.For) contend for Python's Global Interpreter
Lock (GIL). This makes parallel execution slower than sequential. Setting
max thread pool workers to 1 forces sequential execution and removes that
overhead. In pure C#, you can remove this line and parallelism will work as
intended.

This is also why we set sampler.ParallelizeChains = False for every example.
It defaults to True, which works well in C#, but it slows the sampler down
in Python'''
ThreadPool.SetMaxThreads(1, 1) # (workerThreads, completionPortThreads)

# NOTE FOR DEMO USERS:
# When calling Numerics MCMC samplers from Python via pythonnet, the samplers'
# internal parallel chains (Parallel.For) contend for Python's Global Interpreter
# Lock (GIL). This makes parallel execution slower than sequential. This is why
# we set sampler.ParallelizeChains = False below. It defaults to True, which
# works well in C#, but it slows the sampler down when driven from Python.

x = np.linspace(0, 10, 80)
true_a, true_b, true_sigma = 2.0, 1.4, 1.2
Expand Down
28 changes: 23 additions & 5 deletions examples/flood_frequency_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
and tables will be output to the terminal.
"""

import os
from pathlib import Path

import matplotlib.pyplot as plt
Expand All @@ -13,12 +14,29 @@
import clr


def _resolve_numerics_dll():
"""Resolve Numerics.dll from NUMERICS_DLL env var, the NuGet cache, or a local packages/ folder."""
env = os.environ.get("NUMERICS_DLL")
if env:
return Path(env)
cache = Path.home() / ".nuget" / "packages" / "rmc.numerics"
if cache.exists():
hits = sorted(cache.glob("*/lib/net8.0/Numerics.dll"), reverse=True)
if hits:
return hits[0]
for root in (Path.cwd(), Path(__file__).parent.parent):
local = sorted((root / "packages").glob("RMC.Numerics.*/lib/net8.0/Numerics.dll"), reverse=True)
if local:
return local[0]
raise FileNotFoundError(
"Numerics DLL not found. Install via `dotnet add package RMC.Numerics` "
"(pulls latest; append `--version 2.0.1` to pin) or set the NUMERICS_DLL "
"environment variable."
)


def load_numerics():
dll_path = Path(r"C:\GIT\Numerics\Numerics\bin\Debug\net8.0\Numerics.dll")
if not dll_path.exists():
raise FileNotFoundError(
f"Numerics DLL not found at {dll_path}. Update `dll_path` in this script."
)
dll_path = _resolve_numerics_dll()
clr.AddReference(str(dll_path))


Expand Down
32 changes: 25 additions & 7 deletions examples/reliability_analysis.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Reliability analysis demo using Monte Carlo simulation. Once this file runs you will have a popup window of graphs
and tables will be ouput to the terminal."""
"""Reliability analysis demo using Monte Carlo simulation. Once this file runs you will have a popup window of graphs
and tables will be output to the terminal."""

import math
import os
from pathlib import Path

import matplotlib.pyplot as plt
Expand All @@ -14,12 +15,29 @@
import clr


def _resolve_numerics_dll():
"""Resolve Numerics.dll from NUMERICS_DLL env var, the NuGet cache, or a local packages/ folder."""
env = os.environ.get("NUMERICS_DLL")
if env:
return Path(env)
cache = Path.home() / ".nuget" / "packages" / "rmc.numerics"
if cache.exists():
hits = sorted(cache.glob("*/lib/net8.0/Numerics.dll"), reverse=True)
if hits:
return hits[0]
for root in (Path.cwd(), Path(__file__).parent.parent):
local = sorted((root / "packages").glob("RMC.Numerics.*/lib/net8.0/Numerics.dll"), reverse=True)
if local:
return local[0]
raise FileNotFoundError(
"Numerics DLL not found. Install via `dotnet add package RMC.Numerics` "
"(pulls latest; append `--version 2.0.1` to pin) or set the NUMERICS_DLL "
"environment variable."
)


def load_numerics():
dll_path = Path(r"C:\GIT\Numerics\Numerics\bin\Debug\net8.0\Numerics.dll")
if not dll_path.exists():
raise FileNotFoundError(
f"Numerics DLL not found at {dll_path}. Update `dll_path` in this script."
)
dll_path = _resolve_numerics_dll()
clr.AddReference(str(dll_path))


Expand Down
Loading