Skip to content
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
904 changes: 300 additions & 604 deletions .github/workflows/ci.yaml

Large diffs are not rendered by default.

737 changes: 0 additions & 737 deletions .github/workflows/ql-benchmarks.yaml

This file was deleted.

82 changes: 6 additions & 76 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
##############################################################################
#
#
#
# This file is part of QuantLibAAD, an adaptor module to enable using XAD with
# QuantLib. XAD is a fast and comprehensive C++ library for
# automatic differentiation.
#
# Copyright (C) 2010-2026 Xcelerit Computing Ltd.
# Copyright (C) 2010-2024 Xcelerit Computing Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
Expand All @@ -19,87 +19,17 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
##############################################################################

option(QLAAD_DISABLE_AAD "Disable using XAD for QuantLib's Real, allowing to run samples with double" OFF)
option(QLAAD_ENABLE_FORGE "Enable Forge JIT backend via xad-forge" OFF)
option(QLAAD_USE_FORGE_CAPI "Use Forge C API instead of C++ API for binary compatibility" OFF)

# Backward compatibility for old QLRISKS_* options
foreach(_opt IN ITEMS
DISABLE_AAD
ENABLE_FORGE
USE_FORGE_CAPI
)
if(DEFINED CACHE{QLRISKS_${_opt}})
set(QLAAD_${_opt} ${QLRISKS_${_opt}} CACHE BOOL "" FORCE)
message(WARNING
"CMake option QLRISKS_${_opt} is deprecated. "
"Please use QLAAD_${_opt} instead."
)
endif()
endforeach()

