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
4 changes: 2 additions & 2 deletions .github/workflows/C-test-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ jobs:
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DUNO=/usr/local/lib/libuno.so .

- name: Build example
- name: Build C example
working-directory: ${{github.workspace}}/interfaces/C/example
run: cmake --build ${{github.workspace}}/interfaces/C/example/build --config ${{env.BUILD_TYPE}}

- name: Run example
- name: Run C example
working-directory: ${{github.workspace}}/interfaces/C/example/build
run: ./example_hs015
77 changes: 77 additions & 0 deletions .github/workflows/Rust-test-example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Test Rust 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:
os: [ubuntu-latest]
architecture: [x64]

steps:
- uses: actions/checkout@v4

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

- name: Configure (Linux)
run: |
cmake -B build \
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DCMAKE_C_COMPILER=gcc \
-DCMAKE_CXX_COMPILER=g++ \
-DCMAKE_FORTRAN_COMPILER=gfortran \
-DMUMPS_INCLUDE_DIR=${{github.workspace}}/dependencies/include \
-DMETIS_INCLUDE_DIR=${{github.workspace}}/dependencies/include \
-DBQPD=${{github.workspace}}/dependencies/lib/libbqpd.a \
-DMETIS_LIBRARY=${{github.workspace}}/dependencies/lib/libmetis.a \
-DMUMPS_LIBRARY=${{github.workspace}}/dependencies/lib/libdmumps.a \
-DMUMPS_COMMON_LIBRARY=${{github.workspace}}/dependencies/lib/libmumps_common.a \
-DMUMPS_PORD_LIBRARY=${{github.workspace}}/dependencies/lib/libpord.a \
-DMUMPS_MPISEQ_LIBRARY=${{github.workspace}}/dependencies/lib/libmpiseq.a \
-DBLAS_LIBRARIES="${{github.workspace}}/dependencies/lib/libcblas.a;${{github.workspace}}/dependencies/lib/libblas.a" \
-DLAPACK_LIBRARIES=${{github.workspace}}/dependencies/lib/liblapack.a \
-DHIGHS=${{github.workspace}}/dependencies/lib/libhighs.a \
-DBUILD_STATIC_LIBS=ON \
-DBUILD_SHARED_LIBS=ON

- name: Build
run: cmake --build build --config ${{env.BUILD_TYPE}} -j4

- name: Install Uno
run: sudo cmake --install ${{github.workspace}}/build

- name: Update dynamic linker cache
run: sudo ldconfig

- name: Build Rust example
working-directory: ${{github.workspace}}/interfaces/Rust
run: cargo build --bin hs015

