/// <summary> /// Merges two prescriptions. The general prescription behaves as default values that can be overriden by the /// specific prescription. /// </summary> /// <param name="general">The general prescription.</param> /// <param name="specific">The specific prescription.</param> /// <returns>The merged prescription.</returns> public static PrescriptionSolverConfig Merge(PrescriptionSolverConfig general, PrescriptionSolverConfig specific) { return(new PrescriptionSolverConfig { RandomSeed = specific == null || specific.RandomSeed.HasValue == false ? general.RandomSeed : specific.RandomSeed.Value, TimeLimit = specific == null || specific.TimeLimit.HasValue == false ? general.TimeLimit : specific.TimeLimit.Value, NumWorkers = specific == null || specific.NumWorkers.HasValue == false ? general.NumWorkers : specific.NumWorkers.Value, PresolveLevel = specific == null || specific.PresolveLevel.HasValue == false ? general.PresolveLevel : specific.PresolveLevel.Value, }); }
private static int Run(CmdOptions opts) { var prescriptionPath = ExperimentPrescriptionPath(opts); if (!File.Exists(prescriptionPath)) { Console.WriteLine($"Experiment prescription file {prescriptionPath} does not exist."); return(1); } var prescription = JsonConvert.DeserializeObject <Prescription>( File.ReadAllText(prescriptionPath), new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Populate }); if (!Directory.Exists(Program.DatasetsPath(opts))) { Console.WriteLine($"Datasets directory {Program.DatasetsPath(opts)} does not exist."); return(1); } foreach (var datasetName in prescription.DatasetNames) { var datasetPath = DatasetPath(opts, datasetName); if (!Directory.Exists(datasetPath)) { Console.WriteLine($"Dataset directory {datasetPath} does not exist."); return(1); } } if (opts.FromScratch) { foreach (var datasetName in prescription.DatasetNames) { foreach (var solverPrescription in prescription.Solvers) { var solverResultsPath = ResultsExperimentDatasetSolverPath( opts, datasetName, solverPrescription.Id); if (Directory.Exists(solverResultsPath)) { Directory.Delete(solverResultsPath, true); } } } } // TODO: if (opts.NumThreads != 1) { Console.WriteLine($"Parallel instance solving is not currently supported due to:"); Console.WriteLine($"- optimal switching cost is computed in parallel and there is no option to disable this"); return(1); } var objectLock = new object(); foreach (var datasetName in prescription.DatasetNames) { var instancePaths = Directory.EnumerateFiles(DatasetPath(opts, datasetName)).ToList(); foreach (var solverPrescription in prescription.Solvers) { var prescriptionSolverConfig = PrescriptionSolverConfig.Merge( prescription.GlobalConfig, solverPrescription.Config); Parallel.ForEach( instancePaths, new ParallelOptions { MaxDegreeOfParallelism = opts.NumThreads }, (instancePath) => { try { Console.WriteLine($"Solving {instancePath} using {solverPrescription.Id}"); var resultPath = ResultPath( opts, datasetName, solverPrescription.Id, Path.GetFileName(instancePath)); if (opts.FromScratch == false && File.Exists(resultPath)) { Console.WriteLine($"{instancePath} using {solverPrescription.Id} already solved"); return; } var instance = new InputReader().ReadFromPath(instancePath); SolverConfig solverConfig; lock (objectLock) { solverConfig = prescriptionSolverConfig.ToSolverConfig(solverPrescription.SpecializedSolverConfig); } if (solverPrescription.InitStartTimesFrom != null) { var initStartTimesResultPath = ResultPath( opts, datasetName, solverPrescription.InitStartTimesFrom, Path.GetFileName(instancePath)); var initStartTimesResult = JsonConvert.DeserializeObject <Result>( File.ReadAllText(initStartTimesResultPath)); if (initStartTimesResult.Status == Status.Optimal || initStartTimesResult.Status == Status.Heuristic) { solverConfig.InitStartTimes = initStartTimesResult.StartTimes; } } if (solverPrescription.SubstractExtendedInstanceGenerationFromTimeLimit && solverConfig.TimeLimit.HasValue && instance.TimeForExtendedInstance.HasValue) { solverConfig.TimeLimit = new TimeSpan(Math.Max( 0, solverConfig.TimeLimit.Value.Ticks - instance.TimeForExtendedInstance.Value.Ticks)); } var solver = new SolverFactory().Create(solverPrescription.SolverName); var solverResult = solver.Solve(solverConfig, instance); if (solverResult.Status == Status.Optimal || solverResult.Status == Status.Heuristic) { var feasibilityChecker = new FeasibilityChecker(); var feasibilityStatus = feasibilityChecker.Check(instance, solverResult.StartTimes, solverConfig, solverResult.Objective); if (feasibilityStatus != FeasibilityChecker.FeasibilityStatus.Feasible) { throw new Exception($"Feasibility check failed: {feasibilityStatus}, {instancePath}, {solverPrescription.Id}"); } } lock (objectLock) { if (!Directory.Exists(Path.GetDirectoryName(resultPath))) { Directory.CreateDirectory(Path.GetDirectoryName(resultPath)); } } File.WriteAllText( resultPath, JsonConvert.SerializeObject(Result.FromSolverResult(solverResult))); } catch (Exception) { Console.WriteLine($"Error while solving {instancePath} using {solverPrescription.Id}"); throw; } }); } } return(0); }