Browse Source

Merge branch 'fspowerpack'

v2
Christoph Ruegg 14 years ago
parent
commit
4e122689de
  1. 11
      MathNet.Numerics.Portable.sln
  2. 2
      MathNet.Numerics.sln.DotSettings
  3. 2
      packages/repositories.config
  4. 34
      src/FSharp/BigIntegerExtensions.fs
  5. 307
      src/FSharp/BigRational.fs
  6. 94
      src/FSharp/BigRational.fsi
  7. 152
      src/FSharp/Complex.fs
  8. 253
      src/FSharp/Complex.fsi
  9. 10
      src/FSharp/FSharp.fsproj
  10. 52
      src/FSharp/LinearAlgebra.Double.Matrix.fs
  11. 50
      src/FSharp/LinearAlgebra.Double.Vector.fs
  12. 18
      src/FSharp/LinearAlgebra.fs
  13. 95
      src/FSharp/RandomVariable.fs
  14. 2
      src/FSharpExamples/Apply.fs
  15. 20
      src/FSharpExamples/MCMC.fs
  16. 18
      src/FSharpPortable/FSharpPortable.fsproj
  17. 11
      src/FSharpPortableUnitTests/App.config
  18. 104
      src/FSharpPortableUnitTests/FSharpPortableUnitTests.fsproj
  19. 4
      src/FSharpPortableUnitTests/packages.config
  20. 6
      src/FSharpUnitTests/App.config
  21. 606
      src/FSharpUnitTests/BigRationalTests.fs
  22. 51
      src/FSharpUnitTests/DenseMatrixTests.fs
  23. 35
      src/FSharpUnitTests/DenseVectorTests.fs
  24. 21
      src/FSharpUnitTests/FSharpUnitTests.fsproj
  25. 314
      src/FSharpUnitTests/FsUnit.fs
  26. 112
      src/FSharpUnitTests/MatrixTests.fs
  27. 98
      src/FSharpUnitTests/PokerTests.fs
  28. 223
      src/FSharpUnitTests/Program.fs
  29. 79
      src/FSharpUnitTests/RandomVariableTests.fs
  30. 28
      src/FSharpUnitTests/SparseMatrixTests.fs
  31. 21
      src/FSharpUnitTests/SparseVectorTests.fs
  32. 128
      src/FSharpUnitTests/Utilities.fs
  33. 103
      src/FSharpUnitTests/VectorTests.fs
  34. 4
      src/FSharpUnitTests/packages.config
  35. 1105
      src/Numerics/Complex32.cs
  36. 1217
      src/Numerics/Complex64.cs
  37. 272
      src/Numerics/ComplexExtensions.cs
  38. 6
      src/Numerics/LinearAlgebra/Complex32/Matrix.cs
  39. 2
      src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs
  40. 2
      src/Numerics/NumberTheory/IntegerTheory.Euclid.Big.cs
  41. 7
      src/Numerics/Numerics.csproj
  42. 2
      src/Numerics/SpecialFunctions/Stability.cs
  43. 16
      src/Numerics/TargetedPatchingOptOutAttribute.cs
  44. 22
      src/Numerics/Trigonometry.cs
  45. 3
      src/Portable/Portable.csproj
  46. 4
      src/UnitTests/ComplexTests/Complex32Test.TextHandling.cs
  47. 82
      src/UnitTests/ComplexTests/Complex32Test.cs
  48. 20
      src/UnitTests/ComplexTests/ComplexTest.cs
  49. 2
      src/UnitTests/LinearAlgebraTests/Complex32/VectorTests.cs
  50. 8
      src/UnitTests/TrigonometryTest.cs

11
MathNet.Numerics.Portable.sln

@ -12,6 +12,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable", "src\Portable\Po
EndProject EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpPortable", "src\FSharpPortable\FSharpPortable.fsproj", "{F5F14D76-428D-43D7-8431-5B885F1BA419}" Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpPortable", "src\FSharpPortable\FSharpPortable.fsproj", "{F5F14D76-428D-43D7-8431-5B885F1BA419}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{81D2CBEF-1C80-4389-A341-F010E8F86CDB}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpPortableUnitTests", "src\FSharpPortableUnitTests\FSharpPortableUnitTests.fsproj", "{90CE8E32-354E-4728-8FE6-87342F469321}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -26,8 +30,15 @@ Global
{F5F14D76-428D-43D7-8431-5B885F1BA419}.Debug|Any CPU.Build.0 = Debug|Any CPU {F5F14D76-428D-43D7-8431-5B885F1BA419}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5F14D76-428D-43D7-8431-5B885F1BA419}.Release|Any CPU.ActiveCfg = Release|Any CPU {F5F14D76-428D-43D7-8431-5B885F1BA419}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5F14D76-428D-43D7-8431-5B885F1BA419}.Release|Any CPU.Build.0 = Release|Any CPU {F5F14D76-428D-43D7-8431-5B885F1BA419}.Release|Any CPU.Build.0 = Release|Any CPU
{90CE8E32-354E-4728-8FE6-87342F469321}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{90CE8E32-354E-4728-8FE6-87342F469321}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90CE8E32-354E-4728-8FE6-87342F469321}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90CE8E32-354E-4728-8FE6-87342F469321}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{90CE8E32-354E-4728-8FE6-87342F469321} = {81D2CBEF-1C80-4389-A341-F010E8F86CDB}
EndGlobalSection
EndGlobal EndGlobal

2
MathNet.Numerics.sln.DotSettings

@ -11,5 +11,7 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_ANONYMOUS_METHOD_BLOCK/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_ANONYMOUS_METHOD_BLOCK/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_EMBRACED_INITIALIZER_BLOCK/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_EMBRACED_INITIALIZER_BLOCK/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_BINARY_OPSIGN/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_BINARY_OPSIGN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean></wpf:ResourceDictionary>

2
packages/repositories.config

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<repositories> <repositories>
<repository path="..\src\FSharpPortableUnitTests\packages.config" />
<repository path="..\src\FSharpUnitTests\packages.config" />
<repository path="..\src\Numerics.IO\packages.config" /> <repository path="..\src\Numerics.IO\packages.config" />
<repository path="..\src\UnitTests\packages.config" /> <repository path="..\src\UnitTests\packages.config" />
</repositories> </repositories>

34
src/FSharp/BigIntegerExtensions.fs

@ -0,0 +1,34 @@
namespace System.Numerics
open System
#if PORTABLE
[<AutoOpen>]
module BigIntegerExtensions =
let private parse str =
let len = String.length str
let rec build acc i =
if i = len then
acc
else
let c = str.[i]
let d = int c - int '0'
if 0 <= d && d <= 9 then
build (10I * acc + (bigint d)) (i+1)
else
raise (new FormatException("The value could not be parsed"))
build 0I 0
type BigInteger with
static member Parse(text: string) =
let len = text.Length
if len = 0 then raise (new FormatException("The value could not be parsed"))
if text.[0..0] = "-" then
parse text.[1..len-1] |> bigint.Negate
else
parse text
#endif

307
src/FSharp/BigRational.fs

@ -0,0 +1,307 @@
// First version copied from the F# Power Pack
// https://raw.github.com/fsharp/powerpack/master/src/FSharp.PowerPack/math/q.fs
// (c) Microsoft Corporation. All rights reserved
#nowarn "44" // OK to use the "compiler only" function RangeGeneric
#nowarn "52" // The value has been copied to ensure the original is not mutated by this operation
namespace MathNet.Numerics
open System
open System.Numerics
open System.Globalization
module BigRationalLargeImpl =
let ZeroI = new BigInteger(0)
let OneI = new BigInteger(1)
let bigint (x:int) = new BigInteger(x)
let ToDoubleI (x:BigInteger) = double x
let ToInt32I (x:BigInteger) = int32 x
open BigRationalLargeImpl
[<CustomEquality; CustomComparison>]
type BigRationalLarge =
| Q of BigInteger * BigInteger // invariants: (p,q) in lowest form, q >= 0
override n.ToString() =
let (Q(p,q)) = n
if q.IsOne then p.ToString()
else p.ToString() + "/" + q.ToString()
static member Hash (Q(ap,aq)) =
// This hash code must be identical to the hash for BigInteger when the numbers coincide.
if aq.IsOne then ap.GetHashCode() else (ap.GetHashCode() <<< 3) + aq.GetHashCode()
override x.GetHashCode() = BigRationalLarge.Hash(x)
static member Equals(Q(ap,aq), Q(bp,bq)) =
BigInteger.(=) (ap,bp) && BigInteger.(=) (aq,bq) // normal form, so structural equality
static member LessThan(Q(ap,aq), Q(bp,bq)) =
BigInteger.(<) (ap * bq,bp * aq)
// note: performance improvement possible here
static member Compare(p,q) =
if BigRationalLarge.LessThan(p,q) then -1
elif BigRationalLarge.LessThan(q,p)then 1
else 0
interface System.IComparable with
member this.CompareTo(obj:obj) =
match obj with
| :? BigRationalLarge as that -> BigRationalLarge.Compare(this,that)
| _ -> invalidArg "obj" "the object does not have the correct type"
override this.Equals(that:obj) =
match that with
| :? BigRationalLarge as that -> BigRationalLarge.Equals(this,that)
| _ -> false
member x.IsNegative = let (Q(ap,_)) = x in sign ap < 0
member x.IsPositive = let (Q(ap,_)) = x in sign ap > 0
member x.Numerator = let (Q(p,_)) = x in p
member x.Denominator = let (Q(_,q)) = x in q
member x.Sign = (let (Q(p,_)) = x in sign p)
static member ToDouble (Q(p,q)) =
ToDoubleI p / ToDoubleI q
static member Normalize (p:BigInteger,q:BigInteger) =
if q.IsZero then
raise (System.DivideByZeroException()) (* throw for any x/0 *)
elif q.IsOne then
Q(p,q)
else
let k = BigInteger.GreatestCommonDivisor(p,q)
let p = p / k
let q = q / k
if sign q < 0 then Q(-p,-q) else Q(p,q)
static member Rational (p:int,q:int) = BigRationalLarge.Normalize (bigint p,bigint q)
static member RationalZ (p,q) = BigRationalLarge.Normalize (p,q)
static member Parse (str:string) =
let len = str.Length
if len=0 then invalidArg "str" "empty string";
let j = str.IndexOf '/'
if j >= 0 then
let p = BigInteger.Parse (str.Substring(0,j))
let q = BigInteger.Parse (str.Substring(j+1,len-j-1))
BigRationalLarge.RationalZ (p,q)
else
let p = BigInteger.Parse str
BigRationalLarge.RationalZ (p,OneI)
static member (~-) (Q(bp,bq)) = Q(-bp,bq) // still coprime, bq >= 0
static member (+) (Q(ap,aq),Q(bp,bq)) = BigRationalLarge.Normalize ((ap * bq) + (bp * aq),aq * bq)
static member (-) (Q(ap,aq),Q(bp,bq)) = BigRationalLarge.Normalize ((ap * bq) - (bp * aq),aq * bq)
static member (*) (Q(ap,aq),Q(bp,bq)) = BigRationalLarge.Normalize (ap * bp,aq * bq)
static member (/) (Q(ap,aq),Q(bp,bq)) = BigRationalLarge.Normalize (ap * bq,aq * bp)
static member ( ~+ )(n1:BigRationalLarge) = n1
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module BigRationalLarge =
open System.Numerics
let inv (Q(ap,aq)) = BigRationalLarge.Normalize(aq,ap)
let pown (Q(p,q)) (n:int) = Q(BigInteger.Pow(p,n),BigInteger.Pow (q,n)) // p,q powers still coprime
let equal (Q(ap,aq)) (Q(bp,bq)) = ap=bp && aq=bq // normal form, so structural equality
let lt a b = BigRationalLarge.LessThan(a,b)
let gt a b = BigRationalLarge.LessThan(b,a)
let lte (Q(ap,aq)) (Q(bp,bq)) = BigInteger.(<=) (ap * bq,bp * aq)
let gte (Q(ap,aq)) (Q(bp,bq)) = BigInteger.(>=) (ap * bq,bp * aq)
let of_bigint z = BigRationalLarge.RationalZ(z,OneI)
let of_int n = BigRationalLarge.Rational(n,1)
// integer part
let integer (Q(p,q)) =
let mutable r = BigInteger(0)
let d = BigInteger.DivRem (p,q,&r) // have p = d.q + r, |r| < |q|
if r < ZeroI
then d - OneI // p = (d-1).q + (r+q)
else d // p = d.q + r
//----------------------------------------------------------------------------
// BigRational
//--------------------------------------------------------------------------
[<CustomEquality; CustomComparison>]
[<StructuredFormatDisplay("{StructuredDisplayString}N")>]
type BigRational =
| Z of BigInteger
| Q of BigRationalLarge
static member ( + )(n1,n2) =
match n1,n2 with
| Z z ,Z zz -> Z (z + zz)
| Q q ,Q qq -> Q (q + qq)
| Z z ,Q qq -> Q (BigRationalLarge.of_bigint z + qq)
| Q q ,Z zz -> Q (q + BigRationalLarge.of_bigint zz)
static member ( * )(n1,n2) =
match n1,n2 with
| Z z ,Z zz -> Z (z * zz)
| Q q ,Q qq -> Q (q * qq)
| Z z ,Q qq -> Q (BigRationalLarge.of_bigint z * qq)
| Q q ,Z zz -> Q (q * BigRationalLarge.of_bigint zz)
static member ( - )(n1,n2) =
match n1,n2 with
| Z z ,Z zz -> Z (z - zz)
| Q q ,Q qq -> Q (q - qq)
| Z z ,Q qq -> Q (BigRationalLarge.of_bigint z - qq)
| Q q ,Z zz -> Q (q - BigRationalLarge.of_bigint zz)
static member ( / )(n1,n2) =
match n1,n2 with
| Z z ,Z zz -> Q (BigRationalLarge.RationalZ(z,zz))
| Q q ,Q qq -> Q (q / qq)
| Z z ,Q qq -> Q (BigRationalLarge.of_bigint z / qq)
| Q q ,Z zz -> Q (q / BigRationalLarge.of_bigint zz)
static member ( ~- )(n1) =
match n1 with
| Z z -> Z (-z)
| Q q -> Q (-q)
static member ( ~+ )(n1:BigRational) = n1
// nb. Q and Z hash codes must match up - see notes above
override n.GetHashCode() =
match n with
| Z z -> z.GetHashCode()
| Q q -> q.GetHashCode()
override this.Equals(obj:obj) =
match obj with
| :? BigRational as that -> BigRational.(=)(this, that)
| _ -> false
interface System.IComparable with
member n1.CompareTo(obj:obj) =
match obj with
| :? BigRational as n2 ->
if BigRational.(<)(n1, n2) then -1 elif BigRational.(=)(n1, n2) then 0 else 1
| _ -> invalidArg "obj" "the objects are not comparable"
static member FromInt (x:int) = Z (bigint x)
static member FromBigInt x = Z x
static member Zero = BigRational.FromInt(0)
static member One = BigRational.FromInt(1)
static member PowN (n,i:int) =
match n with
| Z z -> Z (BigInteger.Pow (z,i))
| Q q -> Q (BigRationalLarge.pown q i)
static member op_Equality (n,nn) =
match n,nn with
| Z z ,Z zz -> BigInteger.(=) (z,zz)
| Q q ,Q qq -> (BigRationalLarge.equal q qq)
| Z z ,Q qq -> (BigRationalLarge.equal (BigRationalLarge.of_bigint z) qq)
| Q q ,Z zz -> (BigRationalLarge.equal q (BigRationalLarge.of_bigint zz))
static member op_Inequality (n,nn) = not (BigRational.op_Equality(n,nn))
static member op_LessThan (n,nn) =
match n,nn with
| Z z ,Z zz -> BigInteger.(<) (z,zz)
| Q q ,Q qq -> (BigRationalLarge.lt q qq)
| Z z ,Q qq -> (BigRationalLarge.lt (BigRationalLarge.of_bigint z) qq)
| Q q ,Z zz -> (BigRationalLarge.lt q (BigRationalLarge.of_bigint zz))
static member op_GreaterThan (n,nn) =
match n,nn with
| Z z ,Z zz -> BigInteger.(>) (z,zz)
| Q q ,Q qq -> (BigRationalLarge.gt q qq)
| Z z ,Q qq -> (BigRationalLarge.gt (BigRationalLarge.of_bigint z) qq)
| Q q ,Z zz -> (BigRationalLarge.gt q (BigRationalLarge.of_bigint zz))
static member op_LessThanOrEqual (n,nn) =
match n,nn with
| Z z ,Z zz -> BigInteger.(<=) (z,zz)
| Q q ,Q qq -> (BigRationalLarge.lte q qq)
| Z z ,Q qq -> (BigRationalLarge.lte (BigRationalLarge.of_bigint z) qq)
| Q q ,Z zz -> (BigRationalLarge.lte q (BigRationalLarge.of_bigint zz))
static member op_GreaterThanOrEqual (n,nn) =
match n,nn with
| Z z ,Z zz -> BigInteger.(>=) (z,zz)
| Q q ,Q qq -> (BigRationalLarge.gte q qq)
| Z z ,Q qq -> (BigRationalLarge.gte (BigRationalLarge.of_bigint z) qq)
| Q q ,Z zz -> (BigRationalLarge.gte q (BigRationalLarge.of_bigint zz))
member n.IsNegative =
match n with
| Z z -> sign z < 0
| Q q -> q.IsNegative
member n.IsPositive =
match n with
| Z z -> sign z > 0
| Q q -> q.IsPositive
member n.Numerator =
match n with
| Z z -> z
| Q q -> q.Numerator
member n.Denominator =
match n with
| Z _ -> OneI
| Q q -> q.Denominator
member n.Sign =
if n.IsNegative then -1
elif n.IsPositive then 1
else 0
static member Abs(n:BigRational) =
if n.IsNegative then -n else n
static member ToDouble(n:BigRational) =
match n with
| Z z -> ToDoubleI z
| Q q -> BigRationalLarge.ToDouble q
static member ToBigInt(n:BigRational) =
match n with
| Z z -> z
| Q q -> BigRationalLarge.integer q
static member ToInt32(n:BigRational) =
match n with
| Z z -> ToInt32I(z)
| Q q -> ToInt32I(BigRationalLarge.integer q)
static member op_Explicit (n:BigRational) = BigRational.ToInt32 n
static member op_Explicit (n:BigRational) = BigRational.ToDouble n
static member op_Explicit (n:BigRational) = BigRational.ToBigInt n
override n.ToString() =
match n with
| Z z -> z.ToString()
| Q q -> q.ToString()
member x.StructuredDisplayString = x.ToString()
static member Parse(s:string) = Q (BigRationalLarge.Parse s)
type BigNum = BigRational
type bignum = BigNum
module NumericLiteralN =
let FromZero () = BigRational.Zero
let FromOne () = BigRational.One
let FromInt32 i = BigRational.FromInt i
let FromInt64 (i64:int64) = BigRational.FromBigInt (new BigInteger(i64))
let FromString s = BigRational.Parse s

94
src/FSharp/BigRational.fsi

@ -0,0 +1,94 @@
// First version copied from the F# Power Pack
// https://raw.github.com/fsharp/powerpack/master/src/FSharp.PowerPack/math/q.fsi
// (c) Microsoft Corporation 2005-2009.
namespace MathNet.Numerics
open System
open System.Numerics
/// The type of arbitrary-sized rational numbers
[<Sealed>]
type BigRational =
/// Return the sum of two rational numbers
static member ( + ) : BigRational * BigRational -> BigRational
/// Return the product of two rational numbers
static member ( * ) : BigRational * BigRational -> BigRational
/// Return the difference of two rational numbers
static member ( - ) : BigRational * BigRational -> BigRational
/// Return the ratio of two rational numbers
static member ( / ) : BigRational * BigRational -> BigRational
/// Return the negation of a rational number
static member ( ~- ): BigRational -> BigRational
/// Return the given rational number
static member ( ~+ ): BigRational -> BigRational
override ToString: unit -> string
override GetHashCode: unit -> int
interface System.IComparable
/// Get zero as a rational number
static member Zero : BigRational
/// Get one as a rational number
static member One : BigRational
/// This operator is for use from other .NET languages
static member op_Equality : BigRational * BigRational -> bool
/// This operator is for use from other .NET languages
static member op_Inequality : BigRational * BigRational -> bool
/// This operator is for use from other .NET languages
static member op_LessThan: BigRational * BigRational -> bool
/// This operator is for use from other .NET languages
static member op_GreaterThan: BigRational * BigRational -> bool
/// This operator is for use from other .NET languages
static member op_LessThanOrEqual: BigRational * BigRational -> bool
/// This operator is for use from other .NET languages
static member op_GreaterThanOrEqual: BigRational * BigRational -> bool
/// Return a boolean indicating if this rational number is strictly negative
member IsNegative: bool
/// Return a boolean indicating if this rational number is strictly positive
member IsPositive: bool
/// Return the numerator of the normalized rational number
member Numerator: BigInteger
/// Return the denominator of the normalized rational number
member Denominator: BigInteger
member StructuredDisplayString : string
/// Return the absolute value of a rational number
static member Abs : BigRational -> BigRational
/// Return the sign of a rational number; 0, +1 or -1
member Sign : int
/// Return the result of raising the given rational number to the given power
static member PowN : BigRational * int -> BigRational
/// Return the result of converting the given integer to a rational number
static member FromInt : int -> BigRational
/// Return the result of converting the given big integer to a rational number
static member FromBigInt : BigInteger -> BigRational
/// Return the result of converting the given rational number to a floating point number
static member ToDouble: BigRational -> float
/// Return the result of converting the given rational number to a big integer
static member ToBigInt: BigRational -> BigInteger
/// Return the result of converting the given rational number to an integer
static member ToInt32 : BigRational -> int
/// Return the result of converting the given rational number to a floating point number
static member op_Explicit : BigRational -> float
/// Return the result of converting the given rational number to a big integer
static member op_Explicit : BigRational -> BigInteger
/// Return the result of converting the given rational number to an integer
static member op_Explicit : BigRational -> int
/// Return the result of converting the string to a rational number
static member Parse: string -> BigRational
type BigNum = BigRational
type bignum = BigRational
[<RequireQualifiedAccess>]
module NumericLiteralN =
val FromZero : unit -> BigRational
val FromOne : unit -> BigRational
val FromInt32 : int32 -> BigRational
val FromInt64 : int64 -> BigRational
val FromString : string -> BigRational

152
src/FSharp/Complex.fs

@ -0,0 +1,152 @@
// First version copied from the F# Power Pack
// https://raw.github.com/fsharp/powerpack/master/src/FSharp.PowerPack/math/complex.fs
// (c) Microsoft Corporation 2005-2009.
namespace MathNet.Numerics
open Microsoft.FSharp.Math
open System
open System.Globalization
open System.Numerics
type complex = Complex
type complex32 = Complex32
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module Complex =
let mkRect(a,b) = new Complex(a,b)
let mkPolar(a,b) = Complex.FromPolarCoordinates(a,b)
let cis b = mkPolar(1.0,b)
let ofComplex32 (x:complex32) = new Complex(float x.Real, float x.Imaginary)
let zero = Complex.Zero
let one = Complex.One
let onei = Complex.ImaginaryOne
let pi = mkRect (Math.PI,0.0)
let realPart (c:complex) = c.Real
let imagPart (c:complex) = c.Imaginary
let magnitude (c:complex) = c.Magnitude
let phase (c:complex) = c.Phase
let neg (a:complex) = -a
let conjugate (c:complex) = c.Conjugate()
let add (a:complex) (b:complex) = a + b
let sub (a:complex) (b:complex) = a - b
let mul (a:complex) (b:complex) = a * b
let div (x:complex) (y:complex) = x / y
let smul (a:float) (b:complex) = new Complex(a * b.Real, a * b.Imaginary)
let muls (a:complex) (b:float) = new Complex(a.Real * b, a.Imaginary * b)
let exp (x:complex) = Complex.Exp(x)
let ln x = Complex.Log(x)
let log10 x = Complex.Log10(x)
let log b x = Complex.Log(x,b)
let pow (power:complex) x = Complex.Pow(x,power)
let powf (power:float) x = Complex.Pow(x,power)
let sqr (x:complex) = x.Square()
let sqrt (x:complex) = x.SquareRoot() // numerically more stable than Complex.Sqrt
let sin x = Complex.Sin(x)
let cos x = Complex.Cos(x)
let tan x = Complex.Tan(x)
let asin x = Complex.Asin(x)
let acos x = Complex.Acos(x)
let atan x = Complex.Atan(x)
let sinh x = Complex.Sinh(x)
let cosh x = Complex.Cosh(x)
let tanh x = Complex.Tanh(x)
let sec (x:complex) = Trig.Secant(x)
let csc (x:complex) = Trig.Cosecant(x)
let cot (x:complex) = Trig.Cotangent(x)
let asec (x:complex) = Trig.InverseSecant(x)
let acsc (x:complex) = Trig.InverseCosecant(x)
let acot (x:complex) = Trig.InverseCotangent(x)
let sech (x:complex) = Trig.HyperbolicSecant(x)
let csch (x:complex) = Trig.HyperbolicCosecant(x)
let coth (x:complex) = Trig.HyperbolicCotangent(x)
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module Complex32 =
let mkRect(a,b) = new Complex32(a,b)
let mkPolar(a,b) = Complex32.FromPolarCoordinates(a,b)
let cis b = mkPolar(1.0f,b)
let ofComplex (x:complex) = new Complex32(float32 x.Real, float32 x.Imaginary)
let zero = Complex32.Zero
let one = Complex32.One
let onei = Complex32.ImaginaryOne
let pi = mkRect (float32 Math.PI,0.0f)
let realPart (c:complex32) = c.Real
let imagPart (c:complex32) = c.Imaginary
let magnitude (c:complex32) = c.Magnitude
let phase (c:complex32) = c.Phase
let neg (a:complex32) = -a
let conjugate (c:complex32) = c.Conjugate()
let add (a:complex32) (b:complex32) = a + b
let sub (a:complex32) (b:complex32) = a - b
let mul (a:complex32) (b:complex32) = a * b
let div (x:complex32) (y:complex32) = x / y
let smul (a:float32) (b:complex32) = new Complex32(a * b.Real, a * b.Imaginary)
let muls (a:complex32) (b:float32) = new Complex32(a.Real * b, a.Imaginary * b)
let exp (x:complex32) = Complex32.Exp(x)
let ln x = Complex32.Log(x)
let log10 x = Complex32.Log10(x)
let log b x = Complex32.Log(x,b)
let pow (power:complex32) x = Complex32.Pow(x,power)
let powf (power:float32) x = Complex32.Pow(x,power)
let sqr (x:complex32) = x.Square()
let sqrt (x:complex32) = x.SquareRoot() // numerically more stable than Complex.Sqrt
let sin x = Complex32.Sin(x)
let cos x = Complex32.Cos(x)
let tan x = Complex32.Tan(x)
let asin x = Complex32.Asin(x)
let acos x = Complex32.Acos(x)
let atan x = Complex32.Atan(x)
let sinh x = Complex32.Sinh(x)
let cosh x = Complex32.Cosh(x)
let tanh x = Complex32.Tanh(x)
// no complex32 implementations available yet, fix once available
let sec (x:complex32) = ofComplex <| Trig.Secant(x.ToComplex())
let csc (x:complex32) = ofComplex <| Trig.Cosecant(x.ToComplex())
let cot (x:complex32) = ofComplex <| Trig.Cotangent(x.ToComplex())
let asec (x:complex32) = ofComplex <| Trig.InverseSecant(x.ToComplex())
let acsc (x:complex32) = ofComplex <| Trig.InverseCosecant(x.ToComplex())
let acot (x:complex32) = ofComplex <| Trig.InverseCotangent(x.ToComplex())
let sech (x:complex32) = ofComplex <| Trig.HyperbolicSecant(x.ToComplex())
let csch (x:complex32) = ofComplex <| Trig.HyperbolicCosecant(x.ToComplex())
let coth (x:complex32) = ofComplex <| Trig.HyperbolicCotangent(x.ToComplex())
[<AutoOpen>]
module ComplexExtensions =
let complex x y = Complex.mkRect (x,y)
let complex32 x y = Complex32.mkRect (x,y)
type Complex with
member x.r = x.Real
member x.i = x.Imaginary
static member Create(a,b) = Complex.mkRect (a,b)
static member CreatePolar(a,b) = Complex.mkPolar (a,b)
type Complex32 with
member x.r = x.Real
member x.i = x.Imaginary
static member Create(a,b) = Complex32.mkRect (a,b)
static member CreatePolar(a,b) = Complex32.mkPolar (a,b)

253
src/FSharp/Complex.fsi

@ -0,0 +1,253 @@
// First version copied from the F# Power Pack
// https://raw.github.com/fsharp/powerpack/master/src/FSharp.PowerPack/math/complex.fsi
// (c) Microsoft Corporation 2005-2009.
namespace MathNet.Numerics
open System
open System.Numerics
/// The type of complex numbers
type complex = Complex
type complex32 = Complex32
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module Complex =
/// Create a complex number using real and imaginary parts
val mkRect : float * float -> complex
/// Create a complex number using magnitude/phase polar coordinates
val mkPolar : float * float -> complex
/// A complex of magnitude 1 and the given phase and , i.e. cis x = mkPolar 1.0 x
val cis : float -> complex
/// The complex number 0+0i
val zero : complex
/// The complex number 1+0i
val one : complex
/// The complex number 0+1i
val onei : complex
/// pi
val pi : complex
/// The real part of a complex number
val realPart : complex -> float
/// The imaginary part of a complex number
val imagPart : complex -> float
/// The polar-coordinate magnitude of a complex number
val magnitude : complex -> float
/// The polar-coordinate phase of a complex number
val phase : complex -> float
/// Unary negation of a complex number
val neg : complex -> complex
/// The conjugate of a complex number, i.e. x-yi
val conjugate : complex -> complex
/// Add two complex numbers
val add : complex -> complex -> complex
/// Subtract one complex number from another
val sub : complex -> complex -> complex
/// Multiply two complex numbers
val mul : complex -> complex -> complex
/// Complex division of two complex numbers
val div : complex -> complex -> complex
/// Multiply a scalar by a complex number
val smul : float -> complex -> complex
/// Multiply a complex number by a scalar
val muls : complex -> float -> complex
/// exp(x) = e^x
val exp : complex -> complex
/// ln(x) is natural log (base e)
val ln : complex -> complex
/// log10(x) is common log (base 10)
val log10 : complex -> complex
/// log(base,x) is log with custom base
val log : float -> complex -> complex
/// pow(power,x) is the complex power
val pow : complex -> complex -> complex
/// pow(power,x) is the float power
val powf : float -> complex -> complex
/// sqr(x) is the square (power 2)
val sqr : complex -> complex
/// sqrt(x) and 0 <= phase(x) < pi
val sqrt : complex -> complex
/// Sine
val sin : complex -> complex
/// Cosine
val cos : complex -> complex
/// Tagent
val tan : complex -> complex
/// Arc Sine
val asin : complex -> complex
/// Arc Cosine
val acos : complex -> complex
/// Arc Tagent
val atan : complex -> complex
/// Hyperbolic Sine
val sinh : complex -> complex
/// Hyperbolic Cosine
val cosh : complex -> complex
/// Hyperbolic Tagent
val tanh : complex -> complex
/// Secant
val sec : complex -> complex
/// Cosecant
val csc : complex -> complex
/// Cotangent
val cot : complex -> complex
/// Arc Secant
val asec : complex -> complex
/// Arc Cosecant
val acsc : complex -> complex
/// Arc Cotangent
val acot : complex -> complex
/// Hyperbolic Secant
val sech : complex -> complex
/// Hyperbolic Cosecant
val csch : complex -> complex
/// Hyperbolic Cotangent
val coth : complex -> complex
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module Complex32 =
/// Create a complex number using real and imaginary parts
val mkRect : float32 * float32 -> complex32
/// Create a complex number using magnitude/phase polar coordinates
val mkPolar : float32 * float32 -> complex32
/// A complex of magnitude 1 and the given phase and , i.e. cis x = mkPolar 1.0 x
val cis : float32 -> complex32
/// The complex number 0+0i
val zero : complex32
/// The complex number 1+0i
val one : complex32
/// The complex number 0+1i
val onei : complex32
/// pi
val pi : complex32
/// The real part of a complex number
val realPart : complex32 -> float32
/// The imaginary part of a complex number
val imagPart : complex32 -> float32
/// The polar-coordinate magnitude of a complex number
val magnitude : complex32 -> float32
/// The polar-coordinate phase of a complex number
val phase : complex32 -> float32
/// Unary negation of a complex number
val neg : complex32 -> complex32
/// The conjugate of a complex number, i.e. x-yi
val conjugate : complex32 -> complex32
/// Add two complex numbers
val add : complex32 -> complex32 -> complex32
/// Subtract one complex number from another
val sub : complex32 -> complex32 -> complex32
/// Multiply two complex numbers
val mul : complex32 -> complex32 -> complex32
/// Complex division of two complex numbers
val div : complex32 -> complex32 -> complex32
/// Multiply a scalar by a complex number
val smul : float32 -> complex32 -> complex32
/// Multiply a complex number by a scalar
val muls : complex32 -> float32 -> complex32
/// exp(x) = e^x
val exp : complex32 -> complex32
/// ln(x) is natural log (base e)
val ln : complex32 -> complex32
/// log10(x) is common log (base 10)
val log10 : complex32 -> complex32
/// log(base,x) is log with custom base
val log : float32 -> complex32 -> complex32
/// pow(power,x) is the complex power
val pow : complex32 -> complex32 -> complex32
/// pow(power,x) is the float power
val powf : float32 -> complex32 -> complex32
/// sqr(x) is the square (power 2)
val sqr : complex32 -> complex32
/// sqrt(x) and 0 <= phase(x) < pi
val sqrt : complex32 -> complex32
/// Sine
val sin : complex32 -> complex32
/// Cosine
val cos : complex32 -> complex32
/// Tagent
val tan : complex32 -> complex32
/// Arc Sine
val asin : complex32 -> complex32
/// Arc Cosine
val acos : complex32 -> complex32
/// Arc Tagent
val atan : complex32 -> complex32
/// Hyperbolic Sine
val sinh : complex32 -> complex32
/// Hyperbolic Cosine
val cosh : complex32 -> complex32
/// Hyperbolic Tagent
val tanh : complex32 -> complex32
/// Secant
val sec : complex32 -> complex32
/// Cosecant
val csc : complex32 -> complex32
/// Cotangent
val cot : complex32 -> complex32
/// Arc Secant
val asec : complex32 -> complex32
/// Arc Cosecant
val acsc : complex32 -> complex32
/// Arc Cotangent
val acot : complex32 -> complex32
/// Hyperbolic Secant
val sech : complex32 -> complex32
/// Hyperbolic Cosecant
val csch : complex32 -> complex32
/// Hyperbolic Cotangent
val coth : complex32 -> complex32
[<AutoOpen>]
module ComplexExtensions =
/// Constructs a double precision complex number from both the real and imaginary part.
val complex : float -> float -> complex
/// Constructs a single precision complex number from both the real and imaginary part.
val complex32 : float32 -> float32 -> complex32
/// The type of complex numbers stored as pairs of 64-bit floating point numbers in rectangular coordinates
type Complex with
/// Create a complex number x+ij using rectangular coordinates
static member Create : float * float -> Complex
/// Create a complex number using magnitude/phase polar coordinates
static member CreatePolar : float * float -> Complex
/// The real part of a complex number
member r: float
/// The imaginary part of a complex number
member i: float
/// The type of complex numbers stored as pairs of 32-bit floating point numbers in rectangular coordinates
type Complex32 with
/// Create a complex number x+ij using rectangular coordinates
static member Create : float32 * float32 -> Complex32
/// Create a complex number using magnitude/phase polar coordinates
static member CreatePolar : float32 * float32 -> Complex32
/// The real part of a complex number
member r: float32
/// The imaginary part of a complex number
member i: float32

10
src/FSharp/FSharp.fsproj

@ -19,7 +19,7 @@
<Optimize>false</Optimize> <Optimize>false</Optimize>
<Tailcalls>false</Tailcalls> <Tailcalls>false</Tailcalls>
<OutputPath>..\..\out\debug\Net40\</OutputPath> <OutputPath>..\..\out\debug\Net40\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>TRACE;DEBUG</DefineConstants>
<WarningLevel>3</WarningLevel> <WarningLevel>3</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
@ -38,7 +38,7 @@
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<Tailcalls>true</Tailcalls> <Tailcalls>true</Tailcalls>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE;STRONGNAME</DefineConstants>
<WarningLevel>3</WarningLevel> <WarningLevel>3</WarningLevel>
<DocumentationFile>..\..\out\lib\Net40\MathNet.Numerics.FSharp.xml</DocumentationFile> <DocumentationFile>..\..\out\lib\Net40\MathNet.Numerics.FSharp.xml</DocumentationFile>
<OutputPath>bin\Release-Signed\</OutputPath> <OutputPath>bin\Release-Signed\</OutputPath>
@ -57,6 +57,12 @@
<Compile Include="LinearAlgebra.Double.Vector.fs" /> <Compile Include="LinearAlgebra.Double.Vector.fs" />
<Compile Include="LinearAlgebra.Double.Matrix.fs" /> <Compile Include="LinearAlgebra.Double.Matrix.fs" />
<Compile Include="LinearAlgebra.Double.fs" /> <Compile Include="LinearAlgebra.Double.fs" />
<Compile Include="Complex.fsi" />
<Compile Include="Complex.fs" />
<Compile Include="BigIntegerExtensions.fs" />
<Compile Include="BigRational.fsi" />
<Compile Include="BigRational.fs" />
<Compile Include="RandomVariable.fs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="FSharp.Core" /> <Reference Include="FSharp.Core" />

52
src/FSharp/LinearAlgebra.Double.Matrix.fs

