Skip to content

Add external function library #3648

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

Merged
merged 44 commits into from
Aug 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
bc29a64
Add external fuction library
Jun 25, 2025
427ae10
Add external funcion docs
Jun 26, 2025
93a95cf
Run black
Jun 26, 2025
4a146b0
Fix doc math cases
Jun 26, 2025
fa0a9ca
Fix cases more
Jun 26, 2025
533ddb1
Fix wonky underscore
mrmundt Jun 26, 2025
1ce0c10
Merge branch 'main' into func_lib
blnicho Jun 28, 2025
967a111
Add figs for sinc
Jun 30, 2025
9c6c6b6
Merge branch 'func_lib' of https://github.com/eslickj/pyomo into func…
Jun 30, 2025
79d0d55
Merge branch 'main' into func_lib
mrmundt Jul 1, 2025
4d115c8
Merge branch 'main' of https://github.com/pyomo/pyomo into func_lib
Jul 7, 2025
d76ea88
Add signed square root approximation
Jul 7, 2025
f4fb50a
Minor test formatting
Jul 7, 2025
a74351c
Test formatting and sqrt test
Jul 7, 2025
a0f92fa
Update index.rst
eslickj Jul 8, 2025
16be337
Fix copy-paste error in doc
eslickj Jul 9, 2025
a5f3770
Merge branch 'main' of https://github.com/pyomo/pyomo into func_lib
Jul 24, 2025
5b86b0a
Rename function library
Jul 24, 2025
5d63a10
Update doc/OnlineDocs/explanation/modeling_utils/external_functions/i…
eslickj Jul 24, 2025
4db46dc
Update doc/OnlineDocs/explanation/modeling_utils/external_functions/i…
eslickj Jul 24, 2025
e2302d0
Update doc/OnlineDocs/explanation/modeling_utils/external_functions/i…
eslickj Jul 24, 2025
dcc87f2
Update doc/OnlineDocs/explanation/modeling_utils/external_functions/i…
eslickj Jul 24, 2025
a7f5333
Update doc/OnlineDocs/explanation/modeling_utils/external_functions/i…
eslickj Jul 24, 2025
1c3c6f2
Update doc/OnlineDocs/explanation/modeling_utils/external_functions/i…
eslickj Jul 24, 2025
bf8ad36
Merge branch 'func_lib' of https://github.com/eslickj/pyomo into func…
Jul 24, 2025
5e4cb24
Doc update
Jul 24, 2025
0eac381
doc update 2
Jul 24, 2025
1d45a86
Reordering to keep in alphabetical order
blnicho Jul 26, 2025
f2547c3
Merge branch 'main' into func_lib
blnicho Jul 26, 2025
857b48b
Fixing section header in index.rst
blnicho Jul 27, 2025
66161c2
Update index.rst fix underscore
eslickj Jul 28, 2025
f8e4857
Attempt to fix math in index.rst
mrmundt Jul 31, 2025
fc0a021
Edited wrong lines in index.rst
mrmundt Jul 31, 2025
f2476b2
Missed two instances
mrmundt Jul 31, 2025
a6be015
Merge branch 'func_lib' of github.com:eslickj/pyomo into eslick-build
mrmundt Jul 31, 2025
ee7d13f
Print out skip reasons
mrmundt Jul 31, 2025
936ec3c
Flipped - should be not flib
mrmundt Jul 31, 2025
ca1b43a
Rename the library
mrmundt Jul 31, 2025
ac3a579
Correct docs for new name
mrmundt Jul 31, 2025
bf21a22
Extra space
mrmundt Jul 31, 2025
58b6451
Merge branch 'main' into func_lib
jsiirola Aug 1, 2025
4a7ced2
Merge branch 'main' of https://github.com/pyomo/pyomo into func_lib
Aug 2, 2025
4e58993
Rerename library
Aug 2, 2025
a84f9e4
Fix library name in find_library calls
Aug 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 114 additions & 0 deletions doc/OnlineDocs/explanation/modeling_utils/aslfunctions/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
aslfunctions
============

Pyomo provides a set of AMPL user-defined functions that commonly occur but cannot be easily written as Pyomo expressions.

Using These AMPL External Functions
-----------------------------------

Build
~~~~~

You must build the Pyomo extensions to use these functions. Run ``pyomo build-extensions`` in the terminal and make sure the ``aslfunctions`` build status is "ok."

Example
~~~~~~~

.. doctest::

>>> import pyomo.environ as pyo
>>> from pyomo.common.fileutils import find_library
>>> flib = find_library("aslfunctions")
>>> m = pyo.ConcreteModel(name = 'AMPLExternalFunctions')
>>> m.sinc = pyo.ExternalFunction(library=flib, function="sinc")
>>> m.x = pyo.Var()
>>> m.z = pyo.Var()
>>> m.constraint = pyo.Constraint(expr = m.z == m.sinc(m.x))

Functions
---------

sinc(x)
~~~~~~~

This function is defined as:

.. math::

\text{sinc}(x) = \begin{cases}
\sin(x) / x & \text{if } x \neq 0 \\
1 & \text{if } x = 0
\end{cases}

In this implementation, the region :math:`-0.1 < x < 0.1` is replaced by a Taylor series with enough terms that the function should be at least :math:`C^2` smooth. The difference between the function and the Tayor series is near the limits of machine precision, about :math:`1 \times 10^{-16}` for the function value, :math:`1 \times 10^{-16}` for the first derivative, and :math:`1 \times 10^{-14}` for the second derivative.

These figures show the sinc(x) function, the Taylor series and where the Taylor series is used.

.. image:: figs/sinc_f.png

.. image:: figs/sinc_fx.png

