Skip to content

Code review fixes + launch readiness for public release - #1

Merged
HadenSmith merged 18 commits into
mainfrom
code-review-fixes-and-enhancements
Apr 23, 2026
Merged

Code review fixes + launch readiness for public release#1
HadenSmith merged 18 commits into
mainfrom
code-review-fixes-and-enhancements

Conversation

@HadenSmith

Copy link
Copy Markdown
Contributor

Summary

Two-phase code-review + launch-readiness pass before flipping the repo public. 17 commits on this branch touch every notebook, all three example scripts, README, CITATION.cff, CONTRIBUTING.md, and .gitignore.

Correctness fixes — verified against the Numerics C# source

  • nb06: demcz.BurnIn / demcz.SampleSize don't exist as properties. pythonnet silently created phantom attributes, so the multimodal-mixture demo ran with default 1750/3500 iterations while advertising 10,000. Fixed to WarmupIterations / Iterations.
  • nb11: KMeans examples were feeding samples-as-columns matrices. The committed output literally said Samples: 4, Features: 150 for Iris. Fixed via Matrix(convert_to_dotnet_2d_array(X)).
  • nb05: Weibull-vs-PyMC table had κ/λ labels swapped; saved output showed a fake ~478,851% "difference". Swapped so Lambda lines up with ParameterResults[0] and Kappa with ParameterResults[1].
  • nb01 GEV: Hosking-convention type bullets were backwards. κ<0 gives a finite lower bound (Fréchet); κ>0 gives a finite upper bound (Weibull).
  • nb02: prose promised "Normal (MOM) / LogNormal (MLE) / GEV (L-Moments)" but all three code fits were LogNormal. Labels now match.
  • nb03-06: removed dead ThreadPool.SetMaxThreads(1, 1) workaround (silently returned False on multi-core; visible in saved output). sampler.ParallelizeChains = False is the correct fix and was already set.
  • nb03: commented-out hint lines suggested SampleSize and BurnInSamples — neither exists on MCMCSampler. Replaced with real Iterations and WarmupIterations.

UX: RMC.Numerics NuGet-based DLL resolution

  • New resolve_numerics_dll() in notebooks/helper_functions.py auto-discovers Numerics.dll via NUMERICS_DLL env var → global NuGet cache → local packages/ folder.
  • README Quick Start switches from git clone + dotnet build to dotnet add package RMC.Numerics (pulls latest; pin with --version 2.0.1).
  • All 13 notebooks + 3 example scripts use the resolver — no more per-user path editing.

nb08 feature additions

  • Best-objective-vs-function-evaluations convergence plot comparing PSO / SA / DE / MultiStart / MLSL / SCE on 2D Rosenbrock (auto-zoomed x-axis so SA's long run doesn't dominate).
  • 2×3 grid of Rosenbrock contour plots with each optimizer's accepted-step path overlaid.
  • Added "Best f(x,y)" and "Func Evals" columns to per-function benchmark tables.
  • MLSL/SCE Eggholder settings now match Test_MLSL.Test_Eggholder (SampleSize=200) and Test_ShuffledComplexEvolution.Test_Eggholder (Complexes=30, CCEIterations=10). Both methods now find the global minimum at (512, 404.2319), f ≈ -959.64.
  • Defensive imports on the Eggholder cell so it runs standalone against a restarted kernel.
  • Stripped ~138 MB of embedded anim.to_jshtml() HTML outputs before commit; PNG plots retained; animations regenerate locally.

nb05 Weibull/NUTS → Gumbel retool

Weibull's numerical-derivative surface thrashes HMC/NUTS step-size adaptation. Swapped the gradient-sampler comparison to a Gumbel target, matching the pattern Numerics itself uses in Test_NUTS.Test_NUTS_GumbelDist_RStan.

