Skip to content

Commit 7a8e200

Browse files
committed
I added Json serialization/deserialization to Tools. Added more flexibility for computing the inverse CDF of a mixture or competing risk model. Additional checks for double.NaN on the tabular function.
1 parent ff30fd2 commit 7a8e200

12 files changed

Lines changed: 207 additions & 102 deletions

File tree

4.8.1/Numerics/Distributions/Univariate/CompetingRisks.cs

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ public CompetingRisks(IUnivariateDistribution[] distributions)
7878
}
7979

8080
private UnivariateDistributionBase[] _distributions;
81-
private EmpiricalDistribution _inverseCDF;
81+
private EmpiricalDistribution _empiricalCDF;
8282
private bool _momentsComputed = false;
8383
private double u1, u2, u3, u4;
84-
private bool _inverseCDFCreated = false;
84+
private bool _empiricalCDFCreated = false;
8585
private double[,] _correlationMatrix;
8686
private bool _mvnCreated = false;
8787
private MultivariateNormal _mvn;
@@ -364,7 +364,7 @@ public void SetParameters(UnivariateDistributionBase[] distributions)
364364
if (distributions == null) throw new ArgumentNullException(nameof(Distributions));
365365
_distributions = distributions;
366366
_momentsComputed = false;
367-
_inverseCDFCreated = false;
367+
_empiricalCDFCreated = false;
368368
_mvnCreated = false;
369369
}
370370

@@ -381,7 +381,7 @@ public void SetParameters(IUnivariateDistribution[] distributions)
381381
_distributions[i] = (UnivariateDistributionBase)distributions[i];
382382
}
383383
_momentsComputed = false;
384-
_inverseCDFCreated = false;
384+
_empiricalCDFCreated = false;
385385
_mvnCreated = false;
386386
}
387387

@@ -403,7 +403,7 @@ public override void SetParameters(IList<double> parameters)
403403
}
404404

405405
_momentsComputed = false;
406-
_inverseCDFCreated = false;
406+
_empiricalCDFCreated = false;
407407
_mvnCreated = false;
408408
}
409409

@@ -566,22 +566,29 @@ public override double InverseCDF(double probability)
566566
return Distributions[0].InverseCDF(probability);
567567
}
568568

569-
// Otherwise use a root finder to solve the inverse CDF
570-
var xVals = Distributions.Select(d => d.InverseCDF(probability));
571-
double minX = xVals.Min();
572-
double maxX = xVals.Max();
573569
double x = 0;
574-
try
570+
if (_empiricalCDFCreated == true)
575571
{
576-
Brent.Bracket((y) => { return probability - CDF(y); }, ref minX, ref maxX, out var f1, out var f2);
577-
x = Brent.Solve((y) => { return probability - CDF(y); }, minX, maxX, 1E-6, 100, true);
572+
x = _empiricalCDF.InverseCDF(probability);
578573
}
579-
catch (Exception)
574+
else
580575
{
581-
// If the root finder fails, create an empirical inverse CDF
582-
if (_inverseCDFCreated == false)
583-
CreateInverseCDF();
584-
x = _inverseCDF.InverseCDF(probability);
576+
// use a root finder to solve the inverse CDF
577+
var xVals = Distributions.Select(d => d.InverseCDF(probability));
578+
double minX = xVals.Min();
579+
double maxX = xVals.Max();
580+
try
581+
{
582+
Brent.Bracket((y) => { return probability - CDF(y); }, ref minX, ref maxX, out var f1, out var f2);
583+
x = Brent.Solve((y) => { return probability - CDF(y); }, minX, maxX, 1E-6, 100, true);
584+
}
585+
catch (Exception)
586+
{
587+
// If the root finder fails, create an empirical CDF
588+
if (_empiricalCDFCreated == false)
589+
CreateEmpiricalCDF();
590+
x = _empiricalCDF.InverseCDF(probability);
591+
}
585592
}
586593
double min = Minimum;
587594
double max = Maximum;
@@ -815,11 +822,10 @@ private void CreateMultivariateNormal()
815822
_mvnCreated = true;
816823
}
817824

