Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
47929da
Renamed UNO_OPTION_TYPE_INT to UNO_OPTION_TYPE_INTEGER
stefphd Oct 15, 2025
873c2df
Moved stream callbacks to UserModel.hpp
stefphd Oct 15, 2025
a4ae849
Added Vector(begin, end) constructor
stefphd Oct 15, 2025
c74073a
Added typed option getters
stefphd Oct 15, 2025
ce7ece0
Added Matlab MEX interface
stefphd Oct 15, 2025
3bb120a
Create README for Matlab interface
stefphd Oct 15, 2025
ff6f04c
Added Matlab example
stefphd Oct 15, 2025
c322a01
Fixed missing include
stefphd Oct 15, 2025
c79b6bf
Matlab libut not required
stefphd Oct 15, 2025
571f82b
Added explicit sparsity patterns in matlab interface
stefphd Oct 15, 2025
ea06c51
Updated matlab example to use explicit sparsity
stefphd Oct 15, 2025
d6474ec
Updated matlab README
stefphd Oct 15, 2025
9f1a5b2
Simplified struct to option conversion
stefphd Oct 15, 2025
ef5fb87
Added conversion of matlab string to std::string
stefphd Oct 15, 2025
2ade211
Accept matlab string in option preset
stefphd Oct 15, 2025
e731182
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd Oct 16, 2025
28f2af1
Removed redundant callbacks in matlab interface
stefphd Oct 16, 2025
f671410
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd Oct 16, 2025
a7cdf6c
Updated matlab with number model evaluations
stefphd Oct 16, 2025
35c8b36
Updated the matlab example
stefphd Oct 17, 2025
bdfb559
Added function argument validation
stefphd Oct 17, 2025
e364415
Reorganized matlab interface sources
stefphd Oct 18, 2025
e5c888c
Link matlab interface to uno default lib
stefphd Oct 19, 2025
568e59b
Validate user callback outputs during optimization
stefphd Oct 19, 2025
577b605
Removed unused functions
stefphd Oct 19, 2025
c83e3f5
Update example_hs015.m
stefphd Oct 19, 2025
d0b7d8b
Added matlab Polak5 example
stefphd Oct 19, 2025
252f39f
Flip multiplier sign back before eval (data are copied)
stefphd Oct 19, 2025
95bda52
Update example_polak5.m
stefphd Oct 19, 2025
fd716f3
Renamed validate_matlab_handle to validate_matlab_handle_field
stefphd Oct 19, 2025
5e516dd
Added high-level Matlab interface
stefphd Oct 23, 2025
0668266
Fixed missing (:) in uno.m
stefphd Oct 23, 2025
f333c0b
Fixed typo in Matlab readme
stefphd Oct 23, 2025
26bade9
Added Test Matlab interface workflow
stefphd Oct 23, 2025
7fe875b
Fixed typo in Matlab readme
stefphd Oct 23, 2025
71b1b3d
Exclude auto build of Matlab interface
stefphd Oct 23, 2025
9a4d24d
Try install Matlab files
stefphd Oct 23, 2025
f17e229
Added explicit error messages in Uno matlab interface
stefphd Oct 23, 2025
d9101e2
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd Oct 23, 2025
9843722
Fixed unomex_optimize hessian and problem type
stefphd Oct 23, 2025
09e3a74
Clear uno_optimize after calling uno
stefphd Oct 23, 2025
3f5a38a
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd Oct 24, 2025
799876c
Merged C API with main changes
stefphd Oct 24, 2025
cc4329a
unomex_* renamed to uno_
stefphd Oct 24, 2025
16ae619
Added validate_string_field
stefphd Oct 24, 2025
eb36f1e
Added missing return
stefphd Oct 24, 2025
88abf78
Updated Matlab examples with new problem_type
stefphd Oct 24, 2025
390bd6b
Link Matlab libut in unomex-options target
stefphd Oct 24, 2025
08bbf4f
Divided C++ classes for Matlab interface into multiple files
stefphd Oct 24, 2025
6f6eca7
Added Matlab test example on MacOS
stefphd Oct 24, 2025
0ddef43
Fixed platform in github workflow
stefphd Oct 24, 2025
b0f5d1d
Try adding fortran compiler in macod workflow
stefphd Oct 24, 2025
2842a66
Fixed wrong slash in include
stefphd Oct 24, 2025
1988033
Fixed wrong slash in include (missing)
stefphd Oct 24, 2025
0fc34b5
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd Oct 27, 2025
49165f3
Updated multiplier sign convention in Materlab interface
stefphd Oct 27, 2025
752601d
compile the Unomex source files once
stefphd Oct 27, 2025
8cce827
Try fix rpath for macos Matlab interface
stefphd Oct 27, 2025
717131a
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd Dec 17, 2025
6d55ff1
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd Mar 9, 2026
3048834
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd May 26, 2026
c9c6e2d
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd Jun 8, 2026
e307407
Update C interface for breaking changes
stefphd Jun 8, 2026
6feed33
Update CMakeLists.txt for breaking changes
stefphd Jun 8, 2026
60a42e3
Remove old function members (not needed)
stefphd Jun 8, 2026
f1929ba
Update for braking changes in Uno interface
stefphd Jun 8, 2026
73f56ea
Use HessianFnc to mimic Matlab fmincon
stefphd Jun 8, 2026
6313475
Add minimum equired version
stefphd Jun 8, 2026
732679e
Fix typo
stefphd Jun 8, 2026
0c4e0bf
Update MATLAB documentation
stefphd Jun 8, 2026
44b7943
Fix wrong matlab install dir
stefphd Jun 8, 2026
7dbaaff
Make sure to print all messages into matlab command window
stefphd Jun 8, 2026
d51f8e4
Update matlab-test workflow
stefphd Jun 9, 2026
75fc5ba
Fix wrong line separator in Windows configure
stefphd Jun 9, 2026
d825726
Try to add pause before exiting to avoid matlab crash
stefphd Jun 9, 2026
b5ba9c7
Remove pause (not wroking to avoid matlab crash)
stefphd Jun 9, 2026
1f0ceb1
Use 'cmd' shell for Windows configure
stefphd Jun 9, 2026
d481125
Remove options.HessianFnc after use to avoid Uno warning
stefphd Jun 9, 2026
6020886
Try to lock mex to prevent matlab crash on cleanup
stefphd Jun 9, 2026
3a41b5c
Add link for mexLock() workaround
stefphd Jun 9, 2026
8ffaa20
Merge branch 'main' of https://github.com/cvanaret/Uno
stefphd Jun 9, 2026
c5571ad
Add missing result fields
stefphd Jun 9, 2026
1f5788d
Fix typo in error strings
stefphd Jun 9, 2026
46657a8
Fix wrong line for initial_primal_iterate
stefphd Jun 9, 2026
cf05ae6
Handle the option preset
stefphd Jun 9, 2026
63294c5
Added missing include
cvanaret Jun 9, 2026
8b85f02
Removed LTO
cvanaret Jun 9, 2026
f901899
Fixed linking order of (C)BLAS
cvanaret Jun 9, 2026
875e66f
Merge branch 'main' of https://github.com/stefphd/Uno
stefphd Jun 9, 2026
4dff350
Fix wrong initial iterate for interior-point
stefphd Jun 9, 2026
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
3 changes: 1 addition & 2 deletions .github/workflows/build-python-wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ jobs:
CMAKE_Fortran_COMPILER=C:/mingw64/bin/gfortran.exe
CIBW_CONFIG_SETTINGS_WINDOWS: >
cmake.define.METIS_LIBRARY=dependencies/bin/libmetis.dll
cmake.define.BLAS_LIBRARIES="dependencies/lib/libblas.a;dependencies/lib/libcblas.a"
cmake.define.AUXILIARY_LIBRARIES=dependencies/lib/libstdc++.a