.. image:: figs/sinc_fxx.png


sgnsqr(x)
~~~~~~~~~

This function is defined as:

.. math::

\text{sgnsqr}(x) = \text{sgn}(x)x^2

This function is only :math:`C^1` smooth because at 0 the second derivative is undefined and the jumps from -2 to 2.

sgnsqr_c4(x)
~~~~~~~~~~~~


This function is defined as:

.. math::

\operatorname{sgnsqr\_c4}(x) =
\begin{cases}
\operatorname{sgn}(x)\,x^2 & \text{if } |x| \ge 0.1, \\
\displaystyle\sum_{i=0}^{11} c_i x^i & \text{if } |x| < 0.1
\end{cases}

This function is :math:`C^4` smooth. The region :math:`-0.1 < x < 0.1` is replaced by an 11th order polynomial that approximates :math:`\text{sgn}(x)x^2`. This function has well behaved derivatives at :math:`x=0`. If you need to use this function with very small numbers and high accuracy is important, you can scale the argument up (e.g. :math:`\operatorname{sgnsqr\_c4}(sx)/s^2`).

These figures show the sgnsqr(x) function compared to the smooth approximation sgnsqr_c4(x).

.. image:: figs/sgnsqr_f.png

.. image:: figs/sgnsqr_fx.png

.. image:: figs/sgnsqr_fxx.png


sgnsqrt_c4(x)
~~~~~~~~~~~~~

This function is a signed square root approximation defined as:

.. math::

\operatorname{sgnsqrt\_c4}(x) =
\begin{cases}
\operatorname{sgn}(x)\,|x|^{0.5} & \text{if } |x| \ge 0.1, \\
\displaystyle\sum_{i=0}^{11} c_i x^i & \text{if } |x| < 0.1
\end{cases}

This function is :math:`C^4` smooth. The region :math:`-0.1 < x < 0.1` is replaced by an 11th order polynomial that approximates :math:`\text{sgn}(x)|x|^{0.5}`. This function has well behaved derivatives at :math:`x=0`. If you need to use this function with very small numbers and high accuracy is important, you can scale the argument up (e.g. :math:`\operatorname{sgnsqrt\_c4}(sx)/s^{0.5}`).

These figures show the signed square root function compared to the smooth approximation sgnsqrt_c4(x).

.. image:: figs/sgnsqrt_c4_err.png

.. image:: figs/sgnsqrt_c4_f.png

.. image:: figs/sgnsqrt_c4_fx.png

.. image:: figs/sgnsqrt_c4_fxx.png

2 changes: 1 addition & 1 deletion doc/OnlineDocs/explanation/modeling_utils/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Modeling Utilities
latex_printer
preprocessing
scaling

aslfunctions/index


..
Expand Down
10 changes: 10 additions & 0 deletions pyomo/contrib/aslfunctions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2025
# 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.
# ___________________________________________________________________________
32 changes: 32 additions & 0 deletions pyomo/contrib/aslfunctions/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2025
# 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 sys
from pyomo.common.cmake_builder import build_cmake_project


def build_aslfunctions(user_args=[], parallel=None):
return build_cmake_project(
targets=["src"],
package_name="aslfunctions",
description="Useful AMPL external functions",
user_args=["-DBUILD_AMPLASL_IF_NEEDED=ON"] + user_args,
parallel=parallel,
)


class LibASLFunctionsBuilder(object):
def __call__(self, parallel):
return build_aslfunctions(parallel=parallel)


if __name__ == "__main__":
build_aslfunctions(sys.argv[1:])
17 changes: 17 additions & 0 deletions pyomo/contrib/aslfunctions/plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2025
# 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.
# ___________________________________________________________________________

from pyomo.common.extensions import ExtensionBuilderFactory
from pyomo.contrib.aslfunctions.build import LibASLFunctionsBuilder


def load():
ExtensionBuilderFactory.register("aslfunctions")(LibASLFunctionsBuilder)
43 changes: 43 additions & 0 deletions pyomo/contrib/aslfunctions/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2025
# 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.
# ___________________________________________________________________________

cmake_minimum_required(VERSION 3.0...3.31)
# This was developed against CMake 3.0, and appears to comply with 3.5

PROJECT( aslfunctions )

INCLUDE(
"${CMAKE_CURRENT_SOURCE_DIR}/../../ampl_function_demo/src/FindASL.cmake")

# Targets in this project
OPTION(BUILD_EXTERNAL_FCN_LIBRARY
"Build the ASL external function example library" ON)

IF( BUILD_EXTERNAL_FCN_LIBRARY )
ADD_LIBRARY( aslfunctions SHARED "functions.cpp" )
TARGET_LINK_LIBRARIES( aslfunctions
PUBLIC ${ASL_LIBRARY} ${CMAKE_DL_LIBS})
TARGET_INCLUDE_DIRECTORIES( aslfunctions
PUBLIC ${ASL_INCLUDE_DIR}
INTERFACE . )
# If you need a CPP directive defined when building the library (e.g.,
# for managing __declspec(dllimport) under Windows) uncomment the
# following:
#TARGET_COMPILE_DEFINITIONS( aslfunctions PRIVATE BUILDING_ASL_DEMO )
#SET_TARGET_PROPERTIES( aslfunctions PROPERTIES ENABLE_EXPORTS 1 )
INSTALL( TARGETS aslfunctions LIBRARY DESTINATION lib
RUNTIME DESTINATION lib )
IF( BUILD_AMPLASL )
# If we are building AMPL/asl (from FindASL), it is possible that we
# are linking against it, so we will add the appropriate dependency
add_dependencies(aslfunctions ampl_asl)
ENDIF()
ENDIF()
Loading
Loading