Metadata

  • CITATION.cff: populated blank repository-code, version 1.0.0, date-released: "2026-04-23", author "Tiki" → "Julian" to match parent repo, added ORCID for Julian Gonzalez. All three authors now have ORCIDs.
  • CONTRIBUTING.md: replaced C#-specific "XML documentation on all public types" with PEP 8 + docstring guidance; "notebooks run end to end without errors" in the last bullet.
  • README: Python-fenced code blocks (were bash), Debug→Release build path, Python 3.10–3.13 recommendation (pythonnet doesn't yet support 3.14), link to this repo's own LICENSE.

Hygiene

  • Removed duplicate gitignore.txt, internal scoping doc, tracked .pyc, .vscode/settings.json, .vscode/extensions.json.
  • Added .claude/, .venv/, venv/, packages/ to .gitignore.

Test plan

  • Fresh Python 3.12 venv + pip install -r notebook-requirements.txt
  • dotnet add package RMC.Numerics --version 2.0.1 installed to global cache
  • Smoke test: Normal(100, 15).Mean == 100.0
  • Every notebook (00–12) re-executed end-to-end via jupyter nbconvert --execute — zero error cells
  • examples/flood_frequency_analysis.py and examples/reliability_analysis.py smoke-run against NuGet-installed DLL
  • Verified nb11 KMeans output reports Samples: 150, Features: 4
  • Verified nb06 multimodal DEMCz runs 10,000 iterations (not the 3,500 default)
  • Verified nb08 Eggholder: MLSL finds f≈-959.66, SCE finds f=-959.64
  • git grep for C:\GIT\Numerics\...\bin\Debug, BurnIn/SampleSize MCMC properties, ThreadPool.SetMaxThreads → all empty

- Remove gitignore.txt (byte-for-byte duplicate of .gitignore)
- Remove numerics-python-demos-scope.md (internal planning doc)
- Untrack notebooks/__pycache__/helper_functions.cpython-313.pyc (Python-version-specific bytecode)
- Untrack .vscode/settings.json and .vscode/extensions.json (personal IDE config with AI-assistant extension recommendations; drop the whitelist lines from .gitignore)
Replace per-machine hard-coded DLL paths across all 13 notebooks,
3 example scripts, and the README Quick Start with a resolver that
searches in order:
  1. NUMERICS_DLL environment variable (explicit override)
  2. Global NuGet cache (~/.nuget/packages/rmc.numerics/...)
  3. Local ./packages/ folder (from nuget install -OutputDirectory)

The helper lives in notebooks/helper_functions.py and is inlined into
examples/*.py so they can run without the helper module on sys.path.

README Quick Start now installs the RMC.Numerics 2.0.1 NuGet package
via `dotnet add package` (or `nuget install`) instead of cloning and
building Numerics from source. The clone-and-build path is retained
as a developer option via the NUMERICS_DLL env var.

Notebook 00 is rewritten to introduce the resolver and to make the
Test_Numerics demo optional (gated on NUMERICS_TEST_DLL, since
Test_Numerics is not distributed via NuGet).

Also adds .claude/ and packages/ to .gitignore.
nb00 edits:
- 5 H8 typos: Crl+Shift+P, Instal ipykernel, Mac/Linx (x3), verison 2
- convert_to_donet_2d_array -> convert_to_dotnet_2d_array (would NameError)
- Kurtosis note clarifying Numerics returns Pearson (non-excess), since
  scipy/numpy users typically see excess kurtosis = 0 for a Normal
- Cleared outputs of DLL-load cell (65dc539a) to remove leaked
  C:\Users\haden\... personal path from the saved notebook

Repo-wide: unpin RMC.Numerics NuGet install to pull latest by default
(both dotnet add package and nuget install). Append --version 2.0.1 /
-Version 2.0.1 to pin. Touches README Quick Start, notebook-requirements,
helper_functions.py error message, and all 3 example scripts.

Also: add .venv/ and venv/ to .gitignore.
Technical correctness:
- GEV type bullets were swapped vs Numerics' Hosking parameterization.
  Per GeneralizedExtremeValue.cs:302-331, kappa<0 gives a finite lower
  bound and unbounded upper tail (Fréchet); kappa>0 gives a finite upper
  bound (Weibull). The notebook had the labels reversed.
- Also fix the example cell's legend labels and variable names to match.

Pearson kurtosis note (H12): add a one-line clarifier after the Normal
moments table matching the note we already landed in nb00, so readers
comparing to scipy/numpy (which report excess = 0 for Normal) understand
why Numerics returns 3.

Triangular typos (M8): 'When to us:' -> 'When to use:'; heading level
'#####' -> '####' to match every other distribution section.

Minor typos: 'ploting' -> 'plotting' (code comment), 'specifcs' ->
'specifics' (printed string, appeared in cell output).

Notebook re-executed end to end with UTF-8 forced; no leaked paths in
outputs.
… spacing

- C5: three fits are all LogNormal (MOM, MLE, L-Moments). Prose and labels
  in the comparison table and CDF plot were calling them Normal/LogNormal/
  GEV, which was factually wrong given the code.
- H13: 'smaller, less negative log-likelihood' flipped the direction. It's
  larger (less negative) that indicates a better fit.
- H10: title was '02.Distribution Fitting'; fixed to '02. Distribution
  Fitting' for consistency with other notebook titles.
- H9: 'Quartly Maxima' / 'Quartly Peak' / 'Qaurterly Peak' were all
  misspellings of 'Quarterly'. Fixed in the table header, plot title, and
  axis label.
- M5: missing_before was computed on the clean daily series `ts`, which
  has zero missing values, so the before/after comparison was misleading.
  Changed to the gap series `ts_gap`.
…res; k=2.6

- C2 (the big one): the Iris and synthetic-blobs KMeans examples were
  feeding Numerics matrices with samples-as-columns instead of
  samples-as-rows. The Matrix(List<double[]>) constructor defaults to
  byColumn=true, so the original code produced a 4x150 matrix for Iris
  and KMeans clustered "4 samples of 150 features" — the dataset summary
  correctly reported this but it was nonsense. Switched both cells to use
  convert_to_dotnet_2d_array(X) so the shape matches numpy's (N, D).
- H15: benchmark's regressor was setting Features=p//3 while sklearn's
  RandomForestRegressor default is max_features=1.0 (all features). Now
  uses all features on both sides so it's apples-to-apples.
- M10: added a one-sentence factual caveat above the benchmark table
  clarifying that the runtime gap is an implementation difference (C# vs
  Cython), not a pythonnet/GIL issue.
- M7: exercise typo 'Fit K Means with k=2.6' (non-integer k) -> 'k=2, 3, 4,
  5, 6 and plot the inertia for each'.
The setup cell imported System.Threading.ThreadPool and called
`ThreadPool.SetMaxThreads(1, 1)` to "force sequential execution" for MCMC
samplers. On any multi-core machine the call silently returns False
(visible in the saved output), so the line did nothing. The real fix is
`sampler.ParallelizeChains = False`, which every example below already
sets. Dropped the import, the dead call, and the now-orphan "optional
restore" commented block. Tightened the NOTE FOR DEMO USERS comment to
stop mentioning the deleted workaround.
…ol cleanup

- H11: the Normal-fitting cell printed 'Logistic Distribution Results' as
  a header, a copy-paste artifact from the Logistic section below.
  Changed to 'Normal Distribution Results'.
- H11: markdown said 'We go into more detail on this topic in notebook 10!'
  when the linear-models notebook is actually notebook 12. Fixed the
  cross-reference.
- H14: same ThreadPool cleanup as nb03.
No source-code changes. These notebooks had no pre-flagged issues; this
is just a clean re-run against the current resolver and NuGet-installed
RMC.Numerics 2.0.1 so the committed outputs reflect the launch state.
…ation; typo

User ask: Weibull is among the slowest distributions for HMC/NUTS because
its numerical-derivative surface can force the step-size adaptation to
thrash. Swapped the gradient-sampler comparison cell to a Gumbel example,
which has a smooth log-density that plays well with HMC/NUTS (same pattern
used in Test_NUTS.Test_NUTS_GumbelDist_RStan for the library's own
regression test against rstan). ARWMH/DEMCz/DEMCzs/HMC/NUTS are still all
compared head-to-head; only the target distribution changed.

Also:
- H5: Weibull-vs-PyMC comparison table had Kappa/Lambda column labels
  swapped vs the Numerics prior order ([lambda_prior, kappa_prior]).
  The stored output showed a fake ~478,851% "difference" from PyMC that
  made Numerics look broken. Fixed the label order and comparisonResults
  so Lambda and Kappa line up on both sides.
- M9: ARWMH citation pointed to [2] (Roberts 1997) but should point to [1]
  (Haario, Saksman, Tamminen 2001), the paper that actually introduces the
  adaptive algorithm. Fixed.
- Spelling: "Adaptive Random Walk Metroplis Hastings" -> "Metropolis-
  Hastings" in the section header and the inline mention (both appeared
  verbatim in rendered output).
- H14: dropped the dead ThreadPool.SetMaxThreads workaround, same cleanup
  as nb03/nb04/nb06.
- C4: the multimodal-mixture cell set demcz.BurnIn = 3000 and
  demcz.SampleSize = 10000, but Numerics MCMCSampler exposes
  WarmupIterations (default 1750) and Iterations (default 3500) — not
  BurnIn/SampleSize. pythonnet silently creates phantom Python attributes
  for unknown setters, so the sampler was running with defaults while the
  notebook advertised 10000 iterations. Fixed to the real property names.
- H7: '06. MCMC Convergnce Diagnostics' -> 'Convergence' in the title cell.
- H14: same ThreadPool cleanup as nb03-05.
- Added best-objective-vs-function-evaluations log-scale trace plot for
  PSO, SA, DE, MultiStart, MLSL, SCE on 2D Rosenbrock (new cell
  0f08b2d1). Uses the built-in Optimizer.ParameterSetTrace (base-class
  property; RecordTraces=true by default) — verified against
  Numerics/Mathematics/Optimization/Support/Optimizer.cs:145.
- Added a 2x3 small-multiples grid of Rosenbrock contour plots with
  each optimizer's accepted-step path overlaid, start/end markers, and
  the global minimum annotated (new cell f9b11c6a).
- Stripped ~138 MB of embedded `anim.to_jshtml()` HTML animation
  outputs from two pre-existing cells (38870fa8, 8038ddaf) before
  commit. The PNG plots are retained; re-running the notebook locally
  will regenerate the full animations.
- examples/bayesian_regression.py: dropped ThreadPool.SetMaxThreads(1, 1)
  and the System.Threading/os re-imports inside main(). Same no-op pattern
  as the MCMC notebooks' H14 cleanup. sampler.ParallelizeChains = False
  (already set) is the correct and sufficient fix for the GIL issue.
- examples/reliability_analysis.py: 'ouput' -> 'output' in module
  docstring.

Smoke-tested flood_frequency_analysis.py and reliability_analysis.py
end-to-end against RMC.Numerics 2.0.1 from NuGet — both run cleanly and
produce reasonable output.
…olish

CITATION.cff:
- Set version to 1.0.0 (was placeholder 0.0.0).
- Populated repository-code (was blank — would fail CFF 1.2.0 schema).
- Updated date-released to 2026-04-23 (launch date).
- Renamed author "Tiki" -> "Julian" Gonzalez to match the parent Numerics
  CITATION.cff and added the corresponding ORCID (0009-0009-9058-7653).

CONTRIBUTING.md:
- Replaced the C#-specific 'XML documentation on all public types' rule
  (copied from the parent Numerics CONTRIBUTING) with Python-appropriate
  guidance: PEP 8, docstrings, and a reminder to clear notebook outputs
  before submitting via `jupyter nbconvert --clear-output --inplace`.
- Renumbered the bulleted list (was 1,2,3,5 — missing item 4) and tied
  the last item to 'notebooks run end to end without errors'.
… zoom

- MLSL and SCE were not converging on Eggholder with the default settings.
  Added a GLOBAL_TUNING dict with the same aggressive settings the Numerics
  unit tests use (Test_MLSL.Test_Eggholder: SampleSize=200;
  Test_ShuffledComplexEvolution.Test_Eggholder: Complexes=30,
  CCEIterations=10). MLSL and SCE now find the global minimum at
  (512, 404.2319), f ≈ -959.64.
- Added 'Best f(x,y)' and 'Func Evals' columns to the global-benchmark
  tables so the reader can see both objective value and function-evaluation
  cost side by side.
- Convergence plot on 2D Rosenbrock was unreadable because Simulated
  Annealing runs its full 800K-eval schedule while others converge in
  hundreds. Plot now auto-zooms the x-axis to 1.2x the second-longest trace
  (clipped SA gets a '(truncated; full run = ...)' note in its legend),
  and the caption under the plot prints each method's final objective plus
  total function evaluations.
- Eggholder cell (38870fa8) now has defensive imports at top (Func, Array,
  Double, HTML, display, animation, matplotlib) so it runs standalone
  against a restarted kernel without NameError.
- Stripped the re-generated 138 MB of embedded HTML animation outputs
  (anim.to_jshtml()) before commit; PNG plots retained.
… hints

The commented 'Optional: Configure sampler settings' lines suggested
sampler.SampleSize and sampler.BurnInSamples, neither of which exists on
MCMCSampler. Real properties are Iterations and WarmupIterations (verified
MCMCSampler.cs lines 140 and 153). A learner uncommenting the old hints
would silently create phantom Python attributes via pythonnet. Fixed the
hint text only; no change to execution path.
- nb03/nb04/nb05/nb06: converted the H14 'NOTE FOR DEMO USERS' cells
  from code cells holding a bare triple-quoted string (Jupyter echoed
  the string as Out[...] in two different formats depending on the
  viewer) to markdown blockquotes. Same content, no output clutter.

- nb08: removed the BFGS and DE-on-Eggholder inline jshtml animations.
  matplotlib was hitting its animation.embed_limit on both (the warning
  reported sizes of 52 MB and 84 MB); the static objective-trace and
  contour-path plots in the same cells are what made the notebook
  useful anyway. nb08 is now 4.8 MB (was 165 MB with animations).

- .gitignore: add '**/.ipynb_checkpoints/' so checkpoint dirs can't be
  accidentally staged.

Re-executed all 5 affected notebooks; zero error cells, no leaked paths,
no embedded animation HTML.
@HadenSmith
HadenSmith merged commit 45c5f5c into main Apr 23, 2026
@HadenSmith
HadenSmith deleted the code-review-fixes-and-enhancements branch April 24, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant