Repository: Pyomo/pyomo

Issue:
PyNumero support on Windows
We need to make sure PyNumero installs/runs on Windows and make sure any extra installation steps are well documented. Some discussion on this was started in #1253. When this is resolved we also need to make sure to enable the tests currently being skipped on Windows.
PyNumero support on Windows
We need to make sure PyNumero installs/runs on Windows and make sure any extra installation steps are well documented. Some discussion on this was started in #1253. When this is resolved we also need to make sure to enable the tests currently being skipped on Windows.


Discussion:
@blnicho  the easiest way to get those tests running would be to update the conda recipe. In fact, if I remember correctly thats how the travis tests are run. First it gets the libraries from conda-forge and then pyomo uses them. One will need then need to push my latest version of the cmake project to   https://github.com/conda-forge/pynumero_libraries-feedstock and also edit the recipe to manage the windows built. The cmake project works on windows. I have tested it few months ago.
I will update the repo https://github.com/santiagoropb/pynumero_libraries this coming weekend for you to get that cmake project
@santiagoropb thanks for the guidance!
@blnicho I updated the repo with the cmake project. Instructions are provided in the README for all different options available (IPOPT, AMPL-MP, ASL, HSL). I tested building the project from clean with a conda environment with its own gcc and cmake and all the options worked fine. Next thing will be to make a release of that project and link it with the conda recipe. 
@blnicho @jsiirola  do you have a windows machine to test if the conda recipe is working on windows? I reworked the recipe yesterday and now builds a .dll for windows so the command:

`conda install -c conda-forge pynumero_libraries`

should now work on windows as well. I dont have a machine to test if ctypes can successfully use the .dll in pynumero. 

https://anaconda.org/conda-forge/pynumero_libraries

@santiagoropb I tried installing the pynumero_libraries package using that conda command but I think there is still a step missing in the installation instructions for moving the .dll downloaded by conda into the libs folder where PyNumero expects them to be. Or maybe a better solution might be for PyNumero to search more broadly for the .dll? 

Once I moved the .dll I was able to run all of the PyNumero examples successfully on Windows


@blnicho  the easiest way to get those tests running would be to update the conda recipe. In fact, if I remember correctly thats how the travis tests are run. First it gets the libraries from conda-forge and then pyomo uses them. One will need then need to push my latest version of the cmake project to   https://github.com/conda-forge/pynumero_libraries-feedstock and also edit the recipe to manage the windows built. The cmake project works on windows. I have tested it few months ago.
I will update the repo https://github.com/santiagoropb/pynumero_libraries this coming weekend for you to get that cmake project
@santiagoropb thanks for the guidance!
@blnicho I updated the repo with the cmake project. Instructions are provided in the README for all different options available (IPOPT, AMPL-MP, ASL, HSL). I tested building the project from clean with a conda environment with its own gcc and cmake and all the options worked fine. Next thing will be to make a release of that project and link it with the conda recipe. 
@blnicho @jsiirola  do you have a windows machine to test if the conda recipe is working on windows? I reworked the recipe yesterday and now builds a .dll for windows so the command:

`conda install -c conda-forge pynumero_libraries`

should now work on windows as well. I dont have a machine to test if ctypes can successfully use the .dll in pynumero. 

https://anaconda.org/conda-forge/pynumero_libraries

@santiagoropb I tried installing the pynumero_libraries package using that conda command but I think there is still a step missing in the installation instructions for moving the .dll downloaded by conda into the libs folder where PyNumero expects them to be. Or maybe a better solution might be for PyNumero to search more broadly for the .dll? 

Once I moved the .dll I was able to run all of the PyNumero examples successfully on Windows



Resolving patch:
diff --git a/pyomo/contrib/pynumero/extensions/utils.py b/pyomo/contrib/pynumero/extensions/utils.py
--- a/pyomo/contrib/pynumero/extensions/utils.py
+++ b/pyomo/contrib/pynumero/extensions/utils.py
@@ -14,9 +14,14 @@
 
 def find_pynumero_library(library_name):
 
-    asl_path = find_library(library_name)
-    if asl_path is not None:
-        return asl_path
+    lib_path = find_library(library_name)
+    if lib_path is not None:
+        return lib_path
+
+    # On windows the library is prefixed with 'lib'
+    lib_path = find_library('lib'+library_name)
+    if lib_path is not None:
+        return lib_path
     else:
         # try looking into extensions directory now
         file_path = os.path.abspath(__file__)