- name: Run Rust example
working-directory: ${{github.workspace}}/interfaces/Rust
run: cargo run --bin hs015
2 changes: 1 addition & 1 deletion .github/workflows/fortran-wrappers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
julia --color=no --project wrapper_fortran.jl
cd ../../Fortran
git diff --quiet uno_c.f90 uno_fortran.f90 || {
echo "❌ The Fortran wrappers in uno_c.f90 / uno_fortran.f90 are out of date. ❌";
echo "❌ The Fortran wrappers in interfaces/Fortran/uno_c.f90 and interfaces/Fortran/uno_fortran.f90 are out of date. ❌";
echo "Please run wrapper_fortran.jl in interfaces/Julia/gen to regenerate them:";
echo "";
echo "cd interfaces/Julia/gen";
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/julia-wrappers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
julia --color=no --project wrapper_julia.jl
cd ../src
git diff --quiet libuno.jl || {
echo "❌ The Julia wrappers in libuno.jl are out of date. ❌";
echo "❌ The Julia wrappers in interfaces/Julia/src/libuno.jl are out of date. ❌";
echo "Please run wrapper_julia.jl in interfaces/Julia/gen to regenerate them:";
echo "";
echo "cd interfaces/Julia/gen";
Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/rust-wrappers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Rust wrappers
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
name: Check for updates
runs-on: ubuntu-latest
steps:
- name: Checkout Uno
uses: actions/checkout@v4

- name: Install Julia
uses: julia-actions/setup-julia@v2
with:
version: 1
arch: x64

- name: Regenerate the Rust wrappers
shell: bash
run: |
cd interfaces/Julia/gen
julia --color=no --project -e 'using Pkg; Pkg.instantiate()'
julia --color=no --project wrapper_rust.jl
cd ../../Rust/src
git diff --quiet ffi.rs || {
echo "❌ The Rust wrappers in interfaces/Rust/src/ffi.rs are out of date. ❌";
echo "Please run wrapper_rust.jl in interfaces/Julia/gen to regenerate them:";
echo "";
echo "cd interfaces/Julia/gen";
echo "julia --project -e 'using Pkg; Pkg.instantiate()'";
echo "julia --project wrapper_rust.jl";
echo "";
echo "You can also find the instructions at:";
echo "https://github.com/cvanaret/Uno/blob/master/interfaces/Julia/README.md";
exit 1;
}
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ Uno provides a native Fortran interface built on top of its C API using `iso_c_b
It closely mirrors the C interface and is designed as a lightweight wrapper with minimal overhead, making it suitable for integration into existing Fortran codes while retaining full access to Uno's features.
For more details, see its [README.md](interfaces/Fortran/README.md).

### Rust
Uno provides a Rust interface (`uno_rs`) built on top of its C API using Rust's FFI.
It exposes high-level wrappers over the raw bindings in `ffi.rs`.
For more details, see its [README.md](interfaces/Rust/README.md).

## Latest results (August 13, 2025)

Uno presets have been tested against state-of-the-art solvers on 429 small problems of the [CUTEst benchmark](https://arnold-neumaier.at/glopt/coconut/Benchmark/Library2_new_v1.html).
Expand Down
23 changes: 19 additions & 4 deletions interfaces/Julia/gen/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Wrapping headers and generating wrappers

This directory contains scripts `wrapper_julia.jl` and `wrapper_fortran.jl` that can be used
to automatically generate Julia and Fortran wrappers from the C headers of Uno.
This directory contains scripts `wrapper_julia.jl`, `wrapper_fortran.jl` and `wrapper_rust.jl`
that can be used to automatically generate Julia, Fortran and Rust wrappers from the C headers of Uno.
This is done using [Clang.jl](https://github.com/JuliaInterop/Clang.jl).

# Usage
Expand All @@ -17,7 +17,7 @@ julia> ]

## Julia

Regenerate the Julia wrappers with the following commands:
Regenerate the Julia wrappers (`interfaces/Julia/src/libuno.jl`) with the following commands:
```julia
julia> include("wrapper_julia.jl")
julia> main_julia()
Expand All @@ -32,7 +32,7 @@ Note that if new constants are added to `Uno_C_API.h`, a manual update of `prolo

## Fortran

Regenerate the Fortran wrappers with the following commands:
Regenerate the Fortran wrappers (`interfaces/Fortran/src/uno_c.f90` and `interfaces/Fortran/src/uno_fortran.f90`) with the following commands:
```julia
julia> include("wrapper_fortran.jl")
julia> main_fortran()
Expand All @@ -44,3 +44,18 @@ julia --project wrapper_fortran.jl
```

Note that if new constants or callbacks are added to `Uno_C_API.h`, a manual update of `prologue_fortran.f90` is required.

## Rust

Regenerate the Rust FFI bindings (`interfaces/Rust/src/ffi.rs`) with the following commands:
```julia
julia> include("wrapper_rust.jl")
julia> main_rust()
```

If you have already instantiated the environment, you can also run:
```bash
julia --project wrapper_rust.jl
```

Note that if new constants or callbacks are added to `Uno_C_API.h`, a manual update of `prologue_rust.rs` is required.
187 changes: 187 additions & 0 deletions interfaces/Julia/gen/prologue_rust.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Copyright (c) 2026 Alexis Montoison and Charlie Vanaret
// Licensed under the MIT license. See LICENSE file in the project directory for details.

#![allow(non_camel_case_types)]

use std::os::raw::{c_char, c_int, c_void};

//--- UNO_INT_TYPE ---

// ─────────────────────────────────────────────
// Optimization sense
// ─────────────────────────────────────────────
pub const UNO_MINIMIZE: uno_int = 1;
pub const UNO_MAXIMIZE: uno_int = -1;

// ─────────────────────────────────────────────
// Lagrange multiplier sign convention
// ─────────────────────────────────────────────
pub const UNO_MULTIPLIER_POSITIVE: uno_int = 1;
pub const UNO_MULTIPLIER_NEGATIVE: uno_int = -1;

// ─────────────────────────────────────────────
// Problem types
// ─────────────────────────────────────────────
pub const UNO_PROBLEM_LINEAR: &[u8] = b"LP\0";
pub const UNO_PROBLEM_QUADRATIC: &[u8] = b"QP\0";
pub const UNO_PROBLEM_NONLINEAR: &[u8] = b"NLP\0";

// ─────────────────────────────────────────────
// Base indexing style
// ─────────────────────────────────────────────
pub const UNO_ZERO_BASED_INDEXING: uno_int = 0;
pub const UNO_ONE_BASED_INDEXING: uno_int = 1;

// ─────────────────────────────────────────────
// Triangular part
// ─────────────────────────────────────────────
pub const UNO_LOWER_TRIANGLE: c_char = b'L' as c_char;
pub const UNO_UPPER_TRIANGLE: c_char = b'U' as c_char;

// ─────────────────────────────────────────────
// Option type
// ─────────────────────────────────────────────
pub const UNO_OPTION_TYPE_INTEGER: uno_int = 0;
pub const UNO_OPTION_TYPE_DOUBLE: uno_int = 1;
pub const UNO_OPTION_TYPE_BOOL: uno_int = 2;
pub const UNO_OPTION_TYPE_STRING: uno_int = 3;
pub const UNO_OPTION_TYPE_NOT_FOUND: uno_int = -1;

// ─────────────────────────────────────────────
// Optimization status
// ─────────────────────────────────────────────
pub const UNO_SUCCESS: uno_int = 0;
pub const UNO_ITERATION_LIMIT: uno_int = 1;
pub const UNO_TIME_LIMIT: uno_int = 2;
pub const UNO_EVALUATION_ERROR: uno_int = 3;
pub const UNO_ALGORITHMIC_ERROR: uno_int = 4;
pub const UNO_USER_TERMINATION: uno_int = 5;

// ─────────────────────────────────────────────
// Solution status
// ─────────────────────────────────────────────
pub const UNO_NOT_OPTIMAL: uno_int = 0;
pub const UNO_FEASIBLE_KKT_POINT: uno_int = 1;
pub const UNO_FEASIBLE_FJ_POINT: uno_int = 2;
pub const UNO_INFEASIBLE_STATIONARY_POINT: uno_int = 3;
pub const UNO_FEASIBLE_SMALL_STEP: uno_int = 4;
pub const UNO_INFEASIBLE_SMALL_STEP: uno_int = 5;
pub const UNO_UNBOUNDED: uno_int = 6;

// ─────────────────────────────────────────────
// Version
// ─────────────────────────────────────────────
pub const UNO_VERSION_MAJOR: uno_int = 2;
pub const UNO_VERSION_MINOR: uno_int = 7;
pub const UNO_VERSION_PATCH: uno_int = 1;

// ─────────────────────────────────────────────
// Callback type aliases
// ─────────────────────────────────────────────

pub type uno_objective_callback = unsafe extern "C" fn(
number_variables: uno_int,
x: *const f64,
objective_value: *mut f64,
user_data: *mut c_void,
) -> uno_int;

pub type uno_constraints_callback = unsafe extern "C" fn(
number_variables: uno_int,
number_constraints: uno_int,
x: *const f64,
constraint_values: *mut f64,
user_data: *mut c_void,
) -> uno_int;

pub type uno_objective_gradient_callback = unsafe extern "C" fn(
number_variables: uno_int,
x: *const f64,
gradient: *mut f64,
user_data: *mut c_void,
) -> uno_int;

pub type uno_constraints_jacobian_callback = unsafe extern "C" fn(
number_variables: uno_int,
number_jacobian_nonzeros: uno_int,
x: *const f64,
jacobian_values: *mut f64,
user_data: *mut c_void,
) -> uno_int;

pub type uno_lagrangian_hessian_callback = unsafe extern "C" fn(
number_variables: uno_int,
number_constraints: uno_int,
number_hessian_nonzeros: uno_int,
x: *const f64,
objective_multiplier: f64,
multipliers: *const f64,
hessian_values: *mut f64,
user_data: *mut c_void,
) -> uno_int;

pub type uno_constraints_jacobian_operator_callback = unsafe extern "C" fn(
number_variables: uno_int,
number_constraints: uno_int,
x: *const f64,
evaluate_at_x: bool,
vector: *const f64,
result: *mut f64,
user_data: *mut c_void,
) -> uno_int;

pub type uno_constraints_jacobian_transposed_operator_callback = unsafe extern "C" fn(
number_variables: uno_int,
number_constraints: uno_int,
x: *const f64,
evaluate_at_x: bool,
vector: *const f64,
result: *mut f64,
user_data: *mut c_void,
) -> uno_int;

pub type uno_lagrangian_hessian_operator_callback = unsafe extern "C" fn(
number_variables: uno_int,
number_constraints: uno_int,
x: *const f64,
evaluate_at_x: bool,
objective_multiplier: f64,
multipliers: *const f64,
vector: *const f64,
result: *mut f64,
user_data: *mut c_void,
) -> uno_int;

pub type uno_notify_acceptable_iterate_callback = unsafe extern "C" fn(
number_variables: uno_int,
number_constraints: uno_int,
primals: *const f64,
lower_bound_multipliers: *const f64,
upper_bound_multipliers: *const f64,
constraint_multipliers: *const f64,
objective_multiplier: f64,
primal_feasibility_residual: f64,
stationarity_residual: f64,
complementarity_residual: f64,
user_data: *mut c_void,
);

pub type uno_termination_callback = unsafe extern "C" fn(
number_variables: uno_int,
number_constraints: uno_int,
primals: *const f64,
lower_bound_multipliers: *const f64,
upper_bound_multipliers: *const f64,
constraint_multipliers: *const f64,
objective_multiplier: f64,
primal_feasibility_residual: f64,
stationarity_residual: f64,
complementarity_residual: f64,
user_data: *mut c_void,
) -> bool;

pub type uno_logger_stream_callback = unsafe extern "C" fn(
buffer: *const c_char,
length: uno_int,
user_data: *mut c_void,
) -> uno_int;
Loading
Loading