source: branches/2931_OR-Tools_LP_MIP/HeuristicLab.MathematicalOptimization/3.3/LinearProgramming/Problems/LinearProgrammingProblemDefinitionScript.cs @ 16373

Last change on this file since 16373 was 16373, checked in by ddorfmei, 5 months ago

#2931:

  • upgraded Google OR-Tools to version 6.10
  • added TextValue and TextValueView to be able to display and edit a multiline string
  • added parameter to set solver specific parameters for supported solvers
  • added support for the Protocol Buffers representation of models (import/export)
  • added import of MPS models
  • added pause/stop functionality to CplexSolver and GlpkSolver
  • refactored wrapper (LinearSolver and related enums)
  • added new algorithm category Exact for LinearProgrammingAlgorithm
File size: 6.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Linq;
24using System.Reflection;
25using Google.OrTools.LinearSolver;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Optimization;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30using HeuristicLab.Problems.Programmable;
31using HeuristicLab.Scripting;
32
33namespace HeuristicLab.MathematicalOptimization.LinearProgramming.Problems {
34
35  [Item("Linear/Mixed Integer Programming Problem Definition Script", "Script that defines the model and evaluates the solution for a linear/mixed integer programming problem.")]
36  [StorableClass]
37  public sealed class LinearProgrammingProblemDefinitionScript : Script, ILinearProgrammingProblemDefinition, IStorableContent {
38    private bool SuppressEvents { get; set; }
39
40    [Storable]
41    private readonly VariableStore variableStore;
42
43    public VariableStore VariableStore => variableStore;
44
45    [Storable]
46    private bool codeChanged;
47
48    [StorableConstructor]
49    private LinearProgrammingProblemDefinitionScript(bool deserializing) : base(deserializing) { }
50
51    private LinearProgrammingProblemDefinitionScript(LinearProgrammingProblemDefinitionScript original, Cloner cloner)
52      : base(original, cloner) {
53      variableStore = cloner.Clone(original.variableStore);
54      codeChanged = original.codeChanged;
55    }
56
57    public LinearProgrammingProblemDefinitionScript()
58      : base(ScriptTemplates.CompiledLinearProgrammingProblemDefinition) {
59      variableStore = new VariableStore();
60    }
61
62    private readonly object compileLock = new object();
63    private volatile ILinearProgrammingProblemDefinition compiledProblemDefinition;
64
65    private ILinearProgrammingProblemDefinition CompiledProblemDefinition {
66      get {
67        // double checked locking pattern
68        if (compiledProblemDefinition == null) {
69          lock (compileLock) {
70            if (compiledProblemDefinition == null) {
71              if (codeChanged)
72                throw new ProblemDefinitionScriptException("The code has been changed, but was not recompiled.");
73              Compile(false);
74            }
75          }
76        }
77        return compiledProblemDefinition;
78      }
79    }
80
81    public dynamic Instance => compiledProblemDefinition;
82
83    public override Assembly Compile() => Compile(true);
84
85    private Assembly Compile(bool fireChanged) {
86      var assembly = base.Compile();
87      var types = assembly.GetTypes();
88      if (!types.Any(x => typeof(CompiledProblemDefinition).IsAssignableFrom(x)))
89        throw new ProblemDefinitionScriptException("The compiled code doesn't contain a problem definition." +
90                                                   Environment.NewLine +
91                                                   "The problem definition must be a subclass of CompiledProblemDefinition.");
92      if (types.Count(x => typeof(CompiledProblemDefinition).IsAssignableFrom(x)) > 1)
93        throw new ProblemDefinitionScriptException("The compiled code contains multiple problem definitions." +
94                                                   Environment.NewLine +
95                                                   "Only one subclass of CompiledProblemDefinition is allowed.");
96
97      CompiledProblemDefinition inst;
98      try {
99        inst = (CompiledProblemDefinition)Activator.CreateInstance(types.Single(x =>
100         typeof(CompiledProblemDefinition).IsAssignableFrom(x)));
101      } catch (Exception e) {
102        compiledProblemDefinition = null;
103        throw new ProblemDefinitionScriptException(
104          "Instantiating the problem definition failed." + Environment.NewLine + "Check your default constructor.", e);
105      }
106
107      try {
108        inst.vars = new Variables(VariableStore);
109        inst.Initialize();
110      } catch (Exception e) {
111        compiledProblemDefinition = null;
112        throw new ProblemDefinitionScriptException(
113          "Initializing the problem definition failed." + Environment.NewLine + "Check your Initialize() method.", e);
114      }
115
116      try {
117        compiledProblemDefinition = (ILinearProgrammingProblemDefinition)inst;
118        if (fireChanged) OnProblemDefinitionChanged();
119      } catch (Exception e) {
120        compiledProblemDefinition = null;
121        throw new ProblemDefinitionScriptException(
122          "Using the problem definition in the problem failed." + Environment.NewLine +
123          "Examine this error message carefully (often there is an issue with the defined encoding).", e);
124      }
125
126      codeChanged = false;
127      return assembly;
128    }
129
130    protected override void OnCodeChanged() {
131      base.OnCodeChanged();
132      compiledProblemDefinition = null;
133      codeChanged = true;
134    }
135
136    public event EventHandler ProblemDefinitionChanged;
137
138    private void OnProblemDefinitionChanged() => ProblemDefinitionChanged?.Invoke(this, EventArgs.Empty);
139
140    public string Filename { get; set; }
141
142    public override IDeepCloneable Clone(Cloner cloner) {
143      return new LinearProgrammingProblemDefinitionScript(this, cloner);
144    }
145
146    public bool BuildModel(Solver solver) => CompiledProblemDefinition.BuildModel(solver);
147
148    public void Analyze(Solver solver, ResultCollection results) => CompiledProblemDefinition.Analyze(solver, results);
149  }
150}
Note: See TracBrowser for help on using the repository browser.