- name: Store artifacts
Expand Down Expand Up @@ -287,4 +286,4 @@ jobs:

- name: Run example
working-directory: ${{github.workspace}}/interfaces/Python/example
run: python example_hs015.py
run: python example_hs015.py
104 changes: 104 additions & 0 deletions .github/workflows/matlab-test-example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Test the Matlab interface on the example

on:
push:
branches: [ "main" ]
paths-ignore:
- '*.md'
- 'LICENSE'
- '*.cff'
- '*.yml'
- '*.yaml'
- 'docs/**'
pull_request:
branches: [ "main" ]
paths-ignore:
- '*.md'
- 'LICENSE'
- '*.cff'
- '*.yml'
- '*.yaml'
- 'docs/**'

env:
BUILD_TYPE: Debug

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
addpath: install/bin
- os: macos-latest
addpath: install/lib

steps:
- uses: actions/checkout@v4

- name: Set up MATLAB
uses: matlab-actions/setup-matlab@v2

- name: Install Fortran compiler (macOS)
if: startsWith(matrix.os, 'macos')
uses: fortran-lang/setup-fortran@main
with:
compiler: 'gcc'
version: '14'

- name: Setup MSYS2 (Windows)
if: startsWith(matrix.os, 'windows')
uses: msys2/setup-msys2@v2
with:
path-type: inherit
msystem: MINGW64
update: true
install: |
mingw-w64-x86_64-gcc-fortran
mingw-w64-x86_64-cmake
mingw-w64-x86_64-make

