We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Pyomo crashes when solver returns suffix but no value for variables
When the user requests an irreducibly infeasible set of constraints (IIS) for an infeasible mixed-integer program, cplexamp sometimes returns the IIS but not values for the variables. This causes pyomo to crash while reading the solution. Specifically, `pyomo.opt.plugins.sol` only creates entries in `soln_variable` for variables whose values have been returned by the solver, but then it tries to attach the IIS suffix value to a non-existent item in `soln_variable`, causing an uncaught `KeyError()`.

The code below illustrates this problem:

    from pyomo.environ import *
    m = ConcreteModel()
    m.x1 = Var(within=NonNegativeReals)
    m.x2 = Var(within=NonNegativeIntegers)
    m.constraint = Constraint(rule=lambda m: m.x1 + m.x2 <= -1)
    m.objective = Objective(rule=lambda m: m.x1 + m.x2, sense=minimize)
    m.iis = Suffix(direction=Suffix.IMPORT)
    solver = SolverFactory('cplexamp')
    res = solver.solve(m, options_string='iisfind=1', tee=True)
    print("IIS:")
    print("\n".join(sorted(c.name for c in m.iis)))

I have added a pull request to fix this: https://github.com/Pyomo/pyomo/pull/596

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pyomo/opt/plugins/sol.py`
Content:
```
1 #  ___________________________________________________________________________
2 #
3 #  Pyomo: Python Optimization Modeling Objects
4 #  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC
5 #  Under the terms of Contract DE-NA0003525 with National Technology and 
6 #  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain 
7 #  rights in this software.
8 #  This software is distributed under the 3-clause BSD License.
9 #  ___________________________________________________________________________
10 
11 #
12 # Class for reading an AMPL *.sol file
13 #
14 
15 import re
16 
17 import pyutilib.misc
18 
19 from pyomo.common.plugin import alias
20 from pyomo.opt.base import results
21 from pyomo.opt.base.formats import ResultsFormat
22 from pyomo.opt import (SolverResults,
23                        SolutionStatus,
24                        SolverStatus,
25                        TerminationCondition)
26 
27 from six.moves import xrange
28 
29 class ResultsReader_sol(results.AbstractResultsReader):
30     """
31     Class that reads in a *.sol results file and generates a
32     SolverResults object.
33     """
34 
35     alias(str(ResultsFormat.sol))
36 
37     def __init__(self, name=None):
38         results.AbstractResultsReader.__init__(self,ResultsFormat.sol)
39         if not name is None:
40             self.name = name
41 
42     def __call__(self, filename, res=None, soln=None, suffixes=[]):
43         """
44         Parse a *.sol file
45         """
46         try:
47             with open(filename,"r") as f:
48                 return self._load(f, res, soln, suffixes)
49         except ValueError as e:
50             with open(filename,"r") as f:
51                 fdata = f.read()
52             raise ValueError(
53                 "Error reading '%s': %s.\n"
54                 "SOL File Output:\n%s"
55                 % (filename, str(e), fdata))
56 
57     def _load(self, fin, res, soln, suffixes):
58 
59         if res is None:
60             res = SolverResults()
61         #
62         msg = ""
63         line = fin.readline()
64         if line.strip() == "":
65             line = fin.readline()
66         while line:
67             if line[0] == '\n' or (line[0] == '\r' and line[1] == '\n'):
68                 break
69             msg += line
70             line = fin.readline()
71         z = []
72         line = fin.readline()
73         if line[:7] == "Options":
74             line = fin.readline()
75             nopts = int(line)
76             need_vbtol = False
77             if nopts > 4:           # WEH - when is this true?
78                 nopts -= 2
79                 need_vbtol = True
80             for i in xrange(nopts + 4):
81                 line = fin.readline()
82                 z += [int(line)]
83             if need_vbtol:          # WEH - when is this true?
84                 line = fin.readline()
85                 z += [float(line)]
86         else:
87             raise ValueError("no Options line found")
88         n = z[nopts + 3] # variables
89         m = z[nopts + 1] # constraints
90         x = []
91         y = []
92         i = 0
93         while i < m:
94             line = fin.readline()
95             y.append(float(line))
96             i += 1
97         i = 0
98         while i < n:
99             line = fin.readline()
100             x.append(float(line))
101             i += 1
102         objno = [0,0]
103         line = fin.readline()
104         if line:                    # WEH - when is this true?
105             if line[:5] != "objno":         #pragma:nocover
106                 raise ValueError("expected 'objno', found '%s'" % (line))
107             t = line.split()
108             if len(t) != 3:
109                 raise ValueError("expected two numbers in objno line, "
110                                  "but found '%s'" % (line))
111             objno = [int(t[1]), int(t[2])]
112         res.solver.message = msg.strip()
113         res.solver.message = res.solver.message.replace("\n","; ")
114         res.solver.message = pyutilib.misc.yaml_fix(res.solver.message)
115         ##res.solver.instanceName = osrl.header.instanceName
116         ##res.solver.systime = osrl.header.time
117         res.solver.status = SolverStatus.ok
118         soln_status = SolutionStatus.unknown
119         if (objno[1] >= 0) and (objno[1] <= 99):
120             objno_message = "OPTIMAL SOLUTION FOUND!"
121             res.solver.termination_condition = TerminationCondition.optimal
122             res.solver.status = SolverStatus.ok
123             soln_status = SolutionStatus.optimal
124         elif (objno[1] >= 100) and (objno[1] <= 199):
125             objno_message = "Optimal solution indicated, but ERROR LIKELY!"
126             res.solver.termination_condition = TerminationCondition.optimal
127             res.solver.status = SolverStatus.warning
128             soln_status = SolutionStatus.optimal
129         elif (objno[1] >= 200) and (objno[1] <= 299):
130             objno_message = "INFEASIBLE SOLUTION: constraints cannot be satisfied!"
131             res.solver.termination_condition = TerminationCondition.infeasible
132             res.solver.status = SolverStatus.warning
133             soln_status = SolutionStatus.infeasible
134         elif (objno[1] >= 300) and (objno[1] <= 399):
135             objno_message = "UNBOUNDED PROBLEM: the objective can be improved without limit!"
136             res.solver.termination_condition = TerminationCondition.unbounded
137             res.solver.status = SolverStatus.warning
138             soln_status = SolutionStatus.unbounded
139         elif (objno[1] >= 400) and (objno[1] <= 499):
140             objno_message = ("EXCEEDED MAXIMUM NUMBER OF ITERATIONS: the solver "
141                              "was stopped by a limit that you set!")
142             res.solver.termination_condition = TerminationCondition.maxIterations
143             res.solver.status = SolverStatus.warning
144             soln_status = SolutionStatus.stoppedByLimit
145         elif (objno[1] >= 500) and (objno[1] <= 599):
146             objno_message = ("FAILURE: the solver stopped by an error condition "
147                              "in the solver routines!")
148             res.solver.termination_condition = TerminationCondition.internalSolverError
149             res.solver.status = SolverStatus.error
150             soln_status = SolutionStatus.error
151         res.solver.id = objno[1]
152         ##res.problem.name = osrl.header.instanceName
153         if res.solver.termination_condition in [TerminationCondition.unknown,
154                         TerminationCondition.maxIterations,
155                         TerminationCondition.minFunctionValue,
156                         TerminationCondition.minStepLength,
157                         TerminationCondition.globallyOptimal,
158                         TerminationCondition.locallyOptimal,
159                         TerminationCondition.optimal,
160                         TerminationCondition.maxEvaluations,
161                         TerminationCondition.other,
162                         TerminationCondition.infeasible]:
163 
164             if soln is None:
165                 soln = res.solution.add()
166             res.solution.status = soln_status
167             soln.status_description = objno_message
168             soln.message = msg.strip()
169             soln.message = res.solver.message.replace("\n","; ")
170             soln_variable = soln.variable
171             i = 0
172             for var_value in x:
173                 soln_variable["v"+str(i)] = {"Value" : var_value}
174                 i = i + 1
175             soln_constraint = soln.constraint
176             if any(re.match(suf,"dual") for suf in suffixes):
177                 for i in xrange(0,len(y)):
178                     soln_constraint["c"+str(i)] = {"Dual" : y[i]}
179 
180             ### Read suffixes ###
181             line = fin.readline()
182             while line:
183                 line = line.strip()
184                 if line == "":
185                     continue
186                 line = line.split()
187                 if line[0] != 'suffix':
188                     # We assume this is the start of a
189                     # section like kestrel_option, which
190                     # comes after all suffixes.
191                     remaining = ""
192                     line = fin.readline()
193                     while line:
194                         remaining += line.strip()+"; "
195                         line = fin.readline()
196                     res.solver.message += remaining
197                     break
198                 unmasked_kind = int(line[1])
199                 kind = unmasked_kind & 3 # 0-var, 1-con, 2-obj, 3-prob
200                 convert_function = int
201                 if (unmasked_kind & 4) == 4:
202                     convert_function = float
203                 nvalues = int(line[2])
204                 namelen = int(line[3])
205                 tablen = int(line[4])
206                 tabline = int(line[5])
207                 suffix_name = fin.readline().strip()
208                 if any(re.match(suf,suffix_name) for suf in suffixes):
209                     # ignore translation of the table number to string value for now,
210                     # this information can be obtained from the solver documentation
211                     for n in xrange(tabline):
212                         fin.readline()
213                     if kind == 0: # Var
214                         for cnt in xrange(nvalues):
215                             suf_line = fin.readline().split()
216                             soln_variable["v"+suf_line[0]][suffix_name] = \
217                                 convert_function(suf_line[1])
218                     elif kind == 1: # Con
219                         for cnt in xrange(nvalues):
220                             suf_line = fin.readline().split()
221                             key = "c"+suf_line[0]
222                             if key not in soln_constraint:
223                                 soln_constraint[key] = {}
224                             # convert the first letter of the suffix name to upper case,
225                             # mainly for pretty-print / output purposes. these are lower-cased
226                             # when loaded into real suffixes, so it is largely redundant.
227                             translated_suffix_name = suffix_name[0].upper() + suffix_name[1:]
228                             soln_constraint[key][translated_suffix_name] = \
229                                 convert_function(suf_line[1])
230                     elif kind == 2: # Obj
231                         for cnt in xrange(nvalues):
232                             suf_line = fin.readline().split()
233                             soln.objective.setdefault("o"+suf_line[0],{})[suffix_name] = \
234                                 convert_function(suf_line[1])
235                     elif kind == 3: # Prob
236                         # Skip problem kind suffixes for now. Not sure the
237                         # best place to put them in the results object
238                         for cnt in xrange(nvalues):
239                             suf_line = fin.readline().split()
240                             soln.problem[suffix_name] = convert_function(suf_line[1])
241                 else:
242                     # do not store the suffix in the solution object
243                     for cnt in xrange(nvalues):
244                         fin.readline()
245                 line = fin.readline()
246 
247         #
248         # This is a bit of a hack to accommodate PICO.  If
249         # the PICO parser has parsed the # of constraints, then
250         # don't try to read it in from the *.sol file.  The reason
251         # is that these may be inconsistent values!
252         #
253         if res.problem.number_of_constraints == 0:
254             res.problem.number_of_constraints = m
255         res.problem.number_of_variables = n
256         res.problem.number_of_objectives = 1
257         return res
258
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pyomo/opt/plugins/sol.py b/pyomo/opt/plugins/sol.py
--- a/pyomo/opt/plugins/sol.py
+++ b/pyomo/opt/plugins/sol.py
@@ -2,8 +2,8 @@
 #
 #  Pyomo: Python Optimization Modeling Objects
 #  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC
