Skip to content

Commit b5ae6ff

Browse files
authored
Merge pull request #143 from USACE-RMC/bug-fixes-and-enhancements
Prepare v2.1.3 release
2 parents b24037a + ea9ae73 commit b5ae6ff

113 files changed

Lines changed: 3618 additions & 808 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/Snapshot.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ jobs:
1010
with:
1111
dotnet-version: '10.0.x'
1212
project-names: 'Numerics'
13-
# Snapshot workflow appends .<run_number>-dev, so this tracks the next development patch after v2.1.2.
14-
version: '2.1.3'
13+
# Snapshot workflow appends .<run_number>-dev, so this tracks the next development patch after v2.1.3.
14+
version: '2.1.4'
1515
# PR integration already runs the full multi-target test suite.
1616
run-tests: false
1717
nuget-source: 'https://www.hec.usace.army.mil/nexus/repository/consequences-nuget-public/'

‎.gitignore‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## Ignore Visual Studio temporary files, build results, and
1+
## Ignore Visual Studio temporary files, build results, and
22
## files generated by popular Visual Studio add-ons.
33
##
44
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
@@ -370,4 +370,11 @@ MigrationBackup/
370370

371371
#Numerics Specific
372372
/TestResults
373-
/.claude/settings.local.json
373+
374+
# Local developer guidance and settings. These files are for developer machines only.
375+
/CLAUDE.md
376+
/Claude.md
377+
/AGENTS.md
378+
/Agents.md
379+
/.claude/
380+
/.agents/

‎CITATION.cff‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ cff-version: 1.2.0
22
message: "If you use this software, please cite our article in the Journal of Open Source Software."
33
type: software
44
title: "Numerics: A .NET Library for Numerical Computing, Statistical Analysis, and Risk Assessment"
5-
version: "2.1.2"
6-
date-released: "2026-07-09"
5+
version: "2.1.3"
6+
date-released: "2026-07-15"
77
license: 0BSD
88
repository-code: "https://github.com/USACE-RMC/Numerics"
99
url: "https://github.com/USACE-RMC/Numerics"

‎Directory.Build.props‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project>
2+
3+
<PropertyGroup>
4+
<RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
5+
<EnforceXmlDocumentation Condition="'$(EnforceXmlDocumentation)' == ''">true</EnforceXmlDocumentation>
6+
</PropertyGroup>
7+
8+
<PropertyGroup Condition="'$(EnforceXmlDocumentation)' == 'true'">
9+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
10+
<WarningsAsErrors>$(WarningsAsErrors);CS1570;CS1571;CS1572;CS1573;CS1574;CS1584;CS1587;CS1589;CS1591</WarningsAsErrors>
11+
</PropertyGroup>
12+
13+
</Project>