- name: Download dependencies
run: bash dependencies/scripts/download_dependencies.sh

- name: Configure (macOS)
if: startsWith(matrix.os, 'macos')
run: |
cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DBQPD=${{github.workspace}}/dependencies/lib/libbqpd.a \
-DLAPACK_LIBRARIES=${{github.workspace}}/dependencies/lib/liblapack.a \
-DBLAS_LIBRARIES="${{github.workspace}}/dependencies/lib/libblas.a;${{github.workspace}}/dependencies/lib/libcblas.a"

- name: Configure (Windows)
if: startsWith(matrix.os, 'windows')
shell: cmd
run: |
cmake -G "MinGW Makefiles" -B "${{github.workspace}}/build" ^
-DBQPD=${{github.workspace}}/dependencies/lib/libbqpd.a ^
-DLAPACK_LIBRARIES=${{github.workspace}}/dependencies/lib/liblapack.a ^
-DBLAS_LIBRARIES="${{github.workspace}}/dependencies/lib/libblas.a;${{github.workspace}}/dependencies/lib/libcblas.a"

- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel

- name: Build unomex
run: cmake --build ${{github.workspace}}/build --target unomex --config ${{env.BUILD_TYPE}} --parallel

- name: Install unomex
run: cmake --install ${{github.workspace}}/build --prefix ${{github.workspace}}/install

- name: Run example (high-level interface)
uses: matlab-actions/run-command@v2
with:
command: |
addpath('${{ matrix.addpath }}');
run('interfaces/Matlab/example/example_uno.m');

- name: Run example (low-level interface)
uses: matlab-actions/run-command@v2
with:
command: |
addpath('${{ matrix.addpath }}');
run('interfaces/Matlab/example/example_hs015.m');
66 changes: 59 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -370,18 +370,70 @@ if(SKBUILD)
target_compile_definitions(unopy PRIVATE PYBIND11_DETAILED_ERROR_MESSAGES)
endif()

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# link-time optimization
target_compile_options(unopy PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-flto=auto>)
target_link_options(unopy PRIVATE -flto=auto)
endif()

install(TARGETS unopy
LIBRARY DESTINATION unopy # Linux/macOS: unopy/unopy.so
RUNTIME DESTINATION unopy # Windows: unopy/unopy.pyd
)
endif()

############################
# optional Matlab bindings #
############################