-#  Under the terms of Contract DE-NA0003525 with National Technology and 
-#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain 
+#  Under the terms of Contract DE-NA0003525 with National Technology and
+#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
 #  rights in this software.
 #  This software is distributed under the 3-clause BSD License.
 #  ___________________________________________________________________________
@@ -213,7 +213,10 @@
                     if kind == 0: # Var
                         for cnt in xrange(nvalues):
                             suf_line = fin.readline().split()
-                            soln_variable["v"+suf_line[0]][suffix_name] = \
+                            key = "v"+suf_line[0]
+                            if key not in soln_variable:
+                                soln_variable[key] = {}
+                            soln_variable[key][suffix_name] = \
                                 convert_function(suf_line[1])
                     elif kind == 1: # Con
                         for cnt in xrange(nvalues):
@@ -221,9 +224,14 @@
                             key = "c"+suf_line[0]
                             if key not in soln_constraint:
                                 soln_constraint[key] = {}
-                            # convert the first letter of the suffix name to upper case,
-                            # mainly for pretty-print / output purposes. these are lower-cased
-                            # when loaded into real suffixes, so it is largely redundant.
+                            # GH: About the comment below: This makes for a
+                            # confusing results object and more confusing tests.
+                            # We should not muck with the names of suffixes
+                            # coming out of the sol file.
+                            #
+                            #   convert the first letter of the suffix name to upper case,
+                            #   mainly for pretty-print / output purposes. these are lower-cased
+                            #   when loaded into real suffixes, so it is largely redundant.
                             translated_suffix_name = suffix_name[0].upper() + suffix_name[1:]
                             soln_constraint[key][translated_suffix_name] = \
                                 convert_function(suf_line[1])

