Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docplex 2.29.241 #14

Merged
merged 2 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 12 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
Changelog
---------

Changed in 2.28.240:
Changed in 2.29.241:
````````````````````

* each record of a solve history use a unique timestamp for its fields


Changed in 2.28.240 (2024.08):
``````````````````````````````

* In ``docplex.cp``: robustify the handling of callback messages coming from CP Optimizer
* Allows to use numpy 2.0

Changed in 2.27.239 (2024.04):
``````````````````````````````

* Allows to use numpy 2.0

Changed in 2.27.239 (2024.04):
``````````````````````````````

* PEP517, PEP518 build
* Faster PWLs from `PR#6 <https://github.com/IBMDecisionOptimization/docplex/pull/6>`__.

Expand Down
5 changes: 5 additions & 0 deletions docplex/mp/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,11 @@ def multi_objective_values(self):

"""
self_obj = self._objective
model = self.model
if not isinstance(self_obj, list) and model.has_multi_objective():
nbMultiObj = model.number_of_multi_objective_exprs
my_multiobj = model._multi_objective
return [self.get_value(my_multiobj.exprs[i]) for i in range(nbMultiObj)]
return self_obj if is_indexable(self_obj) else [self_obj]

@property
Expand Down
172 changes: 172 additions & 0 deletions docplex/util/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# --------------------------------------------------------------------------
# File: cli.py
# ---------------------------------------------------------------------------
# Licensed Materials - Property of IBM
# 5725-A06 5725-A29 5724-Y48 5724-Y49 5724-Y54 5724-Y55 5655-Y21
# Copyright IBM Corporation 2023, 2024. All Rights Reserved.
#
# US Government Users Restricted Rights - Use, duplication or
# disclosure restricted by GSA ADP Schedule Contract with
# IBM Corp.
# --------------------------------------------------------------------------
import sys
import os
import distutils.ccompiler
import subprocess
import shutil
import glob
import argparse



def get_cos_archname(bindir, so):
arch = [a for a in glob.glob("{}/**/{}".format(bindir, so), recursive=True)]
if len(arch) == 0:
return None
elif len(arch) > 1:
print("Error: multiple source files found: {}".format(arch))
return None
return os.path.basename(os.path.dirname(arch[0]))


def get_cpo_name(version):
return "cpoptimizer.exe" if sys.platform == "win32" else "cpoptimizer"


def get_so_name(version):
ext = distutils.ccompiler.new_compiler().shared_lib_extension
if sys.platform == "darwin" : ext = ".dylib"
prefix = "" if sys.platform == "win32" else "lib"
return "{}cplex{}{}".format(prefix, version, ext)


def check_file(fname, write=False):
if write:
ok = os.access(fname, os.W_OK)
if not ok:
print("Error: {} should be present and writable but is not".format(fname))
else:
ok = os.access(fname, os.R_OK)
if not ok:
print("Error: {} should be present and readable but is not".format(fname))
return ok


def get_cplex_info():
sub_program = """
try:
import cplex
print(cplex.__path__[0], cplex.__version__)
except ModuleNotFoundError as e:
print('Error: could not import module \"cplex\"')

"""

# This needs to be run as another process as there is no other
# way of unloading the 'cplex' module and since we will copy
# a new shared object over the already loaded one, leaving the
# cplex module loaded can create a segmentation fault.
out = subprocess.run(["python", "-c", sub_program], capture_output=True)
if out.returncode == 0:
stdout = out.stdout.decode("utf-8").strip().split(" ")
if stdout[0] != "Error:":
return stdout[0], stdout[1]
return None, None


def copy_so(cos):
cos = os.path.realpath(cos)
pcplex, version = get_cplex_info()

version_mneumonic = "".join(version.split(".")[:3])
so_name = get_so_name(version_mneumonic)
cpo_name = get_cpo_name(version_mneumonic)

target_bindir = os.path.dirname(sys.executable)
target_root = os.path.dirname(target_bindir)

so_targets = [t for t in glob.glob("{}/**/{}".format(target_root, so_name), recursive=True)]
cpo_targets = [t for t in glob.glob("{}/**/{}".format(target_root, cpo_name), recursive=True)]
if len(so_targets) == 0:
print("ERROR: did not find shared object file {} in {}".format(so_name, target_root))
return 1
if len(cpo_targets) == 0:
print("ERROR: did not find executable file {} in {}".format(cpo_name, target_root))
return 1

#
# Find sources so_source, cpo_target
#
bindir = os.path.join(cos, "cplex", "bin")
platform = get_cos_archname(bindir, so_name)
if platform is None:
print(
"ERROR: unable to determine COS architecture mneumonic by searching for {} in {}. Please check your COS installation".format(
so_name, bindir))
return 1

so_source = os.path.join(cos, "cplex", "bin", platform, so_name)
cpo_source = os.path.join(cos, "cpoptimizer", "bin", platform, cpo_name)

ok = check_file(so_source, False)
ok = check_file(cpo_source, False) and ok
for f in so_targets + cpo_targets:
ok = check_file(f, True)

if not ok:
return 1

#
# Make copies
#
copies = tuple((so_source, t) for t in so_targets) + tuple((cpo_source, t) for t in cpo_targets)

print("Performing copies:")
code = 0
try:
for s, t in copies:
print(" {} -> {}".format(s, t))
shutil.copyfile(s, t)
except EnvironmentError as e:
print("ERROR: Could not upgrade packages due to an EnvironmentError: {}".format(e))
print("Consider using the `--user` option or check the permissions.")
code = e.code
except Exception as e:
print("Error: Something went wrong during copying: {}".format(e))
code = 1

return code


def config(args):
if args.cos_root is not None:
if not os.path.isdir(args.cos_root):
print("ERROR: '{}' does not exist or is not a directory".format(args.cos_root))
code = 1
else:
code = copy_so(args.cos_root)

sys.exit(code)


def main():
parser = argparse.ArgumentParser(prog="docplex")

subparsers = parser.add_subparsers(dest="command", title="commands", metavar="<command>")

parser_command1 = subparsers.add_parser("config", help="Manage configuration")
parser_command1.add_argument("--upgrade", dest="cos_root", type=str,
help="Upgrade this module from a Cplex Optimization Studio installation ",
metavar="<cplex_studio_location>", required=True)
parser_command1.set_defaults(func=config)

args = parser.parse_args()

if args.command is None:
parser.print_help()
else:
args.func(args)


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion docplex/util/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,9 +621,9 @@ def update_solve_details(self, details, transaction=None):
def record_in_history(self, details):
self.recorded_solve_details_count += 1
self.logger.debug(lazy(lambda: f"record in history: {json.dumps(details)}"))
current_ts = round(time.time(), self.record_history_time_decimals)
for f in self.record_history_fields:
if f in details:
current_ts = round(time.time(), self.record_history_time_decimals)
current_history_element = [current_ts, details[f]]
l = self.record_history.get(f, deque([], self.record_history_size))
self.record_history[f] = l
Expand Down
6 changes: 3 additions & 3 deletions docplex/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
# This file is generated !
# See script tools/gen_version.py
docplex_version_major = 2
docplex_version_minor = 28
docplex_version_micro = 240
docplex_version_string = '2.28.240'
docplex_version_minor = 29
docplex_version_micro = 241
docplex_version_string = '2.29.241'

latest_cplex_major = 22
latest_cplex_minor = 1
Loading