‎Numerics/Data/Interpolation/Bilinear.cs‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,11 @@ public double Interpolate(double x1, double x2)
142142
x1ub = X1Values[X1LI.Count - 1];
143143
if (X1Transform == Transform.Logarithmic)
144144
{
145-
x1 = Math.Log10(x1);
146-
x1i = Math.Log10(x1i);
147-
x1ii = Math.Log10(x1ii);
148-
x1lb = Math.Log10(x1lb);
149-
x1ub = Math.Log10(x1ub);
145+
x1 = Tools.Log10(x1);
146+
x1i = Tools.Log10(x1i);
147+
x1ii = Tools.Log10(x1ii);
148+
x1lb = Tools.Log10(x1lb);
149+
x1ub = Tools.Log10(x1ub);
150150
}
151151
else if (X1Transform == Transform.NormalZ)
152152
{
@@ -164,11 +164,11 @@ public double Interpolate(double x1, double x2)
164164
x2ub = X2Values[X2LI.Count - 1];
165165
if (X2Transform == Transform.Logarithmic)
166166
{
167-
x2 = Math.Log10(x2);
168-
x2j = Math.Log10(x2j);
169-
x2jj = Math.Log10(x2jj);
170-
x2lb = Math.Log10(x2lb);
171-
x2ub = Math.Log10(x2ub);
167+
x2 = Tools.Log10(x2);
168+
x2j = Tools.Log10(x2j);
169+
x2jj = Tools.Log10(x2jj);
170+
x2lb = Tools.Log10(x2lb);
171+
x2ub = Tools.Log10(x2ub);
172172
}
173173
else if (X2Transform == Transform.NormalZ)
174174
{
@@ -186,10 +186,10 @@ public double Interpolate(double x1, double x2)
186186
yijj = YValues[i, j + 1];
187187
if (YTransform == Transform.Logarithmic)
188188
{
189-
yij = Math.Log10(yij);
190-
yiij = Math.Log10(yiij);
191-
yiijj = Math.Log10(yiijj);
192-
yijj = Math.Log10(yijj);
189+
yij = Tools.Log10(yij);
190+
yiij = Tools.Log10(yiij);
191+
yiijj = Tools.Log10(yiijj);
192+
yijj = Tools.Log10(yijj);
193193
}
194194
else if (YTransform == Transform.NormalZ)
195195
{

‎Numerics/Data/Interpolation/Support/Search.cs‎

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -398,16 +398,34 @@ public static int Bisection(double x, IList<double> values, int start = 0, SortO
398398

399399
// Perform bisection search
400400
int xlo = start, xhi = N, xm = 0;
401-
while (xhi - xlo > 1)
401+
if (order == SortOrder.Ascending)
402402
{
403-
xm = xlo + (xhi - xlo >> 1);
404-
if (x >= values[xm] && order == SortOrder.Ascending)
403+
while (xhi - xlo > 1)
405404
{
406-
xlo = xm;
405+
xm = xlo + (xhi - xlo >> 1);
406+
if (x >= values[xm])
407+
{
408+
xlo = xm;
409+
}
410+
else
411+
{
412+
xhi = xm;
413+
}
407414
}
408-
else
415+
}
416+
else
417+
{
418+
while (xhi - xlo > 1)
409419
{
410-
xhi = xm;
420+
xm = xlo + (xhi - xlo >> 1);
421+
if (x < values[xm])
422+
{
423+
xlo = xm;
424+
}
425+
else
426+
{
427+
xhi = xm;
428+
}
411429
}
412430
}
413431
// Return XLO
@@ -480,16 +498,34 @@ public static int Bisection(double x, OrderedPairedData orderedPairedData, int s
480498

481499
// Perform bisection search
482500
int xlo = start, xhi = N, xm = 0;
483-
while (xhi - xlo > 1)
501+
if (orderedPairedData.OrderX == SortOrder.Ascending)
484502
{
485-
xm = xlo + (xhi - xlo >> 1);
486-
if (x >= orderedPairedData[xm].X && orderedPairedData.OrderX == SortOrder.Ascending)
503+
while (xhi - xlo > 1)
487504
{
488-
xlo = xm;
505+
xm = xlo + (xhi - xlo >> 1);
506+
if (x >= orderedPairedData[xm].X)
507+
{
508+
xlo = xm;
509+
}
510+
else
511+
{
512+
xhi = xm;
513+
}
489514
}
490-
else
515+
}
516+
else
517+
{
518+
while (xhi - xlo > 1)
491519
{
492-
xhi = xm;
520+
xm = xlo + (xhi - xlo >> 1);
521+
if (x < orderedPairedData[xm].X)
522+
{
523+
xlo = xm;
524+
}
525+
else
526+
{
527+
xhi = xm;
528+
}
493529
}
494530
}
495531
// Return XLO
@@ -563,16 +599,34 @@ public static int Bisection(double x, IList<Ordinate> ordinates, int start = 0,
563599

564600
// Perform bisection search
565601
int xlo = start, xhi = N, xm = 0;
566-
while (xhi - xlo > 1)
602+
if (order == SortOrder.Ascending)
567603
{
568-
xm = xlo + (xhi - xlo >> 1);
569-
if (x >= ordinates[xm].X && order == SortOrder.Ascending)
604+
while (xhi - xlo > 1)
570605
{
571-
xlo = xm;
606+
xm = xlo + (xhi - xlo >> 1);
607+
if (x >= ordinates[xm].X)
608+
{
609+
xlo = xm;
610+
}
611+
else
612+
{
613+
xhi = xm;
614+
}
572615
}
573-
else
616+
}
617+
else
618+
{
619+
while (xhi - xlo > 1)
574620
{
575-
xhi = xm;
621+
xm = xlo + (xhi - xlo >> 1);
622+
if (x < ordinates[xm].X)
623+
{
624+
xlo = xm;
625+
}
626+
else
627+
{
628+
xhi = xm;
629+
}
576630
}
577631
}
578632
// Return XLO
@@ -660,15 +714,15 @@ public static int Hunt(double x, IList<double> values, int start = 0, SortOrder
660714
}
661715
else
662716
{
663-
if (x >= values[xlo] && order == SortOrder.Ascending)
717+
if ((x >= values[xlo]) == (order == SortOrder.Ascending))
664718
{
665719
// Hunt up
666720
for (;;)
667721
{
668722
// Not done hunting so double the increment
669723
xhi = xlo + inc;
670724
if (xhi >= N - 1) { xhi = N - 1; break; }
671-
else if (x < values[xhi] && order == SortOrder.Ascending) break;
725+
else if ((x < values[xhi]) == (order == SortOrder.Ascending)) break;
672726
else
673727
{
674728
xlo = xhi;
@@ -684,7 +738,7 @@ public static int Hunt(double x, IList<double> values, int start = 0, SortOrder
684738
{
685739
xlo = xlo - inc;
686740
if (xlo <= 0) { xlo = 0; break; }
687-
else if (x >= values[xlo] && order == SortOrder.Ascending) break;
741+
else if ((x >= values[xlo]) == (order == SortOrder.Ascending)) break;
688742
else
689743
{
690744
xhi = xlo;
@@ -698,7 +752,7 @@ public static int Hunt(double x, IList<double> values, int start = 0, SortOrder
698752
while (xhi - xlo > 1)
699753
{
700754
xm = xlo + (xhi - xlo >> 1);
701-
if (x >= values[xm] && order == SortOrder.Ascending)
755+
if ((x >= values[xm]) == (order == SortOrder.Ascending))
702756
{
703757
xlo = xm;
704758
}
@@ -840,7 +894,7 @@ public static int Hunt(double xValue, OrderedPairedData orderedPairedData, int s
840894
while (XHI - XLO > 1)
841895
{
842896
XM = XLO + (XHI - XLO >> 1);
843-
if (X >= orderedPairedData[XM].X && ASCND == true)
897+
if ((X >= orderedPairedData[XM].X) == ASCND)
844898
{
845899
XLO = XM;
846900
}
@@ -988,7 +1042,7 @@ public static int Hunt(double xValue, IList<Ordinate> ordinateData, int start =
9881042
while (XHI - XLO > 1)
9891043
{
9901044
XM = XLO + (XHI - XLO >> 1);
991-
if (X >= ordinateData[XM].X && ASCND == true)
1045+
if ((X >= ordinateData[XM].X) == ASCND)
9921046
{
9931047
XLO = XM;
9941048
}

‎Numerics/Data/Statistics/Histogram.cs‎

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -397,22 +397,32 @@ public void AddBin(Bin bin)
397397
public void AddData(double data)
398398
{
399399
SortBins();
400-
int index = GetBinIndexOf(data);
401400
if (data <= LowerBound)
402401
{
403-
_bins.First().LowerBound = data;
402+
if (data < LowerBound)
403+
{
404+
_bins.First().LowerBound = data;
405+
LowerBound = data;
406+
_areBinsSorted = false;
407+
}
404408
_bins.First().Frequency += 1;
405-
_areBinsSorted = false;
406409
}
407410
else if (data >= UpperBound)
408411
{
409-
_bins.Last().UpperBound = data;
412+
if (data > UpperBound)
413+
{
414+
_bins.Last().UpperBound = data;
415+
UpperBound = data;
416+
}
410417
_bins.Last().Frequency += 1;
411-
_areBinsSorted = false;
412418
}
413-
else if (index >= 0 && index < NumberOfBins)
419+
else
414420
{
415-
_bins[index].Frequency += 1;
421+
int index = GetBinIndexOf(data);
422+
if (index >= 0 && index < NumberOfBins)
423+
{
424+
_bins[index].Frequency += 1;
425+
}
416426
}
417427
}
418428

‎Numerics/Data/Statistics/Probability.cs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ public static double JointProbabilityHPCM(IList<double> probabilities, int[] ind
305305

306306
// Get z-values
307307
double zMin = -9, zMax = 9;
308+
const double minimumCdf = 1E-300;
308309
var R = new double[n, n];
309310
Array.Copy(correlationMatrix, R, correlationMatrix.Length);
310311
int i, j, k, ir, ic;
@@ -325,7 +326,7 @@ public static double JointProbabilityHPCM(IList<double> probabilities, int[] ind
325326
z1 = R[0, 0];
326327
pdf = Normal.StandardPDF(z1);
327328
cdf = Normal.StandardCDF(z1);
328-
//if (cdf < 1e-300) cdf = 1e-300;
329+
if (cdf < minimumCdf) cdf = minimumCdf;
329330
A = pdf / cdf;
330331
B = A * (z1 + A);
331332
for (k = 1; k < n; k++)
@@ -352,7 +353,7 @@ public static double JointProbabilityHPCM(IList<double> probabilities, int[] ind
352353
z1 = R[j, j - 1];
353354
pdf = Normal.StandardPDF(z1);
354355
cdf = Normal.StandardCDF(z1);
355-
if (cdf < 1e-300) cdf = 1e-300;
356+
if (cdf < minimumCdf) cdf = minimumCdf;
356357
A = pdf / cdf;
357358
B = A * (z1 + A);
358359
for (k = j + 1; k < n; k++)

‎Numerics/Distributions/Bivariate Copulas/AMHCopula.cs‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ public override double ThetaMaximum
8282
/// <inheritdoc/>
8383
public override ArgumentOutOfRangeException? ValidateParameter(double parameter, bool throwException)
8484
{
85+
if (double.IsNaN(parameter) || double.IsInfinity(parameter))
86+
{
87+
var exception = new ArgumentOutOfRangeException(nameof(Theta), "The dependency parameter must be finite.");
88+
if (throwException) throw exception;
89+
return exception;
90+
}
8591
if (parameter < ThetaMinimum)
8692
{
8793
if (throwException) throw new ArgumentOutOfRangeException(nameof(Theta), "The dependency parameter θ (theta) must be greater than or equal to " + ThetaMinimum.ToString() + ".");
@@ -167,7 +173,7 @@ public override double[] InverseCDF(double u, double v)
167173
/// <inheritdoc/>
168174
public override BivariateCopula Clone()
169175
{
170-
return new AMHCopula(Theta, MarginalDistributionX, MarginalDistributionY);
176+
return new AMHCopula(Theta, CloneMarginal(MarginalDistributionX), CloneMarginal(MarginalDistributionY));
171177
}
172178

173179
/// <summary>

‎Numerics/Distributions/Bivariate Copulas/Base/ArchimedeanCopula.cs‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ public override void SetCopulaParameters(double[] parameters)
4949
/// <inheritdoc/>
5050
public override ArgumentOutOfRangeException? ValidateParameter(double parameter, bool throwException)
5151
{
52+
if (double.IsNaN(parameter) || double.IsInfinity(parameter))
53+
{
54+
var exception = new ArgumentOutOfRangeException(nameof(Theta), "The dependency parameter must be finite.");
55+
if (throwException) throw exception;
56+
return exception;
57+
}
5258
if (parameter < ThetaMinimum)
5359
{
5460
if (throwException) throw new ArgumentOutOfRangeException(nameof(Theta), "The dependency parameter θ (theta) must be greater than or equal to " + ThetaMinimum.ToString() + ".");
@@ -60,7 +66,11 @@ public override void SetCopulaParameters(double[] parameters)
6066
if (throwException) throw new ArgumentOutOfRangeException(nameof(Theta), "The dependency parameter θ (theta) must be less than or equal to " + ThetaMaximum.ToString() + ".");
6167
return new ArgumentOutOfRangeException(nameof(Theta), "The dependency parameter θ (theta) must be less than or equal to " + ThetaMaximum.ToString() + ".");
6268
}
63-
return new ArgumentOutOfRangeException(nameof(Theta),"Parameter is valid");
69+
// A valid parameter must return null: the Theta setter derives ParametersValid
70+
// from 'ValidateParameter(value, false) is null', so returning a sentinel
71+
// exception here left ParametersValid permanently false for every Archimedean
72+
// family that did not override this method (Clayton, Gumbel, Joe).
73+
return null;
6474
}
6575

6676
/// <inheritdoc/>

0 commit comments

Comments
 (0)