{"golden_diff": "diff --git a/pyomo/opt/plugins/sol.py b/pyomo/opt/plugins/sol.py\n--- a/pyomo/opt/plugins/sol.py\n+++ b/pyomo/opt/plugins/sol.py\n@@ -2,8 +2,8 @@\n #\n #  Pyomo: Python Optimization Modeling Objects\n #  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC\n-#  Under the terms of Contract DE-NA0003525 with National Technology and \n-#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain \n+#  Under the terms of Contract DE-NA0003525 with National Technology and\n+#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain\n #  rights in this software.\n #  This software is distributed under the 3-clause BSD License.\n #  ___________________________________________________________________________\n@@ -213,7 +213,10 @@\n                     if kind == 0: # Var\n                         for cnt in xrange(nvalues):\n                             suf_line = fin.readline().split()\n-                            soln_variable[\"v\"+suf_line[0]][suffix_name] = \\\n+                            key = \"v\"+suf_line[0]\n+                            if key not in soln_variable:\n+                                soln_variable[key] = {}\n+                            soln_variable[key][suffix_name] = \\\n                                 convert_function(suf_line[1])\n                     elif kind == 1: # Con\n                         for cnt in xrange(nvalues):\n@@ -221,9 +224,14 @@\n                             key = \"c\"+suf_line[0]\n                             if key not in soln_constraint:\n                                 soln_constraint[key] = {}\n-                            # convert the first letter of the suffix name to upper case,\n-                            # mainly for pretty-print / output purposes. these are lower-cased\n-                            # when loaded into real suffixes, so it is largely redundant.\n+                            # GH: About the comment below: This makes for a\n+                            # confusing results object and more confusing tests.\n+                            # We should not muck with the names of suffixes\n+                            # coming out of the sol file.\n+                            #\n+                            #   convert the first letter of the suffix name to upper case,\n+                            #   mainly for pretty-print / output purposes. these are lower-cased\n+                            #   when loaded into real suffixes, so it is largely redundant.\n                             translated_suffix_name = suffix_name[0].upper() + suffix_name[1:]\n                             soln_constraint[key][translated_suffix_name] = \\\n                                 convert_function(suf_line[1])\n", "issue": "Pyomo crashes when solver returns suffix but no value for variables\nWhen the user requests an irreducibly infeasible set of constraints (IIS) for an infeasible mixed-integer program, cplexamp sometimes returns the IIS but not values for the variables. This causes pyomo to crash while reading the solution. Specifically, `pyomo.opt.plugins.sol` only creates entries in `soln_variable` for variables whose values have been returned by the solver, but then it tries to attach the IIS suffix value to a non-existent item in `soln_variable`, causing an uncaught `KeyError()`.\r\n\r\nThe code below illustrates this problem:\r\n\r\n    from pyomo.environ import *\r\n    m = ConcreteModel()\r\n    m.x1 = Var(within=NonNegativeReals)\r\n    m.x2 = Var(within=NonNegativeIntegers)\r\n    m.constraint = Constraint(rule=lambda m: m.x1 + m.x2 <= -1)\r\n    m.objective = Objective(rule=lambda m: m.x1 + m.x2, sense=minimize)\r\n    m.iis = Suffix(direction=Suffix.IMPORT)\r\n    solver = SolverFactory('cplexamp')\r\n    res = solver.solve(m, options_string='iisfind=1', tee=True)\r\n    print(\"IIS:\")\r\n    print(\"\\n\".join(sorted(c.name for c in m.iis)))\r\n\r\nI have added a pull request to fix this: https://github.com/Pyomo/pyomo/pull/596\n", "before_files": [{"content": "#  ___________________________________________________________________________\n#\n#  Pyomo: Python Optimization Modeling Objects\n#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC\n#  Under the terms of Contract DE-NA0003525 with National Technology and \n#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain \n#  rights in this software.\n#  This software is distributed under the 3-clause BSD License.\n#  ___________________________________________________________________________\n\n#\n# Class for reading an AMPL *.sol file\n#\n\nimport re\n\nimport pyutilib.misc\n\nfrom pyomo.common.plugin import alias\nfrom pyomo.opt.base import results\nfrom pyomo.opt.base.formats import ResultsFormat\nfrom pyomo.opt import (SolverResults,\n                       SolutionStatus,\n                       SolverStatus,\n                       TerminationCondition)\n\nfrom six.moves import xrange\n\nclass ResultsReader_sol(results.AbstractResultsReader):\n    \"\"\"\n    Class that reads in a *.sol results file and generates a\n    SolverResults object.\n    \"\"\"\n\n    alias(str(ResultsFormat.sol))\n\n    def __init__(self, name=None):\n        results.AbstractResultsReader.__init__(self,ResultsFormat.sol)\n        if not name is None:\n            self.name = name\n\n    def __call__(self, filename, res=None, soln=None, suffixes=[]):\n        \"\"\"\n        Parse a *.sol file\n        \"\"\"\n        try:\n            with open(filename,\"r\") as f:\n                return self._load(f, res, soln, suffixes)\n        except ValueError as e:\n            with open(filename,\"r\") as f:\n                fdata = f.read()\n            raise ValueError(\n                \"Error reading '%s': %s.\\n\"\n                \"SOL File Output:\\n%s\"\n                % (filename, str(e), fdata))\n\n    def _load(self, fin, res, soln, suffixes):\n\n        if res is None:\n            res = SolverResults()\n        #\n        msg = \"\"\n        line = fin.readline()\n        if line.strip() == \"\":\n            line = fin.readline()\n        while line:\n            if line[0] == '\\n' or (line[0] == '\\r' and line[1] == '\\n'):\n                break\n            msg += line\n            line = fin.readline()\n        z = []\n        line = fin.readline()\n        if line[:7] == \"Options\":\n            line = fin.readline()\n            nopts = int(line)\n            need_vbtol = False\n            if nopts > 4:           # WEH - when is this true?\n                nopts -= 2\n                need_vbtol = True\n            for i in xrange(nopts + 4):\n                line = fin.readline()\n                z += [int(line)]\n            if need_vbtol:          # WEH - when is this true?\n                line = fin.readline()\n                z += [float(line)]\n        else:\n            raise ValueError(\"no Options line found\")\n        n = z[nopts + 3] # variables\n        m = z[nopts + 1] # constraints\n        x = []\n        y = []\n        i = 0\n        while i < m:\n            line = fin.readline()\n            y.append(float(line))\n            i += 1\n        i = 0\n        while i < n:\n            line = fin.readline()\n            x.append(float(line))\n            i += 1\n        objno = [0,0]\n        line = fin.readline()\n        if line:                    # WEH - when is this true?\n            if line[:5] != \"objno\":         #pragma:nocover\n                raise ValueError(\"expected 'objno', found '%s'\" % (line))\n            t = line.split()\n            if len(t) != 3:\n                raise ValueError(\"expected two numbers in objno line, \"\n                                 \"but found '%s'\" % (line))\n            objno = [int(t[1]), int(t[2])]\n        res.solver.message = msg.strip()\n        res.solver.message = res.solver.message.replace(\"\\n\",\"; \")\n        res.solver.message = pyutilib.misc.yaml_fix(res.solver.message)\n        ##res.solver.instanceName = osrl.header.instanceName\n        ##res.solver.systime = osrl.header.time\n        res.solver.status = SolverStatus.ok\n        soln_status = SolutionStatus.unknown\n        if (objno[1] >= 0) and (objno[1] <= 99):\n            objno_message = \"OPTIMAL SOLUTION FOUND!\"\n            res.solver.termination_condition = TerminationCondition.optimal\n            res.solver.status = SolverStatus.ok\n            soln_status = SolutionStatus.optimal\n        elif (objno[1] >= 100) and (objno[1] <= 199):\n            objno_message = \"Optimal solution indicated, but ERROR LIKELY!\"\n            res.solver.termination_condition = TerminationCondition.optimal\n            res.solver.status = SolverStatus.warning\n            soln_status = SolutionStatus.optimal\n        elif (objno[1] >= 200) and (objno[1] <= 299):\n            objno_message = \"INFEASIBLE SOLUTION: constraints cannot be satisfied!\"\n            res.solver.termination_condition = TerminationCondition.infeasible\n            res.solver.status = SolverStatus.warning\n            soln_status = SolutionStatus.infeasible\n        elif (objno[1] >= 300) and (objno[1] <= 399):\n            objno_message = \"UNBOUNDED PROBLEM: the objective can be improved without limit!\"\n            res.solver.termination_condition = TerminationCondition.unbounded\n            res.solver.status = SolverStatus.warning\n            soln_status = SolutionStatus.unbounded\n        elif (objno[1] >= 400) and (objno[1] <= 499):\n            objno_message = (\"EXCEEDED MAXIMUM NUMBER OF ITERATIONS: the solver \"\n                             \"was stopped by a limit that you set!\")\n            res.solver.termination_condition = TerminationCondition.maxIterations\n            res.solver.status = SolverStatus.warning\n            soln_status = SolutionStatus.stoppedByLimit\n        elif (objno[1] >= 500) and (objno[1] <= 599):\n            objno_message = (\"FAILURE: the solver stopped by an error condition \"\n                             \"in the solver routines!\")\n            res.solver.termination_condition = TerminationCondition.internalSolverError\n            res.solver.status = SolverStatus.error\n            soln_status = SolutionStatus.error\n        res.solver.id = objno[1]\n        ##res.problem.name = osrl.header.instanceName\n        if res.solver.termination_condition in [TerminationCondition.unknown,\n                        TerminationCondition.maxIterations,\n                        TerminationCondition.minFunctionValue,\n                        TerminationCondition.minStepLength,\n                        TerminationCondition.globallyOptimal,\n                        TerminationCondition.locallyOptimal,\n                        TerminationCondition.optimal,\n                        TerminationCondition.maxEvaluations,\n                        TerminationCondition.other,\n                        TerminationCondition.infeasible]:\n\n            if soln is None:\n                soln = res.solution.add()\n            res.solution.status = soln_status\n            soln.status_description = objno_message\n            soln.message = msg.strip()\n            soln.message = res.solver.message.replace(\"\\n\",\"; \")\n            soln_variable = soln.variable\n            i = 0\n            for var_value in x:\n                soln_variable[\"v\"+str(i)] = {\"Value\" : var_value}\n                i = i + 1\n            soln_constraint = soln.constraint\n            if any(re.match(suf,\"dual\") for suf in suffixes):\n                for i in xrange(0,len(y)):\n                    soln_constraint[\"c\"+str(i)] = {\"Dual\" : y[i]}\n\n            ### Read suffixes ###\n            line = fin.readline()\n            while line:\n                line = line.strip()\n                if line == \"\":\n                    continue\n                line = line.split()\n                if line[0] != 'suffix':\n                    # We assume this is the start of a\n                    # section like kestrel_option, which\n                    # comes after all suffixes.\n                    remaining = \"\"\n                    line = fin.readline()\n                    while line:\n                        remaining += line.strip()+\"; \"\n                        line = fin.readline()\n                    res.solver.message += remaining\n                    break\n                unmasked_kind = int(line[1])\n                kind = unmasked_kind & 3 # 0-var, 1-con, 2-obj, 3-prob\n                convert_function = int\n                if (unmasked_kind & 4) == 4:\n                    convert_function = float\n                nvalues = int(line[2])\n                namelen = int(line[3])\n                tablen = int(line[4])\n                tabline = int(line[5])\n                suffix_name = fin.readline().strip()\n                if any(re.match(suf,suffix_name) for suf in suffixes):\n                    # ignore translation of the table number to string value for now,\n                    # this information can be obtained from the solver documentation\n                    for n in xrange(tabline):\n                        fin.readline()\n                    if kind == 0: # Var\n                        for cnt in xrange(nvalues):\n                            suf_line = fin.readline().split()\n                            soln_variable[\"v\"+suf_line[0]][suffix_name] = \\\n                                convert_function(suf_line[1])\n                    elif kind == 1: # Con\n                        for cnt in xrange(nvalues):\n                            suf_line = fin.readline().split()\n                            key = \"c\"+suf_line[0]\n                            if key not in soln_constraint:\n                                soln_constraint[key] = {}\n                            # convert the first letter of the suffix name to upper case,\n                            # mainly for pretty-print / output purposes. these are lower-cased\n                            # when loaded into real suffixes, so it is largely redundant.\n                            translated_suffix_name = suffix_name[0].upper() + suffix_name[1:]\n                            soln_constraint[key][translated_suffix_name] = \\\n                                convert_function(suf_line[1])\n                    elif kind == 2: # Obj\n                        for cnt in xrange(nvalues):\n                            suf_line = fin.readline().split()\n                            soln.objective.setdefault(\"o\"+suf_line[0],{})[suffix_name] = \\\n                                convert_function(suf_line[1])\n                    elif kind == 3: # Prob\n                        # Skip problem kind suffixes for now. Not sure the\n                        # best place to put them in the results object\n                        for cnt in xrange(nvalues):\n                            suf_line = fin.readline().split()\n                            soln.problem[suffix_name] = convert_function(suf_line[1])\n                else:\n                    # do not store the suffix in the solution object\n                    for cnt in xrange(nvalues):\n                        fin.readline()\n                line = fin.readline()\n\n        #\n        # This is a bit of a hack to accommodate PICO.  If\n        # the PICO parser has parsed the # of constraints, then\n        # don't try to read it in from the *.sol file.  The reason\n        # is that these may be inconsistent values!\n        #\n        if res.problem.number_of_constraints == 0:\n            res.problem.number_of_constraints = m\n        res.problem.number_of_variables = n\n        res.problem.number_of_objectives = 1\n        return res\n", "path": "pyomo/opt/plugins/sol.py"}], "after_files": [{"content": "#  ___________________________________________________________________________\n#\n#  Pyomo: Python Optimization Modeling Objects\n#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC\n#  Under the terms of Contract DE-NA0003525 with National Technology and\n#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain\n#  rights in this software.\n#  This software is distributed under the 3-clause BSD License.\n#  ___________________________________________________________________________\n\n#\n# Class for reading an AMPL *.sol file\n#\n\nimport re\n\nimport pyutilib.misc\n\nfrom pyomo.common.plugin import alias\nfrom pyomo.opt.base import results\nfrom pyomo.opt.base.formats import ResultsFormat\nfrom pyomo.opt import (SolverResults,\n                       SolutionStatus,\n                       SolverStatus,\n                       TerminationCondition)\n\nfrom six.moves import xrange\n\nclass ResultsReader_sol(results.AbstractResultsReader):\n    \"\"\"\n    Class that reads in a *.sol results file and generates a\n    SolverResults object.\n    \"\"\"\n\n    alias(str(ResultsFormat.sol))\n\n    def __init__(self, name=None):\n        results.AbstractResultsReader.__init__(self,ResultsFormat.sol)\n        if not name is None:\n            self.name = name\n\n    def __call__(self, filename, res=None, soln=None, suffixes=[]):\n        \"\"\"\n        Parse a *.sol file\n        \"\"\"\n        try:\n            with open(filename,\"r\") as f:\n                return self._load(f, res, soln, suffixes)\n        except ValueError as e:\n            with open(filename,\"r\") as f:\n                fdata = f.read()\n            raise ValueError(\n                \"Error reading '%s': %s.\\n\"\n                \"SOL File Output:\\n%s\"\n                % (filename, str(e), fdata))\n\n    def _load(self, fin, res, soln, suffixes):\n\n        if res is None:\n            res = SolverResults()\n        #\n        msg = \"\"\n        line = fin.readline()\n        if line.strip() == \"\":\n            line = fin.readline()\n        while line:\n            if line[0] == '\\n' or (line[0] == '\\r' and line[1] == '\\n'):\n                break\n            msg += line\n            line = fin.readline()\n        z = []\n        line = fin.readline()\n        if line[:7] == \"Options\":\n            line = fin.readline()\n            nopts = int(line)\n            need_vbtol = False\n            if nopts > 4:           # WEH - when is this true?\n                nopts -= 2\n                need_vbtol = True\n            for i in xrange(nopts + 4):\n                line = fin.readline()\n                z += [int(line)]\n            if need_vbtol:          # WEH - when is this true?\n                line = fin.readline()\n                z += [float(line)]\n        else:\n            raise ValueError(\"no Options line found\")\n        n = z[nopts + 3] # variables\n        m = z[nopts + 1] # constraints\n        x = []\n        y = []\n        i = 0\n        while i < m:\n            line = fin.readline()\n            y.append(float(line))\n            i += 1\n        i = 0\n        while i < n:\n            line = fin.readline()\n            x.append(float(line))\n            i += 1\n        objno = [0,0]\n        line = fin.readline()\n        if line:                    # WEH - when is this true?\n            if line[:5] != \"objno\":         #pragma:nocover\n                raise ValueError(\"expected 'objno', found '%s'\" % (line))\n            t = line.split()\n            if len(t) != 3:\n                raise ValueError(\"expected two numbers in objno line, \"\n                                 \"but found '%s'\" % (line))\n            objno = [int(t[1]), int(t[2])]\n        res.solver.message = msg.strip()\n        res.solver.message = res.solver.message.replace(\"\\n\",\"; \")\n        res.solver.message = pyutilib.misc.yaml_fix(res.solver.message)\n        ##res.solver.instanceName = osrl.header.instanceName\n        ##res.solver.systime = osrl.header.time\n        res.solver.status = SolverStatus.ok\n        soln_status = SolutionStatus.unknown\n        if (objno[1] >= 0) and (objno[1] <= 99):\n            objno_message = \"OPTIMAL SOLUTION FOUND!\"\n            res.solver.termination_condition = TerminationCondition.optimal\n            res.solver.status = SolverStatus.ok\n            soln_status = SolutionStatus.optimal\n        elif (objno[1] >= 100) and (objno[1] <= 199):\n            objno_message = \"Optimal solution indicated, but ERROR LIKELY!\"\n            res.solver.termination_condition = TerminationCondition.optimal\n            res.solver.status = SolverStatus.warning\n            soln_status = SolutionStatus.optimal\n        elif (objno[1] >= 200) and (objno[1] <= 299):\n            objno_message = \"INFEASIBLE SOLUTION: constraints cannot be satisfied!\"\n            res.solver.termination_condition = TerminationCondition.infeasible\n            res.solver.status = SolverStatus.warning\n            soln_status = SolutionStatus.infeasible\n        elif (objno[1] >= 300) and (objno[1] <= 399):\n            objno_message = \"UNBOUNDED PROBLEM: the objective can be improved without limit!\"\n            res.solver.termination_condition = TerminationCondition.unbounded\n            res.solver.status = SolverStatus.warning\n            soln_status = SolutionStatus.unbounded\n        elif (objno[1] >= 400) and (objno[1] <= 499):\n            objno_message = (\"EXCEEDED MAXIMUM NUMBER OF ITERATIONS: the solver \"\n                             \"was stopped by a limit that you set!\")\n            res.solver.termination_condition = TerminationCondition.maxIterations\n            res.solver.status = SolverStatus.warning\n            soln_status = SolutionStatus.stoppedByLimit\n        elif (objno[1] >= 500) and (objno[1] <= 599):\n            objno_message = (\"FAILURE: the solver stopped by an error condition \"\n                             \"in the solver routines!\")\n            res.solver.termination_condition = TerminationCondition.internalSolverError\n            res.solver.status = SolverStatus.error\n            soln_status = SolutionStatus.error\n        res.solver.id = objno[1]\n        ##res.problem.name = osrl.header.instanceName\n        if res.solver.termination_condition in [TerminationCondition.unknown,\n                        TerminationCondition.maxIterations,\n                        TerminationCondition.minFunctionValue,\n                        TerminationCondition.minStepLength,\n                        TerminationCondition.globallyOptimal,\n                        TerminationCondition.locallyOptimal,\n                        TerminationCondition.optimal,\n                        TerminationCondition.maxEvaluations,\n                        TerminationCondition.other,\n                        TerminationCondition.infeasible]:\n\n            if soln is None:\n                soln = res.solution.add()\n            res.solution.status = soln_status\n            soln.status_description = objno_message\n            soln.message = msg.strip()\n            soln.message = res.solver.message.replace(\"\\n\",\"; \")\n            soln_variable = soln.variable\n            i = 0\n            for var_value in x:\n                soln_variable[\"v\"+str(i)] = {\"Value\" : var_value}\n                i = i + 1\n            soln_constraint = soln.constraint\n            if any(re.match(suf,\"dual\") for suf in suffixes):\n                for i in xrange(0,len(y)):\n                    soln_constraint[\"c\"+str(i)] = {\"Dual\" : y[i]}\n\n            ### Read suffixes ###\n            line = fin.readline()\n            while line:\n                line = line.strip()\n                if line == \"\":\n                    continue\n                line = line.split()\n                if line[0] != 'suffix':\n                    # We assume this is the start of a\n                    # section like kestrel_option, which\n                    # comes after all suffixes.\n                    remaining = \"\"\n                    line = fin.readline()\n                    while line:\n                        remaining += line.strip()+\"; \"\n                        line = fin.readline()\n                    res.solver.message += remaining\n                    break\n                unmasked_kind = int(line[1])\n                kind = unmasked_kind & 3 # 0-var, 1-con, 2-obj, 3-prob\n                convert_function = int\n                if (unmasked_kind & 4) == 4:\n                    convert_function = float\n                nvalues = int(line[2])\n                namelen = int(line[3])\n                tablen = int(line[4])\n                tabline = int(line[5])\n                suffix_name = fin.readline().strip()\n                if any(re.match(suf,suffix_name) for suf in suffixes):\n                    # ignore translation of the table number to string value for now,\n                    # this information can be obtained from the solver documentation\n                    for n in xrange(tabline):\n                        fin.readline()\n                    if kind == 0: # Var\n                        for cnt in xrange(nvalues):\n                            suf_line = fin.readline().split()\n                            key = \"v\"+suf_line[0]\n                            if key not in soln_variable:\n                                soln_variable[key] = {}\n                            soln_variable[key][suffix_name] = \\\n                                convert_function(suf_line[1])\n                    elif kind == 1: # Con\n                        for cnt in xrange(nvalues):\n                            suf_line = fin.readline().split()\n                            key = \"c\"+suf_line[0]\n                            if key not in soln_constraint:\n                                soln_constraint[key] = {}\n                            # GH: About the comment below: This makes for a\n                            # confusing results object and more confusing tests.\n                            # We should not muck with the names of suffixes\n                            # coming out of the sol file.\n                            #\n                            #   convert the first letter of the suffix name to upper case,\n                            #   mainly for pretty-print / output purposes. these are lower-cased\n                            #   when loaded into real suffixes, so it is largely redundant.\n                            translated_suffix_name = suffix_name[0].upper() + suffix_name[1:]\n                            soln_constraint[key][translated_suffix_name] = \\\n                                convert_function(suf_line[1])\n                    elif kind == 2: # Obj\n                        for cnt in xrange(nvalues):\n                            suf_line = fin.readline().split()\n                            soln.objective.setdefault(\"o\"+suf_line[0],{})[suffix_name] = \\\n                                convert_function(suf_line[1])\n                    elif kind == 3: # Prob\n                        # Skip problem kind suffixes for now. Not sure the\n                        # best place to put them in the results object\n                        for cnt in xrange(nvalues):\n                            suf_line = fin.readline().split()\n                            soln.problem[suffix_name] = convert_function(suf_line[1])\n                else:\n                    # do not store the suffix in the solution object\n                    for cnt in xrange(nvalues):\n                        fin.readline()\n                line = fin.readline()\n\n        #\n        # This is a bit of a hack to accommodate PICO.  If\n        # the PICO parser has parsed the # of constraints, then\n        # don't try to read it in from the *.sol file.  The reason\n        # is that these may be inconsistent values!\n        #\n        if res.problem.number_of_constraints == 0:\n            res.problem.number_of_constraints = m\n        res.problem.number_of_variables = n\n        res.problem.number_of_objectives = 1\n        return res\n", "path": "pyomo/opt/plugins/sol.py"}]}