1 # -------------------------------------------------------------------------
2 # Copyright (c) 2020 AT&T Intellectual Property
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 # -------------------------------------------------------------------------
19 from datetime import datetime
23 from pymzn import chuffed
24 from pymzn import gecode
25 from pymzn import minizinc
26 from pymzn import or_tools
27 from pymzn import Status
29 from osdf.utils.file_utils import delete_file_folder
32 Status.INCOMPLETE: "incomplete",
33 Status.COMPLETE: "complete",
34 Status.UNSATISFIABLE: "unsatisfiable",
35 Status.UNKNOWN: "unknown",
36 Status.UNBOUNDED: "unbounded",
37 Status.UNSATorUNBOUNDED: "unsat_or_unbounded",
50 def map_status(status):
51 return error_status_map.get(status, "failed")
54 def solve(request_json, mzn_content):
55 """Given the request and minizinc content. Translates the json request to the format minizinc understands
57 return: returns the optimized solution.
59 req_info = request_json['requestInfo']
60 opt_info = request_json['optimInfo']
62 mzn_solution = mzn_solver(mzn_content, opt_info)
65 'transactionId': req_info['transactionId'],
66 'requestID': req_info['requestID'],
67 'requestStatus': 'done',
68 'statusMessage': map_status(mzn_solution.status),
69 'solutions': mzn_solution[0] if mzn_solution else {}
71 return 200, json.dumps(response)
72 except Exception as e:
74 'transactionId': req_info['transactionId'],
75 'requestID': req_info['requestID'],
76 'requestStatus': 'failed',
77 'statusMessage': 'Failed due to {}'.format(e)
79 return 400, json.dumps(response)
82 def mzn_solver(mzn_content, opt_info):
83 """Calls the minizinc optimizer.
86 args = opt_info['solverArgs']
87 solver = get_mzn_solver(args.pop('solver'))
91 file_name = persist_opt_data(opt_info)
93 return minizinc(mzn_content, file_name, **mzn_opts, solver=solver)
96 delete_file_folder(file_name)
99 def persist_opt_data(opt_info):
100 """Persist the opt data, if included as part of the request.
102 return: file_name path of the optim_data
103 returns None if no optData is part of the request
106 if 'optData' in opt_info:
107 if opt_info['optData'].get('json'):
108 data_content = json.dumps(opt_info['optData']['json'])
109 file_name = '/tmp/optim_engine_{}.json'.format(datetime.timestamp(datetime.now()))
110 persist_data(data_content, file_name)
111 elif opt_info['optData'].get('text'):
112 data_content = opt_info['optData']['text']
113 file_name = '/tmp/optim_engine_{}.dzn'.format(datetime.timestamp(datetime.now()))
114 persist_data(data_content, file_name)
118 def persist_data(data_content, file_name):
119 """Save the dzn data into a file
122 with open(file_name, "wt") as data:
123 data.write(data_content)
126 def get_mzn_solver(solver):
127 """Returns a solver type object for minizinc optimizers
129 solver: solver that is part of the request
130 return: solver mapped object
132 return solver_dict.get(solver)