0

I'm trying to convert this MS Solver Foundation example from C# to F#, but constantly running into problems with type conversions, in particular in section 5, where C# accepts implicit conversion from double to Rational, something F# does not accept - any ideas how to resolve? The Rational type in itself is a puzzle for me as seems virtually impossible to initialize apart from setting it to the predefined Rational.One or Rational.Zero. Any ideas? See a minimalist down-scaled version below (without using any arrays or anything).

let main argv = 

printfn "%A" argv
Console.WriteLine("\nBegin Solver demo\n")
let mean = 1.0
let solver = new InteriorPointSolver()
let allocation = ref 0
solver.AddVariable("MSFT", allocation) |> ignore
solver.SetBounds(!allocation, Rational.Zero, Rational.One)

let expRet = ref 0
solver.AddRow("expRet", expRet) |> ignore
solver.SetBounds(!expRet, Rational.Zero, Rational.PositiveInfinity)

let unity = ref 0
solver.AddRow("Investments sum to one", unity) |> ignore
solver.SetBounds(!unity, Rational.One, Rational.One)

solver.SetCoefficient(!expRet, !allocation, Rational.)
solver.SetCoefficient(!unity, !allocation, Rational.One);

Console.WriteLine("\nEnd Solver demo\n")
Console.ReadLine() |> ignore
0 // return an integer exit code
Jaap
  • 81,064
  • 34
  • 182
  • 193
Loco Barocco
  • 121
  • 7
  • 6
    Demonstrate some effort – post what you have so far. – ildjarn Sep 18 '16 at 03:47
  • Just added some existing code, please see above, thanks. – Loco Barocco Sep 18 '16 at 15:10
  • Also a good idea to post exactly what the error is and what line it occurs on – John Palmer Sep 18 '16 at 21:12
  • None of the lines where the type name "Rational" is mentioned is working. In the C# version simply decimal values are used, like "0.1", to set coefficients. However, F# strictly requires Rational types here, and I cannot figure out how to create those. MSDN says it's a class, but it doesn't take any parameters in its constructors. – Loco Barocco Sep 19 '16 at 00:45
  • The Rational type is quirky enough, but the strong type checking of F# makes the whole thing even quirkier! I've figured out the following anyhow: First, the Rational number has to be created, like let x = Microsoft.SolverFoundation.Common.Rational();; Then, the numerator and denominator have to be declared separately, like x.Numerator = ... and x.Denominator = ..., problem is, I'm unable to fix this declaration as it requires a BigInt, not the standard F# version but Microsoft.SolverFoundation.Common.BigInt! God have mercy... – Loco Barocco Sep 19 '16 at 12:31
  • I think I pretty much solved the issue: there's a method "op_Implicit" belonging to the Rational class that can be used to achieve the same which is _truly_ implicit in C#: let rat (x : float) = Microsoft.SolverFoundation.Common.Rational.op_Implicit(x) – Loco Barocco Sep 19 '16 at 15:40
  • There is example in F# in solver samples define rational: let rational x = Rational.op_Implicit(x:float). – M.Hassan Sep 21 '16 at 15:44

1 Answers1

0

This is an old post, but no one has answered, and this information may be useful to others.

I don't know F# (so anyone who does, please edit my syntax), but the following methods in the Rational class should be of use. You will also need the BigInteger class from the Microsoft.SolverFoundation.Common name space. (see https://learn.microsoft.com/en-us/previous-versions/visualstudio/ff526610)

First, as you point out, you can construct a Rational directly from other types using any of the many "implicit" constructors:

    let Rational rat5 = Rational.op_Implicit(5.0:float)
    let Rational rat2 = Rational.op_Implicit(2:int)

where I am guessing F# syntax.

As another quite illustrative example, monetary values (e.g. $10.43) can rarely be represented exactly with doubles. (The only "cents" values that wind up exact in a double are xx.00, xx.25, xx.50 and xx.75, all others wind up with numerical errors/differences.) So we often have to be careful when constructing a rational from a double that purports to represent a monetary value. This provides a good sample of another method of constructing rationals:

    let BigInteger bi100 = BigInteger.op_Implicit(100:int)
    let float mv = 1000000000000.43 //I am assuming this gets classified by F# as a double.

    //Now, we assume mv is any double that represents a monetary value, and so should be an even 2 decimal places in base 10
    //I have no idea how to Round in F#, nor how to cast to an integer - I have guessed - but should illustrate the idea if it is not valid F#
    let BigInteger cents = BigInteger.op_Implicit( ( Round(mv * 100.0) ):int ) //get exact monetary value, in cents
    let Rational ratMv = Rational.Get(cents:BigInteger, bi100:BigInteger)

and so we have constructed a Rational, from two BigInteger types, that exactly represents a monetary value mv stored as a double.

