forked from Pyomo/pyomo
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Pyomo#3206 from eslickj/AMPLFUNC_dup_fix
AMPL solver duplicate funcadd fix
- Loading branch information
Showing
5 changed files
with
206 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# ___________________________________________________________________________ | ||
# | ||
# Pyomo: Python Optimization Modeling Objects | ||
# Copyright (c) 2008-2024 | ||
# 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 | ||
# rights in this software. | ||
# This software is distributed under the 3-clause BSD License. | ||
# ___________________________________________________________________________ | ||
|
||
|
||
def amplfunc_string_merge(amplfunc, pyomo_amplfunc): | ||
"""Merge two AMPLFUNC variable strings eliminating duplicate lines""" | ||
# Assume that the strings amplfunc and pyomo_amplfunc don't contain duplicates | ||
# Assume that the path separator is correct for the OS so we don't need to | ||
# worry about comparing Unix and Windows paths. | ||
amplfunc_lines = amplfunc.split("\n") | ||
existing = set(amplfunc_lines) | ||
for line in pyomo_amplfunc.split("\n"): | ||
# Skip lines we already have | ||
if line not in existing: | ||
amplfunc_lines.append(line) | ||
# Remove empty lines which could happen if one or both of the strings is | ||
# empty or there are two new lines in a row for whatever reason. | ||
amplfunc_lines = [s for s in amplfunc_lines if s != ""] | ||
return "\n".join(amplfunc_lines) | ||
|
||
|
||
def amplfunc_merge(env): | ||
"""Merge AMPLFUNC and PYOMO_AMPLFUNC in an environment var dict""" | ||
return amplfunc_string_merge(env.get("AMPLFUNC", ""), env.get("PYOMO_AMPLFUNC", "")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
# ___________________________________________________________________________ | ||
# | ||
# Pyomo: Python Optimization Modeling Objects | ||
# Copyright (c) 2008-2024 | ||
# 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 | ||
# rights in this software. | ||
# This software is distributed under the 3-clause BSD License. | ||
# ___________________________________________________________________________ | ||
|
||
import pyomo.common.unittest as unittest | ||
from pyomo.solvers.amplfunc_merge import amplfunc_string_merge, amplfunc_merge | ||
|
||
|
||
class TestAMPLFUNCStringMerge(unittest.TestCase): | ||
def test_merge_no_dup(self): | ||
s1 = "my/place/l1.so\nanother/place/l1.so" | ||
s2 = "my/place/l2.so" | ||
sm = amplfunc_string_merge(s1, s2) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 3) | ||
# The order of lines should be maintained with the second string | ||
# following the first | ||
self.assertEqual(sm_list[0], "my/place/l1.so") | ||
self.assertEqual(sm_list[1], "another/place/l1.so") | ||
self.assertEqual(sm_list[2], "my/place/l2.so") | ||
|
||
def test_merge_empty1(self): | ||
s1 = "" | ||
s2 = "my/place/l2.so" | ||
sm = amplfunc_string_merge(s1, s2) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 1) | ||
self.assertEqual(sm_list[0], "my/place/l2.so") | ||
|
||
def test_merge_empty2(self): | ||
s1 = "my/place/l2.so" | ||
s2 = "" | ||
sm = amplfunc_string_merge(s1, s2) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 1) | ||
self.assertEqual(sm_list[0], "my/place/l2.so") | ||
|
||
def test_merge_empty_both(self): | ||
s1 = "" | ||
s2 = "" | ||
sm = amplfunc_string_merge(s1, s2) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 1) | ||
self.assertEqual(sm_list[0], "") | ||
|
||
def test_merge_bad_type(self): | ||
self.assertRaises(AttributeError, amplfunc_string_merge, "", 3) | ||
self.assertRaises(AttributeError, amplfunc_string_merge, 3, "") | ||
self.assertRaises(AttributeError, amplfunc_string_merge, 3, 3) | ||
self.assertRaises(AttributeError, amplfunc_string_merge, None, "") | ||
self.assertRaises(AttributeError, amplfunc_string_merge, "", None) | ||
self.assertRaises(AttributeError, amplfunc_string_merge, 2.3, "") | ||
self.assertRaises(AttributeError, amplfunc_string_merge, "", 2.3) | ||
|
||
def test_merge_duplicate1(self): | ||
s1 = "my/place/l1.so\nanother/place/l1.so" | ||
s2 = "my/place/l1.so\nanother/place/l1.so" | ||
sm = amplfunc_string_merge(s1, s2) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 2) | ||
# The order of lines should be maintained with the second string | ||
# following the first | ||
self.assertEqual(sm_list[0], "my/place/l1.so") | ||
self.assertEqual(sm_list[1], "another/place/l1.so") | ||
|
||
def test_merge_duplicate2(self): | ||
s1 = "my/place/l1.so\nanother/place/l1.so" | ||
s2 = "my/place/l1.so" | ||
sm = amplfunc_string_merge(s1, s2) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 2) | ||
# The order of lines should be maintained with the second string | ||
# following the first | ||
self.assertEqual(sm_list[0], "my/place/l1.so") | ||
self.assertEqual(sm_list[1], "another/place/l1.so") | ||
|
||
def test_merge_extra_linebreaks(self): | ||
s1 = "\nmy/place/l1.so\nanother/place/l1.so\n" | ||
s2 = "\nmy/place/l1.so\n\n" | ||
sm = amplfunc_string_merge(s1, s2) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 2) | ||
# The order of lines should be maintained with the second string | ||
# following the first | ||
self.assertEqual(sm_list[0], "my/place/l1.so") | ||
self.assertEqual(sm_list[1], "another/place/l1.so") | ||
|
||
|
||
class TestAMPLFUNCMerge(unittest.TestCase): | ||
def test_merge_no_dup(self): | ||
env = { | ||
"AMPLFUNC": "my/place/l1.so\nanother/place/l1.so", | ||
"PYOMO_AMPLFUNC": "my/place/l2.so", | ||
} | ||
sm = amplfunc_merge(env) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 3) | ||
self.assertEqual(sm_list[0], "my/place/l1.so") | ||
self.assertEqual(sm_list[1], "another/place/l1.so") | ||
self.assertEqual(sm_list[2], "my/place/l2.so") | ||
|
||
def test_merge_empty1(self): | ||
env = {"AMPLFUNC": "", "PYOMO_AMPLFUNC": "my/place/l2.so"} | ||
sm = amplfunc_merge(env) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 1) | ||
self.assertEqual(sm_list[0], "my/place/l2.so") | ||
|
||
def test_merge_empty2(self): | ||
env = {"AMPLFUNC": "my/place/l2.so", "PYOMO_AMPLFUNC": ""} | ||
sm = amplfunc_merge(env) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 1) | ||
self.assertEqual(sm_list[0], "my/place/l2.so") | ||
|
||
def test_merge_empty_both(self): | ||
env = {"AMPLFUNC": "", "PYOMO_AMPLFUNC": ""} | ||
sm = amplfunc_merge(env) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 1) | ||
self.assertEqual(sm_list[0], "") | ||
|
||
def test_merge_duplicate1(self): | ||
env = { | ||
"AMPLFUNC": "my/place/l1.so\nanother/place/l1.so", | ||
"PYOMO_AMPLFUNC": "my/place/l1.so\nanother/place/l1.so", | ||
} | ||
sm = amplfunc_merge(env) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 2) | ||
self.assertEqual(sm_list[0], "my/place/l1.so") | ||
self.assertEqual(sm_list[1], "another/place/l1.so") | ||
|
||
def test_merge_no_pyomo(self): | ||
env = {"AMPLFUNC": "my/place/l1.so\nanother/place/l1.so"} | ||
sm = amplfunc_merge(env) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 2) | ||
self.assertEqual(sm_list[0], "my/place/l1.so") | ||
self.assertEqual(sm_list[1], "another/place/l1.so") | ||
|
||
def test_merge_no_user(self): | ||
env = {"PYOMO_AMPLFUNC": "my/place/l1.so\nanother/place/l1.so"} | ||
sm = amplfunc_merge(env) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 2) | ||
self.assertEqual(sm_list[0], "my/place/l1.so") | ||
self.assertEqual(sm_list[1], "another/place/l1.so") | ||
|
||
def test_merge_nothing(self): | ||
env = {} | ||
sm = amplfunc_merge(env) | ||
sm_list = sm.split("\n") | ||
self.assertEqual(len(sm_list), 1) | ||
self.assertEqual(sm_list[0], "") |