
I think that there is a TruncatedNormal Distribution that exists but I'm not a mathematician and I don't know if it worth it to add it or not. It seeams to me that it could be a good idea to include it.


Coordinator
Jun 5, 2014 at 12:27 AM




This morning I discuss with a colleague about TruncatedNormal.
I realized that in MathLab it is a function that could be applied to a distribution, not a distribution by itself.
But in "rproject" (CRAN) it seems to be distribution function by itself?



Do you just need to sample from a truncated normal?
If so you could simply use rejection sampling.
Sample from the normal and reject samples which are outside your truncated bounds.



Hello Matthew,
I would have liked that it would be as easy as you said but...
In fact, I'm not the one who need it. I'm the programmer who will have to code it.
But I think they want the standard way to do it (at least the MathLab way)... I learned yesterday, from a Statitician guy and MathLab that a truncated normal should stay with its area under the curve at 1 always. When we truncate, we have to raise the normal
until we get 1 as its area under the curve. That will move the real mean but as far as we understand it, that's the way to do it.


Jun 7, 2014 at 10:06 PM
Edited Jun 8, 2014 at 5:41 AM

How about this?
It is written in VB but I think it's pretty similar in C.
Public Class TruncatedNormal
Dim Lower_Bound As Double
Dim Upper_Bound As Double
Dim ParentDistribution As MathNet.Numerics.Distributions.Normal
Dim ParentSubArea As Double
Public Sub New(ByVal Parent_Mean As Double, ByVal Parent_StandardDeviation As Double, _
ByVal LowerBound As Double, ByVal UpperBound As Double)
Lower_Bound = LowerBound
Upper_Bound = UpperBound
ParentDistribution = New MathNet.Numerics.Distributions.Normal(Parent_Mean, Parent_StandardDeviation)
ParentSubArea = ParentDistribution.CumulativeDistribution(Upper_Bound)  ParentDistribution.CumulativeDistribution(Lower_Bound)
'#ParentSubArea is the area under the curve of the parent distribution between the bounds
End Sub
Public Function Sample() As Double
Dim Accepted As Boolean = False
Dim Candidate As Double
Do Until Accepted
Candidate = ParentDistribution.Sample()
If Candidate > Lower_Bound And Candidate < Upper_Bound Then
Accepted = True
End If
Loop
Return Candidate / ParentSubArea
'#Division by ParentSubArea makes the area under the curve of the truncated PDF 1.0
End Function
Public Function Samples(ByVal Number_of_Samples As Integer) As Double()
Dim sample_array(Number_of_Samples  1) As Double
For s = 0 To Number_of_Samples  1
sample_array(s) = Sample()
Next s
Return sample_array
End Function
End Class
The correction term for the area under the curve only needs to be computed once per distribution so it is handled in the constructor.
I included two methods for sampling: single sample and a sample array (similar to Math.Net)
Note: there is no validation checking for UpperBound>LowerBound... so include that if you need it.


Jun 7, 2014 at 10:29 PM
Edited Jun 7, 2014 at 10:55 PM

Did you want the truncated distribution to always have area under curve of 1.0 or to have area under curve the same as the area under the untruncated parent normal?
I think that what Matlab does is the former, which would be as follows:
Public Class TruncatedNormal
Dim Lower_Bound As Double
Dim Upper_Bound As Double
Dim ParentDistribution As MathNet.Numerics.Distributions.Normal
Private CorrectionFactor As Double
Public Sub New(ByVal Parent_Mean As Double, ByVal Parent_StandardDeviation As Double, _
ByVal LowerBound As Double, ByVal UpperBound As Double)
Lower_Bound = LowerBound
Upper_Bound = UpperBound
ParentDistribution = New MathNet.Numerics.Distributions.Normal(Parent_Mean, Parent_StandardDeviation)
CorrectionFactor = Parent_StandardDeviation / _
(ParentDistribution.CumulativeDistribution(Upper_Bound)  ParentDistribution.CumulativeDistribution(Lower_Bound))
'#ParentSubArea is the area under the curve of the parent distribution between the bounds
'#Parent_StandardDeviation is the total area under the untrunctaed parent normal (neg inf to pos inf)
End Sub
Public Function Sample() As Double
Dim Accepted As Boolean = False
Dim Candidate As Double
Do Until Accepted
Candidate = ParentDistribution.Sample()
If Candidate > Lower_Bound And Candidate < Upper_Bound Then
Accepted = True
End If
Loop
Return Candidate * CorrectionFactor
'#Division by ParentSubArea makes the area under the curve of the truncated PDF 1.0
'#Multiplication by Parent_StandardDeviation makes the area the same as total parent area.
End Function
Public Function Samples(ByVal Number_of_Samples As Integer) As Double()
Dim sample_array(Number_of_Samples  1) As Double
For s = 0 To Number_of_Samples  1
sample_array(s) = Sample()
Next s
Return sample_array
End Function
End Class



Hello Matthew,
Sorry for the delay, I had a surgery last Monday...
Yes I think it should stay always with an area under the curve at 1.0 according to my project lead and a statistician that work here.
About the code, I'm really not sure. I'm a big zero in math, I don't know integral but I will check with my project leader.
Thanks a lot.
Eric

