Browse Source

Merge branch 'fspowerpack'

pull/64/merge
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
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpPortable", "src\FSharpPortable\FSharpPortable.fsproj", "{F5F14D76-428D-43D7-8431-5B885F1BA419}"
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
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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}.Release|Any CPU.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{90CE8E32-354E-4728-8FE6-87342F469321} = {81D2CBEF-1C80-4389-A341-F010E8F86CDB}
EndGlobalSection
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_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/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_LINES/@EntryValue">False</s:Boolean></wpf:ResourceDictionary>

2
packages/repositories.config

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<repositories>
<repository path="..\src\FSharpPortableUnitTests\packages.config" />
<repository path="..\src\FSharpUnitTests\packages.config" />
<repository path="..\src\Numerics.IO\packages.config" />
<repository path="..\src\UnitTests\packages.config" />
</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>
<Tailcalls>false</Tailcalls>
<OutputPath>..\..\out\debug\Net40\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<WarningLevel>3</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
@ -38,7 +38,7 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<Tailcalls>true</Tailcalls>
<DefineConstants>TRACE</DefineConstants>
<DefineConstants>TRACE;STRONGNAME</DefineConstants>
<WarningLevel>3</WarningLevel>
<DocumentationFile>..\..\out\lib\Net40\MathNet.Numerics.FSharp.xml</DocumentationFile>
<OutputPath>bin\Release-Signed\</OutputPath>
@ -57,6 +57,12 @@
<Compile Include="LinearAlgebra.Double.Vector.fs" />
<Compile Include="LinearAlgebra.Double.Matrix.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>
<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.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Matrix =
/// Fold a function over all matrix elements.
let inline fold (f: 'a -> float -> 'a) (acc0: 'a) (A: #Matrix<float>) =
let n = A.RowCount
@ -71,8 +71,8 @@ module Matrix =
let n = A.RowCount
let m = A.ColumnCount
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 mutable b = true
let mutable i = 0
@ -82,7 +82,7 @@ module Matrix =
j <- j+1
if j = A.ColumnCount then i <- i+1; j <- 0
b
/// Chechks whether a predicate holds for at least one element of a matrix.
let inline exists (p: float -> bool) (A: #Matrix<float>) =
let mutable b = false
@ -93,7 +93,7 @@ module Matrix =
j <- j+1
if j = A.ColumnCount then i <- i+1; j <- 0
b
/// 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 mutable b = true
@ -104,7 +104,7 @@ module Matrix =
j <- j+1
if j = A.ColumnCount then i <- i+1; j <- 0
b
/// 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 mutable b = false
@ -115,7 +115,7 @@ module Matrix =
j <- j+1
if j = A.ColumnCount then i <- i+1; j <- 0
b
/// Map every matrix element using the given function.
let inline map (f: float -> float) (A: #Matrix<float>) =
let N = A.RowCount
@ -125,7 +125,7 @@ module Matrix =
for j=0 to M-1 do
C.[i,j] <- f (C.Item(i,j))
C
/// Map every matrix element using the given position dependent function.
let inline mapi (f: int -> int -> float -> float) (A: #Matrix<float>) =
let N = A.RowCount
@ -135,7 +135,7 @@ module Matrix =
for j=0 to M-1 do
C.[i,j] <- f i j (C.Item(i,j))
C
/// In-place map every matrix column using the given position dependent function.
let inline inplaceMapCols (f: int -> Vector<float> -> Vector<float>) (A: #Matrix<float>) =
for j = 0 to A.ColumnCount-1 do
@ -165,19 +165,19 @@ module Matrix =
for i=0 to A.RowCount-1 do
for j=0 to A.ColumnCount-1 do
A.Item(i,j) <- f i j
/// In-place map of every matrix element using a position dependent function.
let inline inplaceMapi (f: int -> int -> float -> float) (A: #Matrix<float>) =
for i=0 to A.RowCount-1 do
for j=0 to A.ColumnCount-1 do
A.Item(i,j) <- f i j (A.Item(i,j))
/// Creates a sequence that iterates the non-zero entries in the matrix.
let inline nonZeroEntries (A: #Matrix<float>) =
seq { for i in 0 .. A.RowCount-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)) }
/// Returns the sum of all elements of a matrix.
let inline sum (A: #Matrix<float>) =
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.
let inline sumColsBy (f: int -> Vector<float> -> 'a) (A: #Matrix<float>) =
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.
let inline sumRowsBy (f: int -> Vector<float> -> 'a) (A: #Matrix<float>) =
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
f (A.Item(i,j))
()
/// Iterates over all elements of a matrix using the element indices.
let inline iteri (f: int -> int -> float -> unit) (A: #Matrix<float>) =
for i=0 to A.RowCount-1 do
for j=0 to A.ColumnCount-1 do
f i j (A.Item(i,j))
()
/// Fold one column.
let inline foldCol (f: 'a -> float -> 'a) acc (A: #Matrix<float>) k =
let mutable macc = acc
for i=0 to A.RowCount-1 do
macc <- f macc (A.Item(i,k))
macc
/// Fold one row.
let inline foldRow (f: 'a -> float -> 'a) acc (A: #Matrix<float>) k =
let mutable macc = acc
@ -231,7 +231,7 @@ module Matrix =
macc <- f macc (A.Item(i,k))
v.[k] <- macc
v :> Vector<float>
/// Fold all rows into one column vector.
let inline foldByRow (f: float -> float -> float) acc (A: #Matrix<float>) =
let v = new DenseVector(A.RowCount)
@ -253,7 +253,7 @@ module DenseMatrix =
for j=0 to m-1 do
A.[i,j] <- f i j
A
/// 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 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
List.iteri (fun j f -> A.[i,j] <- f) fl)
A
/// 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 n = Seq.length fss
@ -276,20 +276,20 @@ module DenseMatrix =
/// Create a matrix from a 2D array of floating point numbers.
let inline ofArray2 (arr: float[,]) = new DenseMatrix(arr)
/// Create a matrix with the given entries.
let inline initDense (n: int) (m: int) (es: #seq<int * int * float>) =
let A = new DenseMatrix(n,m)
Seq.iter (fun (i,j,f) -> A.[i,j] <- f) es
A
/// Create a square matrix with constant diagonal entries.
let inline constDiag (n: int) (f: float) =
let A = new DenseMatrix(n,n)
for i=0 to n-1 do
A.[i,i] <- f
A
/// Create a square matrix with the vector elements on the diagonal.
let inline diag (v: #Vector<float>) =
let n = v.Count
@ -313,26 +313,26 @@ module DenseMatrix =
/// A module which implements functional sparse vector operations.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module SparseMatrix =
/// 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 A = new SparseMatrix(rows, cols)
fll |> List.iter (fun (i, j, x) -> A.[i,j] <- x)
A
/// 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 A = new SparseMatrix(rows, cols)
fss |> Seq.iter (fun (i, j, x) -> A.[i,j] <- x)
A
/// Create a square matrix with constant diagonal entries.
let inline constDiag (n: int) (f: float) =
let A = new SparseMatrix(n,n)
for i=0 to n-1 do
A.[i,i] <- f
A
/// Create a square matrix with the vector elements on the diagonal.
let inline diag (v: #Vector<float>) =
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.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Vector =
/// Transform a vector into an array.
let inline toArray (v: #Vector<float>) =
let n = v.Count
Array.init n (fun i -> v.Item(i))
/// Transform a vector into an array.
let inline toList (v: #Vector<float>) =
let n = v.Count
@ -57,30 +57,30 @@ module Vector =
for i=0 to v.Count-1 do
v.Item(i) <- f i (v.Item(i))
()
/// In-place vector addition.
let inline addInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Add(w, v)
/// In place vector subtraction.
let inline subInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Subtract(w, v)
/// 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 w = v.Clone()
mapInPlace (fun x -> f x) w
w
/// Applies a function to all elements of the vector.
let inline iter (f: float -> unit) (v: #Vector<float>) =
for i=0 to v.Count-1 do
f (v.Item i)
/// Applies a function to all elements of the vector.
let inline iteri (f: int -> float -> unit) (v: #Vector<float>) =
for i=0 to v.Count-1 do
f i (v.Item i)
/// 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 w = v.Clone()
@ -107,7 +107,7 @@ module Vector =
for i=0 to v.Count-1 do
acc <- f i acc (v.Item(i))
acc
/// Checks whether a predicate is satisfied for every element in the vector.
let inline forall (p: float -> bool) (v: #Vector<float>) =
let mutable b = true
@ -116,7 +116,7 @@ module Vector =
b <- b && (p (v.Item(i)))
i <- i+1
b
/// Checks whether there is an entry in the vector that satisfies a given predicate.
let inline exists (p: float -> bool) (v: #Vector<float>) =
let mutable b = false
@ -125,7 +125,7 @@ module Vector =
b <- b || (p (v.Item(i)))
i <- i+1
b
/// Checks whether a predicate is true for all entries in a vector.
let inline foralli (p: int -> float -> bool) (v: #Vector<float>) =
let mutable b = true
@ -134,7 +134,7 @@ module Vector =
b <- b && (p i (v.Item(i)))
i <- i+1
b
/// 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 mutable b = false
@ -177,13 +177,13 @@ module Vector =
p
/// Creates a new vector and inserts the given value at the given index.
let inline insert index value (v: #Vector<float>) =
let newV = new DenseVector(v.Count + 1)
for i = 0 to index - 1 do
newV.Item(i) <- v.Item(i)
newV.Item(index) <- value
for i = index + 1 to v.Count do
newV.Item(i) <- v.Item(i - 1)
let inline insert index value (v: #Vector<float>) =
let newV = new DenseVector(v.Count + 1)
for i = 0 to index - 1 do
newV.Item(i) <- v.Item(i)
newV.Item(index) <- value
for i = index + 1 to v.Count do
newV.Item(i) <- v.Item(i - 1)
newV
/// A module which implements functional dense vector operations.
@ -203,14 +203,14 @@ module DenseVector =
let v = DenseVector(n)
fl |> List.iteri (fun i f -> v.[i] <- f)
v
/// Create a vector from a sequences.
let inline ofSeq (fs: #seq<float>) =
let n = Seq.length fs
let v = DenseVector(n)
fs |> Seq.iteri (fun i f -> v.[i] <- f)
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]
let inline rangef (start: float) (step: float) (stop: float) =
let n = (int ((stop - start) / step)) + 1
@ -218,7 +218,7 @@ module DenseVector =
for i=0 to n-1 do
v.[i] <- (float i) * step + start
v
/// Create a vector with integer entries in the given range.
let inline range (start: int) (stop: int) =
new DenseVector([| for i in [start .. stop] -> float i |])
@ -226,13 +226,13 @@ module DenseVector =
/// A module which implements functional sparse vector operations.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module SparseVector =
/// 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 v = new SparseVector(dim)
fl |> List.iter (fun (i, f) -> v.[i] <- f)
v
/// 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 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
// extension members for generic Matrix and Vector types
[<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
type MathNet.Numerics.LinearAlgebra.Generic.
Vector<'T when 'T : struct and 'T : (new : unit -> 'T)
and 'T :> System.IEquatable<'T> and 'T :> System.IFormattable
Vector<'T when 'T : struct and 'T : (new : unit -> 'T)
and 'T :> System.IEquatable<'T> and 'T :> System.IFormattable
and 'T :> System.ValueType> with
/// Gets a slice of a vector starting at a specified index
/// and ending at a specified index (both indices are optional)
/// 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 finish = defaultArg finish (x.Count - 1)
x.SubVector(start, finish - start + 1)
@ -53,14 +53,14 @@ module FSharpExtensions =
// A type extension for the generic matrix type that
// adds the 'GetSlice' method to allow m.[r1 .. r2, c1 .. c2] syntax
type MathNet.Numerics.LinearAlgebra.Generic.
Matrix<'T when 'T : struct and 'T : (new : unit -> 'T)
and 'T :> System.IEquatable<'T> and 'T :> System.IFormattable
Matrix<'T when 'T : struct and 'T : (new : unit -> 'T)
and 'T :> System.IEquatable<'T> and 'T :> System.IFormattable
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)
/// 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 rstart = defaultArg rstart 0
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
else printf "\t%d" sw.ElapsedMilliseconds
sw.Reset()*)
printfn ""

20
src/FSharpExamples/MCMC.fs

@ -45,7 +45,7 @@ let rnd = new MersenneTwister()
// -----------------------------------------------------------------------------
do
printfn "Rejection Sampling Example"
/// The target distribution.
let beta = new Beta(2.7, 6.3)
@ -76,7 +76,7 @@ do
// -----------------------------------------------------------------------------
do
printfn "Metropolis Sampling Example"
let mean, stddev = 1.0, 3.5
let normal = new Normal(mean, stddev)
@ -93,7 +93,7 @@ do
printfn "\tEmpirical StdDev = %f (should be %f)" (Statistics.StandardDeviation(arr)) normal.StdDev
printfn "\tAcceptance rate = %f" ms.AcceptanceRate
printfn ""
//
@ -107,12 +107,12 @@ do
printfn "Metropolis Hastings Sampling Example (Symmetric Proposal)"
let mean, stddev = 1.0, 3.5
let normal = new Normal(mean, stddev)
/// 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)
/// 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,
RandomSource = rnd )
@ -138,22 +138,22 @@ do
printfn "Metropolis Hastings Sampling Example (Assymetric Proposal)"
let mean, stddev = 1.0, 3.5
let normal = new Normal(mean, stddev)
/// 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)
/// Samples from a mixture that is biased towards samples larger than x.
let mixSample x =
if Bernoulli.Sample(rnd, 0.5) = 1 then
Normal.Sample(rnd, x, 0.3)
else
Normal.Sample(rnd, x + 0.1, 0.3)
/// 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))
/// 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,
RandomSource = rnd )
@ -178,7 +178,7 @@ do
printfn "Slice Sampling Example"
let mean, stddev = 1.0, 3.5
let normal = new Normal(mean, stddev)
/// Evaluates the unnormalized logarithm of the normal distribution function.
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">
<Link>LinearAlgebra.Double.fs</Link>
</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>
<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>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{f2f8032b-a31d-4e33-a05e-f2cdcbfaa75d}</ProjectGuid>
<OutputType>Exe</OutputType>
<OutputType>Library</OutputType>
<RootNamespace>FSharpUnitTests</RootNamespace>
<AssemblyName>MathNet.Numerics.FSharp.UnitTests</AssemblyName>
<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'))" />
<ItemGroup>
<Compile Include="FsUnit.fs" />
<Compile Include="Program.fs" />
<None Include="App.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Compile Include="VectorTests.fs" />
<Compile Include="SparseVectorTests.fs" />
<Compile Include="DenseVectorTests.fs" />
<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>
<Reference Include="FSharp.Core" />
<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.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>

314
src/FSharpUnitTests/FsUnit.fs

@ -1,244 +1,70 @@
(*
Copyright (c) 2008, Raymond W. Vernagus (R.Vernagus@gmail.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Raymond W. Vernagus nor the names of FsUnit's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
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
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)
namespace FsUnit
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra.Double
open MathNet.Numerics.LinearAlgebra.Generic
type Result =
| Pass
| Fail of string
| Error of string
type Expectation =
| True
| False
| Empty
| NullOrEmpty
| Null
| SameAs of obj
type Spec =
abstract Check : unit -> Result
abstract NegatedMessage : string
[<AutoOpen>]
module SpecOps =
let internal safeCheck f =
try
f()
with ex -> Error (ex.ToString())
let make f nmsg =
{ new Spec with
member this.Check() = safeCheck f
member this.NegatedMessage = nmsg }
let check (s: Spec) = s.Check()
let not' f x =
let s = f x
match check s with
| Pass -> make (fun () -> Fail s.NegatedMessage) ""
| Fail msg -> make (fun () -> Pass) msg
| Error msg -> make (fun () -> Error msg) msg
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)
module FsUnit
open NUnit.Framework
open NUnit.Framework.Constraints
let should (f : 'a -> #Constraint) x (y : obj) =
let c = f x
let y =
match y with
| :? (unit -> unit) -> box (TestDelegate(y :?> unit -> unit))
| _ -> y
Assert.That(y, c)
let equal x = EqualConstraint(x)
let equalWithin tolerance x = equal(x).Within tolerance
let contain x = ContainsConstraint(x)
let haveLength n = Has.Length.EqualTo(n)
let haveCount n = Has.Count.EqualTo(n)
let be = id
let Null = NullConstraint()
let Empty = EmptyConstraint()
let EmptyString = EmptyStringConstraint()
let NullOrEmptyString = NullOrEmptyStringConstraint()
let True = TrueConstraint()
let False = FalseConstraint()
let sameAs x = SameAsConstraint(x)
let throw = Throws.TypeOf
let greaterThan x = GreaterThanConstraint(x)
let greaterThanOrEqualTo x = GreaterThanOrEqualConstraint(x)
let lessThan x = LessThanConstraint(x)
let lessThanOrEqualTo x = LessThanOrEqualConstraint(x)
let shouldFail (f : unit -> unit) =
TestDelegate(f) |> should throw typeof<AssertionException>
let endWith (s:string) = EndsWithConstraint s
let startWith (s:string) = StartsWithConstraint s
let ofExactType<'a> = ExactTypeConstraint(typeof<'a>)
let instanceOfType<'a> = InstanceOfTypeConstraint(typeof<'a>)
let NaN = NaNConstraint()
let unique = UniqueItemsConstraint()
let not' x = NotConstraint(x)
let array_equal = equal
let array2_equal = equal
let approximately_equal tolerance = equalWithin (10.0 ** (float -tolerance))
let approximately_vector_equal = approximately_equal
let approximately_matrix_equal = approximately_equal

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.Numerics;
#if !PORTABLE
using System.Runtime;
#endif
/// <summary>
/// Extension methods
/// Extension methods for the Complex type provided by System.Numerics
/// </summary>
public static class ComplexExtensions
{
/// <summary>
/// Gets a value indicating whether the <c>Complex32</c> is zero.
/// Gets the squared magnitude of the <c>Complex</c> number.
/// </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)
/// <returns>The squared magnitude of the <c>Complex</c> number.</returns>
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>
/// 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>
/// <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)
/// <returns>The unity of this <c>Complex</c>.</returns>
public static Complex Sign(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>
/// 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;
}
if (double.IsPositiveInfinity(complex.Real) && double.IsNegativeInfinity(complex.Imaginary))
{
return new Complex(Constants.Sqrt1Over2, -Constants.Sqrt1Over2);
}
/// <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);
}
if (double.IsNegativeInfinity(complex.Real) && double.IsPositiveInfinity(complex.Imaginary))
{
return new Complex(-Constants.Sqrt1Over2, -Constants.Sqrt1Over2);
}
/// <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);
}
if (double.IsNegativeInfinity(complex.Real) && double.IsNegativeInfinity(complex.Imaginary))
{
return new Complex(-Constants.Sqrt1Over2, Constants.Sqrt1Over2);
}
/// <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;
}
// don't replace this with "Magnitude"!
var mod = SpecialFunctions.Hypotenuse(complex.Real, complex.Imaginary);
if (mod == 0.0d)
{
return Complex.Zero;
}
/// <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;
return new Complex(complex.Real / mod, complex.Imaginary / mod);
}
/// <summary>
@ -139,19 +106,19 @@ namespace MathNet.Numerics
/// </code>
/// </remarks>
/// <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)
{
return new Complex(complex.Real, -complex.Imaginary);
return Complex.Conjugate(complex);
}
/// <summary>
/// Gets the squared magnitude of the <c>Complex</c> number.
/// Returns the multiplicative inverse of a complex number.
/// </summary>
/// <param name="complex">The <see cref="Complex"/> number to perfom this operation on.</param>
/// <returns>The squared magnitude of the <c>Complex</c> number.</returns>
public static double MagnitudeSquared(this Complex complex)
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static Complex Reciprocal(this Complex complex)
{
return (complex.Real * complex.Real) + (complex.Imaginary * complex.Imaginary);
return Complex.Reciprocal(complex);
}
/// <summary>
@ -161,15 +128,10 @@ namespace MathNet.Numerics
/// <returns>
/// The exponential of this complex number.
/// </returns>
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static Complex Exponential(this Complex complex)
{
var exp = Math.Exp(complex.Real);
if (complex.IsReal())
{
return new Complex(exp, 0.0);
}
return new Complex(exp * Trig.Cosine(complex.Imaginary), exp * Trig.Sine(complex.Imaginary));
return Complex.Exp(complex);
}
/// <summary>
@ -179,14 +141,30 @@ namespace MathNet.Numerics
/// <returns>
/// The natural logarithm of this complex number.
/// </returns>
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static Complex NaturalLogarithm(this Complex complex)
{
if (complex.IsRealNonNegative())
{
return new Complex(Math.Log(complex.Real), 0.0);
}
return Complex.Log(complex);
}
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>
@ -208,25 +186,22 @@ namespace MathNet.Numerics
return Complex.One;
}
if (exponent.Real > 0.0)
if (exponent.Real > 0d)
{
return Complex.Zero;
}
if (exponent.Real < 0)
if (exponent.Real < 0d)
{
if (exponent.Imaginary == 0.0)
{
return new Complex(double.PositiveInfinity, 0.0);
}
return new Complex(double.PositiveInfinity, double.PositiveInfinity);
return exponent.Imaginary == 0d
? new Complex(double.PositiveInfinity, 0d)
: 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>
@ -241,7 +216,7 @@ namespace MathNet.Numerics
/// </returns>
public static Complex Root(this Complex complex, Complex rootExponent)
{
return Power(complex, 1 / rootExponent);
return Complex.Pow(complex, 1 / rootExponent);
}
/// <summary>
@ -270,6 +245,10 @@ namespace MathNet.Numerics
/// </returns>
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())
{
return new Complex(Math.Sqrt(complex.Real), 0.0);
@ -307,6 +286,89 @@ namespace MathNet.Numerics
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>
/// Returns a Norm of a value of this type, which is appropriate for measuring how
/// close this value is to zero.
@ -391,8 +453,8 @@ namespace MathNet.Numerics
var keywords =
new[]
{
textInfo.ListSeparator, numberFormatInfo.NaNSymbol,
numberFormatInfo.NegativeInfinitySymbol, numberFormatInfo.PositiveInfinitySymbol,
textInfo.ListSeparator, numberFormatInfo.NaNSymbol,
numberFormatInfo.NegativeInfinitySymbol, numberFormatInfo.PositiveInfinitySymbol,
"+", "-", "i", "j"
};
@ -521,17 +583,17 @@ namespace MathNet.Numerics
}
/// <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.
/// </summary>
/// <param name="value">
/// A string containing a complex number to convert.
/// A string containing a complex number to convert.
/// </param>
/// <param name="result">
/// The parsed value.
/// </param>
/// <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.
/// </returns>
public static bool TryToComplex(this string value, out Complex result)
@ -615,17 +677,17 @@ namespace MathNet.Numerics
}
/// <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.
/// </summary>
/// <param name="value">
/// A string containing a complex number to convert.
/// A string containing a complex number to convert.
/// </param>
/// <param name="result">
/// The parsed value.
/// </param>
/// <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.
/// </returns>
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>
[Serializable]
public abstract class Matrix : Matrix<Complex32>
{
{
/// <summary>
/// Initializes a new instance of the Matrix class.
/// </summary>
@ -67,7 +67,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<Complex32> ConjugateTranspose()
{
@ -102,7 +102,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
}
/// <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()
{
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.
/// </summary>
/// <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>
public override int GetHashCode()
{

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

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

7
src/Numerics/Numerics.csproj

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

2
src/Numerics/SpecialFunctions/Stability.cs

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

3
src/Portable/Portable.csproj

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

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

@ -90,7 +90,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
var infinity = double.PositiveInfinity.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("(" + 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));
@ -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("(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("(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));

82
src/UnitTests/ComplexTests/Complex32Test.cs

@ -45,7 +45,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
Assert.That((Complex32.NaN + float.NaN).IsNaN());
Assert.That((float.NaN + Complex32.NaN).IsNaN());
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((0.0f + Complex32.One) == Complex32.One);
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()
{
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((new Complex32(1.1f, -2.2f) - new Complex32(1.1f, -2.2f)) == Complex32.Zero);
}
@ -70,10 +70,10 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test]
public void CanAddTwoComplexNumbers()
{
Assert.That(Complex32.NaN.Add(Complex32.NaN).IsNaN());
Assert.That(Complex32.Infinity.Add(Complex32.One).IsInfinity());
Assert.That(Complex32.One.Add(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(Complex32.NaN, (Complex32.NaN)).IsNaN());
Assert.That(Complex32.Add(Complex32.PositiveInfinity, Complex32.One).IsInfinity());
Assert.That(Complex32.Add(Complex32.One, Complex32.Zero) == Complex32.One);
Assert.That(Complex32.Add(new Complex32(1.1f, -2.2f), new Complex32(-1.1f, 2.2f)) == Complex32.Zero);
}
/// <summary>
@ -83,7 +83,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
public void CanAddTwoComplexNumbersUsingOperator()
{
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((new Complex32(1.1f, -2.2f) + new Complex32(-1.1f, 2.2f)) == Complex32.Zero);
}
@ -94,12 +94,11 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test]
public void CanCalculateHashCode()
{
var complex = new Complex32(1, 0);
Assert.AreEqual(1065353216, complex.GetHashCode());
complex = new Complex32(0, 1);
Assert.AreEqual(-1065353216, complex.GetHashCode());
complex = new Complex32(1, 1);
Assert.AreEqual(-16777216, complex.GetHashCode());
Assert.AreEqual(new Complex32(1, 2).GetHashCode(), new Complex32(1, 2).GetHashCode());
Assert.AreNotEqual(new Complex32(1, 0).GetHashCode(), new Complex32(0, 1).GetHashCode());
Assert.AreNotEqual(new Complex32(1, 1).GetHashCode(), new Complex32(2, 2).GetHashCode());
Assert.AreNotEqual(new Complex32(1, 0).GetHashCode(), new Complex32(-1, 0).GetHashCode());
Assert.AreNotEqual(new Complex32(0, 1).GetHashCode(), new Complex32(0, -1).GetHashCode());
}
/// <summary>
@ -285,7 +284,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test]
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(-1.0f, complex.Imaginary, 1e-7f, "Imaginary part is -1.");
}
@ -296,7 +295,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test]
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(-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.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(Complex32.Infinity, 2.0f / Complex32.Zero);
Assert.AreEqual(Complex32.Infinity, Complex32.One / 0);
Assert.AreEqual(Complex32.PositiveInfinity, 2.0f / Complex32.Zero);
Assert.AreEqual(Complex32.PositiveInfinity, Complex32.One / 0);
}
/// <summary>
@ -398,9 +397,9 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test]
public void CanDivideTwoComplexNumbers()
{
Assert.That(Complex32.NaN.Multiply(Complex32.One).IsNaN());
Assert.AreEqual(new Complex32(-2, 0), new Complex32(4, -4).Divide(new Complex32(-2, 2)));
Assert.AreEqual(Complex32.Infinity, Complex32.One.Divide(Complex32.Zero));
Assert.That(Complex32.Divide(Complex32.NaN, Complex32.One).IsNaN());
Assert.AreEqual(new Complex32(-2, 0), Complex32.Divide(new Complex32(4, -4), new Complex32(-2, 2)));
Assert.AreEqual(Complex32.PositiveInfinity, Complex32.Divide(Complex32.One, Complex32.Zero));
}
/// <summary>
@ -411,7 +410,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
{
Assert.That((Complex32.NaN / Complex32.One).IsNaN());
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>
@ -431,8 +430,8 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test]
public void CanMultipleTwoComplexNumbers()
{
Assert.That(Complex32.NaN.Multiply(Complex32.One).IsNaN());
Assert.AreEqual(new Complex32(0, 16), new Complex32(4, -4).Multiply(new Complex32(-2, 2)));
Assert.That(Complex32.Multiply(Complex32.NaN, Complex32.One).IsNaN());
Assert.AreEqual(new Complex32(0, 16), Complex32.Multiply(new Complex32(4, -4), new Complex32(-2, 2)));
}
/// <summary>
@ -452,7 +451,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
public void CanNegateValue()
{
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>
@ -474,7 +473,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
Assert.That((Complex32.NaN - float.NaN).IsNaN());
Assert.That((float.NaN - Complex32.NaN).IsNaN());
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((0.0f - Complex32.One) == -Complex32.One);
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]
public void CanSubtractTwoComplexNumbers()
{
Assert.That(Complex32.NaN.Subtract(Complex32.NaN).IsNaN());
Assert.That(Complex32.Infinity.Subtract(Complex32.One).IsInfinity());
Assert.That(Complex32.One.Subtract(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(Complex32.NaN, Complex32.NaN).IsNaN());
Assert.That(Complex32.Subtract(Complex32.PositiveInfinity, Complex32.One).IsInfinity());
Assert.That(Complex32.Subtract(Complex32.One, Complex32.Zero) == Complex32.One);
Assert.That(Complex32.Subtract(new Complex32(1.1f, -2.2f), new Complex32(1.1f, -2.2f)) == Complex32.Zero);
}
/// <summary>
@ -500,7 +499,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
public void CanTestForEquality()
{
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.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()
{
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));
}
/// <summary>
/// Can use Plus.
/// </summary>
[Test]
public void CanUsePlus()
{
var complex = new Complex32(1.1f, -2.2f);
Assert.AreEqual(complex, complex.Plus());
}
/// <summary>
/// Can use "+" operator.
/// Can use unary "+" operator.
/// </summary>
[Test]
public void CanUsePlusOperator()
@ -537,15 +526,6 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
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>
/// Can compute magnitude.
/// </summary>

20
src/UnitTests/ComplexTests/ComplexTest.cs

@ -106,6 +106,7 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
a = new Complex(0.0, 0.0);
b = new Complex(1.0, 0.0);
AssertHelpers.AlmostEqual(new Complex(0.0, 0.0), a.Power(b), 15);
a = new Complex(0.0, 0.0);
b = new Complex(-1.0, 0.0);
AssertHelpers.AlmostEqual(new Complex(double.PositiveInfinity, 0.0), a.Power(b), 15);
@ -123,21 +124,22 @@ namespace MathNet.Numerics.UnitTests.ComplexTests
[Test]
public void CanComputeRoot()
{
var a = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7);
var 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, -1.19209289550780998537e-7);
b = new Complex(0.0, 0.5);
AssertHelpers.AlmostEqual(new Complex(0.038550761943650161, 0.019526430428319544), a.Root(b), 15);
var a = new Complex(0.0, -1.19209289550780998537e-7);
var b = new Complex(0.0, 0.5);
AssertHelpers.AlmostEqual(new Complex(0.038550761943650161, 0.019526430428319544), a.Root(b), 14);
a = 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);
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);
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);
b = new Complex(1.19209289550780998537e-7, 0.0);
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()
{
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>

8
src/UnitTests/TrigonometryTest.cs

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

Loading…
Cancel
Save