@@ -29,10 +34,10 @@ def find_pynumero_library(library_name):
         else:
             libname = 'lib/Linux/lib{}.so'.format(library_name)
 
-        asl_lib_path = os.path.join(dir_path, libname)
+        lib_path = os.path.join(dir_path, libname)
 
-        if os.path.exists(asl_lib_path):
-            return asl_lib_path
+        if os.path.exists(lib_path):
+            return lib_path
     return None
 
 


Test patch:
diff --git a/.github/workflows/win_python_matrix_test.yml b/.github/workflows/win_python_matrix_test.yml
--- a/.github/workflows/win_python_matrix_test.yml
+++ b/.github/workflows/win_python_matrix_test.yml
@@ -46,6 +46,20 @@ jobs:
         $env:ADDITIONAL_CF_PKGS=$env:ADDITIONAL_CF_PKGS + " glpk ipopt"
         $env:EXP = $env:CONDAFORGE + $env:ADDITIONAL_CF_PKGS
         Invoke-Expression $env:EXP
+        $env:PYNUMERO = $env:CONDAFORGE + " pynumero_libraries"
+        Write-Host ("")
+        Write-Host ("Try to install Pynumero_libraries...")
+        Write-Host ("")
+        try
+        {
+            Invoke-Expression $env:PYNUMERO
+        }
+        catch
+        {
+            Write-Host ("####################################################")
+            Write-Host ("WARNING: Pynumero_libraries is not available for Python ${{matrix.python-version}}")
+            Write-Host ("####################################################")
+        }
         Write-Host ("")
         Write-Host ("Installing GAMS")
         Write-Host ("")
@@ -75,7 +89,7 @@ jobs:
         Write-Host "Pyomo download-extensions"
         Write-Host ("")
         Invoke-Expression "pyomo download-extensions"
-        
+
     - name: Run nightly tests with test.pyomo
       shell: pwsh
       run: |
diff --git a/pyomo/contrib/pynumero/interfaces/tests/test_nlp.py b/pyomo/contrib/pynumero/interfaces/tests/test_nlp.py
--- a/pyomo/contrib/pynumero/interfaces/tests/test_nlp.py
+++ b/pyomo/contrib/pynumero/interfaces/tests/test_nlp.py
@@ -345,7 +345,7 @@ def execute_extended_nlp_interface(self, anlp):
     expected_hess = np.asarray(expected_hess, dtype=np.float64)
     self.assertTrue(np.array_equal(dense_hess, expected_hess))
 
-@unittest.skipIf(os.name in ['nt', 'dos'], "Do not test on windows")
+
 class TestAslNLP(unittest.TestCase):
     @classmethod
     def setUpClass(cls):
@@ -363,7 +363,6 @@ def test_nlp_interface(self):
         anlp = AslNLP(self.filename)
         execute_extended_nlp_interface(self, anlp)
         
-@unittest.skipIf(os.name in ['nt', 'dos'], "Do not test on windows")
 class TestAmplNLP(unittest.TestCase):
     @classmethod
     def setUpClass(cls):
@@ -441,7 +440,6 @@ def test_idxs(self):
         self.assertEqual(sum(ineq_constraint_idxs), 3)
 
 
-@unittest.skipIf(os.name in ['nt', 'dos'], "Do not test on windows")
 class TestPyomoNLP(unittest.TestCase):
     @classmethod
     def setUpClass(cls):
@@ -550,7 +548,6 @@ def test_no_objective(self):
         with self.assertRaises(NotImplementedError):
             nlp = PyomoNLP(m)
 
-@unittest.skipIf(os.name in ['nt', 'dos'], "Do not test on windows")
 class TestUtils(unittest.TestCase):
     @classmethod
     def setUpClass(cls):
diff --git a/pyomo/contrib/pynumero/sparse/tests/test_coomatrix.py b/pyomo/contrib/pynumero/sparse/tests/test_coomatrix.py
--- a/pyomo/contrib/pynumero/sparse/tests/test_coomatrix.py
+++ b/pyomo/contrib/pynumero/sparse/tests/test_coomatrix.py
@@ -21,7 +21,6 @@
 from pyomo.contrib.pynumero.sparse.coo import (diagonal_matrix,
                                                empty_matrix)
 
-@unittest.skipIf(os.name in ['nt', 'dos'], "Do not test on windows")
 class TestEmptyMatrix(unittest.TestCase):
 
     def test_constructor(self):