add_subdirectory(ql)
if(MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
add_subdirectory(Examples)

##############################################################################
# QLAAD-Forge integration via xad-forge
# NOTE: This must be defined BEFORE test-suite so tests can link to it
##############################################################################

if(QLAAD_ENABLE_FORGE)
message(STATUS "QLAAD-Forge: Looking for xad-forge...")

# Pass through the C API option to xad-forge
set(XAD_FORGE_USE_CAPI ${QLRISKS_USE_FORGE_CAPI} CACHE BOOL "" FORCE)

# Option 1: Check if xad-forge was added as subdirectory
if(TARGET xad-forge)
message(STATUS "QLAAD-Forge: Found xad-forge target (subdirectory mode)")
set(XAD_FORGE_FOUND TRUE)
endif()

# Option 2: Try find_package for pre-built xad-forge
if(NOT XAD_FORGE_FOUND)
find_package(xad-forge CONFIG QUIET)
if(xad-forge_FOUND)
message(STATUS "QLAAD-Forge: Found xad-forge package (pre-built mode)")
set(XAD_FORGE_FOUND TRUE)
endif()
endif()

if(XAD_FORGE_FOUND)
# Create qlaad-forge as an INTERFACE library wrapping xad-forge
add_library(qlaad-forge INTERFACE)
add_library(QLAAD::forge ALIAS qlaad-forge)

target_link_libraries(qlaad-forge INTERFACE
XADForge::xad-forge
)

target_compile_definitions(qlaad-forge INTERFACE QLAAD_HAS_FORGE=1)

message(STATUS "QLAAD-Forge: Configured with xad-forge")
else()
message(STATUS "QLAAD-Forge: xad-forge not found - ForgeBackend will not be available")
message(STATUS "QLAAD-Forge: To enable, either:")
message(STATUS " 1. Add xad-forge as subdirectory")
message(STATUS " 2. Set CMAKE_PREFIX_PATH to xad-forge installation")
endif()
if(NOT QLAAD_DISABLE_AAD)
# the test suite is not supporting double
add_subdirectory(test-suite)
endif()

##############################################################################
# Test suite (after QLAAD::forge is defined)
##############################################################################

# Add test-suite if:
# 1. AAD is enabled (for XAD-based tests and benchmarks), OR
# 2. FD benchmark is requested (works with plain double)
if(NOT QLAAD_DISABLE_AAD OR QLAAD_BUILD_BENCHMARK_FD)
add_subdirectory(test-suite)
endif()
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ This repository contains integration headers, examples, and tests required
for this integration.
It is not usable stand-alone.

## JIT Compilation Support

XAD is optimized for computing sensitivities efficiently in a single evaluation pass using adjoint mode. For workflows that require repeated evaluation across many scenarios—such as Monte Carlo simulations, XVA calculations, regulatory stress testing, or scenario-based risk analysis—XAD also supports recording computations into a [`JITGraph`](https://auto-differentiation.github.io/xad/ref/jit/) that can be compiled and re-evaluated efficiently using a JIT backend. The [xad-forge](https://github.com/da-roth/xad-forge) library provides Forge-based backends for this purpose, including vectorized AVX execution. See the [xad-forge README](https://github.com/da-roth/xad-forge#when-to-use-jit) for guidance on when JIT compilation is beneficial.

The repository includes a [swaption benchmark](.github/workflows/ql-benchmarks.yaml) that demonstrates a hybrid workflow: curve bootstrapping with XAD's tape, followed by Monte Carlo pricing with JIT-compiled evaluation, comparing tape-based, JIT, and JIT-AVX performance.

## Getting Started

For detailed build instructions with [XAD](https://auto-differentiation.github.io) and [QuantLib](https://www.quantlib.org), please refer to the [XAD documentation site](https://auto-differentiation.github.io/quantlib-risks/cxx/).
Expand Down
24 changes: 5 additions & 19 deletions ql/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# QuantLib. XAD is a fast and comprehensive C++ library for
# automatic differentiation.
#
# Copyright (C) 2010-2026 Xcelerit Computing Ltd.
# Copyright (C) 2010-2024 Xcelerit Computing Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
Expand All @@ -23,24 +23,23 @@
##############################################################################

set(QLAAD_HEADERS
qlaad.hpp
QLAAD.hpp
)
add_library(QuantLibAAD INTERFACE)
add_library(QuantLib-Risks ALIAS QuantLibAAD) # for compatibility
target_include_directories(QuantLibAAD INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
$<INSTALL_INTERFACE:${QL_INSTALL_INCLUDEDIR}>
)
target_compile_features(QuantLibAAD INTERFACE cxx_std_14)
if(NOT QLAAD_DISABLE_AAD)
target_compile_definitions(QuantLibAAD INTERFACE QL_INCLUDE_FIRST=ql/qlaad.hpp)
target_compile_definitions(QuantLibAAD INTERFACE QL_INCLUDE_FIRST=ql/QLAAD.hpp)
else()
target_compile_definitions(QuantLibAAD INTERFACE QLAAD_DISABLE_AAD=1)
endif()
target_link_libraries(QuantLibAAD INTERFACE XAD::xad)
if(MSVC)
target_compile_options(QuantLibAAD INTERFACE /bigobj)
endif()
target_link_libraries(QuantLibAAD INTERFACE XAD::xad)
set_target_properties(QuantLibAAD PROPERTIES
EXPORT_NAME QuantLibAAD
)
Expand All @@ -62,7 +61,7 @@ endforeach()
#

set(QLAAD_INSTALL_CMAKEDIR "lib/cmake/QuantLibAAD" CACHE STRING
"Installation directory for CMake scripts for QuantLib AAD")
"Installation directory for CMake scripts for QuantLib XAD")

include(CMakePackageConfigHelpers)
configure_file("../cmake/QuantLibAADConfig.cmake.in"
Expand All @@ -76,16 +75,3 @@ configure_package_config_file("../cmake/QuantLibAADConfig.cmake.in"
install(FILES "${PROJECT_BINARY_DIR}/cmake/QuantLibAADConfig.cmake"
DESTINATION "${QLAAD_INSTALL_CMAKEDIR}"
)

# the following is purely for compatibility - it will be removed in the near future
configure_file("../cmake/QuantLibAADConfig.cmake.in"
"${PROJECT_BINARY_DIR}/cmake/QuantLib-RisksConfig.cmake"
COPYONLY
)
configure_package_config_file("../cmake/QuantLibAADConfig.cmake.in"
"${PROJECT_BINARY_DIR}/cmake/QuantLib-RisksConfig.cmake"
INSTALL_DESTINATION "${QLAAD_INSTALL_CMAKEDIR}"
)
install(FILES "${PROJECT_BINARY_DIR}/cmake/QuantLib-RisksConfig.cmake"
DESTINATION "${QLAAD_INSTALL_CMAKEDIR}"
)
89 changes: 3 additions & 86 deletions test-suite/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
option(QLAAD_BUILD_TEST_SUITE "Build the QuantLibAAD test suite" OFF)
option(QLAAD_ENABLE_FORGE_TESTS "Enable Forge JIT tests (requires Forge)" OFF)

set(QLAAD_TEST_SOURCES
americanoption_xad.cpp
barrieroption_xad.cpp
Expand All @@ -12,104 +9,24 @@ set(QLAAD_TEST_SOURCES
forwardrateagreement_xad.cpp
hestonmodel_xad.cpp
swap_xad.cpp

utilities_xad.cpp
quantlibtestsuite_xad.cpp
)

# Forge JIT tests - require Forge's native code backend
# Tests QuantLib-specific JIT functionality (swaption pricing pipeline)
set(QLAAD_FORGE_TESTS_ENABLED FALSE)
if(QLAAD_ENABLE_FORGE_TESTS AND TARGET QLAAD::forge)
message(STATUS "QLAAD test-suite: Adding Forge JIT tests (native code backend)")
list(APPEND QLAAD_TEST_SOURCES swaption_jit_pipeline_xad.cpp)
set(QLAAD_FORGE_TESTS_ENABLED TRUE)
elseif(QLAAD_ENABLE_FORGE_TESTS)
message(WARNING "QLAAD test-suite: QLAAD_ENABLE_FORGE_TESTS=ON but QLAAD::forge not available")
endif()

set(QLAAD_TEST_HEADERS utilities_xad.hpp)

if(QL_BUILD_TEST_SUITE OR QLAAD_BUILD_TEST_SUITE)
if(QL_BUILD_TEST_SUITE)
add_executable(QuantLibAAD_test_suite ${QLAAD_TEST_SOURCES} ${QLAAD_TEST_HEADERS})
set_target_properties(QuantLibAAD_test_suite PROPERTIES OUTPUT_NAME "quantlib-aad-test-suite")
set_target_properties(QuantLibAAD_test_suite PROPERTIES OUTPUT_NAME "QuantLibAAD-test-suite")
if (NOT Boost_USE_STATIC_LIBS)
target_compile_definitions(QuantLibAAD_test_suite PRIVATE BOOST_ALL_DYN_LINK)
endif()
target_link_libraries(QuantLibAAD_test_suite PRIVATE
ql_library
${QL_THREAD_LIBRARIES})

# ONLY link to Forge if Forge tests are actually enabled
# This is important because linking Forge brings in AVX2-compiled code
# which can cause ODR violations if not properly isolated
if(QLAAD_FORGE_TESTS_ENABLED)
message(STATUS "QLAAD test-suite: Linking QLAAD::forge (Forge tests enabled)")
target_link_libraries(QuantLibAAD_test_suite PRIVATE QLAAD::forge)
target_compile_definitions(QuantLibAAD_test_suite PRIVATE QLAAD_HAS_FORGE=1)
else()
message(STATUS "QLAAD test-suite: NOT linking Forge (Forge tests disabled)")
endif()

if (QL_INSTALL_TEST_SUITE)
install(TARGETS QuantLibAAD_test_suite RUNTIME DESTINATION ${QL_INSTALL_BINDIR})
endif()
add_test(NAME QuantLibAAD_test_suite COMMAND QuantLibAAD_test_suite --log_level=message)
endif()

# =============================================================================
# Benchmark - Split FD/AAD executables for fair comparison
# =============================================================================

# FD benchmark - Finite Differences using plain double QuantLib
# This is built WITHOUT XAD to ensure fair FD vs AAD comparison
option(QLAAD_BUILD_BENCHMARK_FD "Build FD benchmark (plain double, no XAD)" OFF)
if(QLAAD_BUILD_BENCHMARK_FD)
message(STATUS "QLAAD: Building FD benchmark (plain double)")
add_executable(benchmark_fd
benchmark_fd.cpp
benchmark_common.hpp
benchmark_pricing.hpp
PlatformInfo.hpp
)
set_target_properties(benchmark_fd PROPERTIES
OUTPUT_NAME "benchmark-fd")
target_link_libraries(benchmark_fd PRIVATE
ql_library
${QL_THREAD_LIBRARIES})

if (QL_INSTALL_TEST_SUITE)
install(TARGETS benchmark_fd RUNTIME DESTINATION ${QL_INSTALL_BINDIR})
endif()
endif()

# AAD benchmark - XAD tape-based AAD and optionally Forge JIT
# Built with XAD-enabled QuantLib, optionally links Forge for JIT benchmarks
option(QLAAD_BUILD_BENCHMARK_AAD "Build AAD benchmark (XAD tape, optionally Forge JIT)" OFF)
if(QLAAD_BUILD_BENCHMARK_AAD)
message(STATUS "QLAAD: Building AAD benchmark")
add_executable(benchmark_aad
benchmark_aad.cpp
benchmark_common.hpp
benchmark_pricing.hpp
PlatformInfo.hpp
)
set_target_properties(benchmark_aad PROPERTIES
OUTPUT_NAME "benchmark-aad")
target_link_libraries(benchmark_aad PRIVATE
ql_library
${QL_THREAD_LIBRARIES})

# Link Forge if available for JIT benchmarks
if(TARGET QLAAD::forge)
message(STATUS "QLAAD AAD benchmark: Linking QLAAD::forge (JIT benchmarks enabled)")
target_link_libraries(benchmark_aad PRIVATE QLAAD::forge)
target_compile_definitions(benchmark_aad PRIVATE QLAAD_HAS_FORGE=1)
else()
message(STATUS "QLAAD AAD benchmark: Building without Forge (XAD tape only)")
endif()

if (QL_INSTALL_TEST_SUITE)
install(TARGETS benchmark_aad RUNTIME DESTINATION ${QL_INSTALL_BINDIR})
endif()
endif()
Loading
Loading