@ -35,7 +35,7 @@ open MathNet.Numerics.LinearAlgebra.Generic
/// A module which implements functional matrix operations. /// A module which implements functional matrix operations.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Matrix = module Matrix =
/// Fold a function over all matrix elements. /// Fold a function over all matrix elements.
let inline fold (f: 'a -> float -> 'a) (acc0: 'a) (A: #Matrix<float>) = let inline fold (f: 'a -> float -> 'a) (acc0: 'a) (A: #Matrix<float>) =
let n = A.RowCount let n = A.RowCount
@ -71,8 +71,8 @@ module Matrix =
let n = A.RowCount let n = A.RowCount
let m = A.ColumnCount let m = A.ColumnCount
Array2D.init n m (fun i j -> (A.Item(i,j))) Array2D.init n m (fun i j -> (A.Item(i,j)))
/// Checks whether a predicate holds for all elements of a matrix. /// Checks whether a predicate holds for all elements of a matrix.
let inline forall (p: float -> bool) (A: #Matrix<float>) = let inline forall (p: float -> bool) (A: #Matrix<float>) =
let mutable b = true let mutable b = true
let mutable i = 0 let mutable i = 0
@ -82,7 +82,7 @@ module Matrix =
j <- j+1 j <- j+1
if j = A.ColumnCount then i <- i+1; j <- 0 if j = A.ColumnCount then i <- i+1; j <- 0
b b
/// Chechks whether a predicate holds for at least one element of a matrix. /// Chechks whether a predicate holds for at least one element of a matrix.
let inline exists (p: float -> bool) (A: #Matrix<float>) = let inline exists (p: float -> bool) (A: #Matrix<float>) =
let mutable b = false let mutable b = false
@ -93,7 +93,7 @@ module Matrix =
j <- j+1 j <- j+1
if j = A.ColumnCount then i <- i+1; j <- 0 if j = A.ColumnCount then i <- i+1; j <- 0
b b
/// Checks whether a position dependent predicate holds for all elements of a matrix. /// Checks whether a position dependent predicate holds for all elements of a matrix.
let inline foralli (p: int -> int -> float -> bool) (A: #Matrix<float>) = let inline foralli (p: int -> int -> float -> bool) (A: #Matrix<float>) =
let mutable b = true let mutable b = true
@ -104,7 +104,7 @@ module Matrix =
j <- j+1 j <- j+1
if j = A.ColumnCount then i <- i+1; j <- 0 if j = A.ColumnCount then i <- i+1; j <- 0
b b
/// Checks whether a position dependent predicate holds for at least one element of a matrix. /// Checks whether a position dependent predicate holds for at least one element of a matrix.
let inline existsi (p: int -> int -> float -> bool) (A: #Matrix<float>) = let inline existsi (p: int -> int -> float -> bool) (A: #Matrix<float>) =
let mutable b = false let mutable b = false
@ -115,7 +115,7 @@ module Matrix =
j <- j+1 j <- j+1
if j = A.ColumnCount then i <- i+1; j <- 0 if j = A.ColumnCount then i <- i+1; j <- 0
b b
/// Map every matrix element using the given function. /// Map every matrix element using the given function.
let inline map (f: float -> float) (A: #Matrix<float>) = let inline map (f: float -> float) (A: #Matrix<float>) =
let N = A.RowCount let N = A.RowCount
@ -125,7 +125,7 @@ module Matrix =
for j=0 to M-1 do for j=0 to M-1 do
C.[i,j] <- f (C.Item(i,j)) C.[i,j] <- f (C.Item(i,j))
C C
/// Map every matrix element using the given position dependent function. /// Map every matrix element using the given position dependent function.
let inline mapi (f: int -> int -> float -> float) (A: #Matrix<float>) = let inline mapi (f: int -> int -> float -> float) (A: #Matrix<float>) =
let N = A.RowCount let N = A.RowCount
@ -135,7 +135,7 @@ module Matrix =
for j=0 to M-1 do for j=0 to M-1 do
C.[i,j] <- f i j (C.Item(i,j)) C.[i,j] <- f i j (C.Item(i,j))
C C
/// In-place map every matrix column using the given position dependent function. /// In-place map every matrix column using the given position dependent function.
let inline inplaceMapCols (f: int -> Vector<float> -> Vector<float>) (A: #Matrix<float>) = let inline inplaceMapCols (f: int -> Vector<float> -> Vector<float>) (A: #Matrix<float>) =
for j = 0 to A.ColumnCount-1 do for j = 0 to A.ColumnCount-1 do
@ -165,19 +165,19 @@ module Matrix =
for i=0 to A.RowCount-1 do for i=0 to A.RowCount-1 do
for j=0 to A.ColumnCount-1 do for j=0 to A.ColumnCount-1 do
A.Item(i,j) <- f i j A.Item(i,j) <- f i j
/// In-place map of every matrix element using a position dependent function. /// In-place map of every matrix element using a position dependent function.
let inline inplaceMapi (f: int -> int -> float -> float) (A: #Matrix<float>) = let inline inplaceMapi (f: int -> int -> float -> float) (A: #Matrix<float>) =
for i=0 to A.RowCount-1 do for i=0 to A.RowCount-1 do
for j=0 to A.ColumnCount-1 do for j=0 to A.ColumnCount-1 do
A.Item(i,j) <- f i j (A.Item(i,j)) A.Item(i,j) <- f i j (A.Item(i,j))
/// Creates a sequence that iterates the non-zero entries in the matrix. /// Creates a sequence that iterates the non-zero entries in the matrix.
let inline nonZeroEntries (A: #Matrix<float>) = let inline nonZeroEntries (A: #Matrix<float>) =
seq { for i in 0 .. A.RowCount-1 do seq { for i in 0 .. A.RowCount-1 do
for j in 0 .. A.ColumnCount-1 do for j in 0 .. A.ColumnCount-1 do
if A.Item(i,j) <> 0.0 then yield (i,j, A.Item(i,j)) } if A.Item(i,j) <> 0.0 then yield (i,j, A.Item(i,j)) }
/// Returns the sum of all elements of a matrix. /// Returns the sum of all elements of a matrix.
let inline sum (A: #Matrix<float>) = let inline sum (A: #Matrix<float>) =
let mutable f = 0.0 let mutable f = 0.0
@ -189,7 +189,7 @@ module Matrix =
/// Returns the sum of the results generated by applying a position dependent function to each column of the matrix. /// Returns the sum of the results generated by applying a position dependent function to each column of the matrix.
let inline sumColsBy (f: int -> Vector<float> -> 'a) (A: #Matrix<float>) = let inline sumColsBy (f: int -> Vector<float> -> 'a) (A: #Matrix<float>) =
A.ColumnEnumerator() |> Seq.map (fun (j,col) -> f j col) |> Seq.reduce (+) A.ColumnEnumerator() |> Seq.map (fun (j,col) -> f j col) |> Seq.reduce (+)
/// Returns the sum of the results generated by applying a position dependent function to each row of the matrix. /// Returns the sum of the results generated by applying a position dependent function to each row of the matrix.
let inline sumRowsBy (f: int -> Vector<float> -> 'a) (A: #Matrix<float>) = let inline sumRowsBy (f: int -> Vector<float> -> 'a) (A: #Matrix<float>) =
A.RowEnumerator() |> Seq.map (fun (i,row) -> f i row) |> Seq.reduce (+) A.RowEnumerator() |> Seq.map (fun (i,row) -> f i row) |> Seq.reduce (+)
@ -200,21 +200,21 @@ module Matrix =
for j=0 to A.ColumnCount-1 do for j=0 to A.ColumnCount-1 do
f (A.Item(i,j)) f (A.Item(i,j))
() ()
/// Iterates over all elements of a matrix using the element indices. /// Iterates over all elements of a matrix using the element indices.
let inline iteri (f: int -> int -> float -> unit) (A: #Matrix<float>) = let inline iteri (f: int -> int -> float -> unit) (A: #Matrix<float>) =
for i=0 to A.RowCount-1 do for i=0 to A.RowCount-1 do
for j=0 to A.ColumnCount-1 do for j=0 to A.ColumnCount-1 do
f i j (A.Item(i,j)) f i j (A.Item(i,j))
() ()
/// Fold one column. /// Fold one column.
let inline foldCol (f: 'a -> float -> 'a) acc (A: #Matrix<float>) k = let inline foldCol (f: 'a -> float -> 'a) acc (A: #Matrix<float>) k =
let mutable macc = acc let mutable macc = acc
for i=0 to A.RowCount-1 do for i=0 to A.RowCount-1 do
macc <- f macc (A.Item(i,k)) macc <- f macc (A.Item(i,k))
macc macc
/// Fold one row. /// Fold one row.
let inline foldRow (f: 'a -> float -> 'a) acc (A: #Matrix<float>) k = let inline foldRow (f: 'a -> float -> 'a) acc (A: #Matrix<float>) k =
let mutable macc = acc let mutable macc = acc
@ -231,7 +231,7 @@ module Matrix =
macc <- f macc (A.Item(i,k)) macc <- f macc (A.Item(i,k))
v.[k] <- macc v.[k] <- macc
v :> Vector<float> v :> Vector<float>
/// Fold all rows into one column vector. /// Fold all rows into one column vector.
let inline foldByRow (f: float -> float -> float) acc (A: #Matrix<float>) = let inline foldByRow (f: float -> float -> float) acc (A: #Matrix<float>) =
let v = new DenseVector(A.RowCount) let v = new DenseVector(A.RowCount)
@ -253,7 +253,7 @@ module DenseMatrix =
for j=0 to m-1 do for j=0 to m-1 do
A.[i,j] <- f i j A.[i,j] <- f i j
A A
/// Create a matrix from a list of float lists. Every list in the master list specifies a row. /// Create a matrix from a list of float lists. Every list in the master list specifies a row.
let inline ofList (fll: float list list) = let inline ofList (fll: float list list) =
let n = List.length fll let n = List.length fll
@ -263,7 +263,7 @@ module DenseMatrix =
if (List.length fl) <> m then failwith "Each subrow must be of the same length." else if (List.length fl) <> m then failwith "Each subrow must be of the same length." else
List.iteri (fun j f -> A.[i,j] <- f) fl) List.iteri (fun j f -> A.[i,j] <- f) fl)
A A
/// Create a matrix from a list of sequences. Every sequence in the master sequence specifies a row. /// Create a matrix from a list of sequences. Every sequence in the master sequence specifies a row.
let inline ofSeq (fss: #seq<#seq<float>>) = let inline ofSeq (fss: #seq<#seq<float>>) =
let n = Seq.length fss let n = Seq.length fss
@ -276,20 +276,20 @@ module DenseMatrix =
/// Create a matrix from a 2D array of floating point numbers. /// Create a matrix from a 2D array of floating point numbers.
let inline ofArray2 (arr: float[,]) = new DenseMatrix(arr) let inline ofArray2 (arr: float[,]) = new DenseMatrix(arr)
/// Create a matrix with the given entries. /// Create a matrix with the given entries.
let inline initDense (n: int) (m: int) (es: #seq<int * int * float>) = let inline initDense (n: int) (m: int) (es: #seq<int * int * float>) =
let A = new DenseMatrix(n,m) let A = new DenseMatrix(n,m)
Seq.iter (fun (i,j,f) -> A.[i,j] <- f) es Seq.iter (fun (i,j,f) -> A.[i,j] <- f) es
A A
/// Create a square matrix with constant diagonal entries. /// Create a square matrix with constant diagonal entries.
let inline constDiag (n: int) (f: float) = let inline constDiag (n: int) (f: float) =
let A = new DenseMatrix(n,n) let A = new DenseMatrix(n,n)
for i=0 to n-1 do for i=0 to n-1 do
A.[i,i] <- f A.[i,i] <- f
A A
/// Create a square matrix with the vector elements on the diagonal. /// Create a square matrix with the vector elements on the diagonal.
let inline diag (v: #Vector<float>) = let inline diag (v: #Vector<float>) =
let n = v.Count let n = v.Count
@ -313,26 +313,26 @@ module DenseMatrix =
/// A module which implements functional sparse vector operations. /// A module which implements functional sparse vector operations.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module SparseMatrix = module SparseMatrix =
/// Create a matrix from a list of float lists. Every list in the master list specifies a row. /// Create a matrix from a list of float lists. Every list in the master list specifies a row.
let inline ofList (rows: int) (cols: int) (fll: list<int * int * float>) = let inline ofList (rows: int) (cols: int) (fll: list<int * int * float>) =
let A = new SparseMatrix(rows, cols) let A = new SparseMatrix(rows, cols)
fll |> List.iter (fun (i, j, x) -> A.[i,j] <- x) fll |> List.iter (fun (i, j, x) -> A.[i,j] <- x)
A A
/// Create a matrix from a list of sequences. Every sequence in the master sequence specifies a row. /// Create a matrix from a list of sequences. Every sequence in the master sequence specifies a row.
let inline ofSeq (rows: int) (cols: int) (fss: #seq<int * int * float>) = let inline ofSeq (rows: int) (cols: int) (fss: #seq<int * int * float>) =
let A = new SparseMatrix(rows, cols) let A = new SparseMatrix(rows, cols)
fss |> Seq.iter (fun (i, j, x) -> A.[i,j] <- x) fss |> Seq.iter (fun (i, j, x) -> A.[i,j] <- x)
A A
/// Create a square matrix with constant diagonal entries. /// Create a square matrix with constant diagonal entries.
let inline constDiag (n: int) (f: float) = let inline constDiag (n: int) (f: float) =
let A = new SparseMatrix(n,n) let A = new SparseMatrix(n,n)
for i=0 to n-1 do for i=0 to n-1 do
A.[i,i] <- f A.[i,i] <- f
A A
/// Create a square matrix with the vector elements on the diagonal. /// Create a square matrix with the vector elements on the diagonal.
let inline diag (v: #Vector<float>) = let inline diag (v: #Vector<float>) =
let n = v.Count let n = v.Count

50
src/FSharp/LinearAlgebra.Double.Vector.fs

@ -35,12 +35,12 @@ open MathNet.Numerics.LinearAlgebra.Generic
/// A module which implements functional vector operations. /// A module which implements functional vector operations.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Vector = module Vector =
/// Transform a vector into an array. /// Transform a vector into an array.
let inline toArray (v: #Vector<float>) = let inline toArray (v: #Vector<float>) =
let n = v.Count let n = v.Count
Array.init n (fun i -> v.Item(i)) Array.init n (fun i -> v.Item(i))
/// Transform a vector into an array. /// Transform a vector into an array.
let inline toList (v: #Vector<float>) = let inline toList (v: #Vector<float>) =
let n = v.Count let n = v.Count
@ -57,30 +57,30 @@ module Vector =
for i=0 to v.Count-1 do for i=0 to v.Count-1 do
v.Item(i) <- f i (v.Item(i)) v.Item(i) <- f i (v.Item(i))
() ()
/// In-place vector addition. /// In-place vector addition.
let inline addInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Add(w, v) let inline addInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Add(w, v)
/// In place vector subtraction. /// In place vector subtraction.
let inline subInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Subtract(w, v) let inline subInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Subtract(w, v)
/// Functional map operator for vectors. /// Functional map operator for vectors.
/// <include file='../../../../FSharpExamples/DenseVector.xml' path='example'/> /// <include file='../../../../FSharpExamples/DenseVector.xml' path='example'/>
let inline map f (v: #Vector<float>) = let inline map f (v: #Vector<float>) =
let w = v.Clone() let w = v.Clone()
mapInPlace (fun x -> f x) w mapInPlace (fun x -> f x) w
w w
/// Applies a function to all elements of the vector. /// Applies a function to all elements of the vector.
let inline iter (f: float -> unit) (v: #Vector<float>) = let inline iter (f: float -> unit) (v: #Vector<float>) =
for i=0 to v.Count-1 do for i=0 to v.Count-1 do
f (v.Item i) f (v.Item i)
/// Applies a function to all elements of the vector. /// Applies a function to all elements of the vector.
let inline iteri (f: int -> float -> unit) (v: #Vector<float>) = let inline iteri (f: int -> float -> unit) (v: #Vector<float>) =
for i=0 to v.Count-1 do for i=0 to v.Count-1 do
f i (v.Item i) f i (v.Item i)
/// Maps a vector to a new vector by applying a function to every element. /// Maps a vector to a new vector by applying a function to every element.
let inline mapi (f: int -> float -> float) (v: #Vector<float>) = let inline mapi (f: int -> float -> float) (v: #Vector<float>) =
let w = v.Clone() let w = v.Clone()
@ -107,7 +107,7 @@ module Vector =
for i=0 to v.Count-1 do for i=0 to v.Count-1 do
acc <- f i acc (v.Item(i)) acc <- f i acc (v.Item(i))
acc acc
/// Checks whether a predicate is satisfied for every element in the vector. /// Checks whether a predicate is satisfied for every element in the vector.
let inline forall (p: float -> bool) (v: #Vector<float>) = let inline forall (p: float -> bool) (v: #Vector<float>) =
let mutable b = true let mutable b = true
@ -116,7 +116,7 @@ module Vector =
b <- b && (p (v.Item(i))) b <- b && (p (v.Item(i)))
i <- i+1 i <- i+1
b b
/// Checks whether there is an entry in the vector that satisfies a given predicate. /// Checks whether there is an entry in the vector that satisfies a given predicate.
let inline exists (p: float -> bool) (v: #Vector<float>) = let inline exists (p: float -> bool) (v: #Vector<float>) =
let mutable b = false let mutable b = false
@ -125,7 +125,7 @@ module Vector =
b <- b || (p (v.Item(i))) b <- b || (p (v.Item(i)))
i <- i+1 i <- i+1
b b
/// Checks whether a predicate is true for all entries in a vector. /// Checks whether a predicate is true for all entries in a vector.
let inline foralli (p: int -> float -> bool) (v: #Vector<float>) = let inline foralli (p: int -> float -> bool) (v: #Vector<float>) =
let mutable b = true let mutable b = true
@ -134,7 +134,7 @@ module Vector =
b <- b && (p i (v.Item(i))) b <- b && (p i (v.Item(i)))
i <- i+1 i <- i+1
b b
/// Checks whether there is an entry in the vector that satisfies a given position dependent predicate. /// Checks whether there is an entry in the vector that satisfies a given position dependent predicate.
let inline existsi (p: int -> float -> bool) (v: #Vector<float>) = let inline existsi (p: int -> float -> bool) (v: #Vector<float>) =
let mutable b = false let mutable b = false
@ -177,13 +177,13 @@ module Vector =
p p
/// Creates a new vector and inserts the given value at the given index. /// Creates a new vector and inserts the given value at the given index.
let inline insert index value (v: #Vector<float>) = let inline insert index value (v: #Vector<float>) =
let newV = new DenseVector(v.Count + 1) let newV = new DenseVector(v.Count + 1)
for i = 0 to index - 1 do for i = 0 to index - 1 do
newV.Item(i) <- v.Item(i) newV.Item(i) <- v.Item(i)
newV.Item(index) <- value newV.Item(index) <- value
for i = index + 1 to v.Count do for i = index + 1 to v.Count do
newV.Item(i) <- v.Item(i - 1) newV.Item(i) <- v.Item(i - 1)
newV newV
/// A module which implements functional dense vector operations. /// A module which implements functional dense vector operations.
@ -203,14 +203,14 @@ module DenseVector =
let v = DenseVector(n) let v = DenseVector(n)
fl |> List.iteri (fun i f -> v.[i] <- f) fl |> List.iteri (fun i f -> v.[i] <- f)
v v
/// Create a vector from a sequences. /// Create a vector from a sequences.
let inline ofSeq (fs: #seq<float>) = let inline ofSeq (fs: #seq<float>) =
let n = Seq.length fs let n = Seq.length fs
let v = DenseVector(n) let v = DenseVector(n)
fs |> Seq.iteri (fun i f -> v.[i] <- f) fs |> Seq.iteri (fun i f -> v.[i] <- f)
v v
/// Create a vector with evenly spaced entries: e.g. rangef -1.0 0.5 1.0 = [-1.0 -0.5 0.0 0.5 1.0] /// Create a vector with evenly spaced entries: e.g. rangef -1.0 0.5 1.0 = [-1.0 -0.5 0.0 0.5 1.0]
let inline rangef (start: float) (step: float) (stop: float) = let inline rangef (start: float) (step: float) (stop: float) =
let n = (int ((stop - start) / step)) + 1 let n = (int ((stop - start) / step)) + 1
@ -218,7 +218,7 @@ module DenseVector =
for i=0 to n-1 do for i=0 to n-1 do
v.[i] <- (float i) * step + start v.[i] <- (float i) * step + start
v v
/// Create a vector with integer entries in the given range. /// Create a vector with integer entries in the given range.
let inline range (start: int) (stop: int) = let inline range (start: int) (stop: int) =
new DenseVector([| for i in [start .. stop] -> float i |]) new DenseVector([| for i in [start .. stop] -> float i |])
@ -226,13 +226,13 @@ module DenseVector =
/// A module which implements functional sparse vector operations. /// A module which implements functional sparse vector operations.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module SparseVector = module SparseVector =
/// Create a sparse vector with a given dimension from a list of entry, value pairs. /// Create a sparse vector with a given dimension from a list of entry, value pairs.
let inline ofList (dim: int) (fl: list<int * float>) = let inline ofList (dim: int) (fl: list<int * float>) =
let v = new SparseVector(dim) let v = new SparseVector(dim)
fl |> List.iter (fun (i, f) -> v.[i] <- f) fl |> List.iter (fun (i, f) -> v.[i] <- f)
v v
/// Create a sparse vector with a given dimension from a sequence of entry, value pairs. /// Create a sparse vector with a given dimension from a sequence of entry, value pairs.
let inline ofSeq (dim: int) (fs: #seq<int * float>) = let inline ofSeq (dim: int) (fs: #seq<int * float>) =
let v = new SparseVector(dim) let v = new SparseVector(dim)

18
src/FSharp/LinearAlgebra.fs

@ -33,19 +33,19 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
// Module that contains implementation of useful F#-specific // Module that contains implementation of useful F#-specific
// extension members for generic Matrix and Vector types // extension members for generic Matrix and Vector types
[<AutoOpen>] [<AutoOpen>]
module FSharpExtensions = module FSharpExtensions =
// A type extension for the generic vector type that // A type extension for the generic vector type that
// adds the 'GetSlice' method to allow vec.[a .. b] syntax // adds the 'GetSlice' method to allow vec.[a .. b] syntax
type MathNet.Numerics.LinearAlgebra.Generic. type MathNet.Numerics.LinearAlgebra.Generic.
Vector<'T when 'T : struct and 'T : (new : unit -> 'T) Vector<'T when 'T : struct and 'T : (new : unit -> 'T)
and 'T :> System.IEquatable<'T> and 'T :> System.IFormattable and 'T :> System.IEquatable<'T> and 'T :> System.IFormattable
and 'T :> System.ValueType> with and 'T :> System.ValueType> with
/// Gets a slice of a vector starting at a specified index /// Gets a slice of a vector starting at a specified index
/// and ending at a specified index (both indices are optional) /// and ending at a specified index (both indices are optional)
/// This method can be used via the x.[start .. finish] syntax /// This method can be used via the x.[start .. finish] syntax
member x.GetSlice(start, finish) = member x.GetSlice(start, finish) =
let start = defaultArg start 0 let start = defaultArg start 0
let finish = defaultArg finish (x.Count - 1) let finish = defaultArg finish (x.Count - 1)
x.SubVector(start, finish - start + 1) x.SubVector(start, finish - start + 1)
@ -53,14 +53,14 @@ module FSharpExtensions =
// A type extension for the generic matrix type that // A type extension for the generic matrix type that
// adds the 'GetSlice' method to allow m.[r1 .. r2, c1 .. c2] syntax // adds the 'GetSlice' method to allow m.[r1 .. r2, c1 .. c2] syntax
type MathNet.Numerics.LinearAlgebra.Generic. type MathNet.Numerics.LinearAlgebra.Generic.
Matrix<'T when 'T : struct and 'T : (new : unit -> 'T) Matrix<'T when 'T : struct and 'T : (new : unit -> 'T)
and 'T :> System.IEquatable<'T> and 'T :> System.IFormattable and 'T :> System.IEquatable<'T> and 'T :> System.IFormattable
and 'T :> System.ValueType> with and 'T :> System.ValueType> with
/// Gets a submatrix using a specified column range and /// Gets a submatrix using a specified column range and
/// row range (all indices are optional) /// row range (all indices are optional)
/// This method can be used via the x.[r1 .. r2, c1 .. c2 ] syntax /// This method can be used via the x.[r1 .. r2, c1 .. c2 ] syntax
member x.GetSlice(rstart, rfinish, cstart, cfinish) = member x.GetSlice(rstart, rfinish, cstart, cfinish) =
let cstart = defaultArg cstart 0 let cstart = defaultArg cstart 0
let rstart = defaultArg rstart 0 let rstart = defaultArg rstart 0
let cfinish = defaultArg cfinish (x.ColumnCount - 1) let cfinish = defaultArg cfinish (x.ColumnCount - 1)

95
src/FSharp/RandomVariable.fs

@ -0,0 +1,95 @@
module MathNet.Numerics.Probability
#nowarn "40"
open System
open System.Collections
open System.Collections.Generic
open MathNet.Numerics
type Outcome<'T> = {
Value: 'T
Probability : BigRational }
type RandomVariable<'T> = Outcome<'T> seq
// P(A AND B) = P(A | B) * P(B)
let private bind f dist =
dist
|> Seq.map (fun p1 ->
f p1.Value
|> Seq.map (fun p2 ->
{ Value = p2.Value;
Probability =
p1.Probability * p2.Probability}))
|> Seq.concat
/// Inject a value into the RandomVariable type
let private returnM value =
Seq.singleton { Value = value ; Probability = 1N/1N }
type RandomVariableBuilder() =
member this.Bind (r, f) = bind f r
member this.Return x = returnM x
member this.ReturnFrom x = x
let randomVariable = RandomVariableBuilder()
type CoinSide =
| Heads
| Tails
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module RandomVariable =
// Create some helpers
let toUniformDistribution seq =
let l = Seq.length seq
seq
|> Seq.map (fun e ->
{ Value = e;
Probability = 1N / bignum.FromInt l })
let probability dist =
dist
|> Seq.map (fun o -> o.Probability)
|> Seq.sum
let certainly = returnM
let impossible<'a> :'a RandomVariable = toUniformDistribution []
let fairDice sides = toUniformDistribution [1..sides]
let fairCoin = toUniformDistribution [Heads; Tails]
let filter predicate dist =
dist |> Seq.filter (fun o -> predicate o.Value)
let filterInAnyOrder items dist =
items
|> Seq.fold (fun d item -> filter (Seq.exists ((=) (item))) d) dist
/// Transforms a RandomVariable value by using a specified mapping function.
let map f dist =
dist
|> Seq.map (fun o -> { Value = f o.Value; Probability = o.Probability })
let selectOne values =
[for e in values -> e,values |> Seq.filter ((<>) e)]
|> toUniformDistribution
let rec selectMany n values =
match n with
| 0 -> certainly ([],values)
| _ ->
randomVariable {
let! (x,c1) = selectOne values
let! (xs,c2) = selectMany (n-1) c1
return x::xs,c2}
let select n values =
selectMany n values
|> map (fst >> List.rev)
let remove items = Seq.filter (fun v -> Seq.forall ((<>) v) items)

2
src/FSharpExamples/Apply.fs

@ -90,5 +90,5 @@ for (name, fs, dotnet) in FunctionList do
if prettyPrint then printfn "\tApply.Map (MKL): %d milliseconds." sw.ElapsedMilliseconds if prettyPrint then printfn "\tApply.Map (MKL): %d milliseconds." sw.ElapsedMilliseconds
else printf "\t%d" sw.ElapsedMilliseconds else printf "\t%d" sw.ElapsedMilliseconds
sw.Reset()*) sw.Reset()*)
printfn "" printfn ""

20
src/FSharpExamples/MCMC.fs

@ -45,7 +45,7 @@ let rnd = new MersenneTwister()
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
do do
printfn "Rejection Sampling Example" printfn "Rejection Sampling Example"
/// The target distribution. /// The target distribution.
let beta = new Beta(2.7, 6.3) let beta = new Beta(2.7, 6.3)
@ -76,7 +76,7 @@ do
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
do do
printfn "Metropolis Sampling Example" printfn "Metropolis Sampling Example"
let mean, stddev = 1.0, 3.5 let mean, stddev = 1.0, 3.5
let normal = new Normal(mean, stddev) let normal = new Normal(mean, stddev)
@ -93,7 +93,7 @@ do
printfn "\tEmpirical StdDev = %f (should be %f)" (Statistics.StandardDeviation(arr)) normal.StdDev printfn "\tEmpirical StdDev = %f (should be %f)" (Statistics.StandardDeviation(arr)) normal.StdDev
printfn "\tAcceptance rate = %f" ms.AcceptanceRate printfn "\tAcceptance rate = %f" ms.AcceptanceRate
printfn "" printfn ""
// //
@ -107,12 +107,12 @@ do
printfn "Metropolis Hastings Sampling Example (Symmetric Proposal)" printfn "Metropolis Hastings Sampling Example (Symmetric Proposal)"
let mean, stddev = 1.0, 3.5 let mean, stddev = 1.0, 3.5
let normal = new Normal(mean, stddev) let normal = new Normal(mean, stddev)
/// Evaluates the log normal distribution. /// Evaluates the log normal distribution.
let npdf x m s = -0.5*(x-m)*(x-m)/(s*s) - 0.5 * log(2.0 * System.Math.PI * s * s) let npdf x m s = -0.5*(x-m)*(x-m)/(s*s) - 0.5 * log(2.0 * System.Math.PI * s * s)
/// Implements the rejection sampling procedure. /// Implements the rejection sampling procedure.
let ms = new MetropolisHastingsSampler<float>( 0.1, (fun x -> log(normal.Density(x))), let ms = new MetropolisHastingsSampler<float>( 0.1, (fun x -> log(normal.Density(x))),
(fun x y -> npdf x y 0.3), (fun x -> Normal.Sample(rnd, x, 0.3)), 10, (fun x y -> npdf x y 0.3), (fun x -> Normal.Sample(rnd, x, 0.3)), 10,
RandomSource = rnd ) RandomSource = rnd )
@ -138,22 +138,22 @@ do
printfn "Metropolis Hastings Sampling Example (Assymetric Proposal)" printfn "Metropolis Hastings Sampling Example (Assymetric Proposal)"
let mean, stddev = 1.0, 3.5 let mean, stddev = 1.0, 3.5
let normal = new Normal(mean, stddev) let normal = new Normal(mean, stddev)
/// Evaluates the logarithm of the normal distribution function. /// Evaluates the logarithm of the normal distribution function.
let npdf x m s = -0.5*(x-m)*(x-m)/(s*s) - 0.5 * log(2.0 * System.Math.PI * s * s) let npdf x m s = -0.5*(x-m)*(x-m)/(s*s) - 0.5 * log(2.0 * System.Math.PI * s * s)
/// Samples from a mixture that is biased towards samples larger than x. /// Samples from a mixture that is biased towards samples larger than x.
let mixSample x = let mixSample x =
if Bernoulli.Sample(rnd, 0.5) = 1 then if Bernoulli.Sample(rnd, 0.5) = 1 then
Normal.Sample(rnd, x, 0.3) Normal.Sample(rnd, x, 0.3)
else else
Normal.Sample(rnd, x + 0.1, 0.3) Normal.Sample(rnd, x + 0.1, 0.3)
/// The transition kernel for the proposal above. /// The transition kernel for the proposal above.
let krnl xnew x = log (0.5 * exp(npdf xnew x 0.3) + 0.5 * exp(npdf xnew (x+0.1) 0.3)) let krnl xnew x = log (0.5 * exp(npdf xnew x 0.3) + 0.5 * exp(npdf xnew (x+0.1) 0.3))
/// Implements the rejection sampling procedure. /// Implements the rejection sampling procedure.
let ms = new MetropolisHastingsSampler<float>( 0.1, (fun x -> log(normal.Density(x))), let ms = new MetropolisHastingsSampler<float>( 0.1, (fun x -> log(normal.Density(x))),
(fun xnew x -> krnl xnew x), (fun x -> mixSample x), 10, (fun xnew x -> krnl xnew x), (fun x -> mixSample x), 10,
RandomSource = rnd ) RandomSource = rnd )
@ -178,7 +178,7 @@ do
printfn "Slice Sampling Example" printfn "Slice Sampling Example"
let mean, stddev = 1.0, 3.5 let mean, stddev = 1.0, 3.5
let normal = new Normal(mean, stddev) let normal = new Normal(mean, stddev)
/// Evaluates the unnormalized logarithm of the normal distribution function. /// Evaluates the unnormalized logarithm of the normal distribution function.
let npdf x m s = -0.5*(x-m)*(x-m)/(s*s) let npdf x m s = -0.5*(x-m)*(x-m)/(s*s)

18
src/FSharpPortable/FSharpPortable.fsproj

@ -62,6 +62,24 @@
<Compile Include="..\FSharp\LinearAlgebra.Double.fs"> <Compile Include="..\FSharp\LinearAlgebra.Double.fs">
<Link>LinearAlgebra.Double.fs</Link> <Link>LinearAlgebra.Double.fs</Link>
</Compile> </Compile>
<Compile Include="..\FSharp\Complex.fsi">
<Link>Complex.fsi</Link>
</Compile>
<Compile Include="..\FSharp\Complex.fs">
<Link>Complex.fs</Link>
</Compile>
<Compile Include="..\FSharp\BigIntegerExtensions.fs">
<Link>BigIntegerExtensions.fs</Link>
</Compile>
<Compile Include="..\FSharp\BigRational.fsi">
<Link>BigRational.fsi</Link>
</Compile>
<Compile Include="..\FSharp\BigRational.fs">
<Link>BigRational.fs</Link>
</Compile>
<Compile Include="..\FSharp\RandomVariable.fs">
<Link>RandomVariable.fs</Link>
</Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Portable\Portable.csproj"> <ProjectReference Include="..\Portable\Portable.csproj">

11
src/FSharpPortableUnitTests/App.config

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

104
src/FSharpPortableUnitTests/FSharpPortableUnitTests.fsproj

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>90ce8e32-354e-4728-8fe6-87342f469321</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>FSharpPortableUnitTests</RootNamespace>
<AssemblyName>FSharpPortableUnitTests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<Name>FSharpPortableUnitTests</Name>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<Tailcalls>false</Tailcalls>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<WarningLevel>3</WarningLevel>
<DocumentationFile>bin\Debug\FSharpPortableUnitTests.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<Tailcalls>true</Tailcalls>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<WarningLevel>3</WarningLevel>
<DocumentationFile>bin\Release\FSharpPortableUnitTests.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets" Condition=" Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')" />
<ItemGroup>
<None Include="packages.config" />
<Compile Include="..\FSharpUnitTests\FsUnit.fs">
<Link>FsUnit.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\VectorTests.fs">
<Link>VectorTests.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\SparseVectorTests.fs">
<Link>SparseVectorTests.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\DenseVectorTests.fs">
<Link>DenseVectorTests.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\MatrixTests.fs">
<Link>MatrixTests.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\SparseMatrixTests.fs">
<Link>SparseMatrixTests.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\DenseMatrixTests.fs">
<Link>DenseMatrixTests.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\Utilities.fs">
<Link>Utilities.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\BigRationalTests.fs">
<Link>BigRationalTests.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\RandomVariableTests.fs">
<Link>RandomVariableTests.fs</Link>
</Compile>
<Compile Include="..\FSharpUnitTests\PokerTests.fs">
<Link>PokerTests.fs</Link>
</Compile>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>True</Private>
</Reference>
<Reference Include="nunit.framework, Version=2.6.2.12296, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
<ProjectReference Include="..\FSharpPortable\FSharpPortable.fsproj">
<Name>FSharpPortable</Name>
<Project>{f5f14d76-428d-43d7-8431-5b885f1ba419}</Project>
<Private>True</Private>
</ProjectReference>
<ProjectReference Include="..\Portable\Portable.csproj">
<Name>Portable</Name>
<Project>{d877f358-a2d2-4cc3-a921-8aa5cf6187e8}</Project>
<Private>True</Private>
</ProjectReference>
</ItemGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

4
src/FSharpPortableUnitTests/packages.config

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="2.6.2" targetFramework="net45" />
</packages>

6
src/FSharpUnitTests/App.config

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
</startup>
</configuration>

606
src/FSharpUnitTests/BigRationalTests.fs

@ -0,0 +1,606 @@
// First version copied from the F# Power Pack
// https://raw.github.com/fsharp/powerpack/master/src/FSharp.PowerPack.Unittests/BigRationalTests.fs
namespace MathNet.Numerics.Tests
open MathNet.Numerics
open NUnit.Framework
open System
open System.Collections
open System.Collections.Generic
open System.Numerics
[<TestFixture>]
type public BigRationalTests() =
// BigRational Tests
// =================
// Notes: What cases to consider?
// For (p,q) cases q=0, q=1, q<>1. [UPDATE: remove (x,0)]
// For (p,q) when q=1 there could be 2 internal representations, either Z or Q.
// For (p,0) this value can be signed, corresponds to +/- infinity point. [Update: remove it]
// Hashes on (p,1) for both representations must agree.
// For binary operators, try for result with and without HCF (normalisation).
// Also: 0/0 is an acceptable representation. See normalisation code. [Update: remove it].
// Overrides to test:
// .ToString()
// .GetHashCode()
// .Equals()
// IComparable.CompareTo()
// Misc construction.
let natA n = BigRational.FromInt n // internally Z
let natB n = (natA n / natA 7) * natA 7 // internally Q
let ratio p q = BigRational.FromInt p / BigRational.FromInt q
let (/%) b c = BigRational.FromBigInt b / BigRational.FromBigInt c
// Misc test values
let q0 = natA 0
let q1 = natA 1
let q2 = natA 2
let q3 = natA 3
let q4 = natA 4
let q5 = natA 5
let minIntI = bigint System.Int32.MinValue
let maxIntI = bigint System.Int32.MaxValue
let ran = System.Random()
let nextZ n = bigint (ran.Next(n))
// A selection of test points.
let points =
// A selection of integer and reciprical points
let points =
[for i in -13I .. 13I -> i,1I] @
[for i in -13I .. 13I -> 1I,i]
// Exclude x/0
let points = [for p,q in points do if q <> 0I then yield p,q ] // PROPOSE: (q,0) never a valid Q value, filter them out of tests...
// Scale by various values, including into BigInt range
let scale (kp,kq) (p,q) = (p*kp,q*kq)
let scales k pqs = List.map (scale k) pqs
let points = List.concat [points;
scales (10000I,1I) points;
scales (1I,10000I) points;
scales (maxIntI,1I) points;
scales (1I,maxIntI) points;
]
points
let pointsNonZero = [for p,q in points do if p<>0I then yield p,q] // non zero points
let makeQs p q =
if q = 1I && minIntI <= p && p <= maxIntI then
// (p,1) where p is int32
let p32 = int32 p
[natA p32;natB p32;BigRational.FromBigInt p] // two reprs for int32
else
[BigRational.FromBigInt p / BigRational.FromBigInt q]
let miscQs = [for p,q in points do yield! makeQs p q]
let product xs ys = [for x in xs do for y in ys do yield x,y]
let vector1s = [for z in points -> z]
let vector2s = product points points
[<Test>]
member this.BasicTests1() =
check "generic format h" "1N" (sprintf "%A" 1N)
check "generic format q" "-1N" (sprintf "%A" (-1N))
test "vliwe98" (id -2N = - 2N)
test "d3oc002" (LanguagePrimitives.GenericZero<bignum> = 0N)
test "d3oc112w" (LanguagePrimitives.GenericOne<bignum> = 1N)
check "weioj3h" (sprintf "%O" 3N) "3"
check "weioj3k" (sprintf "%O" (3N / 4N)) "3/4"
check "weioj3k" (sprintf "%O" (3N / 400000000N)) "3/400000000"
check "weioj3l" (sprintf "%O" (3N / 3N)) "1"
check "weioj3q" (sprintf "%O" (-3N)) "-3"
//check "weioj3w" (sprintf "%O" -3N) "-3"
check "weioj3e" (sprintf "%O" (-3N / -3N)) "1"
// The reason why we do not use hardcoded values is the the representation may change based on the NetFx we are targeting.
// For example, when targeting NetFx4.0, the result is "-3E+61" instead of "-3000....0N"
let v = -30000000000000000000000000000000000000000000000000000000000000N
check "weioj3r" (sprintf "%O" v) ((box v).ToString())
[<Test>]
member this.BasicTests2() =
// Test arithmetic ops: tests
let test2One name f check ((p,q),(pp,qq)) =
// There may be several ways to construct the test rationals
let zs = makeQs p q
let zzs = makeQs pp qq
let results = [for z in zs do for zz in zzs do yield f (z,zz)]
let refP,refQ = check (p,q) (pp,qq)
let refResult = BigRational.FromBigInt refP / BigRational.FromBigInt refQ
let resOK (result:BigRational) =
result.Numerator * refQ = refP * result.Denominator &&
BigRational.Equals(refResult,result)
match List.tryFind (fun result -> not (resOK result)) results with
| None -> () // ok
| Some result -> printf "Test failed. %s (%A,%A) (%A,%A). Expected %A. Observed %A\n" name p q pp qq refResult result
reportFailure "cejkew09"
let test2All name f check vectors = List.iter (test2One name f check) vectors
// Test arithmetic ops: call
test2All "add" (BigRational.(+)) (fun (p,q) (pp,qq) -> (p*qq + q*pp,q*qq)) vector2s
test2All "sub" (BigRational.(-)) (fun (p,q) (pp,qq) -> (p*qq - q*pp,q*qq)) vector2s
test2All "mul" (BigRational.(*)) (fun (p,q) (pp,qq) -> (p*pp,q*qq)) vector2s // *) <-- for EMACS
test2All "div" (BigRational.(/)) (fun (p,q) (pp,qq) -> (p*qq,q*pp)) (product points pointsNonZero)
[<Test>]
member this.RangeTests() =
// Test x0 .. dx .. x1
let checkRange3 (x0:BigRational) dx x1 k =
let f (x:BigRational) = x * BigRational.FromBigInt k |> BigRational.ToBigInt
let rangeA = {x0 .. dx .. x1} |> Seq.map f
let rangeB = {f x0 .. f dx .. f x1}
//printf "Length=%d\n" (Seq.length rangeA)
let same = Seq.forall2 (=) rangeA rangeB
check (sprintf "Range3 %A .. %A .. %A scaled to %A" x0 dx x1 k) same true
checkRange3 (0I /% 1I) (1I /% 7I) (100I /% 1I) (7I*1I)
checkRange3 (0I /% 1I) (1I /% 7I) (100I /% 11I) (7I*11I)
checkRange3 (1I /% 13I) (1I /% 7I) (100I /% 11I) (7I*11I*13I)
for i = 0 to 1000 do
let m = 1000 // max steps is -m to m in steps of 1/m i.e. 2.m^2
let p0,q0 = nextZ m ,nextZ m + 1I
let p1,q1 = nextZ m ,nextZ m + 1I
let pd,qd = nextZ m + 1I,nextZ m + 1I
checkRange3 (p0 /% q0) (pd /% qd) (p1 /% q1) (q0 * q1 * qd)
// Test x0 .. x1
let checkRange2 (x0:BigRational) x1 =
let z0 = BigRational.ToBigInt x0
let z01 = BigRational.ToBigInt (x1 - x0)
let f (x:BigRational) = x |> BigRational.ToBigInt
let rangeA = [x0 .. x1] |> List.map f // range with each item rounded down
let rangeB = [z0 .. z0 + z01] // range of same length from the round down start point
check (sprintf "Range2: %A .. %A" x0 x1) rangeA rangeB
checkRange2 (0I /% 1I) (100I /% 1I)
checkRange2 (0I /% 1I) (100I /% 11I)
checkRange2 (1I /% 13I) (100I /% 11I)
for i = 0 to 1000 do
let m = 10000 // max steps is -m to m in steps of 1 i.e. 2.m
let p0,q0 = nextZ m ,nextZ m + 1I
let p1,q1 = nextZ m ,nextZ m + 1I
checkRange2 (p0 /% q0) (p1 /% q1) //(q0 * q1 * qd)
// ToString()
// Cases: integer, computed integer, rational<1, rational>1, +/-infinity, nan
(natA 1).ToString() |> check "ToString" "1"
(natA 0).ToString() |> check "ToString" "0"
(natA (-12)).ToString() |> check "ToString" "-12"
(natB 1).ToString() |> check "ToString" "1"
(natB 0).ToString() |> check "ToString" "0"
(natB (-12)).ToString() |> check "ToString" "-12"
(1I /% 3I).ToString() |> check "ToString" "1/3"
(12I /% 5I).ToString() |> check "ToString" "12/5"
//(13I /% 0I).ToString() |> check "ToString" "1/0" // + 1/0. Plan to make this invalid value
//(-13I /% 0I).ToString() |> check "ToString" "1/0" // - 1/0. Plan to make this invalid value
//(0I /% 0I).ToString() |> check "ToString" "0/0" // 0/0. Plan to make this invalid value
// GetHashCode
// Cases: zero, integer, computed integer, computed by multiple routes.
let checkSameHashGeneric a b = check (sprintf "GenericHash %A %A" a b) (a.GetHashCode()) (b.GetHashCode())
let checkSameHash (a:BigRational) (b:BigRational) = check (sprintf "BigRationalHash %A %A" a b) (a.GetHashCode()) (b.GetHashCode()); checkSameHashGeneric a b
List.iter (fun n -> checkSameHash (natA n) (natB n)) [-10 .. 10]
List.iter (fun n -> checkSameHash n ((n * q3 + n * q2) / q5)) miscQs
// bug 3488: should non-finite values be supported?
//let x = BigRational.FromBigInt (-1I) / BigRational.FromBigInt 0I
//let q2,q3,q5 = BigRational.FromInt 2,BigRational.FromInt 3,BigRational.FromInt 5
//let x2 = (x * q2 + x * q3) / q5
//x,x2,x = x2
// Test: Zero,One?
check "ZeroA" BigRational.Zero (natA 0)
check "ZeroA" BigRational.Zero (natA 0)
check "OneA" BigRational.One (natB 1)
check "OneB" BigRational.One (natB 1)
[<Test>]
member this.BinaryAndUnaryOperators() =
// Test: generic bop
let testR2One name f check ((p,q),(pp,qq)) =
// There may be several ways to construct the test rationals
let zs = makeQs p q
let zzs = makeQs pp qq
let resultRef = check (p,q) (pp,qq) // : bool
let args = [for z in zs do for zz in zzs do yield (z,zz)]
match List.tryFind (fun (z,zz) -> resultRef <> f (z,zz)) args with
| None -> () // ok
| Some (z,zz) -> printf "Test failed. %s (%A,%A) (%A,%A) = %s %A %A. Expected %A.\n" name p q pp qq name z zz resultRef
reportFailure "cknwe9"
// Test: generic uop
let testR1One name f check (p,q) =
// There may be several ways to construct the test rationals
let zs = makeQs p q
let resultRef = check (p,q) //: bool
match List.tryFind (fun z -> resultRef <> f z) zs with
| None -> () // ok
| Some z -> printf "Test failed. %s (%A,%A) = %s %A. Expected %A.\n" name p q name z resultRef
reportFailure "vekjkrejvre0"
let testR2All name f check vectors = List.iter (testR2One name f check) vectors
let testR1All name f check vectors = List.iter (testR1One name f check) vectors
// Test: relations
let sign (i:BigInteger) = BigInteger(i.Sign)
testR2All "=" BigRational.(=) (fun (p,q) (pp,qq) -> (p*qq = q*pp)) vector2s
testR2All "=" BigRational.op_Equality (fun (p,q) (pp,qq) -> (p*qq = q*pp)) vector2s
testR2All "!=" BigRational.op_Inequality (fun (p,q) (pp,qq) -> (p*qq <> q*pp)) vector2s
// p/q < pp/qq
// iff (p * sign q) / (q * sign q) < (pp * sign qq) / (qq * sign qq)
// iff (p * sign q) * (qq * sign qq) < (pp * sign qq) * (q * sign q) since q*sign q is always +ve.
testR2All "<" BigRational.(<) (fun (p,q) (pp,qq) -> (p * sign q) * (qq * sign qq) < (pp * sign qq) * (q * sign q)) vector2s
testR2All ">" BigRational.(>) (fun (p,q) (pp,qq) -> (p * sign q) * (qq * sign qq) > (pp * sign qq) * (q * sign q)) vector2s
testR2All "<=" BigRational.(<=) (fun (p,q) (pp,qq) -> (p * sign q) * (qq * sign qq) <= (pp * sign qq) * (q * sign q)) vector2s
testR2All ">=" BigRational.(>=) (fun (p,q) (pp,qq) -> (p * sign q) * (qq * sign qq) >= (pp * sign qq) * (q * sign q)) vector2s
// System.IComparable tests
let BigRationalCompareTo (p:BigRational,q:BigRational) = (p :> System.IComparable).CompareTo(q)
testR2All "IComparable.CompareTo" BigRationalCompareTo (fun (p,q) (pp,qq) -> compare ((p * sign q) * (qq * sign qq)) ((pp * sign qq) * (q * sign q))) vector2s
// Test: is negative, is positive
testR1All "IsNegative" (fun (x:BigRational) -> x.IsNegative) (fun (p,q) -> sign p * sign q = -1I) vector1s
testR1All "IsPositive" (fun (x:BigRational) -> x.IsPositive) (fun (p,q) -> sign p * sign q = 1I) vector1s
testR1All "IsZero" (fun (x:BigRational) -> x = q0) (fun (p,q) -> sign p = 0I) vector1s
let test1One name f check (p,q) =
// There may be several ways to construct the test rationals
let zs = makeQs p q
let results = [for z in zs -> f z]
let refP,refQ = check (p,q)
let refResult = BigRational.FromBigInt refP / BigRational.FromBigInt refQ
let resOK (result:BigRational) =
result.Numerator * refQ = refP * result.Denominator &&
BigRational.Equals(refResult,result)
match List.tryFind (fun result -> not (resOK result)) results with
| None -> () // ok
| Some result -> printf "Test failed. %s (%A,%A). Expected %A. Observed %A\n" name p q refResult result
reportFailure "klcwe09wek"
let test1All name f check vectors = List.iter (test1One name f check) vectors
test1All "neg" (BigRational.(~-)) (fun (p,q) -> (-p,q)) vector1s
test1All "pos" (BigRational.(~+)) (fun (p,q) -> (p,q)) vector1s // why have ~+ ???
// Test: Abs,Sign
test1All "Abs" (BigRational.Abs) (fun (p,q) -> (abs p,abs q)) vector1s
testR1All "Sign" (fun (x:BigRational) -> x.Sign) (fun (p,q) -> check "NonZeroDenom" (sign q <> 0I) true; (sign p * sign q) |> int32) vector1s
// Test: PowN
test1All "PowN(x,2)" (fun x -> BigRational.PowN(x,2)) (fun (p,q) -> (p*p,q*q)) vector1s
test1All "PowN(x,1)" (fun x -> BigRational.PowN(x,1)) (fun (p,q) -> (p,q)) vector1s
test1All "PowN(x,0)" (fun x -> BigRational.PowN(x,0)) (fun (p,q) -> (1I,1I)) vector1s
// MatteoT: moved to numbersVS2008\test.ml
//test1All "PowN(x,200)" (fun x -> BigRational.PowN(x,200)) (fun (p,q) -> (BigInteger.Pow(p,200I),BigInteger.Pow(q,200I))) vector1s
// MatteoT: moved to numbersVS2008\test.ml
//let powers = [0I .. 100I]
//powers |> List.iter (fun i -> test1All "PowN(x,i)" (fun x -> BigRational.PowN(x,int i)) (fun (p,q) -> (BigInteger.Pow(p,i),BigInteger.Pow(q,i))) vector1s)
// Test: PowN with negative powers - expect exception
testR1All "PowN(x,-1)" (fun x -> throws (fun () -> BigRational.PowN(x,-1))) (fun (p,q) -> true) vector1s
testR1All "PowN(x,-4)" (fun x -> throws (fun () -> BigRational.PowN(x,-4))) (fun (p,q) -> true) vector1s
[<TestFixture>]
type BigNumType() =
let g_positive1 = 1000000000000000000000000000000000018N
let g_positive2 = 1000000000000000000000000000000000000N
let g_negative1 = -1000000000000000000000000000000000018N
let g_negative2 = -1000000000000000000000000000000000000N
let g_negative3 = -1000000000000000000000000000000000036N
let g_zero = 0N
let g_normal = 88N
let g_bigintpositive = 1000000000000000000000000000000000018I
let g_bigintnegative = -1000000000000000000000000000000000018I
// Interfaces
[<Test>]
member this.IComparable() =
// Legit IC
let ic = g_positive1 :> IComparable
Assert.AreEqual(ic.CompareTo(g_positive1),0)
checkThrowsArgumentException( fun () -> ic.CompareTo(g_bigintpositive) |> ignore)
// Base class methods
[<Test>]
member this.ObjectToString() =
// Currently the CLR 4.0 and CLR 2.0 behavior of BigInt.ToString is different, causing this test to fail.
Assert.AreEqual(g_positive1.ToString(),
"1000000000000000000000000000000000018")
Assert.AreEqual(g_zero.ToString(),"0")
Assert.AreEqual(g_normal.ToString(),"88")
// Static methods
[<Test>]
member this.Abs() =
Assert.AreEqual(bignum.Abs(g_negative1), g_positive1)
Assert.AreEqual(bignum.Abs(g_negative2), g_positive2)
Assert.AreEqual(bignum.Abs(g_positive1), g_positive1)
Assert.AreEqual(bignum.Abs(g_normal), g_normal)
Assert.AreEqual(bignum.Abs(g_zero), g_zero)
()
[<Test>]
member this.FromBigInt() =
Assert.AreEqual(bignum.FromBigInt(g_bigintpositive),
g_positive1)
Assert.AreEqual(bignum.FromBigInt(g_bigintnegative),
g_negative1)
Assert.AreEqual(bignum.FromBigInt(0I),g_zero)
Assert.AreEqual(bignum.FromBigInt(88I),g_normal)
()
[<Test>]
member this.FromInt() =
Assert.AreEqual(bignum.FromInt(2147483647), 2147483647N)
Assert.AreEqual(bignum.FromInt(-2147483648), -2147483648N)
Assert.AreEqual(bignum.FromInt(0), 0N)
Assert.AreEqual(bignum.FromInt(88), 88N)
()
[<Test>]
member this.One() =
Assert.AreEqual(bignum.One,1N)
()
[<Test>]
member this.Parse() =
Assert.AreEqual(bignum.Parse("100"), 100N)
Assert.AreEqual(bignum.Parse("-100"), -100N)
Assert.AreEqual(bignum.Parse("0"), g_zero)
Assert.AreEqual(bignum.Parse("88"), g_normal)
()
[<Test>]
member this.PowN() =
Assert.AreEqual(bignum.PowN(100N,2), 10000N)
Assert.AreEqual(bignum.PowN(-3N,3), -27N)
Assert.AreEqual(bignum.PowN(g_zero,2147483647), 0N)
Assert.AreEqual(bignum.PowN(g_normal,0), 1N)
()
[<Test>]
member this.Sign() =
Assert.AreEqual(g_positive1.Sign, 1)
Assert.AreEqual(g_negative1.Sign, -1)
Assert.AreEqual(g_zero.Sign, 0)
Assert.AreEqual(g_normal.Sign, 1)
()
[<Test>]
member this.ToBigInt() =
Assert.AreEqual(bignum.ToBigInt(g_positive1), g_bigintpositive)
Assert.AreEqual(bignum.ToBigInt(g_negative1), g_bigintnegative)
Assert.AreEqual(bignum.ToBigInt(g_zero), 0I)
Assert.AreEqual(bignum.ToBigInt(g_normal), 88I)
()
[<Test>]
member this.ToDouble() =
Assert.AreEqual(bignum.ToDouble(179769N*1000000000000000N), 1.79769E+20)
Assert.AreEqual(bignum.ToDouble(-179769N*1000000000000000N), -1.79769E+20)
Assert.AreEqual(bignum.ToDouble(0N),0.0)
Assert.AreEqual(bignum.ToDouble(88N),88.0)
Assert.AreEqual(double(179769N*1000000000000000N), 1.79769E+20)
Assert.AreEqual(double(-179769N*1000000000000000N), -1.79769E+20)
Assert.AreEqual(double(0N),0.0)
Assert.AreEqual(double(88N),88.0)
()
[<Test>]
member this.ToInt32() =
Assert.AreEqual(bignum.ToInt32(2147483647N), 2147483647)
Assert.AreEqual(bignum.ToInt32(-2147483648N), -2147483648)
Assert.AreEqual(bignum.ToInt32(0N), 0)
Assert.AreEqual(bignum.ToInt32(88N), 88)
Assert.AreEqual(int32(2147483647N), 2147483647)
Assert.AreEqual(int32(-2147483648N), -2147483648)
Assert.AreEqual(int32(0N), 0)
Assert.AreEqual(int32(88N), 88)
[<Test>]
member this.Zero() =
Assert.AreEqual(bignum.Zero,0N)
()
// operator methods
[<Test>]
member this.test_op_Addition() =
Assert.AreEqual(100N + 200N, 300N)
Assert.AreEqual((-100N) + (-200N), -300N)
Assert.AreEqual(g_positive1 + g_negative1, 0N)
Assert.AreEqual(g_zero + g_zero,0N)
Assert.AreEqual(g_normal + g_normal, 176N)
Assert.AreEqual(g_normal + g_normal, 176N)
()
[<Test>]
member this.test_op_Division() =
Assert.AreEqual(g_positive1 / g_positive1, 1N)
Assert.AreEqual(-100N / 2N, -50N)
Assert.AreEqual(g_zero / g_positive1, 0N)
()
[<Test>]
member this.test_op_Equality() =
Assert.IsTrue((g_positive1 = g_positive1))
Assert.IsTrue((g_negative1 = g_negative1))
Assert.IsTrue((g_zero = g_zero))
Assert.IsTrue((g_normal = g_normal))
()
[<Test>]
member this.test_op_GreaterThan() =
Assert.AreEqual((g_positive1 > g_positive2), true)
Assert.AreEqual((g_negative1 > g_negative2), false)
Assert.AreEqual((g_zero > g_zero), false)
Assert.AreEqual((g_normal > g_normal), false)
()
[<Test>]
member this.test_op_GreaterThanOrEqual() =
Assert.AreEqual((g_positive1 >= g_positive2), true)
Assert.AreEqual((g_positive2 >= g_positive1), false)
Assert.AreEqual((g_negative1 >= g_negative1), true)
Assert.AreEqual((0N >= g_zero), true)
()
[<Test>]
member this.test_op_LessThan() =
Assert.AreEqual((g_positive1 < g_positive2), false)
Assert.AreEqual((g_negative1 < g_negative3), false)
Assert.AreEqual((0N < g_zero), false)
()
[<Test>]
member this.test_op_LessThanOrEqual() =
Assert.AreEqual((g_positive1 <= g_positive2), false)
Assert.AreEqual((g_positive2 <= g_positive1), true)
Assert.AreEqual((g_negative1 <= g_negative1), true)
Assert.AreEqual((0N <= g_zero), true)
()
[<Test>]
member this.test_op_Multiply() =
Assert.AreEqual(3N * 5N, 15N)
Assert.AreEqual((-3N) * (-5N), 15N)
Assert.AreEqual((-3N) * 5N, -15N)
Assert.AreEqual(0N * 5N, 0N)
()
[<Test>]
member this.test_op_Range() =
let resultPos = [0N .. 2N]
let seqPos = [0N; 1N; 2N]
verifySeqsEqual resultPos seqPos
let resultNeg = [-2N .. 0N]
let seqNeg = [-2N; -1N; 0N]
verifySeqsEqual resultNeg seqNeg
let resultSmall = [0N ..5N]
let seqSmall = [0N; 1N; 2N; 3N; 4N; 5N]
verifySeqsEqual resultSmall seqSmall
()
[<Test>]
member this.test_op_RangeStep() =
let resultPos = [0N .. 3N .. 6N]
let seqPos = [0N; 3N; 6N]
verifySeqsEqual resultPos seqPos
let resultNeg = [-6N .. 3N .. 0N]
let seqNeg = [-6N; -3N; 0N]
verifySeqsEqual resultNeg seqNeg
let resultSmall = [0N .. 3N .. 9N]
let seqSmall = [0N; 3N; 6N; 9N]
verifySeqsEqual resultSmall seqSmall
()
[<Test>]
member this.test_op_Subtraction() =
Assert.AreEqual(g_positive1 - g_positive2,18N)
Assert.AreEqual(g_negative1 - g_negative3,18N)
Assert.AreEqual(0N-g_positive1, g_negative1)
()
[<Test>]
member this.test_op_UnaryNegation() =
Assert.AreEqual(-g_positive1, g_negative1)
Assert.AreEqual(-g_negative1, g_positive1)
Assert.AreEqual(-0N,0N)
()
[<Test>]
member this.test_op_UnaryPlus() =
Assert.AreEqual(+g_positive1,g_positive1)
Assert.AreEqual(+g_negative1,g_negative1)
Assert.AreEqual(+0N, 0N)
()
// instance methods
[<Test>]
member this.Denominator() =
Assert.AreEqual(g_positive1.Denominator, 1I)
Assert.AreEqual(g_negative1.Denominator, 1I)
Assert.AreEqual(0N.Denominator, 1I)
()
[<Test>]
member this.IsNegative() =
Assert.IsFalse(g_positive1.IsNegative)
Assert.IsTrue(g_negative1.IsNegative)
Assert.IsFalse( 0N.IsNegative)
Assert.IsFalse(-0N.IsNegative)
()
[<Test>]
member this.IsPositive() =
Assert.IsTrue(g_positive1.IsPositive)
Assert.IsFalse(g_negative1.IsPositive)
Assert.IsFalse( 0N.IsPositive)
Assert.IsFalse(-0N.IsPositive)
()
[<Test>]
member this.Numerator() =
Assert.AreEqual(g_positive1.Numerator, g_bigintpositive)
Assert.AreEqual(g_negative1.Numerator, g_bigintnegative)
Assert.AreEqual(0N.Numerator, 0I)
()

51
src/FSharpUnitTests/DenseMatrixTests.fs

@ -0,0 +1,51 @@
namespace MathNet.Numerics.Tests
open NUnit.Framework
open FsUnit
open MathNet.Numerics.LinearAlgebra.Generic
open MathNet.Numerics.LinearAlgebra.Double
/// Unit tests for the dense matrix type.
module DenseMatrixTests =
/// A small uniform vector.
let smallM = new DenseMatrix( Array2D.create 2 2 0.3 )
/// A large vector with increasingly large entries
let largeM = new DenseMatrix( Array2D.init 100 100 (fun i j -> float i * 100.0 + float j) )
[<Test>]
let ``DenseMatrix.init`` () =
DenseMatrix.init 100 100 (fun i j -> float i * 100.0 + float j) |> should equal largeM
[<Test>]
let ``DenseMatrix.ofList`` () =
DenseMatrix.ofList [[0.3;0.3];[0.3;0.3]] |> should equal smallM
[<Test>]
let ``DenseMatrix.ofSeq`` () =
DenseMatrix.ofSeq (Seq.ofList [[0.3;0.3];[0.3;0.3]]) |> should equal smallM
[<Test>]
let ``DenseMatrix.ofArray2`` () =
DenseMatrix.ofArray2 (Array2D.create 2 2 0.3) |> should equal smallM
[<Test>]
let ``DenseMatrix.initDense`` () =
DenseMatrix.initDense 100 100 (seq { for i in 0 .. 99 do
for j in 0 .. 99 -> (i,j, float i * 100.0 + float j)}) |> should equal largeM
[<Test>]
let ``DenseMatrix.constDiag`` () =
DenseMatrix.constDiag 100 2.0 |> should equal (2.0 * (DenseMatrix.Identity 100))
[<Test>]
let ``DenseMatrix.diag`` () =
DenseMatrix.diag (new DenseVector(100, 2.0)) |> should equal (2.0 * (DenseMatrix.Identity 100))
[<Test>]
let ``DenseMatrix.init_row`` () =
DenseMatrix.initRow 100 100 (fun i -> (DenseVector.init 100 (fun j -> float i * 100.0 + float j))) |> should equal largeM
[<Test>]
let ``DenseMatrix.init_col`` () =
DenseMatrix.initCol 100 100 (fun j -> (DenseVector.init 100 (fun i -> float i * 100.0 + float j))) |> should equal largeM

35
src/FSharpUnitTests/DenseVectorTests.fs

@ -0,0 +1,35 @@
namespace MathNet.Numerics.Tests
open NUnit.Framework
open FsUnit
open MathNet.Numerics.LinearAlgebra.Generic
open MathNet.Numerics.LinearAlgebra.Double
/// Unit tests for the dense vector type.
module DenseVectorTests =
/// A small uniform vector.
let smallv = new DenseVector(5, 0.3 )
/// A large vector with increasingly large entries
let largev = new DenseVector( Array.init 100 (fun i -> float i / 100.0) )
[<Test>]
let ``DenseVector.init`` () =
DenseVector.init 100 (fun i -> float i / 100.0) |> should equal largev
[<Test>]
let ``DenseVector.ofList`` () =
DenseVector.ofList [ for i in 0 .. 99 -> float i / 100.0 ] |> should equal largev
[<Test>]
let ``DenseVector.ofSeq`` () =
DenseVector.ofSeq (seq { for i in 0 .. 99 -> float i / 100.0 }) |> should equal largev
[<Test>]
let ``DenseVector.rangef`` () =
DenseVector.rangef 0.0 0.01 0.99 |> should equal (new DenseVector( [| for i in 0 .. 99 -> 0.01 * float i |] ) )
[<Test>]
let ``DenseVector.range`` () =
DenseVector.range 0 99 |> should equal (new DenseVector( [| for i in 0 .. 99 -> float i |] ) )

21
src/FSharpUnitTests/FSharpUnitTests.fsproj

@ -6,7 +6,7 @@
<ProductVersion>8.0.30703</ProductVersion> <ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{f2f8032b-a31d-4e33-a05e-f2cdcbfaa75d}</ProjectGuid> <ProjectGuid>{f2f8032b-a31d-4e33-a05e-f2cdcbfaa75d}</ProjectGuid>
<OutputType>Exe</OutputType> <OutputType>Library</OutputType>
<RootNamespace>FSharpUnitTests</RootNamespace> <RootNamespace>FSharpUnitTests</RootNamespace>
<AssemblyName>MathNet.Numerics.FSharp.UnitTests</AssemblyName> <AssemblyName>MathNet.Numerics.FSharp.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
@ -46,14 +46,25 @@
<Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets" Condition="(!Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')) And (!Exists('$(MSBuildExtensionsPath32)\..\Microsoft F#\v4.0\Microsoft.FSharp.Targets')) And (Exists('$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets'))" /> <Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets" Condition="(!Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')) And (!Exists('$(MSBuildExtensionsPath32)\..\Microsoft F#\v4.0\Microsoft.FSharp.Targets')) And (Exists('$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets'))" />
<ItemGroup> <ItemGroup>
<Compile Include="FsUnit.fs" /> <Compile Include="FsUnit.fs" />
<Compile Include="Program.fs" /> <Compile Include="VectorTests.fs" />
<None Include="App.config"> <Compile Include="SparseVectorTests.fs" />
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <Compile Include="DenseVectorTests.fs" />
</None> <Compile Include="MatrixTests.fs" />
<Compile Include="SparseMatrixTests.fs" />
<Compile Include="DenseMatrixTests.fs" />
<Compile Include="Utilities.fs" />
<Compile Include="BigRationalTests.fs" />
<Compile Include="RandomVariableTests.fs" />
<Compile Include="PokerTests.fs" />
<None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="FSharp.Core" /> <Reference Include="FSharp.Core" />
<Reference Include="mscorlib" /> <Reference Include="mscorlib" />
<Reference Include="nunit.framework">
<HintPath>..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core"> <Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework> <RequiredTargetFramework>3.5</RequiredTargetFramework>

314
src/FSharpUnitTests/FsUnit.fs

@ -1,244 +1,70 @@
(* module FsUnit
Copyright (c) 2008, Raymond W. Vernagus (R.Vernagus@gmail.com) open NUnit.Framework
All rights reserved. open NUnit.Framework.Constraints
Redistribution and use in source and binary forms, with or without modification, let should (f : 'a -> #Constraint) x (y : obj) =
are permitted provided that the following conditions are met: let c = f x
let y =
* Redistributions of source code must retain the above copyright notice, match y with
this list of conditions and the following disclaimer. | :? (unit -> unit) -> box (TestDelegate(y :?> unit -> unit))
* Redistributions in binary form must reproduce the above copyright notice, | _ -> y
this list of conditions and the following disclaimer in the documentation Assert.That(y, c)
and/or other materials provided with the distribution.
* Neither the name of Raymond W. Vernagus nor the names of FsUnit's let equal x = EqualConstraint(x)
contributors may be used to endorse or promote products derived from this
software without specific prior written permission. let equalWithin tolerance x = equal(x).Within tolerance
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND let contain x = ContainsConstraint(x)
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE let haveLength n = Has.Length.EqualTo(n)
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL let haveCount n = Has.Count.EqualTo(n)
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER let be = id
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF let Null = NullConstraint()
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*) let Empty = EmptyConstraint()
namespace FsUnit
let EmptyString = EmptyStringConstraint()
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra.Double let NullOrEmptyString = NullOrEmptyStringConstraint()
open MathNet.Numerics.LinearAlgebra.Generic
let True = TrueConstraint()
type Result =
| Pass let False = FalseConstraint()
| Fail of string
| Error of string let sameAs x = SameAsConstraint(x)
type Expectation = let throw = Throws.TypeOf
| True
| False let greaterThan x = GreaterThanConstraint(x)
| Empty
| NullOrEmpty let greaterThanOrEqualTo x = GreaterThanOrEqualConstraint(x)
| Null
| SameAs of obj let lessThan x = LessThanConstraint(x)
type Spec = let lessThanOrEqualTo x = LessThanOrEqualConstraint(x)
abstract Check : unit -> Result
abstract NegatedMessage : string let shouldFail (f : unit -> unit) =
TestDelegate(f) |> should throw typeof<AssertionException>
[<AutoOpen>]
module SpecOps = let endWith (s:string) = EndsWithConstraint s
let internal safeCheck f =
try let startWith (s:string) = StartsWithConstraint s
f()
with ex -> Error (ex.ToString()) let ofExactType<'a> = ExactTypeConstraint(typeof<'a>)
let make f nmsg = let instanceOfType<'a> = InstanceOfTypeConstraint(typeof<'a>)
{ new Spec with
member this.Check() = safeCheck f let NaN = NaNConstraint()
member this.NegatedMessage = nmsg }
let unique = UniqueItemsConstraint()
let check (s: Spec) = s.Check()
let not' x = NotConstraint(x)
let not' f x =
let s = f x let array_equal = equal
match check s with let array2_equal = equal
| Pass -> make (fun () -> Fail s.NegatedMessage) "" let approximately_equal tolerance = equalWithin (10.0 ** (float -tolerance))
| Fail msg -> make (fun () -> Pass) msg let approximately_vector_equal = approximately_equal
| Error msg -> make (fun () -> Error msg) msg let approximately_matrix_equal = approximately_equal
let equal expected actual =
make (fun () ->
if actual.Equals(expected)
then Pass
else Fail (sprintf "Expected: %A\nActual: %A" expected actual))
(sprintf "NOT Expected: %A\nActual: %A" expected actual)
let have n lbl s =
make (fun() ->
let len = Seq.length s
if len = n
then Pass
else Fail (sprintf "Expected: %d %s\nActual: %d %s" n lbl len lbl))
(sprintf "NOT Expected: %d %s\nActual: %d %s" n lbl n lbl)
let contain x s =
make (fun () ->
let exists = s |> Seq.exists (fun x' -> x' = x)
if exists
then Pass
else Fail (sprintf "Expected %A to contain %A" s x))
(sprintf "Did NOT expect %A to contain %A" s x)
let raise'<'a when 'a :> System.Exception> f =
let expType = typeof<'a>
make (fun () ->
try
f()
Fail (sprintf "Expected %s but no exception was raised" expType.FullName)
with ex ->
let actualExType = ex.GetType()
if expType = actualExType
then Pass
else Fail (sprintf "Expected: %s\nActual: %s" expType.FullName actualExType.FullName))
(sprintf "Did NOT expect %s to be raised" expType.FullName)
let be expectation x =
let x = box x
let msg = sprintf "Expected: %A\nActual: %A" expectation x
let negmsg = sprintf "NOT Expected: %A\nActual: %A" expectation x
match expectation with
| True ->
make (fun () ->
if x = box true
then Pass
else Fail msg)
negmsg
| False ->
make (fun () ->
if x = box false
then Pass
else Fail msg)
negmsg
| Empty ->
make (fun () ->
if x = box System.String.Empty
then Pass
else Fail msg)
negmsg
| NullOrEmpty ->
make (fun () ->
if System.String.IsNullOrEmpty(x :?> string)
then Pass
else Fail msg)
negmsg
| Null ->
make (fun () ->
if x = null
then Pass
else Fail msg)
negmsg
| SameAs other ->
make (fun () ->
if System.Object.ReferenceEquals(x, other)
then Pass
else Fail (sprintf "Expected actual to be same reference as expected %A" other))
(sprintf "Expected %A to have different reference than %A" x other)
let array_equal (expected: float []) (actual: float []) =
make (fun () ->
let mutable f = true
for i=0 to expected.Length-1 do
f <- f && (expected.[i] = actual.[i])
if f
then Pass
else Fail (sprintf "Expected: %A\nActual: %A" expected actual))
(sprintf "NOT Expected: %A\nActual: %A" expected actual)
let array2_equal (expected: float [,]) (actual: float [,]) =
make (fun () ->
let mutable f = true
for i=0 to expected.GetLength(0)-1 do
for j=0 to expected.GetLength(1)-1 do
f <- f && (expected.[i,j] = actual.[i,j])
if f
then Pass
else Fail (sprintf "Expected: %A\nActual: %A" expected actual))
(sprintf "NOT Expected: %A\nActual: %A" expected actual)
let approximately_equal (places : int) (expected: float) (actual: float) =
make (fun () ->
if Precision.AlmostEqualInDecimalPlaces(actual, expected, places)
then Pass
else Fail (sprintf "Expected: %A\nActual: %A" expected actual))
(sprintf "NOT Expected: %A\nActual: %A" expected actual)
let approximately_vector_equal (places : int) (expected: #Vector<float>) (actual: #Vector<float>) =
make (fun () ->
let mutable f = true
for i=0 to expected.Count-1 do
f <- f && Precision.AlmostEqualInDecimalPlaces(expected.[i], actual.[i], places)
if f
then Pass
else Fail (sprintf "Expected: %A\nActual: %A" expected actual))
(sprintf "NOT Expected: %A\nActual: %A" expected actual)
let approximately_matrix_equal (places : int) (expected: #Matrix<float>) (actual: #Matrix<float>) =
make (fun () ->
let mutable f = true
for i=0 to expected.RowCount-1 do
for j=0 to expected.ColumnCount-1 do
f <- f && Precision.AlmostEqualInDecimalPlaces(expected.[i,j], actual.[i,j], places)
if f
then Pass
else Fail (sprintf "Expected: %A\nActual: %A" expected actual))
(sprintf "NOT Expected: %A\nActual: %A" expected actual)
module Results =
open Microsoft.FSharp.Text
let internal currentResults = new ResizeArray<string * Result>()
let add = currentResults.Add
let passedCount () =
currentResults
|> Seq.filter (function _,Pass -> true | _ -> false)
|> Seq.length
let failed () =
currentResults
|> Seq.filter (function _,Fail _ -> true | _ -> false)
let failedCount () =
failed()
|> Seq.length
let erred () =
currentResults
|> Seq.filter (function _,Error _ -> true | _ -> false)
let erredCount () =
erred()
|> Seq.length
let summary () =
let buff = new System.Text.StringBuilder()
buff.AppendFormat("{0} passed.\n{1} failed.\n{2} erred.", passedCount(), failedCount(), erredCount()) |> ignore
failed()
|> Seq.iter (function (lbl,Fail msg) -> buff.AppendFormat("\n----\nFailed: {0}\n{1}", lbl, msg) |> ignore | _ -> ())
erred()
|> Seq.iter (function (lbl,Error msg) -> buff.AppendFormat("\n----\nErred: {0}\n{1}", lbl, msg) |> ignore | _ -> ())
buff.ToString()
[<AutoOpen>]
module SpecHelpers =
let spec lbl s = (lbl, check s)
let should f x = f x
let specs lbl (results: seq<string * Result>) =
results |> Seq.iter (fun x -> Results.add x)

112
src/FSharpUnitTests/MatrixTests.fs

@ -0,0 +1,112 @@
namespace MathNet.Numerics.Tests
open NUnit.Framework
open FsUnit
open MathNet.Numerics.LinearAlgebra.Generic
open MathNet.Numerics.LinearAlgebra.Double
/// Unit tests for the matrix type.
module MatrixTests =
/// A small uniform vector.
let smallM = new DenseMatrix( Array2D.create 2 2 0.3 )
let failingFoldBackM = DenseMatrix.init 2 3 (fun i j -> 1.0)
/// A large vector with increasingly large entries
let largeM = new DenseMatrix( Array2D.init 100 100 (fun i j -> float i * 100.0 + float j) )
[<Test>]
let ``Matrix.fold`` () =
Matrix.fold (fun a b -> a - b) 0.0 smallM |> should equal -1.2
[<Test>]
let ``Matrix.foldBack`` () =
Matrix.foldBack (fun a b -> a - b) 0.0 smallM |> should equal 0.0
[<Test>]
let ``Matrix.foldBackSummation`` () =
Matrix.foldBack( fun a b -> a + b) 0.0 failingFoldBackM |> should equal 6.0
[<Test>]
let ``Matrix.foldi`` () =
Matrix.foldi (fun i j acc x -> acc + x + float (i+j)) 0.0 smallM |> should equal 5.2
[<Test>]
let ``Matrix.toArray2`` () =
Matrix.toArray2 smallM |> should array2_equal (Array2D.create 2 2 0.3)
[<Test>]
let ``Matrix.forall`` () =
Matrix.forall (fun x -> x = 0.3) smallM |> should equal true
[<Test>]
let ``Matrix.exists`` () =
Matrix.exists (fun x -> x = 0.5) smallM |> should equal false
[<Test>]
let ``Matrix.foralli`` () =
Matrix.foralli (fun i j x -> x = float i * 100.0 + float j) largeM |> should equal true
[<Test>]
let ``Matrix.existsi`` () =
Matrix.existsi (fun i j x -> x = float i * 100.0 + float j) largeM |> should equal true
[<Test>]
let ``Matrix.map`` () =
Matrix.map (fun x -> 2.0 * x) smallM |> should equal (2.0 * smallM)
[<Test>]
let ``Matrix.mapi`` () =
Matrix.mapi (fun i j x -> float i * 100.0 + float j + x) largeM |> should equal (2.0 * largeM)
[<Test>]
let ``Matrix.mapCols`` () =
Matrix.mapCols (fun j col -> col.Add(float j)) smallM |> should (approximately_matrix_equal 14) (matrix [[0.3;1.3];[0.3;1.3]])
[<Test>]
let ``Matrix.mapRows`` () =
Matrix.mapRows (fun i row -> row.Add(float i)) smallM |> should (approximately_matrix_equal 14) (matrix [[0.3;0.3];[1.3;1.3]])
[<Test>]
let ``Matrix.inplaceAssign`` () =
let N = smallM.Clone()
Matrix.inplaceAssign (fun i j -> 0.0) N
N |> should equal (0.0 * smallM)
[<Test>]
let ``Matrix.inplaceMapi`` () =
let N = largeM.Clone()
Matrix.inplaceMapi (fun i j x -> 2.0 * (float i * 100.0 + float j) + x) N
N |> should equal (3.0 * largeM)
[<Test>]
let ``Matrix.nonZeroEntries`` () =
Seq.length (Matrix.nonZeroEntries smallM) |> should equal 4
[<Test>]
let ``Matrix.sum`` () =
Matrix.sum smallM |> should equal 1.2
[<Test>]
let ``Matrix.sumColsBy`` () =
Matrix.sumColsBy (fun j col -> col.[0] * col.[1]) (matrix [[1.0; 2.0]; [3.0; 4.0]]) |> should equal 11.0
[<Test>]
let ``Matrix.sumRowsBy`` () =
Matrix.sumRowsBy (fun i row -> row.[0] * row.[1]) (matrix [[1.0; 2.0]; [3.0; 4.0]]) |> should equal 14.0
[<Test>]
let ``Matrix.foldCol`` () =
Matrix.foldCol (+) 0.0 largeM 0 |> should equal 495000.0
[<Test>]
let ``Matrix.foldRow`` () =
Matrix.foldRow (+) 0.0 largeM 0 |> should equal 4950.0
[<Test>]
let ``Matrix.foldByCol`` () =
Matrix.foldByCol (+) 0.0 smallM |> should equal (DenseVector.ofList [0.6;0.6] :> Vector<float>)
[<Test>]
let ``Matrix.foldByRow`` () =
Matrix.foldByRow (+) 0.0 smallM |> should equal (DenseVector.ofList [0.6;0.6] :> Vector<float>)

98
src/FSharpUnitTests/PokerTests.fs

@ -0,0 +1,98 @@
module MathNet.Numerics.Tests.PokerTests
open MathNet.Numerics
open MathNet.Numerics.Probability
open NUnit.Framework
open FsUnit
type Rank = int
type Suit = | Spades | Hearts | Diamonds | Clubs
type Card = Rank * Suit
let value = fst
let suit = snd
let A,K,Q,J,T = 14,13,12,11,10
let allRanksInSuit suit = [2..A] |> List.map (fun rank -> rank,suit)
let completeDeck =
[Spades; Hearts ; Diamonds; Clubs]
|> List.map allRanksInSuit
|> List.concat
let isPair c1 c2 = value c1 = value c2
let isSuited c1 c2 = suit c1 = suit c2
let isConnected c1 c2 =
let v1,v2 = value c1,value c2
(v1 - v2 |> abs |> (=) 1) ||
(v1 = A && v2 = 2) ||
(v1 = 2 && v2 = A)
[<Test>]
let ``When drawing from a full deck, then the probability for an Ace should equal 4/52``() =
completeDeck
|> RandomVariable.selectOne
|> RandomVariable.map fst
|> RandomVariable.filter (fun card -> value card = A)
|> RandomVariable.probability
|> should equal (4N/52N)
[<Test>]
let ``When drawing from a full deck, then the probability should equal 1/52``() =
completeDeck
|> RandomVariable.selectOne
|> RandomVariable.map fst
|> RandomVariable.filter ((=) (A,Spades))
|> RandomVariable.probability
|> should equal (1N/52N)
[<Test>]
let ``When drawing from a full deck, then the probability for the Ace of Clubs and Ace of Spaces (in order) should equal 1/52 * 1/51``() =
completeDeck
|> RandomVariable.select 2
|> RandomVariable.filter ((=) [A,Clubs; A,Spades])
|> RandomVariable.probability
|> should equal (1N/52N * 1N/51N)
[<Test>]
let ``When drawing from a full deck, then the probability for the Ace of Clubs and Ace of Spaces (in any order) should equal (1/52 * 1/51) * 2``() =
completeDeck
|> RandomVariable.select 2
|> RandomVariable.filterInAnyOrder [A,Clubs; A,Spades]
|> RandomVariable.probability
|> should equal ((1N/52N * 1N/51N) * 2N)
[<Test>]
let ``When drawing the Ace of Spades and the Ace of Clubs, then the probability for drawing another Ace should equal 2/50``() =
completeDeck
|> RandomVariable.remove [A,Clubs; A,Spades]
|> RandomVariable.toUniformDistribution
|> RandomVariable.filter (fun card -> value card = A)
|> RandomVariable.probability
|> should equal (2N/50N)
[<Test>]
let ``When drawing from the full deck, then the probability for drawing a Pair preflop should equal 1/17``() =
completeDeck
|> RandomVariable.select 2
|> RandomVariable.filter (fun (c1::c2::_) -> isPair c1 c2)
|> RandomVariable.probability
|> should equal (1N/17N)
[<Test>]
let ``When drawing from the full deck, then the probability for drawing Suited Connectors should equal 1/25``() =
completeDeck
|> RandomVariable.select 2
|> RandomVariable.filter (fun (c1::c2::_) -> isSuited c1 c2 && isConnected c1 c2)
|> RandomVariable.probability
|> should equal (2N/51N)
[<Test>]
let ``When holding 3 Spades after the flop, than the probability for drawing a flush should equal 10/47*9/46``() =
completeDeck
|> RandomVariable.remove [A,Clubs; A,Spades] // preflop
|> RandomVariable.remove [2,Clubs; 3,Spades; 7,Spades] // flop
|> RandomVariable.select 2
|> RandomVariable.filter (fun (c1::c2::_) -> suit c1 = Spades && suit c2 = Spades)
|> RandomVariable.probability
|> should equal (10N/47N*9N/46N)

223
src/FSharpUnitTests/Program.fs

@ -1,223 +0,0 @@
open FsUnit
open MathNet.Numerics.LinearAlgebra.Generic
open MathNet.Numerics.LinearAlgebra.Double
/// Unit tests for the dense vector type.
let DenseVectorTests =
/// A small uniform vector.
let smallv = new DenseVector(5, 0.3 )
/// A large vector with increasingly large entries
let largev = new DenseVector( Array.init 100 (fun i -> float i / 100.0) )
specs "DenseVector" [
spec "DenseVector.init"
(DenseVector.init 100 (fun i -> float i / 100.0) |> should equal largev)
spec "DenseVector.ofList"
(DenseVector.ofList [ for i in 0 .. 99 -> float i / 100.0 ] |> should equal largev)
spec "DenseVector.ofSeq"
(DenseVector.ofSeq (seq { for i in 0 .. 99 -> float i / 100.0 }) |> should equal largev)
spec "DenseVector.rangef"
(DenseVector.rangef 0.0 0.01 0.99 |> should equal (new DenseVector( [| for i in 0 .. 99 -> 0.01 * float i |] ) ))
spec "DenseVector.range"
(DenseVector.range 0 99 |> should equal (new DenseVector( [| for i in 0 .. 99 -> float i |] ) ))
]
/// Unit tests for the sparse vector type.
let SparseVectorTests =
/// A small uniform vector.
let smallv = new DenseVector( [|0.0;0.3;0.0;0.0;0.0|] ) :> Vector<float>
specs "SparseVector" [
spec "SparseVector.ofList"
((SparseVector.ofList 5 [ (1,0.3) ] :> Vector<float>) |> should equal smallv)
spec "SparseVector.ofSeq"
((SparseVector.ofSeq 5 (List.toSeq [ (1,0.3) ]) :> Vector<float>) |> should equal smallv)
]
/// Unit tests for the vector type.
let VectorTests =
/// A small uniform vector.
let smallv = new DenseVector( [|0.3;0.3;0.3;0.3;0.3|] ) :> Vector<float>
/// A large vector with increasingly large entries
let largev = new DenseVector( Array.init 100 (fun i -> float i / 100.0) ) :> Vector<float>
specs "Vector" [
spec "Vector.toArray"
(Vector.toArray smallv |> should array_equal [|0.3;0.3;0.3;0.3;0.3|])
spec "Vector.toList"
(Vector.toList smallv |> should equal [0.3;0.3;0.3;0.3;0.3])
spec "Vector.mapInPlace"
( let w = smallv.Clone()
Vector.mapInPlace (fun x -> 2.0 * x) w
w |> should equal (2.0 * smallv))
spec "Vector.mapiInPlace"
( let w = largev.Clone()
Vector.mapiInPlace (fun i x -> float i / 100.0) w
w |> should equal (largev))
spec "Vector.addInPlace"
( let w = largev.Clone()
Vector.addInPlace w largev
w |> should equal (2.0 * largev))
spec "Vector.subInPlace"
( let w = largev.Clone()
Vector.subInPlace w largev
w |> should equal (0.0 * largev))
spec "Vector.map"
(Vector.map (fun x -> 2.0 * x) largev |> should equal (2.0 * largev))
spec "Vector.mapi"
(Vector.mapi (fun i x -> float i / 100.0) largev |> should equal largev)
spec "Vector.fold"
(Vector.fold (fun a b -> a - b) 0.0 smallv |> should equal -1.5)
spec "Vector.foldBack"
(Vector.foldBack (fun a b -> a - b) 0.0 smallv |> should equal 0.0)
spec "Vector.foldi"
(Vector.foldi (fun i a b -> a + b) 0.0 smallv |> should equal 1.5)
spec "Vector.forall"
(Vector.forall (fun x -> x = 0.3) smallv |> should equal true)
spec "Vector.exists"
(Vector.exists (fun x -> x = 0.3) smallv |> should equal true)
spec "Vector.foralli"
(Vector.foralli (fun i x -> x = 0.3 && i < 5) smallv |> should equal true)
spec "Vector.existsi"
(Vector.existsi (fun i x -> x = 0.3 && i = 2) smallv |> should equal true)
spec "Vector.scan"
(Vector.scan (fun acc x -> acc + x) smallv |> should approximately_vector_equal 14 (new DenseVector( [|0.3;0.6;0.9;1.2;1.5|] ) :> Vector<float>) )
spec "Vector.scanBack"
(Vector.scanBack (fun x acc -> acc + x) smallv |> should approximately_vector_equal 14 (new DenseVector( [|1.5;1.2;0.9;0.6;0.3|] ) :> Vector<float>) )
spec "Vector.reduce"
(Vector.reduce (fun acc x -> acc ** x) smallv |> should approximately_equal 14 0.990295218585507)
spec "Vector.reduceBack"
(Vector.reduceBack (fun x acc -> x ** acc) smallv |> should approximately_equal 14 0.488911287726319)
spec "Vector.insert"
(Vector.insert 2 0.5 smallv |> should approximately_vector_equal 14 (new DenseVector ( [|0.3;0.3;0.5;0.3;0.3;0.3|] ) :> Vector<float>) )
]
/// Unit tests for the matrix type.
let MatrixTests =
/// A small uniform vector.
let smallM = new DenseMatrix( Array2D.create 2 2 0.3 )
let failingFoldBackM = DenseMatrix.init 2 3 (fun i j -> 1.0)
/// A large vector with increasingly large entries
let largeM = new DenseMatrix( Array2D.init 100 100 (fun i j -> float i * 100.0 + float j) )
specs "Matrix" [
spec "Matrix.fold"
(Matrix.fold (fun a b -> a - b) 0.0 smallM |> should equal -1.2)
spec "Matrix.foldBack"
(Matrix.foldBack (fun a b -> a - b) 0.0 smallM |> should equal 0.0)
spec "Matrix.foldBackSummation"
(Matrix.foldBack( fun a b -> a + b) 0.0 failingFoldBackM |> should equal 6.0)
spec "Matrix.foldi"
(Matrix.foldi (fun i j acc x -> acc + x + float (i+j)) 0.0 smallM |> should equal 5.2)
spec "Matrix.toArray2"
(Matrix.toArray2 smallM |> should array2_equal (Array2D.create 2 2 0.3))
spec "Matrix.forall"
(Matrix.forall (fun x -> x = 0.3) smallM |> should equal true)
spec "Matrix.exists"
(Matrix.exists (fun x -> x = 0.5) smallM |> should equal false)
spec "Matrix.foralli"
(Matrix.foralli (fun i j x -> x = float i * 100.0 + float j) largeM |> should equal true)
spec "Matrix.existsi"
(Matrix.existsi (fun i j x -> x = float i * 100.0 + float j) largeM |> should equal true)
spec "Matrix.map"
(Matrix.map (fun x -> 2.0 * x) smallM |> should equal (2.0 * smallM))
spec "Matrix.mapi"
(Matrix.mapi (fun i j x -> float i * 100.0 + float j + x) largeM |> should equal (2.0 * largeM))
spec "Matrix.mapCols"
(Matrix.mapCols (fun j col -> col.Add(float j)) smallM |> should approximately_matrix_equal 14 (matrix [[0.3;1.3];[0.3;1.3]]))
spec "Matrix.mapRows"
(Matrix.mapRows (fun i row -> row.Add(float i)) smallM |> should approximately_matrix_equal 14 (matrix [[0.3;0.3];[1.3;1.3]]))
spec "Matrix.inplaceAssign"
( let N = smallM.Clone()
Matrix.inplaceAssign (fun i j -> 0.0) N
N |> should equal (0.0 * smallM))
spec "Matrix.inplaceMapi"
( let N = largeM.Clone()
Matrix.inplaceMapi (fun i j x -> 2.0 * (float i * 100.0 + float j) + x) N
N |> should equal (3.0 * largeM))
spec "Matrix.nonZeroEntries"
(Seq.length (Matrix.nonZeroEntries smallM) |> should equal 4)
spec "Matrix.sum"
(Matrix.sum smallM |> should equal 1.2)
spec "Matrix.sumColsBy"
(Matrix.sumColsBy (fun j col -> col.[0] * col.[1]) (matrix [[1.0; 2.0]; [3.0; 4.0]]) |> should equal 11.0)
spec "Matrix.sumRowsBy"
(Matrix.sumRowsBy (fun i row -> row.[0] * row.[1]) (matrix [[1.0; 2.0]; [3.0; 4.0]]) |> should equal 14.0)
spec "Matrix.foldCol"
(Matrix.foldCol (+) 0.0 largeM 0 |> should equal 495000.0)
spec "Matrix.foldRow"
(Matrix.foldRow (+) 0.0 largeM 0 |> should equal 4950.0)
spec "Matrix.foldByCol"
(Matrix.foldByCol (+) 0.0 smallM |> should equal (DenseVector.ofList [0.6;0.6] :> Vector<float>))
spec "Matrix.foldByRow"
(Matrix.foldByRow (+) 0.0 smallM |> should equal (DenseVector.ofList [0.6;0.6] :> Vector<float>))
]
/// Unit tests for the dense matrix type.
let DenseMatrixTests =
/// A small uniform vector.
let smallM = new DenseMatrix( Array2D.create 2 2 0.3 )
/// A large vector with increasingly large entries
let largeM = new DenseMatrix( Array2D.init 100 100 (fun i j -> float i * 100.0 + float j) )
specs "DenseMatrix" [
spec "DenseMatrix.init"
(DenseMatrix.init 100 100 (fun i j -> float i * 100.0 + float j) |> should equal largeM)
spec "DenseMatrix.ofList"
(DenseMatrix.ofList [[0.3;0.3];[0.3;0.3]] |> should equal smallM)
spec "DenseMatrix.ofSeq"
(DenseMatrix.ofSeq (Seq.ofList [[0.3;0.3];[0.3;0.3]]) |> should equal smallM)
spec "DenseMatrix.ofArray2"
(DenseMatrix.ofArray2 (Array2D.create 2 2 0.3) |> should equal smallM)
spec "DenseMatrix.initDense"
(DenseMatrix.initDense 100 100 (seq { for i in 0 .. 99 do
for j in 0 .. 99 -> (i,j, float i * 100.0 + float j)}) |> should equal largeM)
spec "DenseMatrix.constDiag"
(DenseMatrix.constDiag 100 2.0 |> should equal (2.0 * (DenseMatrix.Identity 100)))
spec "DenseMatrix.diag"
(DenseMatrix.diag (new DenseVector(100, 2.0)) |> should equal (2.0 * (DenseMatrix.Identity 100)))
spec "DenseMatrix.init_row"
(DenseMatrix.initRow 100 100 (fun i -> (DenseVector.init 100 (fun j -> float i * 100.0 + float j))) |> should equal largeM)
spec "DenseMatrix.init_col"
(DenseMatrix.initCol 100 100 (fun j -> (DenseVector.init 100 (fun i -> float i * 100.0 + float j))) |> should equal largeM)
]
/// Unit tests for the sparse matrix type.
let SparseMatrixTests =
/// A small uniform vector.
let smallM = DenseMatrix.init 4 4 (fun i j -> if i = 1 && j = 2 then 1.0 else 0.0) :> Matrix<float>
specs "SparseMatrix" [
spec "SparseMatrix.ofList"
((SparseMatrix.ofList 4 4 [(1,2,1.0)] :> Matrix<float>) |> should equal smallM)
spec "SparseMatrix.ofSeq"
((SparseMatrix.ofSeq 4 4 (Seq.ofList [(1,2,1.0)]) :> Matrix<float>) |> should equal smallM)
spec "SparseMatrix.constDiag"
(SparseMatrix.constDiag 100 2.0 |> should equal (2.0 * (SparseMatrix.Identity 100)))
spec "SparseMatrix.diag"
(SparseMatrix.diag (new DenseVector(100, 2.0)) |> should equal (2.0 * (SparseMatrix.Identity 100)))
]
/// Report on errors and success and exit.
printfn "F# Test Results:"
printfn "%s" (Results.summary())
let code = if Results.erredCount() > 0 || Results.failedCount() > 0 then -1 else 0;;
exit code;;

79
src/FSharpUnitTests/RandomVariableTests.fs

@ -0,0 +1,79 @@
module MathNet.Numerics.Tests.RandomVariableTests
open MathNet.Numerics
open MathNet.Numerics.Probability
open NUnit.Framework
open FsUnit
[<Test>]
let ``When creating a empty randomVariable, then the probability should be 1``() =
let actual = randomVariable { return () }
RandomVariable.probability actual |> should equal (1N/1N)
let sumOfTwoFairDices = randomVariable {
let! d1 = RandomVariable.fairDice 6
let! d2 = RandomVariable.fairDice 6
return d1 + d2 }
[<Test>]
let ``When creating two fair dices, then P(Sum of 2 dices = 7) should be 1/6``() =
sumOfTwoFairDices
|> RandomVariable.filter ((=) 7)
|> RandomVariable.probability
|> should equal (1N/6N)
let fairCoinAndDice = randomVariable {
let! d = RandomVariable.fairDice 6
let! c = RandomVariable.fairCoin
return d,c }
[<Test>]
let ``When creating a fair coin and a fair dice, then P(Heads) should be 1/2``() =
fairCoinAndDice
|> RandomVariable.filter (fun (_,c) -> c = Heads)
|> RandomVariable.probability
|> should equal (1N/2N)
[<Test>]
let ``When creating a fair coin and a fair dice, then P(Heads and dice > 3) should be 1/4``() =
fairCoinAndDice
|> RandomVariable.filter (fun (d,c) -> c = Heads && d > 3)
|> RandomVariable.probability
|> should equal (1N/4N)
// MontyHall Problem
// See Martin Erwig and Steve Kollmansberger's paper
// "Functional Pearls: Probabilistic functional programming in Haskell"
type Outcome =
| Car
| Goat
let firstChoice = RandomVariable.toUniformDistribution [Car; Goat; Goat]
let switch firstCoice =
match firstCoice with
| Car ->
// If you had the car and you switch ==> you lose since there are only goats left
RandomVariable.certainly Goat
| Goat ->
// If you had the goat, the host has to take out another goat ==> you win
RandomVariable.certainly Car
[<Test>]
let ``When making the first choice in a MontyHall situation, the chances to win should be 1/3``() =
firstChoice
|> RandomVariable.filter ((=) Car)
|> RandomVariable.probability
|> should equal (1N/3N)
let montyHallWithSwitch = randomVariable {
let! firstDoor = firstChoice
return! switch firstDoor }
[<Test>]
let ``When switching in a MontyHall situation, the chances to win should be 2/3``() =
montyHallWithSwitch
|> RandomVariable.filter ((=) Car)
|> RandomVariable.probability
|> should equal (2N/3N)

28
src/FSharpUnitTests/SparseMatrixTests.fs

@ -0,0 +1,28 @@
namespace MathNet.Numerics.Tests
open NUnit.Framework
open FsUnit
open MathNet.Numerics.LinearAlgebra.Generic
open MathNet.Numerics.LinearAlgebra.Double
/// Unit tests for the sparse matrix type.
module SparseMatrixTests =
/// A small uniform vector.
let smallM = DenseMatrix.init 4 4 (fun i j -> if i = 1 && j = 2 then 1.0 else 0.0) :> Matrix<float>
[<Test>]
let ``SparseMatrix.ofList`` () =
(SparseMatrix.ofList 4 4 [(1,2,1.0)] :> Matrix<float>) |> should equal smallM
[<Test>]
let ``SparseMatrix.ofSeq`` () =
(SparseMatrix.ofSeq 4 4 (Seq.ofList [(1,2,1.0)]) :> Matrix<float>) |> should equal smallM
[<Test>]
let ``SparseMatrix.constDiag`` () =
SparseMatrix.constDiag 100 2.0 |> should equal (2.0 * (SparseMatrix.Identity 100))
[<Test>]
let ``SparseMatrix.diag`` () =
SparseMatrix.diag (new DenseVector(100, 2.0)) |> should equal (2.0 * (SparseMatrix.Identity 100))

21
src/FSharpUnitTests/SparseVectorTests.fs

@ -0,0 +1,21 @@
namespace MathNet.Numerics.Tests
open NUnit.Framework
open FsUnit
open MathNet.Numerics.LinearAlgebra.Generic
open MathNet.Numerics.LinearAlgebra.Double
/// Unit tests for the sparse vector type.
module SparseVectorTests =
/// A small uniform vector.
let smallv = new DenseVector( [|0.0;0.3;0.0;0.0;0.0|] ) :> Vector<float>
[<Test>]
let ``SparseVector.ofList`` () =
(SparseVector.ofList 5 [ (1,0.3) ] :> Vector<float>) |> should equal smallv
[<Test>]
let ``SparseVector.ofSeq`` () =
(SparseVector.ofSeq 5 (List.toSeq [ (1,0.3) ]) :> Vector<float>) |> should equal smallv

128
src/FSharpUnitTests/Utilities.fs

@ -0,0 +1,128 @@
// First version copied from the F# Power Pack
// https://raw.github.com/fsharp/powerpack/master/src/FSharp.PowerPack.Unittests/Utilities.fs
namespace MathNet.Numerics.Tests
open NUnit.Framework
open System
open System.Collections.Generic
[<AutoOpen>]
module Utilities =
let test msg b = Assert.IsTrue(b, "MiniTest '" + msg + "'")
let logMessage msg =
System.Console.WriteLine("LOG:" + msg)
// System.Diagnostics.Trace.WriteLine("LOG:" + msg)
let check msg v1 v2 = test msg (v1 = v2)
let reportFailure msg = Assert.Fail msg
let numActiveEnumerators = ref 0
let throws f = try f() |> ignore; false with e -> true
let countEnumeratorsAndCheckedDisposedAtMostOnceAtEnd (seq: seq<'a>) =
let enumerator() =
numActiveEnumerators := !numActiveEnumerators + 1;
let disposed = ref false in
let endReached = ref false in
let ie = seq.GetEnumerator() in
{ new System.Collections.Generic.IEnumerator<'a> with
member x.Current =
test "rvlrve0" (not !endReached);
test "rvlrve1" (not !disposed);
ie.Current
member x.Dispose() =
test "rvlrve2" !endReached;
test "rvlrve4" (not !disposed);
numActiveEnumerators := !numActiveEnumerators - 1;
disposed := true;
ie.Dispose()
interface System.Collections.IEnumerator with
member x.MoveNext() =
test "rvlrve0" (not !endReached);
test "rvlrve3" (not !disposed);
endReached := not (ie.MoveNext());
not !endReached
member x.Current =
test "qrvlrve0" (not !endReached);
test "qrvlrve1" (not !disposed);
box ie.Current
member x.Reset() =
ie.Reset()
} in
{ new seq<'a> with
member x.GetEnumerator() = enumerator()
interface System.Collections.IEnumerable with
member x.GetEnumerator() = (enumerator() :> _) }
let countEnumeratorsAndCheckedDisposedAtMostOnce (seq: seq<'a>) =
let enumerator() =
let disposed = ref false in
let endReached = ref false in
let ie = seq.GetEnumerator() in
numActiveEnumerators := !numActiveEnumerators + 1;
{ new System.Collections.Generic.IEnumerator<'a> with
member x.Current =
test "qrvlrve0" (not !endReached);
test "qrvlrve1" (not !disposed);
ie.Current
member x.Dispose() =
test "qrvlrve4" (not !disposed);
numActiveEnumerators := !numActiveEnumerators - 1;
disposed := true;
ie.Dispose()
interface System.Collections.IEnumerator with
member x.MoveNext() =
test "qrvlrve0" (not !endReached);
test "qrvlrve3" (not !disposed);
endReached := not (ie.MoveNext());
not !endReached
member x.Current =
test "qrvlrve0" (not !endReached);
test "qrvlrve1" (not !disposed);
box ie.Current
member x.Reset() =
ie.Reset()
} in
{ new seq<'a> with
member x.GetEnumerator() = enumerator()
interface System.Collections.IEnumerable with
member x.GetEnumerator() = (enumerator() :> _) }
// Verifies two sequences are equal (same length, equiv elements)
let verifySeqsEqual seq1 seq2 =
if Seq.length seq1 <> Seq.length seq2 then Assert.Fail()
let zippedElements = Seq.zip seq1 seq2
if zippedElements |> Seq.forall (fun (a, b) -> a = b)
then ()
else Assert.Fail()
/// Check that the lamda throws an exception of the given type. Otherwise
/// calls Assert.Fail()
let private checkThrowsExn<'a when 'a :> exn> (f : unit -> unit) =
let funcThrowsAsExpected =
try
let _ = f ()
false // Did not throw!
with
| :? 'a
-> true // Thew null ref, OK
| _ -> false // Did now throw a null ref exception!
if funcThrowsAsExpected
then ()
else Assert.Fail()
// Illegitimate exceptions. Once we've scrubbed the library, we should add an
// attribute to flag these exception's usage as a bug.
let checkThrowsNullRefException f = checkThrowsExn<NullReferenceException> f
let checkThrowsIndexOutRangException f = checkThrowsExn<IndexOutOfRangeException> f
// Legit exceptions
let checkThrowsNotSupportedException f = checkThrowsExn<NotSupportedException> f
let checkThrowsArgumentException f = checkThrowsExn<ArgumentException> f
let checkThrowsArgumentNullException f = checkThrowsExn<ArgumentNullException> f
let checkThrowsKeyNotFoundException f = checkThrowsExn<KeyNotFoundException> f
let checkThrowsDivideByZeroException f = checkThrowsExn<DivideByZeroException> f
let checkThrowsInvalidOperationExn f = checkThrowsExn<InvalidOperationException> f

103
src/FSharpUnitTests/VectorTests.fs

@ -0,0 +1,103 @@
namespace MathNet.Numerics.Tests
open NUnit.Framework
open FsUnit
open MathNet.Numerics.LinearAlgebra.Generic
open MathNet.Numerics.LinearAlgebra.Double
/// Unit tests for the vector type.
module VectorTests =
/// A small uniform vector.
let smallv = new DenseVector([|0.3;0.3;0.3;0.3;0.3|]) :> Vector<float>
/// A large vector with increasingly large entries
let largev = new DenseVector(Array.init 100 (fun i -> float i / 100.0)) :> Vector<float>
[<Test>]
let ``Vector.toArray`` () =
Vector.toArray smallv |> should array_equal [|0.3;0.3;0.3;0.3;0.3|]
[<Test>]
let ``Vector.toList`` () =
Vector.toList smallv |> should equal [0.3;0.3;0.3;0.3;0.3]
[<Test>]
let ``Vector.mapInPlace`` () =
let w = smallv.Clone()
Vector.mapInPlace (fun x -> 2.0 * x) w
w |> should equal (2.0 * smallv)
[<Test>]
let ``Vector.mapiInPlace`` () =
let w = largev.Clone()
Vector.mapiInPlace (fun i x -> float i / 100.0) w
w |> should equal (largev)
[<Test>]
let ``Vector.addInPlace`` () =
let w = largev.Clone()
Vector.addInPlace w largev
w |> should equal (2.0 * largev)
[<Test>]
let ``Vector.subInPlace`` () =
let w = largev.Clone()
Vector.subInPlace w largev
w |> should equal (0.0 * largev)
[<Test>]
let ``Vector.map`` () =
Vector.map (fun x -> 2.0 * x) largev |> should equal (2.0 * largev)
[<Test>]
let ``Vector.mapi`` () =
Vector.mapi (fun i x -> float i / 100.0) largev |> should equal largev
[<Test>]
let ``Vector.fold`` () =
Vector.fold (fun a b -> a - b) 0.0 smallv |> should equal -1.5
[<Test>]
let ``Vector.foldBack`` () =
Vector.foldBack (fun a b -> a - b) 0.0 smallv |> should equal 0.0
[<Test>]
let ``Vector.foldi`` () =
Vector.foldi (fun i a b -> a + b) 0.0 smallv |> should equal 1.5
[<Test>]
let ``Vector.forall`` () =
Vector.forall (fun x -> x = 0.3) smallv |> should equal true
[<Test>]
let ``Vector.exists`` () =
Vector.exists (fun x -> x = 0.3) smallv |> should equal true
[<Test>]
let ``Vector.foralli`` () =
Vector.foralli (fun i x -> x = 0.3 && i < 5) smallv |> should equal true
[<Test>]
let ``Vector.existsi`` () =
Vector.existsi (fun i x -> x = 0.3 && i = 2) smallv |> should equal true
[<Test>]
let ``Vector.scan`` () =
Vector.scan (fun acc x -> acc + x) smallv |> should (approximately_vector_equal 14) (new DenseVector( [|0.3;0.6;0.9;1.2;1.5|] ) :> Vector<float>)
[<Test>]
let ``Vector.scanBack`` () =
Vector.scanBack (fun x acc -> acc + x) smallv |> should (approximately_vector_equal 14) (new DenseVector( [|1.5;1.2;0.9;0.6;0.3|] ) :> Vector<float>)
[<Test>]
let ``Vector.reduce`` () =
Vector.reduce (fun acc x -> acc ** x) smallv |> should (approximately_equal 14) 0.990295218585507
[<Test>]
let ``Vector.reduceBack`` () =
Vector.reduceBack (fun x acc -> x ** acc) smallv |> should (approximately_equal 14) 0.488911287726319
[<Test>]
let ``Vector.insert`` () =
Vector.insert 2 0.5 smallv |> should (approximately_vector_equal 14) (new DenseVector ( [|0.3;0.3;0.5;0.3;0.3;0.3|] ) :> Vector<float>)

4
src/FSharpUnitTests/packages.config

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="2.6.2" targetFramework="net40" />
</packages>

1105
src/Numerics/Complex32.cs

File diff suppressed because it is too large

1217
src/Numerics/Complex64.cs

File diff suppressed because it is too large

272
src/Numerics/ComplexExtensions.cs

@ -34,92 +34,59 @@ namespace MathNet.Numerics
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics; using System.Numerics;
#if !PORTABLE
using System.Runtime;
#endif
/// <summary> /// <summary>
/// Extension methods /// Extension methods for the Complex type provided by System.Numerics
/// </summary> /// </summary>
public static class ComplexExtensions public static class ComplexExtensions
{ {
/// <summary> /// <summary>
/// Gets a value indicating whether the <c>Complex32</c> is zero. /// Gets the squared magnitude of the <c>Complex</c> number.
/// </summary> /// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param> /// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns><c>true</c> if this instance is zero; otherwise, <c>false</c>.</returns> /// <returns>The squared magnitude of the <c>Complex</c> number.</returns>
public static bool IsZero(this Complex complex) public static double MagnitudeSquared(this Complex complex)
{ {
return complex.Real == 0.0 && complex.Imaginary == 0.0; return (complex.Real * complex.Real) + (complex.Imaginary * complex.Imaginary);
} }
/// <summary> /// <summary>
/// Gets a value indicating whether the <c>Complex32</c> is one. /// Gets the unity of this complex (same argument, but on the unit circle; exp(I*arg))
/// </summary> /// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param> /// <returns>The unity of this <c>Complex</c>.</returns>
/// <returns><c>true</c> if this instance is one; otherwise, <c>false</c>.</returns> public static Complex Sign(this Complex complex)
public static bool IsOne(this Complex complex)
{ {
return complex.Real == 1.0 && complex.Imaginary == 0.0; if (double.IsPositiveInfinity(complex.Real) && double.IsPositiveInfinity(complex.Imaginary))
} {
return new Complex(Constants.Sqrt1Over2, Constants.Sqrt1Over2);
}
/// <summary> if (double.IsPositiveInfinity(complex.Real) && double.IsNegativeInfinity(complex.Imaginary))
/// Gets a value indicating whether the <c>Complex32</c> is the imaginary unit. {
/// </summary> return new Complex(Constants.Sqrt1Over2, -Constants.Sqrt1Over2);
/// <returns><c>true</c> if this instance is ImaginaryOne; otherwise, <c>false</c>.</returns> }
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
public static bool IsImaginaryOne(this Complex complex)
{
return complex.Real == 0.0 && complex.Imaginary == 1.0;
}
/// <summary> if (double.IsNegativeInfinity(complex.Real) && double.IsPositiveInfinity(complex.Imaginary))
/// Gets a value indicating whether the provided <c>Complex32</c>evaluates {
/// to a value that is not a number. return new Complex(-Constants.Sqrt1Over2, -Constants.Sqrt1Over2);
/// </summary> }
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns>
/// <c>true</c> if this instance is <c>NaN</c>; otherwise,
/// <c>false</c>.
/// </returns>
public static bool IsNaN(this Complex complex)
{
return double.IsNaN(complex.Real) || double.IsNaN(complex.Imaginary);
}
/// <summary> if (double.IsNegativeInfinity(complex.Real) && double.IsNegativeInfinity(complex.Imaginary))
/// Gets a value indicating whether the provided <c>Complex32</c> evaluates to an {
/// infinite value. return new Complex(-Constants.Sqrt1Over2, Constants.Sqrt1Over2);
/// </summary> }
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns>
/// <c>true</c> if this instance is infinite; otherwise, <c>false</c>.
/// </returns>
/// <remarks>
/// True if it either evaluates to a complex infinity
/// or to a directed infinity.
/// </remarks>
public static bool IsInfinity(this Complex complex)
{
return double.IsInfinity(complex.Real) || double.IsInfinity(complex.Imaginary);
}
/// <summary> // don't replace this with "Magnitude"!
/// Gets a value indicating whether the provided <c>Complex32</c> is real. var mod = SpecialFunctions.Hypotenuse(complex.Real, complex.Imaginary);
/// </summary> if (mod == 0.0d)
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param> {
/// <returns><c>true</c> if this instance is a real number; otherwise, <c>false</c>.</returns> return Complex.Zero;
public static bool IsReal(this Complex complex) }
{
return complex.Imaginary == 0.0;
}
/// <summary> return new Complex(complex.Real / mod, complex.Imaginary / mod);
/// Gets a value indicating whether the provided <c>Complex32</c> is real and not negative, that is &gt;= 0.
/// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns>
/// <c>true</c> if this instance is real nonnegative number; otherwise, <c>false</c>.
/// </returns>
public static bool IsRealNonNegative(this Complex complex)
{
return complex.Imaginary == 0.0f && complex.Real >= 0;
} }
/// <summary> /// <summary>
@ -139,19 +106,19 @@ namespace MathNet.Numerics
/// </code> /// </code>
/// </remarks> /// </remarks>
/// <returns>The conjugate of the <see cref="Complex"/> number.</returns> /// <returns>The conjugate of the <see cref="Complex"/> number.</returns>
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static Complex Conjugate(this Complex complex) public static Complex Conjugate(this Complex complex)
{ {
return new Complex(complex.Real, -complex.Imaginary); return Complex.Conjugate(complex);
} }
/// <summary> /// <summary>
/// Gets the squared magnitude of the <c>Complex</c> number. /// Returns the multiplicative inverse of a complex number.
/// </summary> /// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param> [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
/// <returns>The squared magnitude of the <c>Complex</c> number.</returns> public static Complex Reciprocal(this Complex complex)
public static double MagnitudeSquared(this Complex complex)
{ {
return (complex.Real * complex.Real) + (complex.Imaginary * complex.Imaginary); return Complex.Reciprocal(complex);
} }
/// <summary> /// <summary>
@ -161,15 +128,10 @@ namespace MathNet.Numerics
/// <returns> /// <returns>
/// The exponential of this complex number. /// The exponential of this complex number.
/// </returns> /// </returns>
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static Complex Exponential(this Complex complex) public static Complex Exponential(this Complex complex)
{ {
var exp = Math.Exp(complex.Real); return Complex.Exp(complex);
if (complex.IsReal())
{
return new Complex(exp, 0.0);
}
return new Complex(exp * Trig.Cosine(complex.Imaginary), exp * Trig.Sine(complex.Imaginary));
} }
/// <summary> /// <summary>
@ -179,14 +141,30 @@ namespace MathNet.Numerics
/// <returns> /// <returns>
/// The natural logarithm of this complex number. /// The natural logarithm of this complex number.
/// </returns> /// </returns>
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static Complex NaturalLogarithm(this Complex complex) public static Complex NaturalLogarithm(this Complex complex)
{ {
if (complex.IsRealNonNegative()) return Complex.Log(complex);
{ }
return new Complex(Math.Log(complex.Real), 0.0);
}
return new Complex(0.5 * Math.Log(complex.MagnitudeSquared()), complex.Phase); /// <summary>
/// Common Logarithm of this <c>Complex</c> (Base 10).
/// </summary>
/// <returns>The common logarithm of this complex number.</returns>
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static Complex CommonLogarithm(this Complex complex)
{
return Complex.Log10(complex);
}
/// <summary>
/// Logarithm of this <c>Complex</c> with custom base.
/// </summary>
/// <returns>The logarithm of this complex number.</returns>
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static Complex Logarithm(this Complex complex, double baseValue)
{
return Complex.Log(complex, baseValue);
} }
/// <summary> /// <summary>
@ -208,25 +186,22 @@ namespace MathNet.Numerics
return Complex.One; return Complex.One;
} }
if (exponent.Real > 0.0) if (exponent.Real > 0d)
{ {
return Complex.Zero; return Complex.Zero;
} }
if (exponent.Real < 0) if (exponent.Real < 0d)
{ {
if (exponent.Imaginary == 0.0) return exponent.Imaginary == 0d
{ ? new Complex(double.PositiveInfinity, 0d)
return new Complex(double.PositiveInfinity, 0.0); : new Complex(double.PositiveInfinity, double.PositiveInfinity);
}
return new Complex(double.PositiveInfinity, double.PositiveInfinity);
} }
return double.NaN; return new Complex(double.NaN, double.NaN);
} }
return (exponent * complex.NaturalLogarithm()).Exponential(); return Complex.Pow(complex, exponent);
} }
/// <summary> /// <summary>
@ -241,7 +216,7 @@ namespace MathNet.Numerics
/// </returns> /// </returns>
public static Complex Root(this Complex complex, Complex rootExponent) public static Complex Root(this Complex complex, Complex rootExponent)
{ {
return Power(complex, 1 / rootExponent); return Complex.Pow(complex, 1 / rootExponent);
} }
/// <summary> /// <summary>
@ -270,6 +245,10 @@ namespace MathNet.Numerics
/// </returns> /// </returns>
public static Complex SquareRoot(this Complex complex) public static Complex SquareRoot(this Complex complex)
{ {
// Note: the following code should be equivalent to Complex.Sqrt(complex),
// but it turns out that is implemented poorly in System.Numerics,
// hence we provide our own implementation here. Do not replace.
if (complex.IsRealNonNegative()) if (complex.IsRealNonNegative())
{ {
return new Complex(Math.Sqrt(complex.Real), 0.0); return new Complex(Math.Sqrt(complex.Real), 0.0);
@ -307,6 +286,89 @@ namespace MathNet.Numerics
return result; return result;
} }
/// <summary>
/// Gets a value indicating whether the <c>Complex32</c> is zero.
/// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns><c>true</c> if this instance is zero; otherwise, <c>false</c>.</returns>
public static bool IsZero(this Complex complex)
{
return complex.Real == 0.0 && complex.Imaginary == 0.0;
}
/// <summary>
/// Gets a value indicating whether the <c>Complex32</c> is one.
/// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns><c>true</c> if this instance is one; otherwise, <c>false</c>.</returns>
public static bool IsOne(this Complex complex)
{
return complex.Real == 1.0 && complex.Imaginary == 0.0;
}
/// <summary>
/// Gets a value indicating whether the <c>Complex32</c> is the imaginary unit.
/// </summary>
/// <returns><c>true</c> if this instance is ImaginaryOne; otherwise, <c>false</c>.</returns>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
public static bool IsImaginaryOne(this Complex complex)
{
return complex.Real == 0.0 && complex.Imaginary == 1.0;
}
/// <summary>
/// Gets a value indicating whether the provided <c>Complex32</c>evaluates
/// to a value that is not a number.
/// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns>
/// <c>true</c> if this instance is <c>NaN</c>; otherwise,
/// <c>false</c>.
/// </returns>
public static bool IsNaN(this Complex complex)
{
return double.IsNaN(complex.Real) || double.IsNaN(complex.Imaginary);
}
/// <summary>
/// Gets a value indicating whether the provided <c>Complex32</c> evaluates to an
/// infinite value.
/// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns>
/// <c>true</c> if this instance is infinite; otherwise, <c>false</c>.
/// </returns>
/// <remarks>
/// True if it either evaluates to a complex infinity
/// or to a directed infinity.
/// </remarks>
public static bool IsInfinity(this Complex complex)
{
return double.IsInfinity(complex.Real) || double.IsInfinity(complex.Imaginary);
}
/// <summary>
/// Gets a value indicating whether the provided <c>Complex32</c> is real.
/// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns><c>true</c> if this instance is a real number; otherwise, <c>false</c>.</returns>
public static bool IsReal(this Complex complex)
{
return complex.Imaginary == 0.0;
}
/// <summary>
/// Gets a value indicating whether the provided <c>Complex32</c> is real and not negative, that is &gt;= 0.
/// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns>
/// <c>true</c> if this instance is real nonnegative number; otherwise, <c>false</c>.
/// </returns>
public static bool IsRealNonNegative(this Complex complex)
{
return complex.Imaginary == 0.0f && complex.Real >= 0;
}
/// <summary> /// <summary>
/// Returns a Norm of a value of this type, which is appropriate for measuring how /// Returns a Norm of a value of this type, which is appropriate for measuring how
/// close this value is to zero. /// close this value is to zero.
@ -391,8 +453,8 @@ namespace MathNet.Numerics
var keywords = var keywords =
new[] new[]
{ {
textInfo.ListSeparator, numberFormatInfo.NaNSymbol, textInfo.ListSeparator, numberFormatInfo.NaNSymbol,
numberFormatInfo.NegativeInfinitySymbol, numberFormatInfo.PositiveInfinitySymbol, numberFormatInfo.NegativeInfinitySymbol, numberFormatInfo.PositiveInfinitySymbol,
"+", "-", "i", "j" "+", "-", "i", "j"
}; };
@ -521,17 +583,17 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Converts the string representation of a complex number to a double-precision complex number equivalent. /// Converts the string representation of a complex number to a double-precision complex number equivalent.
/// A return value indicates whether the conversion succeeded or failed. /// A return value indicates whether the conversion succeeded or failed.
/// </summary> /// </summary>
/// <param name="value"> /// <param name="value">
/// A string containing a complex number to convert. /// A string containing a complex number to convert.
/// </param> /// </param>
/// <param name="result"> /// <param name="result">
/// The parsed value. /// The parsed value.
/// </param> /// </param>
/// <returns> /// <returns>
/// If the conversion succeeds, the result will contain a complex number equivalent to value. /// If the conversion succeeds, the result will contain a complex number equivalent to value.
/// Otherwise the result will contain Complex.Zero. This parameter is passed uninitialized. /// Otherwise the result will contain Complex.Zero. This parameter is passed uninitialized.
/// </returns> /// </returns>
public static bool TryToComplex(this string value, out Complex result) public static bool TryToComplex(this string value, out Complex result)
@ -615,17 +677,17 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Converts the string representation of a complex number to a single-precision complex number equivalent. /// Converts the string representation of a complex number to a single-precision complex number equivalent.
/// A return value indicates whether the conversion succeeded or failed. /// A return value indicates whether the conversion succeeded or failed.
/// </summary> /// </summary>
/// <param name="value"> /// <param name="value">
/// A string containing a complex number to convert. /// A string containing a complex number to convert.
/// </param> /// </param>
/// <param name="result"> /// <param name="result">
/// The parsed value. /// The parsed value.
/// </param> /// </param>
/// <returns> /// <returns>
/// If the conversion succeeds, the result will contain a complex number equivalent to value. /// If the conversion succeeds, the result will contain a complex number equivalent to value.
/// Otherwise the result will contain complex32.Zero. This parameter is passed uninitialized. /// Otherwise the result will contain complex32.Zero. This parameter is passed uninitialized.
/// </returns> /// </returns>
public static bool TryToComplex32(this string value, out Complex32 result) public static bool TryToComplex32(this string value, out Complex32 result)

6
src/Numerics/LinearAlgebra/Complex32/Matrix.cs

@ -37,7 +37,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// </summary> /// </summary>
[Serializable] [Serializable]
public abstract class Matrix : Matrix<Complex32> public abstract class Matrix : Matrix<Complex32>
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the Matrix class. /// Initializes a new instance of the Matrix class.
/// </summary> /// </summary>
@ -67,7 +67,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <summary> /// <summary>
/// Returns the conjugate transpose of this matrix. /// Returns the conjugate transpose of this matrix.
/// </summary> /// </summary>
/// <returns>The conjugate transpose of this matrix.</returns> /// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<Complex32> ConjugateTranspose() public override Matrix<Complex32> ConjugateTranspose()
{ {
@ -102,7 +102,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override Complex32 InfinityNorm() public override Complex32 InfinityNorm()
{ {
var norm = 0.0f; var norm = 0.0f;

2
src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs

@ -127,7 +127,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
/// Returns a hash code for this instance. /// Returns a hash code for this instance.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns> /// </returns>
public override int GetHashCode() public override int GetHashCode()
{ {

2
src/Numerics/NumberTheory/IntegerTheory.Euclid.Big.cs

@ -28,7 +28,7 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
#if SYSNUMERICS #if !PORTABLE
namespace MathNet.Numerics.NumberTheory namespace MathNet.Numerics.NumberTheory
{ {
using System; using System;

7
src/Numerics/Numerics.csproj

@ -43,7 +43,7 @@
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<DefineConstants>TRACE;DEBUG;SYSNUMERICS</DefineConstants> <DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<DocumentationFile> <DocumentationFile>
@ -57,7 +57,7 @@
<SignAssembly>false</SignAssembly> <SignAssembly>false</SignAssembly>
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<DefineConstants>TRACE;SYSNUMERICS</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
@ -70,7 +70,7 @@
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<DefineConstants>TRACE;SYSNUMERICS;STRONGNAME</DefineConstants> <DefineConstants>TRACE;STRONGNAME</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
@ -104,6 +104,7 @@
<Compile Include="Constants.cs" /> <Compile Include="Constants.cs" />
<Compile Include="Control.cs" /> <Compile Include="Control.cs" />
<Compile Include="Complex32.cs" /> <Compile Include="Complex32.cs" />
<Compile Include="TargetedPatchingOptOutAttribute.cs" />
<Compile Include="Distributions\Continuous\Cauchy.cs" /> <Compile Include="Distributions\Continuous\Cauchy.cs" />
<Compile Include="Distributions\Continuous\Chi.cs" /> <Compile Include="Distributions\Continuous\Chi.cs" />
<Compile Include="Distributions\Continuous\ChiSquare.cs" /> <Compile Include="Distributions\Continuous\ChiSquare.cs" />

2
src/Numerics/SpecialFunctions/Stability.cs

@ -192,4 +192,4 @@ namespace MathNet.Numerics
return sum; return sum;
} }
} }
} }

16
src/Numerics/TargetedPatchingOptOutAttribute.cs

@ -0,0 +1,16 @@
#if PORTABLE
using System;
namespace MathNet.Numerics
{
[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class TargetedPatchingOptOutAttribute : Attribute
{
public string Reason { get; private set; }
public TargetedPatchingOptOutAttribute(string reason)
{
Reason = reason;
}
}
}
#endif

22
src/Numerics/Trigonometry.cs

@ -111,7 +111,7 @@ namespace MathNet.Numerics
} }
return new Complex( return new Complex(
Cosine(value.Real) * HyperbolicCosine(value.Imaginary), Cosine(value.Real) * HyperbolicCosine(value.Imaginary),
-Sine(value.Real) * HyperbolicSine(value.Imaginary)); -Sine(value.Real) * HyperbolicSine(value.Imaginary));
} }
@ -209,7 +209,7 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Trigonometric Hyperbolic Cosecant /// Trigonometric Hyperbolic Cosecant
/// </summary> /// </summary>
/// <param name="radian"> /// <param name="radian">
/// The angle in radian. /// The angle in radian.
@ -279,12 +279,12 @@ namespace MathNet.Numerics
} }
return new Complex( return new Complex(
HyperbolicCosine(value.Real) * Cosine(value.Imaginary), HyperbolicCosine(value.Real) * Cosine(value.Imaginary),
HyperbolicSine(value.Real) * Sine(value.Imaginary)); HyperbolicSine(value.Real) * Sine(value.Imaginary));
} }
/// <summary> /// <summary>
/// Trigonometric Hyperbolic Cotangent /// Trigonometric Hyperbolic Cotangent
/// </summary> /// </summary>
/// <param name="radian"> /// <param name="radian">
/// The angle in radian angle. /// The angle in radian angle.
@ -345,7 +345,7 @@ namespace MathNet.Numerics
/// The angle in radian angle. /// The angle in radian angle.
/// </param> /// </param>
/// <returns> /// <returns>
/// The hyperbolic secant of the radian angle. /// The hyperbolic secant of the radian angle.
/// </returns> /// </returns>
public static double HyperbolicSecant(double radian) public static double HyperbolicSecant(double radian)
{ {
@ -409,7 +409,7 @@ namespace MathNet.Numerics
} }
return new Complex( return new Complex(
HyperbolicSine(value.Real) * Cosine(value.Imaginary), HyperbolicSine(value.Real) * Cosine(value.Imaginary),
HyperbolicCosine(value.Real) * Sine(value.Imaginary)); HyperbolicCosine(value.Real) * Sine(value.Imaginary));
} }
@ -566,7 +566,7 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Trigonometric Hyperbolic Arc Cosecant /// Trigonometric Hyperbolic Arc Cosecant
/// </summary> /// </summary>
/// <param name="radian"> /// <param name="radian">
/// The angle in radian angle. /// The angle in radian angle.
@ -595,7 +595,7 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Trigonometric Hyperbolic Area Cosine /// Trigonometric Hyperbolic Area Cosine
/// </summary> /// </summary>
/// <param name="radian"> /// <param name="radian">
/// The angle in radian angle. /// The angle in radian angle.
@ -652,7 +652,7 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Trigonometric Hyperbolic Area Secant /// Trigonometric Hyperbolic Area Secant
/// </summary> /// </summary>
/// <param name="radian"> /// <param name="radian">
/// The angle in radian angle. /// The angle in radian angle.
@ -681,7 +681,7 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Trigonometric Hyperbolic Area Sine /// Trigonometric Hyperbolic Area Sine
/// </summary> /// </summary>
/// <param name="radian"> /// <param name="radian">
/// The angle in radian angle. /// The angle in radian angle.
@ -918,7 +918,7 @@ namespace MathNet.Numerics
} }
return new Complex( return new Complex(
Sine(value.Real) * HyperbolicCosine(value.Imaginary), Sine(value.Real) * HyperbolicCosine(value.Imaginary),
Cosine(value.Real) * HyperbolicSine(value.Imaginary)); Cosine(value.Real) * HyperbolicSine(value.Imaginary));
} }

3
src/Portable/Portable.csproj

@ -1032,6 +1032,9 @@
<Compile Include="..\Numerics\Statistics\Statistics.cs"> <Compile Include="..\Numerics\Statistics\Statistics.cs">
<Link>Statistics\Statistics.cs</Link> <Link>Statistics\Statistics.cs</Link>
</Compile> </Compile>
<Compile Include="..\Numerics\TargetedPatchingOptOutAttribute.cs">
<Link>TargetedPatchingOptOutAttribute.cs</Link>
</Compile>
<Compile Include="..\Numerics\Threading\CommonParallel.cs"> <Compile Include="..\Numerics\Threading\CommonParallel.cs">
<Link>Threading\CommonParallel.cs</Link> <Link>Threading\CommonParallel.cs</Link>
</Compile> </Compile>

4
src/UnitTests/ComplexTests/Complex32Test.TextHandling.cs

@ -90,7 +90,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
var infinity = double.PositiveInfinity.ToString(provider); var infinity = double.PositiveInfinity.ToString(provider);
Assert.AreEqual("(" + nan + ", " + nan + ")", Complex32.NaN.ToString(provider)); Assert.AreEqual("(" + nan + ", " + nan + ")", Complex32.NaN.ToString(provider));
Assert.AreEqual("(" + infinity + ", " + infinity + ")", Complex32.Infinity.ToString(provider)); Assert.AreEqual("(" + infinity + ", " + infinity + ")", Complex32.PositiveInfinity.ToString(provider));
Assert.AreEqual("(0, 0)", Complex32.Zero.ToString(provider)); Assert.AreEqual("(0, 0)", Complex32.Zero.ToString(provider));
Assert.AreEqual("(" + String.Format("{0}", number) + ", 0)", new Complex32(1.1f, 0.0f).ToString(provider)); Assert.AreEqual("(" + String.Format("{0}", number) + ", 0)", new Complex32(1.1f, 0.0f).ToString(provider));
Assert.AreEqual("(" + String.Format("-{0}", number) + ", 0)", new Complex32(-1.1f, 0f).ToString(provider)); Assert.AreEqual("(" + String.Format("-{0}", number) + ", 0)", new Complex32(-1.1f, 0f).ToString(provider));
@ -133,7 +133,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
Assert.AreEqual("(1.100, 1.100)", String.Format(culture, "{0:.000}", new Complex32(1.1f, 1.1f))); Assert.AreEqual("(1.100, 1.100)", String.Format(culture, "{0:.000}", new Complex32(1.1f, 1.1f)));
Assert.AreEqual("(NaN, NaN)", Complex32.NaN.ToString("#.000", culture)); Assert.AreEqual("(NaN, NaN)", Complex32.NaN.ToString("#.000", culture));
Assert.AreEqual("(Infinity, Infinity)", Complex32.Infinity.ToString("#.000", culture)); Assert.AreEqual("(Infinity, Infinity)", Complex32.PositiveInfinity.ToString("#.000", culture));
Assert.AreEqual("(.000, .000)", Complex32.Zero.ToString("#.000", culture)); Assert.AreEqual("(.000, .000)", Complex32.Zero.ToString("#.000", culture));
Assert.AreEqual("(1.100, .000)", new Complex32(1.1f, 0.0f).ToString("#.000", culture)); Assert.AreEqual("(1.100, .000)", new Complex32(1.1f, 0.0f).ToString("#.000", culture));
Assert.AreEqual("(.000, -1.100)", new Complex32(0.0f, -1.1f).ToString("#.000", culture)); Assert.AreEqual("(.000, -1.100)", new Complex32(0.0f, -1.1f).ToString("#.000", culture));

82
src/UnitTests/ComplexTests/Complex32Test.cs

@ -45,7 +45,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
Assert.That((Complex32.NaN + float.NaN).IsNaN()); Assert.That((Complex32.NaN + float.NaN).IsNaN());
Assert.That((float.NaN + Complex32.NaN).IsNaN()); Assert.That((float.NaN + Complex32.NaN).IsNaN());
Assert.That((float.PositiveInfinity + Complex32.One).IsInfinity()); Assert.That((float.PositiveInfinity + Complex32.One).IsInfinity());
Assert.That((Complex32.Infinity + 1.0f).IsInfinity()); Assert.That((Complex32.PositiveInfinity + 1.0f).IsInfinity());
Assert.That((Complex32.One + 0.0f) == Complex32.One); Assert.That((Complex32.One + 0.0f) == Complex32.One);
Assert.That((0.0f + Complex32.One) == Complex32.One); Assert.That((0.0f + Complex32.One) == Complex32.One);
Assert.That(new Complex32(1.1f, -2.2f) + 1.1f == new Complex32(2.2f, -2.2f)); Assert.That(new Complex32(1.1f, -2.2f) + 1.1f == new Complex32(2.2f, -2.2f));
@ -59,7 +59,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
public void CanAddSubtractComplexNumbersUsingOperator() public void CanAddSubtractComplexNumbersUsingOperator()
{ {
Assert.That((Complex32.NaN - Complex32.NaN).IsNaN()); Assert.That((Complex32.NaN - Complex32.NaN).IsNaN());
Assert.That((Complex32.Infinity - Complex32.One).IsInfinity()); Assert.That((Complex32.PositiveInfinity - Complex32.One).IsInfinity());
Assert.That((Complex32.One - Complex32.Zero) == Complex32.One); Assert.That((Complex32.One - Complex32.Zero) == Complex32.One);
Assert.That((new Complex32(1.1f, -2.2f) - new Complex32(1.1f, -2.2f)) == Complex32.Zero); Assert.That((new Complex32(1.1f, -2.2f) - new Complex32(1.1f, -2.2f)) == Complex32.Zero);
} }
@ -70,10 +70,10 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test] [Test]
public void CanAddTwoComplexNumbers() public void CanAddTwoComplexNumbers()
{ {
Assert.That(Complex32.NaN.Add(Complex32.NaN).IsNaN()); Assert.That(Complex32.Add(Complex32.NaN, (Complex32.NaN)).IsNaN());
Assert.That(Complex32.Infinity.Add(Complex32.One).IsInfinity()); Assert.That(Complex32.Add(Complex32.PositiveInfinity, Complex32.One).IsInfinity());
Assert.That(Complex32.One.Add(Complex32.Zero) == Complex32.One); Assert.That(Complex32.Add(Complex32.One, Complex32.Zero) == Complex32.One);
Assert.That(new Complex32(1.1f, -2.2f).Add(new Complex32(-1.1f, 2.2f)) == Complex32.Zero); Assert.That(Complex32.Add(new Complex32(1.1f, -2.2f), new Complex32(-1.1f, 2.2f)) == Complex32.Zero);
} }
/// <summary> /// <summary>
@ -83,7 +83,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
public void CanAddTwoComplexNumbersUsingOperator() public void CanAddTwoComplexNumbersUsingOperator()
{ {
Assert.That((Complex32.NaN + Complex32.NaN).IsNaN()); Assert.That((Complex32.NaN + Complex32.NaN).IsNaN());
Assert.That((Complex32.Infinity + Complex32.One).IsInfinity()); Assert.That((Complex32.PositiveInfinity + Complex32.One).IsInfinity());
Assert.That((Complex32.One + Complex32.Zero) == Complex32.One); Assert.That((Complex32.One + Complex32.Zero) == Complex32.One);
Assert.That((new Complex32(1.1f, -2.2f) + new Complex32(-1.1f, 2.2f)) == Complex32.Zero); Assert.That((new Complex32(1.1f, -2.2f) + new Complex32(-1.1f, 2.2f)) == Complex32.Zero);
} }
@ -94,12 +94,11 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test] [Test]
public void CanCalculateHashCode() public void CanCalculateHashCode()
{ {
var complex = new Complex32(1, 0); Assert.AreEqual(new Complex32(1, 2).GetHashCode(), new Complex32(1, 2).GetHashCode());
Assert.AreEqual(1065353216, complex.GetHashCode()); Assert.AreNotEqual(new Complex32(1, 0).GetHashCode(), new Complex32(0, 1).GetHashCode());
complex = new Complex32(0, 1); Assert.AreNotEqual(new Complex32(1, 1).GetHashCode(), new Complex32(2, 2).GetHashCode());
Assert.AreEqual(-1065353216, complex.GetHashCode()); Assert.AreNotEqual(new Complex32(1, 0).GetHashCode(), new Complex32(-1, 0).GetHashCode());
complex = new Complex32(1, 1); Assert.AreNotEqual(new Complex32(0, 1).GetHashCode(), new Complex32(0, -1).GetHashCode());
Assert.AreEqual(-16777216, complex.GetHashCode());
} }
/// <summary> /// <summary>
@ -285,7 +284,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test] [Test]
public void CanCreateComplexNumberWithModulusArgument() public void CanCreateComplexNumberWithModulusArgument()
{ {
var complex = Complex32.WithModulusArgument(2, (float)-Math.PI / 6); var complex = Complex32.FromPolarCoordinates(2, (float)-Math.PI / 6);
Assert.AreEqual((float)Math.Sqrt(3), complex.Real, 1e-7f, "Real part is Sqrt(3)."); Assert.AreEqual((float)Math.Sqrt(3), complex.Real, 1e-7f, "Real part is Sqrt(3).");
Assert.AreEqual(-1.0f, complex.Imaginary, 1e-7f, "Imaginary part is -1."); Assert.AreEqual(-1.0f, complex.Imaginary, 1e-7f, "Imaginary part is -1.");
} }
@ -296,7 +295,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test] [Test]
public void CanCreateComplexNumberWithRealImaginaryInitializer() public void CanCreateComplexNumberWithRealImaginaryInitializer()
{ {
var complex = Complex32.WithRealImaginary(1.1f, -2.2f); var complex = new Complex32(1.1f, -2.2f);
Assert.AreEqual(1.1f, complex.Real, "Real part is 1.1f."); Assert.AreEqual(1.1f, complex.Real, "Real part is 1.1f.");
Assert.AreEqual(-2.2f, complex.Imaginary, "Imaginary part is -2.2f."); Assert.AreEqual(-2.2f, complex.Imaginary, "Imaginary part is -2.2f.");
} }
@ -388,8 +387,8 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
Assert.That((Complex32.NaN * 1.0f).IsNaN()); Assert.That((Complex32.NaN * 1.0f).IsNaN());
Assert.AreEqual(new Complex32(-2, 2), new Complex32(4, -4) / -2); Assert.AreEqual(new Complex32(-2, 2), new Complex32(4, -4) / -2);
Assert.AreEqual(new Complex32(0.25f, 0.25f), 2 / new Complex32(4, -4)); Assert.AreEqual(new Complex32(0.25f, 0.25f), 2 / new Complex32(4, -4));
Assert.AreEqual(Complex32.Infinity, 2.0f / Complex32.Zero); Assert.AreEqual(Complex32.PositiveInfinity, 2.0f / Complex32.Zero);
Assert.AreEqual(Complex32.Infinity, Complex32.One / 0); Assert.AreEqual(Complex32.PositiveInfinity, Complex32.One / 0);
} }
/// <summary> /// <summary>
@ -398,9 +397,9 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test] [Test]
public void CanDivideTwoComplexNumbers() public void CanDivideTwoComplexNumbers()
{ {
Assert.That(Complex32.NaN.Multiply(Complex32.One).IsNaN()); Assert.That(Complex32.Divide(Complex32.NaN, Complex32.One).IsNaN());
Assert.AreEqual(new Complex32(-2, 0), new Complex32(4, -4).Divide(new Complex32(-2, 2))); Assert.AreEqual(new Complex32(-2, 0), Complex32.Divide(new Complex32(4, -4), new Complex32(-2, 2)));
Assert.AreEqual(Complex32.Infinity, Complex32.One.Divide(Complex32.Zero)); Assert.AreEqual(Complex32.PositiveInfinity, Complex32.Divide(Complex32.One, Complex32.Zero));
} }
/// <summary> /// <summary>
@ -411,7 +410,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
{ {
Assert.That((Complex32.NaN / Complex32.One).IsNaN()); Assert.That((Complex32.NaN / Complex32.One).IsNaN());
Assert.AreEqual(new Complex32(-2, 0), new Complex32(4, -4) / new Complex32(-2, 2)); Assert.AreEqual(new Complex32(-2, 0), new Complex32(4, -4) / new Complex32(-2, 2));
Assert.AreEqual(Complex32.Infinity, Complex32.One / Complex32.Zero); Assert.AreEqual(Complex32.PositiveInfinity, Complex32.One / Complex32.Zero);
} }
/// <summary> /// <summary>
@ -431,8 +430,8 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test] [Test]
public void CanMultipleTwoComplexNumbers() public void CanMultipleTwoComplexNumbers()
{ {
Assert.That(Complex32.NaN.Multiply(Complex32.One).IsNaN()); Assert.That(Complex32.Multiply(Complex32.NaN, Complex32.One).IsNaN());
Assert.AreEqual(new Complex32(0, 16), new Complex32(4, -4).Multiply(new Complex32(-2, 2))); Assert.AreEqual(new Complex32(0, 16), Complex32.Multiply(new Complex32(4, -4), new Complex32(-2, 2)));
} }
/// <summary> /// <summary>
@ -452,7 +451,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
public void CanNegateValue() public void CanNegateValue()
{ {
var complex = new Complex32(1.1f, -2.2f); var complex = new Complex32(1.1f, -2.2f);
Assert.AreEqual(new Complex32(-1.1f, 2.2f), complex.Negate()); Assert.AreEqual(new Complex32(-1.1f, 2.2f), Complex32.Negate(complex));
} }
/// <summary> /// <summary>
@ -474,7 +473,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
Assert.That((Complex32.NaN - float.NaN).IsNaN()); Assert.That((Complex32.NaN - float.NaN).IsNaN());
Assert.That((float.NaN - Complex32.NaN).IsNaN()); Assert.That((float.NaN - Complex32.NaN).IsNaN());
Assert.That((float.PositiveInfinity - Complex32.One).IsInfinity()); Assert.That((float.PositiveInfinity - Complex32.One).IsInfinity());
Assert.That((Complex32.Infinity - 1.0f).IsInfinity()); Assert.That((Complex32.PositiveInfinity - 1.0f).IsInfinity());
Assert.That((Complex32.One - 0.0f) == Complex32.One); Assert.That((Complex32.One - 0.0f) == Complex32.One);
Assert.That((0.0f - Complex32.One) == -Complex32.One); Assert.That((0.0f - Complex32.One) == -Complex32.One);
Assert.That(new Complex32(1.1f, -2.2f) - 1.1f == new Complex32(0.0f, -2.2f)); Assert.That(new Complex32(1.1f, -2.2f) - 1.1f == new Complex32(0.0f, -2.2f));
@ -487,10 +486,10 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test] [Test]
public void CanSubtractTwoComplexNumbers() public void CanSubtractTwoComplexNumbers()
{ {
Assert.That(Complex32.NaN.Subtract(Complex32.NaN).IsNaN()); Assert.That(Complex32.Subtract(Complex32.NaN, Complex32.NaN).IsNaN());
Assert.That(Complex32.Infinity.Subtract(Complex32.One).IsInfinity()); Assert.That(Complex32.Subtract(Complex32.PositiveInfinity, Complex32.One).IsInfinity());
Assert.That(Complex32.One.Subtract(Complex32.Zero) == Complex32.One); Assert.That(Complex32.Subtract(Complex32.One, Complex32.Zero) == Complex32.One);
Assert.That(new Complex32(1.1f, -2.2f).Subtract(new Complex32(1.1f, -2.2f)) == Complex32.Zero); Assert.That(Complex32.Subtract(new Complex32(1.1f, -2.2f), new Complex32(1.1f, -2.2f)) == Complex32.Zero);
} }
/// <summary> /// <summary>
@ -500,7 +499,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
public void CanTestForEquality() public void CanTestForEquality()
{ {
Assert.AreNotEqual(Complex32.NaN, Complex32.NaN); Assert.AreNotEqual(Complex32.NaN, Complex32.NaN);
Assert.AreEqual(Complex32.Infinity, Complex32.Infinity); Assert.AreEqual(Complex32.PositiveInfinity, Complex32.PositiveInfinity);
Assert.AreEqual(new Complex32(1.1f, -2.2f), new Complex32(1.1f, -2.2f)); Assert.AreEqual(new Complex32(1.1f, -2.2f), new Complex32(1.1f, -2.2f));
Assert.AreNotEqual(new Complex32(-1.1f, 2.2f), new Complex32(1.1f, -2.2f)); Assert.AreNotEqual(new Complex32(-1.1f, 2.2f), new Complex32(1.1f, -2.2f));
} }
@ -512,23 +511,13 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
public void CanTestForEqualityUsingOperators() public void CanTestForEqualityUsingOperators()
{ {
Assert.That(Complex32.NaN != Complex32.NaN); Assert.That(Complex32.NaN != Complex32.NaN);
Assert.That(Complex32.Infinity == Complex32.Infinity); Assert.That(Complex32.PositiveInfinity == Complex32.PositiveInfinity);
Assert.That(new Complex32(1.1f, -2.2f) == new Complex32(1.1f, -2.2f)); Assert.That(new Complex32(1.1f, -2.2f) == new Complex32(1.1f, -2.2f));
Assert.That(new Complex32(-1.1f, 2.2f) != new Complex32(1.1f, -2.2f)); Assert.That(new Complex32(-1.1f, 2.2f) != new Complex32(1.1f, -2.2f));
} }
/// <summary> /// <summary>
/// Can use Plus. /// Can use unary "+" operator.
/// </summary>
[Test]
public void CanUsePlus()
{
var complex = new Complex32(1.1f, -2.2f);
Assert.AreEqual(complex, complex.Plus());
}
/// <summary>
/// Can use "+" operator.
/// </summary> /// </summary>
[Test] [Test]
public void CanUsePlusOperator() public void CanUsePlusOperator()
@ -537,15 +526,6 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
Assert.AreEqual(complex, +complex); Assert.AreEqual(complex, +complex);
} }
/// <summary>
/// With negative modulus argument throws <c>ArgumentOutOfRangeException</c>.
/// </summary>
[Test]
public void WithNegativeModulusArgumentThrowsArgumentOutOfRangeException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => Complex32.WithModulusArgument(-1, 1), "Throws exception because modulus is negative.");
}
/// <summary> /// <summary>
/// Can compute magnitude. /// Can compute magnitude.
/// </summary> /// </summary>

20
src/UnitTests/ComplexTests/ComplexTest.cs

@ -106,6 +106,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
a = new Complex(0.0, 0.0); a = new Complex(0.0, 0.0);
b = new Complex(1.0, 0.0); b = new Complex(1.0, 0.0);
AssertHelpers.AlmostEqual(new Complex(0.0, 0.0), a.Power(b), 15); AssertHelpers.AlmostEqual(new Complex(0.0, 0.0), a.Power(b), 15);
a = new Complex(0.0, 0.0); a = new Complex(0.0, 0.0);
b = new Complex(-1.0, 0.0); b = new Complex(-1.0, 0.0);
AssertHelpers.AlmostEqual(new Complex(double.PositiveInfinity, 0.0), a.Power(b), 15); AssertHelpers.AlmostEqual(new Complex(double.PositiveInfinity, 0.0), a.Power(b), 15);
@ -123,21 +124,22 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test] [Test]
public void CanComputeRoot() public void CanComputeRoot()
{ {
var a = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7); var a = new Complex(0.0, -1.19209289550780998537e-7);
var b = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7); var b = new Complex(0.0, 0.5);
AssertHelpers.AlmostEqual(new Complex(0.0, 0.0), a.Root(b), 15); AssertHelpers.AlmostEqual(new Complex(0.038550761943650161, 0.019526430428319544), a.Root(b), 14);
a = new Complex(0.0, -1.19209289550780998537e-7);
b = new Complex(0.0, 0.5);
AssertHelpers.AlmostEqual(new Complex(0.038550761943650161, 0.019526430428319544), a.Root(b), 15);
a = new Complex(0.0, 0.5); a = new Complex(0.0, 0.5);
b = new Complex(0.0, -0.5); b = new Complex(0.0, -0.5);
AssertHelpers.AlmostEqual(new Complex(0.007927894711475968, -0.042480480425152213), a.Root(b), 15); AssertHelpers.AlmostEqual(new Complex(0.007927894711475968, -0.042480480425152213), a.Root(b), 14);
a = new Complex(0.0, -0.5); a = new Complex(0.0, -0.5);
b = new Complex(0.0, 1.0); b = new Complex(0.0, 1.0);
AssertHelpers.AlmostEqual(new Complex(0.15990905692806806, 0.13282699942462053), a.Root(b), 15); AssertHelpers.AlmostEqual(new Complex(0.15990905692806806, 0.13282699942462053), a.Root(b), 14);
a = new Complex(0.0, 2.0); a = new Complex(0.0, 2.0);
b = new Complex(0.0, -2.0); b = new Complex(0.0, -2.0);
AssertHelpers.AlmostEqual(new Complex(0.42882900629436788, 0.15487175246424678), a.Root(b), 15); AssertHelpers.AlmostEqual(new Complex(0.42882900629436788, 0.15487175246424678), a.Root(b), 14);
//a = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7);
//b = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7);
//AssertHelpers.AlmostEqual(new Complex(0.0, 0.0), a.Root(b), 15);
a = new Complex(0.0, -8.388608e6); a = new Complex(0.0, -8.388608e6);
b = new Complex(1.19209289550780998537e-7, 0.0); b = new Complex(1.19209289550780998537e-7, 0.0);
AssertHelpers.AlmostEqual(new Complex(double.PositiveInfinity, double.NegativeInfinity), a.Root(b), 15); AssertHelpers.AlmostEqual(new Complex(double.PositiveInfinity, double.NegativeInfinity), a.Root(b), 15);

2
src/UnitTests/LinearAlgebraTests/Complex32/VectorTests.cs

@ -230,7 +230,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
public void CanGetHashCode() public void CanGetHashCode()
{ {
var vector = CreateVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1) }); var vector = CreateVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1) });
Assert.AreEqual(-1051736064, vector.GetHashCode()); Assert.AreEqual(-1042380805, vector.GetHashCode());
} }
/// <summary> /// <summary>