find_package(Matlab 23.2 COMPONENTS MAIN_PROGRAM MEX_COMPILER) # >=23.2 = R2023b
if(Matlab_FOUND)
message(STATUS "Found Matlab ${Matlab_VERSION}")

file(GLOB MATLAB_SOURCE_FILES
interfaces/Matlab/cpp_classes/*.cpp
interfaces/Matlab/unomex/*.cpp
)

# libut matlab library
# cf. https://undocumentedmatlab.com/articles/mex-ctrl-c-interrupt#:~:text=The%20relevant%20functions%20seem%20to,utLongjmpIfInterruptPending(?)
get_filename_component(Matlab_MX_LIBRARY_PATH ${Matlab_MX_LIBRARY} DIRECTORY )
find_library(MXLIBUT NAMES libut ut
PATHS ${Matlab_MX_LIBRARY_PATH})
if(MXLIBUT)
add_definitions("-D HAS_MXLIBUT")
endif()

# compile the Unomex source files once
add_library(compiled_unomex_files EXCLUDE_FROM_ALL OBJECT ${MATLAB_SOURCE_FILES})
target_link_libraries(compiled_unomex_files PUBLIC uno_dependencies)
set_property(TARGET compiled_unomex_files PROPERTY POSITION_INDEPENDENT_CODE ON)
target_include_directories(compiled_unomex_files PUBLIC ${Matlab_INCLUDE_DIRS})

# uno_optimize
matlab_add_mex(NAME unomex-optimize SRC $<TARGET_OBJECTS:compiled_unomex_files> interfaces/Matlab/uno_optimize.cpp
EXCLUDE_FROM_ALL
OUTPUT_NAME uno_optimize
LINK_TO ${DEFAULT_UNO_LIB} uno_dependencies ${MXLIBUT})

# uno_options
matlab_add_mex(NAME unomex-options SRC $<TARGET_OBJECTS:compiled_unomex_files> interfaces/Matlab/uno_options.cpp
EXCLUDE_FROM_ALL
OUTPUT_NAME uno_options
LINK_TO ${DEFAULT_UNO_LIB} uno_dependencies ${MXLIBUT})
target_include_directories(unomex-options PUBLIC ${directory})

# logical target to compile both mex
add_custom_target(unomex DEPENDS unomex-optimize unomex-options)

# cf. https://github.com/cvanaret/Uno/pull/360#issuecomment-3431367949
if(APPLE)
set(MEX_RPATH "@executable_path/../extern/bin/maci64;@executable_path/../extern/bin/maca64;@executable_path/../../extern/bin/maci64;@executable_path/../../extern/bin/maca64")
set_target_properties(unomex-optimize PROPERTIES BUILD_RPATH "${MEX_RPATH};${CMAKE_BUILD_RPATH}" INSTALL_RPATH "${MEX_RPATH};${CMAKE_INSTALL_RPATH}")
set_target_properties(unomex-options PROPERTIES BUILD_RPATH "${MEX_RPATH};${CMAKE_BUILD_RPATH}" INSTALL_RPATH "${MEX_RPATH};${CMAKE_INSTALL_RPATH}")
endif()

# install
set(MATLAB_INSTALL_FILES "interfaces/Matlab/uno.m;interfaces/Matlab/uno_optimize.m;interfaces/Matlab/uno_options.m")
install(TARGETS unomex-optimize LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS unomex-options LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES ${MATLAB_INSTALL_FILES} DESTINATION $<IF:$<PLATFORM_ID:Windows>,bin,lib>)
endif()

# ======================
# GoogleTest unit tests
# ======================
Expand Down Expand Up @@ -434,4 +486,4 @@ install(TARGETS ${INSTALL_TARGETS}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static libraries
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared libraries
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/uno # headers
)
)
88 changes: 22 additions & 66 deletions interfaces/C/Uno_C_API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

#include <algorithm>
#include <cstring>
#include <iostream>
#include <streambuf>
#include "Uno_C_API.h"
#include "../UserModel.hpp"
#include "Uno.hpp"
Expand Down Expand Up @@ -379,75 +377,29 @@ class CUserCallbacks: public UserCallbacks {
void* user_data;
};

// std::streambuf wrapper around uno_logger_stream_callback
class CStreamBuffer : public std::streambuf {
public:
explicit CStreamBuffer(uno_logger_stream_callback logger_stream_callback, void* user_data, std::size_t buffer_size) :
logger_stream_callback(logger_stream_callback), user_data(user_data) {
// allocate output buffer and set stream buffer pointer
this->buffer = new char[buffer_size];
this->setp(this->buffer, this->buffer + buffer_size - 1);
}
~CStreamBuffer() override {
// flush remaining data and release buffer memory
this->sync();
delete[] this->buffer;
}
class CStreamCallback : public UserStreamCallback {
public:
CStreamCallback(uno_logger_stream_callback logger_stream_callback, void* user_data) :
UserStreamCallback(), logger_stream_callback(logger_stream_callback), user_data(user_data) { }
~CStreamCallback() override { }

protected:
// called on buffer overflow
int overflow(int character) override {
if (character != EOF) {
// insert the character into the buffer
*this->pptr() = traits_type::to_char_type(character);
this->pbump(1);
int32_t operator()(const char* buf, int32_t len) const override {
if (this->logger_stream_callback) {
return this->logger_stream_callback(buf, len, this->user_data);
}
else {
return 0;
}
// return EOF for error
return (this->flush_buffer() == 0) ? character : EOF;
}

int sync() override {
return this->flush_buffer();
}

private:
uno_logger_stream_callback logger_stream_callback;
void* user_data;
char* buffer;

// flush buffer to the logger callback
int flush_buffer() {
// check for invalid stream callback
if (!this->logger_stream_callback) {
return -1;
}
std::ptrdiff_t current_used_buffer_size = this->pptr() - this->pbase();
if (current_used_buffer_size > 0) {
// call user logger callback
const uno_int callback_result = this->logger_stream_callback(this->pbase(), static_cast<uno_int>(current_used_buffer_size),
this->user_data);
if (callback_result != static_cast<uno_int>(current_used_buffer_size)) {
return -1;
}
// move buffer pointer
this->pbump(static_cast<int>(-current_used_buffer_size));
}
return 0;
}
};

// std::ostream wrapper around uno_logger_stream_callback
class COStream : public std::ostream {
public:
COStream(uno_logger_stream_callback logger_stream_callback, void* user_data, std::size_t buffer_size = 1024) : // 1024 default buffer size
std::ostream(&this->buffer), buffer(logger_stream_callback, user_data, buffer_size) { }

private:
// internal stream buffer that sends output to the uno_logger_stream_callback
CStreamBuffer buffer;
};

COStream* c_ostream = nullptr;
CStreamCallback* c_stream_callback = nullptr;
UserOStream* ostream = nullptr;

struct Solver {
Uno* solver;
Expand Down Expand Up @@ -939,15 +891,19 @@ bool uno_set_solver_callbacks(void* solver, uno_notify_acceptable_iterate_callba
}

bool uno_set_logger_stream_callback(uno_logger_stream_callback logger_stream_callback, void* user_data) {
delete c_ostream;
c_ostream = new COStream(logger_stream_callback, user_data);
Logger::set_stream(*c_ostream);
delete c_stream_callback;
delete ostream;
c_stream_callback = new CStreamCallback(logger_stream_callback, user_data);
ostream = new UserOStream(c_stream_callback);
Logger::set_stream(*ostream);
return true;
}

bool uno_reset_logger_stream() {
delete c_ostream;
c_ostream = nullptr;
delete ostream;
delete c_stream_callback;
c_stream_callback = nullptr;
ostream = nullptr;
Logger::set_stream(std::cout);
return true;
}
Expand Down
Loading
Loading