Here is the entire Rational interface, albeit in c#-syntax:

namespace Microsoft.SolverFoundation.Common
{
    [CLSCompliant(true)]
    public struct Rational : IComparable, IComparable<Rational>, IEquatable<Rational>, IComparable<BigInteger>, IEquatable<BigInteger>, IComparable<int>, IEquatable<int>, IComparable<uint>, IEquatable<uint>, IComparable<long>, IEquatable<long>, IComparable<ulong>, IEquatable<ulong>, IComparable<double>, IEquatable<double>
    {
        public static readonly Rational NegativeInfinity;
        public static readonly Rational Zero;
        public static readonly Rational One;
        public static readonly Rational PositiveInfinity;
        public static readonly Rational Indeterminate;
        public static readonly Rational UnsignedInfinity;

        public bool IsOne { get; }
        public bool IsFinite { get; }
        public bool IsIndeterminate { get; }
        public bool IsInfinite { get; }
        public bool IsSignedInfinity { get; }
        public bool IsUnsignedInfinity { get; }
        public bool HasSign { get; }
        public bool IsNegativeInfinity { get; }
        public bool IsZero { get; }
        public int BitCount { get; }
        public int Sign { get; }
        public BigInteger Numerator { get; }
        public bool IsPositiveInfinity { get; }
        public BigInteger Denominator { get; }
        public Rational AbsoluteValue { get; }

        public static Rational AddMul(Rational ratAdd, Rational ratMul1, Rational ratMul2);
        public static Rational Get(BigInteger bnNum, BigInteger bnDen);
        public static void Negate(ref Rational num);
        public static bool Power(Rational ratBase, Rational ratExp, out Rational ratRes);
        public void AppendDecimalString(StringBuilder sb, int cchMax);
        public int CompareTo(BigInteger bn);
        [CLSCompliant(false)]
        public int CompareTo(uint u);
        public int CompareTo(Rational rat);
        public int CompareTo(long nn);
        [CLSCompliant(false)]
        public int CompareTo(ulong uu);
        public int CompareTo(double dbl);
        public int CompareTo(int n);
        public int CompareTo(object obj);
        [CLSCompliant(false)]
        public bool Equals(uint u);
        public bool Equals(Rational rat);
        public bool Equals(long nn);
        [CLSCompliant(false)]
        public bool Equals(ulong uu);
        public bool Equals(int n);
        public bool Equals(BigInteger bn);
        public override bool Equals(object obj);
        public bool Equals(double dbl);
        public Rational GetCeiling();
        public Rational GetCeilingResidual();
        public Rational GetFloor();
        public Rational GetFloorResidual();
        public Rational GetFractionalPart();
        public override int GetHashCode();
        public Rational GetIntegerPart();
        public double GetSignedDouble();
        public Rational Invert();
        public bool IsInteger(out BigInteger bn);
        public bool IsInteger();
        public double ToDouble();
        public override string ToString();