818-
819825
/// <summary>
820-
/// Create empirical distribution for the inverse CDF.
826+
/// Create empirical distribution for the CDF.
821827
/// </summary>
822-
private void CreateInverseCDF()
828+
public void CreateEmpiricalCDF()
823829
{
824830
// Get min & max
825831
double minP = 1E-16;
@@ -858,8 +864,8 @@ private void CreateInverseCDF()
858864
xValues.Add(x);
859865
pValues.Add(p);
860866
}
861-
_inverseCDF = new EmpiricalDistribution(xValues, pValues) { XTransform = XTransform, ProbabilityTransform = ProbabilityTransform };
862-
_inverseCDFCreated = true;
867+
_empiricalCDF = new EmpiricalDistribution(xValues, pValues) { XTransform = XTransform, ProbabilityTransform = ProbabilityTransform };
868+
_empiricalCDFCreated = true;
863869
}
864870

865871
/// <inheritdoc/>

4.8.1/Numerics/Distributions/Univariate/Deterministic.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public override string ShortDisplayName
112112
get
113113
{
114114
var parmString = new string[1, 2];
115-
parmString[0, 0] = "Y";
115+
parmString[0, 0] = "Value";
116116
parmString[0, 1] = Value.ToString();
117117
return parmString;
118118
}

4.8.1/Numerics/Distributions/Univariate/Mixture.cs

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ public Mixture(double[] weights, IUnivariateDistribution[] distributions)
8181

8282
private double[] _weights;
8383
private UnivariateDistributionBase[] _distributions;
84-
private EmpiricalDistribution _inverseCDF;
84+
private EmpiricalDistribution _empiricalCDF;
8585
private bool _momentsComputed = false;
8686
private double u1, u2, u3, u4;
87-
private bool _inverseCDFCreated = false;
87+
private bool _empiricalCDFCreated = false;
8888

8989
/// <summary>
9090
/// Returns the array of distribution weights.
@@ -408,7 +408,7 @@ public void SetParameters(double[] weights, UnivariateDistributionBase[] distrib
408408
_weights = weights;
409409
_distributions = distributions;
410410
_momentsComputed = false;
411-
_inverseCDFCreated = false;
411+
_empiricalCDFCreated = false;
412412
}
413413

414414
/// <summary>
@@ -430,7 +430,7 @@ public void SetParameters(double[] weights, IUnivariateDistribution[] distributi
430430
_distributions[i] = (UnivariateDistributionBase)distributions[i];
431431
}
432432
_momentsComputed = false;
433-
_inverseCDFCreated = false;
433+
_empiricalCDFCreated = false;
434434
}
435435

436436
/// <summary>
@@ -463,7 +463,7 @@ public void SetParameters(double[] weights, double[] parameters)
463463
t += Distributions[i].NumberOfParameters;
464464
}
465465
_momentsComputed = false;
466-
_inverseCDFCreated = false;
466+
_empiricalCDFCreated = false;
467467
}
468468

469469
/// <inheritdoc/>
@@ -496,7 +496,7 @@ public override void SetParameters(IList<double> parameters)
496496
// Validate parameters
497497
_parametersValid = ValidateParameters(parameters, false) is null;
498498
_momentsComputed = false;
499-
_inverseCDFCreated = false;
499+
_empiricalCDFCreated = false;
500500
}
501501

502502
/// <summary>
@@ -576,7 +576,7 @@ public void SetParameters(ref double[] parameters)
576576
// Validate parameters
577577
_parametersValid = ValidateParameters(parameters, false) is null;
578578
_momentsComputed = false;
579-
_inverseCDFCreated = false;
579+
_empiricalCDFCreated = false;
580580
}
581581