8
src/UnitTests/TrigonometryTest.cs

@ -116,7 +116,7 @@ namespace MathNet.Numerics.UnitTests
} }
/// <summary> /// <summary>
/// Can compute cosine. /// Can compute cosine.
/// </summary> /// </summary>
/// <param name="value">Input value.</param> /// <param name="value">Input value.</param>
/// <param name="expected">Expected value.</param> /// <param name="expected">Expected value.</param>
@ -164,7 +164,7 @@ namespace MathNet.Numerics.UnitTests
} }
/// <summary> /// <summary>
/// Can compute hyperbolic cosine. /// Can compute hyperbolic cosine.
/// </summary> /// </summary>
/// <param name="value">Input value.</param> /// <param name="value">Input value.</param>
/// <param name="expected">Expected value.</param> /// <param name="expected">Expected value.</param>
@ -379,7 +379,7 @@ namespace MathNet.Numerics.UnitTests
} }
/// <summary> /// <summary>
/// Can compute inverse secant. /// Can compute inverse secant.
/// </summary> /// </summary>
/// <param name="value">Input value.</param> /// <param name="value">Input value.</param>
/// <param name="expected">Expected value.</param> /// <param name="expected">Expected value.</param>
@ -501,7 +501,7 @@ namespace MathNet.Numerics.UnitTests
} }
/// <summary> /// <summary>
/// Can convert grad to radian. /// Can convert grad to radian.
/// </summary> /// </summary>
[Test] [Test]
public void CanConvertGradToRadian() public void CanConvertGradToRadian()

Loading…
Cancel
Save