/// <summary> /// Loads solutions from a stream (a file) /// </summary> /// <param name="r"></param> /// <returns></returns> public static LPSolution LoadSolution(StreamReader r, int precision, LpNumber upperBound) { LPSolution sol = new LPSolution(); sol.UpperBound = upperBound; string str = r.ReadLine(); if (str == null) throw new Exception("Two numbers are expected on the first line"); string[] els = str.Split(' '); if (els.Length != 2) throw new Exception("Two numbers are expected on the first line"); // Subtract one since we don't count the objective function sol.NumberOfConstraints = int.Parse(els[0]) - 1; sol.NumberOfVariables = int.Parse(els[1]); // Optimal var vals = ReadThirdValue(r, 1, precision); sol.Optimal = vals[0]; // Skip one line (the objective function) ReadThirdValue(r, 1, precision); // Constraints sol.ConstraintMarginals = ReadThirdValue(r, sol.NumberOfConstraints, precision); // Bounds sol.VariableMarginals = ReadThirdValue(r, sol.NumberOfVariables, precision); return sol; }
/// <summary> /// Private constructor /// </summary> private Inequality(Label id, IneqType type, LinearFunction lhs, LpNumber rhs, bool negFlag) { this.Id = id; this.type = type; this.lhs = lhs; this.rhs = rhs; this.NegFlag = negFlag; }
/// <summary> /// Loads solutions from a stream (a file) /// </summary> /// <param name="r"></param> /// <returns></returns> public static LPSolution LoadSolution(StreamReader r, int precision, LpNumber upperBound, bool infeasible) { LPSolution sol = new LPSolution(); sol.UpperBound = upperBound; if (infeasible) { sol.UpperBound = new LpNumber(0); } string str = r.ReadLine(); if (str == null) throw new Exception("Two numbers are expected on the first line"); string[] els = str.Split(' '); if (els.Length != 2) throw new Exception("Two numbers are expected on the first line"); int nc = int.Parse(els[0]); int nv = int.Parse(els[1]); if (infeasible) { sol.NumberOfConstraints = nc; // Do not count slack variables sol.NumberOfVariables = nv - nc; } else { // Subtract one since we don't count the objective function for a feasible solution sol.NumberOfConstraints = nc - 1; sol.NumberOfVariables = nv; } // Optimal var vals = ReadThirdValue(r, 1, precision); sol.Optimal = vals[0]; if (!infeasible) { // Skip one line (the objective function) ReadThirdValue(r, 1, precision); } // Constraints sol.ConstraintMarginals = ReadThirdValue(r, sol.NumberOfConstraints, precision); if (infeasible) { // Skip slack variables ReadThirdValue(r, nc, precision); } // Bounds sol.VariableMarginals = ReadThirdValue(r, sol.NumberOfVariables, precision); return sol; }
/// <summary> /// Generates a test for arithmetic /// </summary> static void GenerateArithTest() { FileStream fs = new FileStream("arith_test_data.hl", FileMode.Create); StreamWriter w = new StreamWriter(fs); Random rnd = new Random(0); w.WriteLine("let data = ["); for (int i = 0; i < 1000; i++) { decimal n1 = rnd.Next(1000000000, 2000000000); decimal n2 = rnd.Next(1000000000, 2000000000); // n1 *= rnd.Next(1000000000, 2000000000); // n2 *= rnd.Next(1000000000, 2000000000); n1 *= rnd.Next(100000, 500000); n2 *= rnd.Next(100000, 500000); int x1 = (int)Math.Log10((double)n1); int x2 = (int)Math.Log10((double)n2); LpNumber m1 = new LpNumber(n1); LpNumber m2 = new LpNumber(n2); w.Write(m1.ToHOLExplicit(0)); w.Write(","); w.Write(m2.ToHOLExplicit(0)); if (i < 999) w.Write(";"); w.Write("(* {0}, {1} *)", x1, x2); w.WriteLine(); } w.WriteLine("];;"); w.Flush(); fs.Close(); }
/// <summary> /// Creates files for a formal proof for a general linear program /// </summary> static bool processLPGeneral(string fname, int precision, LpNumber upperBound) { if (precision > 10) throw new Exception("Cannot solve the problem (precision > 10): " + fname); LP lp; LPSolution sol; // Load an LP FileStream fs = new FileStream(fname + ".lp", FileMode.Open); using (fs) { StreamReader r = new StreamReader(fs); Scanner scanner = new Scanner(r, fname + ".lp"); lp = LP.ParseLP(scanner); } // Load solutions fs = new FileStream(fname + ".txt", FileMode.Open); using (fs) { sol = LPSolution.LoadSolution(new StreamReader(fs), precision, upperBound); } if (!lp.SetSolution(sol, precision)) return false; // Create a test file containing all inequalities explicitly FileStream test = new FileStream(fname + "_test.hl", FileMode.Create); lp.ConvertToHOL(new StreamWriter(test), precision); test.Close(); return true; }
/// <summary> /// Creates files for producing a formal proof for the given linear program /// </summary> static bool ProcessLP(string fname, LpNumber upperBound, int precision, ListHyp hypermap) { if (precision > 5) throw new Exception("Cannot solve the problem: " + fname); LP lp; LPSolution sol; // Load an LP FileStream fs = new FileStream(fname + ".lp", FileMode.Open); using (fs) { StreamReader r = new StreamReader(fs); Scanner scanner = new Scanner(r, fname + ".lp"); lp = LP.ParseLP(scanner); } // Load solutions fs = new FileStream(fname + ".txt", FileMode.Open); using (fs) { sol = LPSolution.LoadSolution(new StreamReader(fs), precision, upperBound); } if (sol.Optimal.value > upperBound.value) throw new Exception("Optimal value is greater than " + upperBound.value + ": " + fname); if (!lp.SetSolution(sol, precision)) return false; // Create a test file containing all inequalities explicitly FileStream test = new FileStream(fname + "_test.hl", FileMode.Create); lp.ConvertToHOL(new StreamWriter(test), precision); test.Close(); // Create a certificate file FileStream main = new FileStream(fname + "_out.hl", FileMode.Create); lp.PrintCertificate(new StreamWriter(main), precision, hypermap, log); main.Close(); return true; }
/// <summary> /// Creates files for producing a formal proof for the given linear program. /// The precision is selected automatically /// </summary> static void ProcessLP(string fname, LpNumber upperBound, ListHyp hypermap) { Console.WriteLine("Processing {0}...", fname); try { for (int precision = 3; ; precision++) { Console.WriteLine("Precision = {0}", precision); if (hypermap != null) { if (ProcessLP(fname, upperBound, precision, hypermap)) break; } else { if (processLPGeneral(fname, precision, upperBound)) break; } } } catch (Exception e) { Console.Error.WriteLine("ERROR: {0}", e.Message); } Console.WriteLine("done\n"); }
// Main static void Main(string[] args) { FileStream flog = new FileStream("log.txt", FileMode.Create); log = new StreamWriter(flog); using (log) { // GenerateArithTest(); // return; // Flyspeck if (args.Length == 0) { Console.WriteLine("Processing Flyspeck linear programs"); Console.WriteLine(); ProcessFlyspeckLP(); return; } // Incorrect number of arguments if (args.Length != 2) { Console.WriteLine("Usage: LP-HL lp_name upper_bound"); Console.WriteLine("Files {lp_name}.lp and {lp_name}.txt must be in the current directory."); Console.WriteLine("{upper_bound} is a decimal number"); return; } // Specific LP string name = args[0]; LpNumber upperBound = new LpNumber(decimal.Parse(args[1])); ProcessLP(name, upperBound, null); } }
/// <summary> /// Reads k third values from the input stream /// </summary> /// <param name="k"></param> /// <returns></returns> private static List<LpNumber> ReadThirdValue(StreamReader r, int k, int precision) { List<LpNumber> result = new List<LpNumber>(); for (int i = 0; i < k; i++) { string str = r.ReadLine(); if (str == null) throw new Exception("Unexpected end of file"); string[] els = str.Split(' '); if (els.Length != 3) throw new Exception("Triples are expected: " + str); LpNumber val = new LpNumber(double.Parse(els[2]), precision); result.Add(val); } return result; }
/// <summary> /// Returns the equality 0 = 0 /// </summary> public static Inequality Zero() { Label id = new Label("ZERO", ""); LinearFunction lhs = new LinearFunction(new List<decimal>(), new List<string>()); LpNumber rhs = new LpNumber(0); Inequality ineq = new Inequality(id, IneqType.Eq, lhs, rhs, false); return ineq; }
/// <summary> /// Parses an inequality /// </summary> /// <param name="scanner"></param> /// <returns></returns> public static Inequality ParseInequality(Scanner scanner) { Token t; // Identifier Label id = Label.ParseLabel(scanner); // : t = scanner.nextToken(); if (t.Type != TokenType.Colon) throw new Exception(": expected: " + t); // lhs LinearFunction lhs = LinearFunction.ParseFunction(scanner); // type t = scanner.nextToken(); IneqType type; switch (t.Type) { case TokenType.Le: type = IneqType.Le; break; case TokenType.Ge: type = IneqType.Ge; break; case TokenType.Eq: type = IneqType.Eq; break; default: throw new Exception("<=, =>, or = expected: " + t); } // rhs t = scanner.nextToken(); if (t.Type != TokenType.Integer && t.Type != TokenType.Double) throw new Exception("A number is expected: " + t); LpNumber rhs = new LpNumber(decimal.Parse(t.StringValue)); return new Inequality(id, type, lhs, rhs, false); }
/// <summary> /// Processes all inequalities based on the given solution /// </summary> /// <param name="sol"></param> /// <param name="precision"></param> /// <returns></returns> public bool SetSolution(LPSolution sol, int precision, bool infeasible) { if (sol.NumberOfVariables != vars.Number) throw new Exception("Inconsistent number of variables"); if (sol.NumberOfConstraints != originalIneqs.Count) throw new Exception("Inconsistent number of constraints"); if (infeasible) { ResortVariables(); } ineqs = new List<Inequality>(); // ineqMarginals = new List<LpNumber>(); // Constraints for (int i = 0; i < sol.NumberOfConstraints; i++) { LpNumber m = sol.ConstraintMarginals[i]; if (m.IsZero(precision)) continue; Inequality ineq = originalIneqs[i]; if (m.value < 0) { ineq = -ineq; m = -m; } ineq = ineq.Round(precision); ineq.Marginal = m; ineqs.Add(ineq); // ineqMarginals.Add(m); } // Variables List<Inequality> tmpIneqs = new List<Inequality>(); for (int i = 0; i < sol.NumberOfVariables; i++) { Variable var = vars[i]; LpNumber m = sol.VariableMarginals[i]; if (m.IsZero(precision)) continue; Inequality ineq; if (m.value < 0) { var.LMarginal = -m; ineq = -Inequality.FromLowerBound(var); ineq = ineq.Round(precision) * (-m.value); } else { var.UMarginal = m; ineq = Inequality.FromUpperBound(var); ineq = ineq.Round(precision) * m.value; } tmpIneqs.Add(ineq); } // Compute additional inequality // Inequality sum1 = ineqs[0] * ineqs[0].Marginal.value; //ineqMarginals[0].value; Inequality sum1 = Inequality.Zero(); for (int i = 0; i < ineqs.Count; i++) { sum1 += ineqs[i] * ineqs[i].Marginal.value; //ineqMarginals[i].value; } Inequality sum2 = sum1; for (int i = 0; i < tmpIneqs.Count; i++) { sum2 += tmpIneqs[i]; } // df LinearFunction df; if (infeasible) { df = -sum2.lhs; } else { df = objective - sum2.lhs; } // Compute corrections for marginals foreach (var term in df.Terms) { LpNumber c = term.c; if (c.value < 0) { vars[term.varName].LMarginal -= c; } else { vars[term.varName].UMarginal += c; } } // Verification LpNumber sum = sum1.rhs; for (int i = 0; i < vars.Number; i++) { Variable var = vars[i]; if (!var.LMarginal.IsZero(precision)) { sum -= var.LMarginal * LpNumber.RoundDown(var.LBound, precision); } if (!var.UMarginal.IsZero(precision)) { sum += var.UMarginal * LpNumber.RoundUp(var.UBound, precision); } } LpNumber eps = sol.UpperBound - sum; Console.WriteLine("eps = {0}", eps); if (eps.value < 0) return false; // Set the upper bound upperBound = sol.UpperBound; // Generate inequalities for variables Console.Write("Generating inequalities for variables..."); varIneqs = new List<Inequality>(); // varIneqMarginals = new List<LpNumber>(); for (int i = 0; i < vars.Number; i++) { Variable var = vars[i]; Inequality ineq; if (!var.LMarginal.IsZero(precision)) { ineq = -Inequality.FromLowerBound(var); ineq = ineq.Round(precision); ineq.Marginal = var.LMarginal; varIneqs.Add(ineq); // varIneqMarginals.Add(var.LMarginal); } if (!var.UMarginal.IsZero(precision)) { ineq = Inequality.FromUpperBound(var); ineq = ineq.Round(precision); ineq.Marginal = var.UMarginal; varIneqs.Add(ineq); // varIneqMarginals.Add(var.UMarginal); } } Console.WriteLine("done"); return true; }