Code review fixes + launch readiness for public release - #1
Merged
Conversation
- 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
demcz.BurnIn/demcz.SampleSizedon'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 toWarmupIterations/Iterations.Samples: 4, Features: 150for Iris. Fixed viaMatrix(convert_to_dotnet_2d_array(X)).ThreadPool.SetMaxThreads(1, 1)workaround (silently returned False on multi-core; visible in saved output).sampler.ParallelizeChains = Falseis the correct fix and was already set.SampleSizeandBurnInSamples— neither exists on MCMCSampler. Replaced with realIterationsandWarmupIterations.UX:
RMC.NumericsNuGet-based DLL resolutionresolve_numerics_dll()innotebooks/helper_functions.pyauto-discoversNumerics.dllviaNUMERICS_DLLenv var → global NuGet cache → localpackages/folder.git clone + dotnet buildtodotnet add package RMC.Numerics(pulls latest; pin with--version 2.0.1).nb08 feature additions
Test_MLSL.Test_Eggholder(SampleSize=200) andTest_ShuffledComplexEvolution.Test_Eggholder(Complexes=30, CCEIterations=10). Both methods now find the global minimum at (512, 404.2319), f ≈ -959.64.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
repository-code, version1.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.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
gitignore.txt, internal scoping doc, tracked.pyc,.vscode/settings.json,.vscode/extensions.json..claude/,.venv/,venv/,packages/to.gitignore.Test plan
pip install -r notebook-requirements.txtdotnet add package RMC.Numerics --version 2.0.1installed to global cacheNormal(100, 15).Mean == 100.0jupyter nbconvert --execute— zero error cellsexamples/flood_frequency_analysis.pyandexamples/reliability_analysis.pysmoke-run against NuGet-installed DLLSamples: 150, Features: 4git grepforC:\GIT\Numerics\...\bin\Debug,BurnIn/SampleSizeMCMC properties,ThreadPool.SetMaxThreads→ all empty