        public static Rational operator +(Rational rat1, Rational rat2);
        public static Rational operator -(Rational rat);
        public static Rational operator -(Rational rat1, Rational rat2);
        public static Rational operator *(Rational rat1, Rational rat2);
        public static Rational operator /(Rational rat1, Rational rat2);
        [CLSCompliant(false)]
        public static bool operator ==(uint n, Rational rat);
        [CLSCompliant(false)]
        public static bool operator ==(Rational rat, uint n);
        public static bool operator ==(int n, Rational rat);
        public static bool operator ==(long n, Rational rat);
        public static bool operator ==(Rational rat, BigInteger bn);
        public static bool operator ==(Rational rat, int n);
        public static bool operator ==(Rational rat, long n);
        public static bool operator ==(BigInteger bn, Rational rat);
        public static bool operator ==(double dbl, Rational rat);
        [CLSCompliant(false)]
        public static bool operator ==(Rational rat, ulong n);
        public static bool operator ==(Rational rat1, Rational rat2);
        [CLSCompliant(false)]
        public static bool operator ==(ulong n, Rational rat);
        public static bool operator ==(Rational rat, double dbl);
        [CLSCompliant(false)]
        public static bool operator !=(ulong n, Rational rat);
        [CLSCompliant(false)]
        public static bool operator !=(Rational rat, ulong n);
        [CLSCompliant(false)]
        public static bool operator !=(uint n, Rational rat);
        public static bool operator !=(BigInteger bn, Rational rat);
        [CLSCompliant(false)]
        public static bool operator !=(Rational rat, uint n);
        public static bool operator !=(double dbl, Rational rat);
        public static bool operator !=(int n, Rational rat);
        public static bool operator !=(Rational rat, int n);
        public static bool operator !=(long n, Rational rat);
        public static bool operator !=(Rational rat, BigInteger bn);
        public static bool operator !=(Rational rat1, Rational rat2);
        public static bool operator !=(Rational rat, double dbl);
        public static bool operator !=(Rational rat, long n);
        public static bool operator <(double dbl, Rational rat);
        public static bool operator <(Rational rat, double dbl);
        [CLSCompliant(false)]
        public static bool operator <(ulong n, Rational rat);
        [CLSCompliant(false)]
        public static bool operator <(Rational rat, ulong n);
        [CLSCompliant(false)]
        public static bool operator <(uint n, Rational rat);
        public static bool operator <(Rational rat1, Rational rat2);
        public static bool operator <(Rational rat, BigInteger bn);
        public static bool operator <(long n, Rational rat);
        public static bool operator <(BigInteger bn, Rational rat);
        public static bool operator <(Rational rat, int n);
        public static bool operator <(int n, Rational rat);
        [CLSCompliant(false)]
        public static bool operator <(Rational rat, uint n);
        public static bool operator <(Rational rat, long n);
        public static bool operator >(long n, Rational rat);
        public static bool operator >(Rational rat1, Rational rat2);
        public static bool operator >(Rational rat, BigInteger bn);
        public static bool operator >(BigInteger bn, Rational rat);
        public static bool operator >(Rational rat, int n);
        [CLSCompliant(false)]
        public static bool operator >(Rational rat, uint n);
        public static bool operator >(double dbl, Rational rat);
        [CLSCompliant(false)]
        public static bool operator >(uint n, Rational rat);
        public static bool operator >(int n, Rational rat);
        public static bool operator >(Rational rat, long n);
        public static bool operator >(Rational rat, double dbl);
        [CLSCompliant(false)]
        public static bool operator >(ulong n, Rational rat);
        [CLSCompliant(false)]
        public static bool operator >(Rational rat, ulong n);
        [CLSCompliant(false)]
        public static bool operator <=(ulong n, Rational rat);
        public static bool operator <=(Rational rat, int n);
        public static bool operator <=(Rational rat, BigInteger bn);
        public static bool operator <=(int n, Rational rat);
        [CLSCompliant(false)]
        public static bool operator <=(Rational rat, uint n);
        public static bool operator <=(BigInteger bn, Rational rat);
        [CLSCompliant(false)]
        public static bool operator <=(Rational rat, ulong n);
        public static bool operator <=(Rational rat1, Rational rat2);
        public static bool operator <=(long n, Rational rat);
        public static bool operator <=(Rational rat, double dbl);
        public static bool operator <=(double dbl, Rational rat);
        [CLSCompliant(false)]
        public static bool operator <=(uint n, Rational rat);
        public static bool operator <=(Rational rat, long n);
        public static bool operator >=(Rational rat, BigInteger bn);
        public static bool operator >=(Rational rat1, Rational rat2);
        [CLSCompliant(false)]
        public static bool operator >=(Rational rat, ulong n);
        [CLSCompliant(false)]
        public static bool operator >=(uint n, Rational rat);
        public static bool operator >=(Rational rat, long n);
        public static bool operator >=(int n, Rational rat);
        public static bool operator >=(BigInteger bn, Rational rat);
        public static bool operator >=(Rational rat, int n);
        [CLSCompliant(false)]
        public static bool operator >=(ulong n, Rational rat);
        public static bool operator >=(long n, Rational rat);
        public static bool operator >=(double dbl, Rational rat);
        [CLSCompliant(false)]
        public static bool operator >=(Rational rat, uint n);
        public static bool operator >=(Rational rat, double dbl);

        public static implicit operator Rational(double dbl);
        public static implicit operator Rational(BigInteger bn);
        [CLSCompliant(false)]
        public static implicit operator Rational(uint u);
        public static implicit operator Rational(long nn);
        [CLSCompliant(false)]
        public static implicit operator Rational(ulong uu);
        public static implicit operator Rational(int n);
        public static explicit operator BigInteger(Rational rat);
        public static explicit operator double(Rational rat);
        [CLSCompliant(false)]
        public static explicit operator ulong(Rational rat);
        public static explicit operator long(Rational rat);
        [CLSCompliant(false)]
        public static explicit operator uint(Rational rat);
        public static explicit operator int(Rational rat);
    }
}

The other very useful bit of information that can be found at the above link is this table:

"The following table lists how special cases of rational numbers are represented.

Rational number Representation
Non-zero finite rational values (numerator, denominator) with denominator > 0
Zero (0, 0)
Negative infinity (-1, 0)
Positive infinity (+1, 0)
Unsigned infinity (+2, 0)
Indeterminate (NaN) (+3, 0)

Dividing a nonzero value by zero results in unsigned infinity because 0 is unsigned. Dividing a finite value by any infinite value results in 0."

David I. McIntosh
  • 2,038
  • 4
  • 23
  • 45