582582
/// <inheritdoc/>
@@ -919,35 +919,42 @@ public override double InverseCDF(double probability)
919919
return Distributions[0].InverseCDF(probability);
920920
}
921921

922-
// Otherwise use a root finder to solve the inverse CDF
923-
var xVals = Distributions.Select(d => d.InverseCDF(probability));
924-
double minX = xVals.Min();
925-
double maxX = xVals.Max();
926922
double x = 0;
927-
try
923+
if (_empiricalCDFCreated == true)
928924
{
929-
if (IsZeroInflated)
930-
{
931-
Brent.Bracket((y) => { return probability - CDF(y); }, ref minX, ref maxX, out var f1, out var f2);
932-
}
933-
x = Brent.Solve((y) => { return probability - CDF(y); }, minX, maxX, 1E-6, 100, true);
925+
x = _empiricalCDF.InverseCDF(probability);
934926
}
935-
catch (Exception)
927+
else
936928
{
937-
// If the root finder fails, create an empirical inverse CDF
938-
if (_inverseCDFCreated == false)
939-
CreateInverseCDF();
940-
x = _inverseCDF.InverseCDF(probability);
929+
// Use a root finder to solve the inverse CDF
930+
var xVals = Distributions.Select(d => d.InverseCDF(probability));
931+
double minX = xVals.Min();
932+
double maxX = xVals.Max();
933+
try
934+
{
935+
if (IsZeroInflated)
936+
{
937+
Brent.Bracket((y) => { return probability - CDF(y); }, ref minX, ref maxX, out var f1, out var f2);
938+
}
939+
x = Brent.Solve((y) => { return probability - CDF(y); }, minX, maxX, 1E-6, 100, true);
940+
}
941+
catch (Exception)
942+
{
943+
// If the root finder fails, create an empirical CDF
944+
if (_empiricalCDFCreated == false)
945+
CreateEmpiricalCDF();
946+
x = _empiricalCDF.InverseCDF(probability);
947+
}
941948
}
942949
double min = Minimum;
943950
double max = Maximum;
944951
return x < min ? min : x > max ? max : x;
945952
}
946953

947954
/// <summary>
948-
/// Create empirical distribution for the inverse CDF.
955+
/// Create empirical distribution for the CDF.
949956
/// </summary>
950-
private void CreateInverseCDF()
957+
public void CreateEmpiricalCDF()
951958
{
952959
// Get min & max
953960
double minP = 1E-16;
@@ -986,8 +993,8 @@ private void CreateInverseCDF()
986993
xValues.Add(x);
987994
pValues.Add(p);
988995
}
989-
_inverseCDF = new EmpiricalDistribution(xValues, pValues) { XTransform = XTransform, ProbabilityTransform = ProbabilityTransform };
990-
_inverseCDFCreated = true;
996+
_empiricalCDF = new EmpiricalDistribution(xValues, pValues) { XTransform = XTransform, ProbabilityTransform = ProbabilityTransform };
997+
_empiricalCDFCreated = true;
991998
}
992999

9931000
/// <inheritdoc/>

4.8.1/Numerics/Functions/TabularFunction.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public double Function(double x)
167167
// Validate parameters
168168
if (ParametersValid == false) ValidateParameters(new double[] {0}, true);
169169
double y = opd.GetYFromX(x, XTransform, YTransform);
170-
y = AllowNegativeYValues == false && y < 0 ? 0 : y;
170+
y = AllowNegativeYValues == false && (double.IsNaN(y) || y < 0) ? 0 : y;
171171
return y;
172172
}
173173

@@ -176,7 +176,7 @@ public double InverseFunction(double y)
176176
{
177177
// Validate parameters
178178
if (ParametersValid == false) ValidateParameters(new double[] { 0 }, true);
179-
y = AllowNegativeYValues == false && y < 0 ? 0 : y;
179+
y = AllowNegativeYValues == false && (double.IsNaN(y) || y < 0) ? 0 : y;
180180
return opd.GetXFromY(y, XTransform, YTransform);
181181
}
182182
}

4.8.1/Numerics/Numerics.csproj

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,40 @@
7777
<WarningsAsErrors>41999,42016,42017,42018,42019,42020,42021,42022,42032,42036</WarningsAsErrors>
7878
</PropertyGroup>
7979
<ItemGroup>
80+
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
81+
<HintPath>..\..\8.0\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
82+
</Reference>
8083
<Reference Include="System" />
84+
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
85+
<HintPath>..\..\8.0\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
86+
</Reference>
8187
<Reference Include="System.ComponentModel.DataAnnotations" />
8288
<Reference Include="System.Data" />
8389
<Reference Include="System.IO.Compression" />
8490
<Reference Include="System.IO.Compression.FileSystem" />
91+
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
92+
<HintPath>..\..\8.0\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
93+
</Reference>
94+
<Reference Include="System.Numerics" />
95+
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
96+
<HintPath>..\..\8.0\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
97+
</Reference>
98+
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
99+
<HintPath>..\..\8.0\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
100+
</Reference>
85101
<Reference Include="System.Runtime.Serialization" />
102+
<Reference Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
103+
<HintPath>..\..\8.0\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
104+
</Reference>
105+
<Reference Include="System.Text.Json, Version=8.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
106+
<HintPath>..\..\8.0\packages\System.Text.Json.8.0.5\lib\net462\System.Text.Json.dll</HintPath>
107+
</Reference>
108+
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
109+
<HintPath>..\..\8.0\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
110+
</Reference>
111+
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
112+
<HintPath>..\..\8.0\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
113+
</Reference>
86114
<Reference Include="System.Xml" />
87115
<Reference Include="System.Xml.Linq" />
88116
</ItemGroup>
@@ -325,6 +353,7 @@
325353
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
326354
</None>
327355
<EmbeddedResource Include="new-joe-kuo-6.21201" />
356+
<None Include="packages.config" />
328357
</ItemGroup>
329358
<ItemGroup>
330359
<Folder Include="Properties\" />

4.8.1/Numerics/Utilities/Tools.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@
3030

3131
using Numerics.Data.Statistics;
3232
using System;
33+
using System.Collections;
3334
using System.Collections.Generic;
3435
using System.IO;
3536
using System.IO.Compression;
37+
using System.Runtime.Serialization.Formatters.Binary;
38+
using System.Security.Cryptography;
39+
using System.Text.Json;
3640
using System.Threading;
3741

3842
namespace Numerics
@@ -632,7 +636,23 @@ public static byte[] Decompress(byte[] data)
632636
return output.ToArray();
633637
}
634638

639+
/// <summary>
640+
/// Returns the object as a byte array.
641+
/// </summary>
642+
/// <param name="obj">The object to convert.</param>
643+
public static byte[] ToByteArray(object obj)
644+
{
645+
return JsonSerializer.SerializeToUtf8Bytes(obj);
646+
}
635647

648+
/// <summary>
649+
/// Returns the object from a byte array.
650+
/// </summary>
651+
/// <param name="bytes">Byte array.</param>
652+
public static T FromByteArray<T>(byte[] bytes)
653+
{
654+
return JsonSerializer.Deserialize<T>(bytes);
655+
}
636656

637657
}
638658
}

4.8.1/Numerics/packages.config

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net481" />
4+
<package id="System.Buffers" version="4.5.1" targetFramework="net481" />
5+
<package id="System.Memory" version="4.5.5" targetFramework="net481" />
6+
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net481" />
7+
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net481" />
8+
<package id="System.Text.Encodings.Web" version="8.0.0" targetFramework="net481" />
9+
<package id="System.Text.Json" version="8.0.5" targetFramework="net481" />
10+
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net481" />
11+
<package id="System.ValueTuple" version="4.5.0" targetFramework="net481" />
12+
</packages>

0 commit comments

Comments
 (0)