Skip to content

Commit 30890fa

Browse files
authoredFeb 27, 2025··
Merge pull request #58 from osqp/im/cleanup
Various tweaks and cleanups
2 parents 43a9293 + 6780421 commit 30890fa

17 files changed

+932
-817
lines changed
 

‎.clang-format

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# minimum clang-format 10
2+
BasedOnStyle: LLVM
3+
4+
Language: Cpp
5+
Standard: c++17
6+
7+
TabWidth: 4
8+
UseTab: Never
9+
10+
AccessModifierOffset: -4
11+
12+
AlignAfterOpenBracket: Align
13+
AlignConsecutiveAssignments: false
14+
AlignConsecutiveDeclarations: true
15+
AlignOperands: true
16+
AlignTrailingComments: true
17+
18+
AllowAllConstructorInitializersOnNextLine: false
19+
AllowAllParametersOfDeclarationOnNextLine: false
20+
AllowShortBlocksOnASingleLine: Never
21+
AllowShortCaseLabelsOnASingleLine: true
22+
AllowShortFunctionsOnASingleLine: InlineOnly
23+
AllowShortIfStatementsOnASingleLine: Never
24+
AllowShortLambdasOnASingleLine: None
25+
AllowShortLoopsOnASingleLine: false
26+
27+
AlwaysBreakAfterReturnType: None
28+
AlwaysBreakBeforeMultilineStrings: false
29+
AlwaysBreakTemplateDeclarations: Yes
30+
31+
BinPackArguments: true
32+
BinPackParameters: true
33+
34+
BreakBeforeBinaryOperators: NonAssignment
35+
BreakBeforeBraces: Attach
36+
BreakBeforeTernaryOperators: true
37+
BreakConstructorInitializers: AfterColon
38+
BreakConstructorInitializersBeforeComma: false
39+
BreakStringLiterals: true
40+
41+
ColumnLimit: 100
42+
ConstructorInitializerAllOnOneLineOrOnePerLine: false
43+
ConstructorInitializerIndentWidth: 8
44+
ContinuationIndentWidth: 8
45+
Cpp11BracedListStyle: false
46+
DerivePointerAlignment: false
47+
DisableFormat: false
48+
IndentCaseLabels: false
49+
IndentWidth: 4
50+
IndentWrappedFunctionNames: false
51+
KeepEmptyLinesAtTheStartOfBlocks: false
52+
MaxEmptyLinesToKeep: 2
53+
NamespaceIndentation: Inner
54+
PointerAlignment: Left
55+
ReflowComments: false
56+
SortIncludes: false
57+
58+
SpaceAfterCStyleCast: true
59+
SpaceBeforeAssignmentOperators: true
60+
SpaceBeforeParens: Never
61+
SpaceInEmptyParentheses: false
62+
SpacesBeforeTrailingComments: 1
63+
SpacesInAngles: false
64+
SpacesInCStyleCastParentheses: false
65+
SpacesInParentheses: false
66+
SpacesInSquareBrackets: false
67+

‎.github/workflows/ci.yml

+61-17
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,107 @@ on: [push, pull_request]
44

55
env:
66
# The CMake build type
7-
BUILD_TYPE: Release
7+
BUILD_TYPE: Debug
88

99
jobs:
1010
build:
1111
strategy:
1212
fail-fast: false
1313
matrix:
14-
os: [ubuntu-latest, macos-latest, windows-latest]
14+
os: [ubuntu, macos, windows]
1515
include:
16-
- os: ubuntu-latest
16+
- variant: ubuntu
17+
# Use 24.04 explicitly to get newer GCC version
18+
os: ubuntu-24.04
19+
compiler: gcc
20+
gcc: 14
21+
extra_c_flags: "-fdiagnostics-format=sarif-file"
22+
test_target: "test"
1723
coverage: ON
18-
- os: macos-latest
24+
analysis: ON
25+
asan: ON
26+
- variant: macos
27+
os: macos-latest
28+
extra_c_flags: ""
29+
test_target: "test"
1930
coverage: OFF
20-
- os: windows-latest
31+
analysis: OFF
32+
asan: OFF
33+
- variant: windows
34+
os: windows-latest
35+
extra_c_flags: ""
36+
test_target: "RUN_TESTS"
2137
coverage: OFF
38+
analysis: OFF
39+
asan: OFF
2240

2341
runs-on: ${{ matrix.os }}
42+
name: ${{ matrix.variant }}
43+
44+
env:
45+
QDLDL_BUILD_DIR_PREFIX: ${{ github.workspace }}/build
46+
CTEST_OUTPUT_ON_FAILURE: 1
2447

2548
steps:
2649
- name: Check out repository
2750
uses: actions/checkout@v4
2851
with:
2952
submodules: 'recursive'
3053

31-
- name: Setup Environment
32-
run: cmake -E make_directory ${{ runner.workspace }}/build
54+
# - name: Setup Environment
55+
# run: cmake -E make_directory $QDLDL_BUILD_DIR_PREFIX
3356

3457
- name: Configure
3558
shell: bash
36-
working-directory: ${{ runner.workspace }}/build
37-
run: cmake --warn-uninitialized -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DQDLDL_UNITTESTS=ON -DCOVERAGE=${{ matrix.coverage }} $GITHUB_WORKSPACE
59+
run: |
60+
cmake -S ./ -B $QDLDL_BUILD_DIR_PREFIX \
61+
--warn-uninitialized \
62+
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
63+
-DQDLDL_UNITTESTS=ON \
64+
-DQDLDL_DEV_COVERAGE=${{ matrix.coverage }} \
65+
-DQDLDL_DEV_ANALYSIS=${{ matrix.analysis }} \
66+
-DQDLDL_DEV_ASAN=${{ matrix.asan }} \
67+
-DCMAKE_C_FLAGS=${{ matrix.extra_c_flags }}
3868
3969
- name: Build
4070
shell: bash
41-
working-directory: ${{ runner.workspace }}/build
42-
run: cmake --build . --config $BUILD_TYPE
71+
run: cmake --build $QDLDL_BUILD_DIR_PREFIX --config $BUILD_TYPE
4372

4473
- name: Run tests
4574
shell: bash
46-
working-directory: ${{ runner.workspace }}/build
47-
run: ctest -C $BUILD_TYPE
75+
run: cmake --build $QDLDL_BUILD_DIR_PREFIX --target ${{ matrix.test_target }}
4876

4977
# Only parse and upload coverage if it was generated
5078
- name: Process coverage
5179
if: ${{ matrix.coverage == 'ON' }}
5280
uses: imciner2/run-lcov@v1
5381
with:
54-
input_directory: '${{ runner.workspace }}/build'
55-
exclude: '"$GITHUB_WORKSPACE/tests/*" "$GITHUB_WORKSPACE/examples/*" "/usr/include/x86_64-linux-gnu/bits/*"'
56-
output_file: '${{ runner.workspace }}/build/coverage.info'
82+
input_directory: ${{ github.workspace }}/build
83+
exclude: '"$GITHUB_WORKSPACE/tests/*"'
84+
output_file: '${{ github.workspace }}/build/coverage.info'
5785

5886
- name: Upload coverage
5987
if: ${{ matrix.coverage == 'ON' }}
6088
uses: coverallsapp/github-action@master
6189
with:
6290
github-token: ${{ secrets.GITHUB_TOKEN }}
63-
path-to-lcov: '${{ runner.workspace }}/build/coverage.info'
91+
path-to-lcov: '${{ github.workspace }}/build/coverage.info'
92+
93+
- name: Merge diagnostics
94+
if: ${{ matrix.analysis == 'ON' }}
95+
uses: microsoft/sarif-actions@v0.1
96+
with:
97+
# Command to be sent to SARIF Multitool. Runs by default in github.workspace, and including any absolute
98+
# paths seems to not work, so everything must be relative.
99+
command: merge ./build/*.c.c.sarif --recurse true --output-directory=./build/ --output-file=gcc.sarif
100+
101+
- name: Upload diagnostics
102+
if: ${{ matrix.analysis == 'ON' }}
103+
uses: github/codeql-action/upload-sarif@v3
104+
with:
105+
# Path to SARIF file relative to the root of the repository
106+
sarif_file: ${{ github.workspace }}/build/gcc.sarif
107+
category: gcc
64108

65109

66110
test_configs:

‎CMakeLists.txt

+31-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ set(QDLDL_VERSION "${QDLDL_VERSION_MAJOR}.${QDLDL_VERSION_MINOR}.${QDLDL_VERSION
1010
project(qdldl VERSION ${QDLDL_VERSION})
1111

1212
include( CMakeDependentOption )
13+
include( CheckCXXCompilerFlag )
1314

1415
option( QDLDL_BUILD_STATIC_LIB "Build the static library" ON )
1516
option( QDLDL_BUILD_SHARED_LIB "Build the shared library" ON )
@@ -24,6 +25,14 @@ cmake_dependent_option( QDLDL_UNITTESTS
2425
OFF # Default to off
2526
QDLDL_BUILD_STATIC_LIB OFF ) # Force off if the static library isn't built
2627

28+
# Dev options
29+
option( QDLDL_DEV_COVERAGE "Include coverage information in the library" OFF )
30+
option( QDLDL_DEV_ANALYSIS "Run the compiler static analysis checks" OFF )
31+
option( QDLDL_DEV_ASAN "Build with ASAN" OFF )
32+
33+
mark_as_advanced( OSQP_DEV_COVERAGE )
34+
mark_as_advanced( OSQP_DEV_ANALYSIS )
35+
2736
# Set the output folder where your program will be created
2837
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/out)
2938
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/out)
@@ -62,14 +71,35 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) # -fPIC
6271
# Add compiler options if we are not on windows
6372
if (NOT MSVC)
6473

65-
if (COVERAGE)
74+
if (QDLDL_DEV_COVERAGE)
6675
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage")
6776

6877
if(FORTRAN)
6978
set(CMAKE_FORTRAN_FLAGS "${CMAKE_FORTRAN_FLAGS} --coverage")
7079
endif(FORTRAN)
7180
endif()
7281

82+
if (QDLDL_DEV_ANALYSIS)
83+
check_cxx_compiler_flag( "-fanalyzer" COMPILER_SUPPORTS_FANALYZER )
84+
85+
if( COMPILER_SUPPORTS_FANALYZER )
86+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fanalyzer")
87+
88+
message( STATUS "Enabling -fanalyzer static analysis" )
89+
endif()
90+
endif()
91+
92+
if(OSQP_ASAN)
93+
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer" )
94+
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -D_GLIBCXX_SANITIZE_VECTOR -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer" )
95+
96+
# ASAN shouldn't be used with these options (https://github.com/google/sanitizers/wiki/AddressSanitizer#faq)
97+
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-stack-protector -U_FORTIFY_SOURCE" )
98+
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector -U_FORTIFY_SOURCE" )
99+
100+
message( STATUS "Enabling ASAN" )
101+
endif()
102+
73103
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
74104
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g")
75105
endif (NOT MSVC)

‎configure/qdldl_types.h.in

+7-6
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@
2222
* SPDX-ExternalRef: PACKAGE_MANAGER purl pkg:github/osqp/qdldl
2323
*/
2424
#ifndef QDLDL_TYPES_H
25-
# define QDLDL_TYPES_H
25+
#define QDLDL_TYPES_H
2626

27-
# ifdef __cplusplus
27+
#ifdef __cplusplus
2828
extern "C" {
29-
# endif /* ifdef __cplusplus */
29+
#endif /* ifdef __cplusplus */
3030

31-
#include <limits.h> //for the QDLDL_INT_TYPE_MAX
31+
// For the QDLDL_INT_TYPE_MAX
32+
#include <limits.h>
3233

3334
// QDLDL integer and float types
3435

@@ -49,8 +50,8 @@ typedef @QDLDL_BOOL_TYPE@ QDLDL_bool; /* for boolean values */
4950
/* When defined, QDLDL is using long long instead of int types */
5051
#cmakedefine QDLDL_LONG
5152

52-
# ifdef __cplusplus
53+
#ifdef __cplusplus
5354
}
54-
# endif /* ifdef __cplusplus */
55+
#endif /* ifdef __cplusplus */
5556

5657
#endif /* ifndef QDLDL_TYPES_H */

‎examples/example.c

+153-159
Original file line numberDiff line numberDiff line change
@@ -1,177 +1,171 @@
11
#include "qdldl.h"
2-
#include <stdlib.h>
32
#include <stdio.h>
3+
#include <stdlib.h>
44

5-
void print_arrayi(const QDLDL_int* data, QDLDL_int n,char* varName);
5+
void print_arrayi(const QDLDL_int* data, QDLDL_int n, char* varName);
66
void print_arrayf(const QDLDL_float* data, QDLDL_int n, char* varName);
77
void print_line(void);
88

9-
const QDLDL_int An = 10;
10-
const QDLDL_int Ap[] = {0, 1, 2, 4, 5, 6, 8, 10, 12, 14, 17};
11-
const QDLDL_int Ai[] = {0, 1, 1, 2, 3, 4, 1, 5, 0, 6, 3, 7, 6, 8, 1, 2, 9};
12-
const QDLDL_float Ax[] = {1.0, 0.460641, -0.121189, 0.417928, 0.177828, 0.1,
13-
-0.0290058, -1.0, 0.350321, -0.441092, -0.0845395,
14-
-0.316228, 0.178663, -0.299077, 0.182452, -1.56506, -0.1};
15-
const QDLDL_float b[] = {1,2,3,4,5,6,7,8,9,10};
9+
const QDLDL_int An = 10;
10+
const QDLDL_int Ap[] = { 0, 1, 2, 4, 5, 6, 8, 10, 12, 14, 17 };
11+
const QDLDL_int Ai[] = { 0, 1, 1, 2, 3, 4, 1, 5, 0, 6, 3, 7, 6, 8, 1, 2, 9 };
12+
const QDLDL_float Ax[] = { 1.0, 0.460641, -0.121189, 0.417928, 0.177828, 0.1,
13+
-0.0290058, -1.0, 0.350321, -0.441092, -0.0845395, -0.316228,
14+
0.178663, -0.299077, 0.182452, -1.56506, -0.1 };
15+
const QDLDL_float b[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
1616

1717
int main()
18-
1918
{
20-
QDLDL_int i; // Counter
21-
22-
//data for L and D factors
23-
QDLDL_int Ln = An;
24-
QDLDL_int *Lp;
25-
QDLDL_int *Li;
26-
QDLDL_float *Lx;
27-
QDLDL_float *D;
28-
QDLDL_float *Dinv;
29-
30-
//data for elim tree calculation
31-
QDLDL_int *etree;
32-
QDLDL_int *Lnz;
33-
QDLDL_int sumLnz;
34-
35-
//working data for factorisation
36-
QDLDL_int *iwork;
37-
QDLDL_bool *bwork;
38-
QDLDL_float *fwork;
39-
40-
//Data for results of A\b
41-
QDLDL_float *x;
42-
43-
44-
/*--------------------------------
45-
* pre-factorisation memory allocations
46-
*---------------------------------*/
47-
48-
//These can happen *before* the etree is calculated
49-
//since the sizes are not sparsity pattern specific
50-
51-
//For the elimination tree
52-
etree = (QDLDL_int*)malloc(sizeof(QDLDL_int)*An);
53-
Lnz = (QDLDL_int*)malloc(sizeof(QDLDL_int)*An);
54-
55-
//For the L factors. Li and Lx are sparsity dependent
56-
//so must be done after the etree is constructed
57-
Lp = (QDLDL_int*)malloc(sizeof(QDLDL_int)*(An+1));
58-
D = (QDLDL_float*)malloc(sizeof(QDLDL_float)*An);
59-
Dinv = (QDLDL_float*)malloc(sizeof(QDLDL_float)*An);
60-
61-
//Working memory. Note that both the etree and factor
62-
//calls requires a working vector of QDLDL_int, with
63-
//the factor function requiring 3*An elements and the
64-
//etree only An elements. Just allocate the larger
65-
//amount here and use it in both places
66-
iwork = (QDLDL_int*)malloc(sizeof(QDLDL_int)*(3*An));
67-
bwork = (QDLDL_bool*)malloc(sizeof(QDLDL_bool)*An);
68-
fwork = (QDLDL_float*)malloc(sizeof(QDLDL_float)*An);
69-
70-
/*--------------------------------
71-
* elimination tree calculation
72-
*---------------------------------*/
73-
sumLnz = QDLDL_etree(An,Ap,Ai,iwork,Lnz,etree);
74-
75-
/*--------------------------------
76-
* LDL factorisation
77-
*---------------------------------*/
78-
79-
//First allocate memory for Li and Lx
80-
Li = (QDLDL_int*)malloc(sizeof(QDLDL_int)*sumLnz);
81-
Lx = (QDLDL_float*)malloc(sizeof(QDLDL_float)*sumLnz);
82-
83-
//now factor
84-
QDLDL_factor(An,Ap,Ai,Ax,Lp,Li,Lx,D,Dinv,Lnz,etree,bwork,iwork,fwork);
85-
86-
/*--------------------------------
87-
* solve
88-
*---------------------------------*/
89-
x = (QDLDL_float*)malloc(sizeof(QDLDL_float)*An);
90-
91-
//when solving A\b, start with x = b
92-
for(i=0;i < Ln; i++) x[i] = b[i];
93-
QDLDL_solve(Ln,Lp,Li,Lx,Dinv,x);
94-
95-
/*--------------------------------
96-
* print factors and solution
97-
*---------------------------------*/
98-
printf("\n");
99-
printf("A (CSC format):\n");
100-
print_line();
101-
print_arrayi(Ap, An + 1, "A.p");
102-
print_arrayi(Ai, Ap[An], "A.i");
103-
print_arrayf(Ax, Ap[An], "A.x");
104-
printf("\n\n");
105-
106-
printf("elimination tree:\n");
107-
print_line();
108-
print_arrayi(etree, Ln, "etree");
109-
print_arrayi(Lnz, Ln, "Lnz");
110-
printf("\n\n");
111-
112-
printf("L (CSC format):\n");
113-
print_line();
114-
print_arrayi(Lp, Ln + 1, "L.p");
115-
print_arrayi(Li, Lp[Ln], "L.i");
116-
print_arrayf(Lx, Lp[Ln], "L.x");
117-
printf("\n\n");
118-
119-
printf("D:\n");
120-
print_line();
121-
print_arrayf(D, An, "diag(D) ");
122-
print_arrayf(Dinv, An, "diag(D^{-1})");
123-
printf("\n\n");
124-
125-
printf("solve results:\n");
126-
print_line();
127-
print_arrayf(b, An, "b");
128-
print_arrayf(x, An, "A\\b");
129-
printf("\n\n");
130-
131-
132-
/*--------------------------------
133-
* clean up
134-
*---------------------------------*/
135-
free(Lp);
136-
free(Li);
137-
free(Lx);
138-
free(D);
139-
free(Dinv);
140-
free(etree);
141-
free(Lnz);
142-
free(iwork);
143-
free(bwork);
144-
free(fwork);
145-
free(x);
146-
147-
return 0 ;
148-
149-
19+
QDLDL_int i; // Counter
20+
21+
// data for L and D factors
22+
QDLDL_int Ln = An;
23+
QDLDL_int* Lp;
24+
QDLDL_int* Li;
25+
QDLDL_float* Lx;
26+
QDLDL_float* D;
27+
QDLDL_float* Dinv;
28+
29+
// data for elim tree calculation
30+
QDLDL_int* etree;
31+
QDLDL_int* Lnz;
32+
QDLDL_int sumLnz;
33+
34+
// working data for factorisation
35+
QDLDL_int* iwork;
36+
QDLDL_bool* bwork;
37+
QDLDL_float* fwork;
38+
39+
// Data for results of A\b
40+
QDLDL_float* x;
41+
42+
/*--------------------------------
43+
* pre-factorisation memory allocations
44+
*---------------------------------*/
45+
46+
// These can happen *before* the etree is calculated
47+
// since the sizes are not sparsity pattern specific
48+
49+
// For the elimination tree
50+
etree = (QDLDL_int*) malloc(sizeof(QDLDL_int) * An);
51+
Lnz = (QDLDL_int*) malloc(sizeof(QDLDL_int) * An);
52+
53+
// For the L factors. Li and Lx are sparsity dependent
54+
// so must be done after the etree is constructed
55+
Lp = (QDLDL_int*) malloc(sizeof(QDLDL_int) * (An + 1));
56+
D = (QDLDL_float*) malloc(sizeof(QDLDL_float) * An);
57+
Dinv = (QDLDL_float*) malloc(sizeof(QDLDL_float) * An);
58+
59+
// Working memory. Note that both the etree and factor
60+
// calls requires a working vector of QDLDL_int, with
61+
// the factor function requiring 3*An elements and the
62+
// etree only An elements. Just allocate the larger
63+
// amount here and use it in both places
64+
iwork = (QDLDL_int*) malloc(sizeof(QDLDL_int) * (3 * An));
65+
bwork = (QDLDL_bool*) malloc(sizeof(QDLDL_bool) * An);
66+
fwork = (QDLDL_float*) malloc(sizeof(QDLDL_float) * An);
67+
68+
/*--------------------------------
69+
* elimination tree calculation
70+
*---------------------------------*/
71+
sumLnz = QDLDL_etree(An, Ap, Ai, iwork, Lnz, etree);
72+
73+
/*--------------------------------
74+
* LDL factorisation
75+
*---------------------------------*/
76+
77+
// First allocate memory for Li and Lx
78+
Li = (QDLDL_int*) malloc(sizeof(QDLDL_int) * sumLnz);
79+
Lx = (QDLDL_float*) malloc(sizeof(QDLDL_float) * sumLnz);
80+
81+
// now factor
82+
QDLDL_factor(An, Ap, Ai, Ax, Lp, Li, Lx, D, Dinv, Lnz, etree, bwork, iwork, fwork);
83+
84+
/*--------------------------------
85+
* solve
86+
*---------------------------------*/
87+
x = (QDLDL_float*) malloc(sizeof(QDLDL_float) * An);
88+
89+
// when solving A\b, start with x = b
90+
for(i = 0; i < Ln; i++) {
91+
x[i] = b[i];
92+
}
93+
QDLDL_solve(Ln, Lp, Li, Lx, Dinv, x);
94+
95+
/*--------------------------------
96+
* print factors and solution
97+
*---------------------------------*/
98+
printf("\n");
99+
printf("A (CSC format):\n");
100+
print_line();
101+
print_arrayi(Ap, An + 1, "A.p");
102+
print_arrayi(Ai, Ap[An], "A.i");
103+
print_arrayf(Ax, Ap[An], "A.x");
104+
printf("\n\n");
105+
106+
printf("elimination tree:\n");
107+
print_line();
108+
print_arrayi(etree, Ln, "etree");
109+
print_arrayi(Lnz, Ln, "Lnz");
110+
printf("\n\n");
111+
112+
printf("L (CSC format):\n");
113+
print_line();
114+
print_arrayi(Lp, Ln + 1, "L.p");
115+
print_arrayi(Li, Lp[Ln], "L.i");
116+
print_arrayf(Lx, Lp[Ln], "L.x");
117+
printf("\n\n");
118+
119+
printf("D:\n");
120+
print_line();
121+
print_arrayf(D, An, "diag(D) ");
122+
print_arrayf(Dinv, An, "diag(D^{-1})");
123+
printf("\n\n");
124+
125+
printf("solve results:\n");
126+
print_line();
127+
print_arrayf(b, An, "b");
128+
print_arrayf(x, An, "A\\b");
129+
printf("\n\n");
130+
131+
/*--------------------------------
132+
* clean up
133+
*---------------------------------*/
134+
free(Lp);
135+
free(Li);
136+
free(Lx);
137+
free(D);
138+
free(Dinv);
139+
free(etree);
140+
free(Lnz);
141+
free(iwork);
142+
free(bwork);
143+
free(fwork);
144+
free(x);
145+
146+
return 0;
150147
}
151148

152-
153-
void print_line(void){
154-
printf("--------------------------\n");
149+
void print_line(void) {
150+
printf("--------------------------\n");
155151
}
156152

157-
void print_arrayi(const QDLDL_int* data, QDLDL_int n,char* varName){
158-
159-
QDLDL_int i;
160-
printf("%s = [",varName);
161-
for(i=0; i< n; i++){
162-
printf("%i,",(int)data[i]);
163-
}
164-
printf("]\n");
153+
void print_arrayi(const QDLDL_int* data, QDLDL_int n, char* varName) {
154+
QDLDL_int i;
155+
printf("%s = [", varName);
165156

157+
for(i = 0; i < n; i++) {
158+
printf("%i,", (int) data[i]);
159+
}
160+
printf("]\n");
166161
}
167162

168-
void print_arrayf(const QDLDL_float* data, QDLDL_int n, char* varName){
169-
170-
QDLDL_int i;
171-
printf("%s = [",varName);
172-
for(i=0; i< n; i++){
173-
printf("%.3g,",data[i]);
174-
}
175-
printf("]\n");
163+
void print_arrayf(const QDLDL_float* data, QDLDL_int n, char* varName) {
164+
QDLDL_int i;
165+
printf("%s = [", varName);
176166

167+
for(i = 0; i < n; i++) {
168+
printf("%.3g,", data[i]);
169+
}
170+
printf("]\n");
177171
}

‎include/qdldl.h

+99-122
Original file line numberDiff line numberDiff line change
@@ -31,121 +31,108 @@
3131
// Define the function attributes that are needed to mark functions as being
3232
// visible for linking in the shared library version of QDLDL
3333
#if defined(_WIN32)
34-
# if defined(BUILDING_QDLDL)
35-
# define QDLDL_API_EXPORT __declspec(dllexport)
36-
# else
37-
# define QDLDL_API_EXPORT __declspec(dllimport)
38-
# endif
34+
#if defined(BUILDING_QDLDL)
35+
#define QDLDL_API_EXPORT __declspec(dllexport)
3936
#else
40-
# if defined(BUILDING_QDLDL)
41-
# define QDLDL_API_EXPORT __attribute__((visibility("default")))
42-
# else
43-
# define QDLDL_API_EXPORT
44-
# endif
37+
#define QDLDL_API_EXPORT __declspec(dllimport)
38+
#endif
39+
#else
40+
#if defined(BUILDING_QDLDL)
41+
#define QDLDL_API_EXPORT __attribute__((visibility("default")))
42+
#else
43+
#define QDLDL_API_EXPORT
44+
#endif
4545
#endif
4646

4747
// Only define API export parts when using the shared library
4848
#if defined(QDLDL_SHARED_LIB)
49-
# define QDLDL_API QDLDL_API_EXPORT
49+
#define QDLDL_API QDLDL_API_EXPORT
5050
#else
51-
# define QDLDL_API
51+
#define QDLDL_API
5252
#endif
5353

54-
# ifdef __cplusplus
54+
#ifdef __cplusplus
5555
extern "C" {
56-
# endif // ifdef __cplusplus
56+
#endif // ifdef __cplusplus
5757

5858
/**
59-
* Compute the elimination tree for a quasidefinite matrix
60-
* in compressed sparse column form, where the input matrix is
61-
* assumed to contain data for the upper triangular part of A only,
62-
* and there are no duplicate indices.
63-
*
64-
* Returns an elimination tree for the factorization A = LDL^T and a
65-
* count of the nonzeros in each column of L that are strictly below the
66-
* diagonal.
67-
*
68-
* Does not use MALLOC. It is assumed that the arrays work, Lnz, and
69-
* etree will be allocated with a number of elements equal to n.
70-
*
71-
* The data in (n,Ap,Ai) are from a square matrix A in CSC format, and
72-
* should include the upper triangular part of A only.
73-
*
74-
* This function is only intended for factorisation of QD matrices specified
75-
* by their upper triangular part. An error is returned if any column has
76-
* data below the diagonal or s completely empty.
77-
*
78-
* For matrices with a non-empty column but a zero on the corresponding diagonal,
79-
* this function will *not* return an error, as it may still be possible to factor
80-
* such a matrix in LDL form. No promises are made in this case though...
81-
*
82-
* @param n number of columns in CSC matrix A (assumed square)
83-
* @param Ap column pointers (size n+1) for columns of A
84-
* @param Ai row indices of A. Has Ap[n] elements
85-
* @param work work vector (size n) (no meaning on return)
86-
* @param Lnz count of nonzeros in each column of L (size n) below diagonal
87-
* @param etree elimination tree (size n)
88-
* @return total sum of Lnz (i.e. total nonzeros in L below diagonal).
89-
* Returns -1 if the input is not triu or has an empty column.
90-
* Returns -2 if the return value overflows QDLDL_int.
91-
*
92-
*/
93-
QDLDL_API QDLDL_int QDLDL_etree(const QDLDL_int n,
94-
const QDLDL_int* Ap,
95-
const QDLDL_int* Ai,
96-
QDLDL_int* work,
97-
QDLDL_int* Lnz,
98-
QDLDL_int* etree);
59+
* Compute the elimination tree for a quasidefinite matrix
60+
* in compressed sparse column form, where the input matrix is
61+
* assumed to contain data for the upper triangular part of A only,
62+
* and there are no duplicate indices.
63+
*
64+
* Returns an elimination tree for the factorization A = LDL^T and a
65+
* count of the nonzeros in each column of L that are strictly below the
66+
* diagonal.
67+
*
68+
* Does not use MALLOC. It is assumed that the arrays work, Lnz, and
69+
* etree will be allocated with a number of elements equal to n.
70+
*
71+
* The data in (n,Ap,Ai) are from a square matrix A in CSC format, and
72+
* should include the upper triangular part of A only.
73+
*
74+
* This function is only intended for factorisation of QD matrices specified
75+
* by their upper triangular part. An error is returned if any column has
76+
* data below the diagonal or s completely empty.
77+
*
78+
* For matrices with a non-empty column but a zero on the corresponding diagonal,
79+
* this function will *not* return an error, as it may still be possible to factor
80+
* such a matrix in LDL form. No promises are made in this case though...
81+
*
82+
* @param n number of columns in CSC matrix A (assumed square)
83+
* @param Ap column pointers (size n+1) for columns of A
84+
* @param Ai row indices of A. Has Ap[n] elements
85+
* @param work work vector (size n) (no meaning on return)
86+
* @param Lnz count of nonzeros in each column of L (size n) below diagonal
87+
* @param etree elimination tree (size n)
88+
* @return total sum of Lnz (i.e. total nonzeros in L below diagonal).
89+
* Returns -1 if the input is not triu or has an empty column.
90+
* Returns -2 if the return value overflows QDLDL_int.
91+
*
92+
*/
93+
QDLDL_API QDLDL_int QDLDL_etree(const QDLDL_int n, const QDLDL_int* Ap, const QDLDL_int* Ai,
94+
QDLDL_int* work, QDLDL_int* Lnz, QDLDL_int* etree);
9995

10096

10197
/**
102-
* Compute an LDL decomposition for a quasidefinite matrix
103-
* in compressed sparse column form, where the input matrix is
104-
* assumed to contain data for the upper triangular part of A only,
105-
* and there are no duplicate indices.
106-
*
107-
* Returns factors L, D and Dinv = 1./D.
108-
*
109-
* Does not use MALLOC. It is assumed that L will be a compressed
110-
* sparse column matrix with data (n,Lp,Li,Lx) with sufficient space
111-
* allocated, with a number of nonzeros equal to the count given
112-
* as a return value by QDLDL_etree
113-
*
114-
* @param n number of columns in L and A (both square)
115-
* @param Ap column pointers (size n+1) for columns of A (not modified)
116-
* @param Ai row indices of A. Has Ap[n] elements (not modified)
117-
* @param Ax data of A. Has Ap[n] elements (not modified)
118-
* @param Lp column pointers (size n+1) for columns of L
119-
* @param Li row indices of L. Has Lp[n] elements
120-
* @param Lx data of L. Has Lp[n] elements
121-
* @param D vectorized factor D. Length is n
122-
* @param Dinv reciprocal of D. Length is n
123-
* @param Lnz count of nonzeros in each column of L below diagonal,
124-
* as given by QDLDL_etree (not modified)
125-
* @param etree elimination tree as as given by QDLDL_etree (not modified)
126-
* @param bwork working array of bools. Length is n
127-
* @param iwork working array of integers. Length is 3*n
128-
* @param fwork working array of floats. Length is n
129-
* @return Returns a count of the number of positive elements
130-
* in D. Returns -1 and exits immediately if any element
131-
* of D evaluates exactly to zero (matrix is not quasidefinite
132-
* or otherwise LDL factorisable)
133-
*
134-
*/
135-
QDLDL_API QDLDL_int QDLDL_factor(const QDLDL_int n,
136-
const QDLDL_int* Ap,
137-
const QDLDL_int* Ai,
138-
const QDLDL_float* Ax,
139-
QDLDL_int* Lp,
140-
QDLDL_int* Li,
141-
QDLDL_float* Lx,
142-
QDLDL_float* D,
143-
QDLDL_float* Dinv,
144-
const QDLDL_int* Lnz,
145-
const QDLDL_int* etree,
146-
QDLDL_bool* bwork,
147-
QDLDL_int* iwork,
148-
QDLDL_float* fwork);
98+
* Compute an LDL decomposition for a quasidefinite matrix
99+
* in compressed sparse column form, where the input matrix is
100+
* assumed to contain data for the upper triangular part of A only,
101+
* and there are no duplicate indices.
102+
*
103+
* Returns factors L, D and Dinv = 1./D.
104+
*
105+
* Does not use MALLOC. It is assumed that L will be a compressed
106+
* sparse column matrix with data (n,Lp,Li,Lx) with sufficient space
107+
* allocated, with a number of nonzeros equal to the count given
108+
* as a return value by QDLDL_etree
109+
*
110+
* @param n number of columns in L and A (both square)
111+
* @param Ap column pointers (size n+1) for columns of A (not modified)
112+
* @param Ai row indices of A. Has Ap[n] elements (not modified)
113+
* @param Ax data of A. Has Ap[n] elements (not modified)
114+
* @param Lp column pointers (size n+1) for columns of L
115+
* @param Li row indices of L. Has Lp[n] elements
116+
* @param Lx data of L. Has Lp[n] elements
117+
* @param D vectorized factor D. Length is n
118+
* @param Dinv reciprocal of D. Length is n
119+
* @param Lnz count of nonzeros in each column of L below diagonal,
120+
* as given by QDLDL_etree (not modified)
121+
* @param etree elimination tree as as given by QDLDL_etree (not modified)
122+
* @param bwork working array of bools. Length is n
123+
* @param iwork working array of integers. Length is 3*n
124+
* @param fwork working array of floats. Length is n
125+
* @return Returns a count of the number of positive elements
126+
* in D. Returns -1 and exits immediately if any element
127+
* of D evaluates exactly to zero (matrix is not quasidefinite
128+
* or otherwise LDL factorisable)
129+
*
130+
*/
131+
QDLDL_API QDLDL_int QDLDL_factor(const QDLDL_int n, const QDLDL_int* Ap, const QDLDL_int* Ai,
132+
const QDLDL_float* Ax, QDLDL_int* Lp, QDLDL_int* Li,
133+
QDLDL_float* Lx, QDLDL_float* D, QDLDL_float* Dinv,
134+
const QDLDL_int* Lnz, const QDLDL_int* etree, QDLDL_bool* bwork,
135+
QDLDL_int* iwork, QDLDL_float* fwork);
149136

150137

151138
/**
@@ -161,13 +148,9 @@ QDLDL_API QDLDL_int QDLDL_factor(const QDLDL_int n,
161148
* @param Dinv reciprocal of D. Length is n
162149
* @param x initialized to b. Equal to x on return
163150
*
164-
*/
165-
QDLDL_API void QDLDL_solve(const QDLDL_int n,
166-
const QDLDL_int* Lp,
167-
const QDLDL_int* Li,
168-
const QDLDL_float* Lx,
169-
const QDLDL_float* Dinv,
170-
QDLDL_float* x);
151+
*/
152+
QDLDL_API void QDLDL_solve(const QDLDL_int n, const QDLDL_int* Lp, const QDLDL_int* Li,
153+
const QDLDL_float* Lx, const QDLDL_float* Dinv, QDLDL_float* x);
171154

172155

173156
/**
@@ -182,12 +165,9 @@ QDLDL_API void QDLDL_solve(const QDLDL_int n,
182165
* @param Lx data of L. Has Lp[n] elements
183166
* @param x initialized to b. Equal to x on return
184167
*
185-
*/
186-
QDLDL_API void QDLDL_Lsolve(const QDLDL_int n,
187-
const QDLDL_int* Lp,
188-
const QDLDL_int* Li,
189-
const QDLDL_float* Lx,
190-
QDLDL_float* x);
168+
*/
169+
QDLDL_API void QDLDL_Lsolve(const QDLDL_int n, const QDLDL_int* Lp, const QDLDL_int* Li,
170+
const QDLDL_float* Lx, QDLDL_float* x);
191171

192172

193173
/**
@@ -202,15 +182,12 @@ QDLDL_API void QDLDL_Lsolve(const QDLDL_int n,
202182
* @param Lx data of L. Has Lp[n] elements
203183
* @param x initialized to b. Equal to x on return
204184
*
205-
*/
206-
QDLDL_API void QDLDL_Ltsolve(const QDLDL_int n,
207-
const QDLDL_int* Lp,
208-
const QDLDL_int* Li,
209-
const QDLDL_float* Lx,
210-
QDLDL_float* x);
185+
*/
186+
QDLDL_API void QDLDL_Ltsolve(const QDLDL_int n, const QDLDL_int* Lp, const QDLDL_int* Li,
187+
const QDLDL_float* Lx, QDLDL_float* x);
211188

212-
# ifdef __cplusplus
189+
#ifdef __cplusplus
213190
}
214-
# endif // ifdef __cplusplus
191+
#endif // ifdef __cplusplus
215192

216193
#endif // ifndef QDLDL_H

‎src/qdldl.c

+242-239
Large diffs are not rendered by default.

‎tests/qdldl_tester.c

+143-135
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,9 @@
3131
#include "minunit.h"
3232
#include "qdldl.h"
3333

34-
//utility functions for solves
34+
// Utility functions for solves
3535
QDLDL_float vec_diff_norm(QDLDL_float* x, QDLDL_float* y, QDLDL_int len);
36-
int ldl_factor_solve(QDLDL_int An, QDLDL_int* Ap,QDLDL_int* Ai,
37-
QDLDL_float* Ax,QDLDL_float* b);
36+
int ldl_factor_solve(QDLDL_int An, QDLDL_int* Ap, QDLDL_int* Ai, QDLDL_float* Ax, QDLDL_float* b);
3837

3938
// Include tests
4039
#include "test_basic.h"
@@ -52,148 +51,157 @@ int tests_run = 0;
5251

5352

5453
static char* all_tests() {
55-
mu_run_test(test_basic);
56-
mu_run_test(test_identity);
57-
mu_run_test(test_rank_deficient);
58-
mu_run_test(test_singleton);
59-
mu_run_test(test_sym_structure);
60-
mu_run_test(test_tril_structure);
61-
mu_run_test(test_two_by_two);
62-
mu_run_test(test_zero_on_diag);
63-
mu_run_test(test_osqp_kkt);
64-
65-
return 0;
54+
mu_run_test(test_basic);
55+
mu_run_test(test_identity);
56+
mu_run_test(test_rank_deficient);
57+
mu_run_test(test_singleton);
58+
mu_run_test(test_sym_structure);
59+
mu_run_test(test_tril_structure);
60+
mu_run_test(test_two_by_two);
61+
mu_run_test(test_zero_on_diag);
62+
mu_run_test(test_osqp_kkt);
63+
64+
return 0;
6665
}
6766

6867

68+
QDLDL_float vec_diff_norm(QDLDL_float* x, QDLDL_float* y, QDLDL_int len) {
69+
QDLDL_float maxDiff = 0.0;
70+
QDLDL_float elDiff = 0.0;
71+
QDLDL_int i = 0;
6972

70-
71-
72-
QDLDL_float vec_diff_norm(QDLDL_float* x, QDLDL_float* y, QDLDL_int len){
73-
74-
QDLDL_float maxDiff = 0.0;
75-
QDLDL_float elDiff = 0.0;
76-
QDLDL_int i;
77-
78-
for(i = 0; i < len; i++){
79-
elDiff = x[i] - y[i];
80-
maxDiff = (elDiff > maxDiff) ? elDiff : ((-elDiff > maxDiff) ? -elDiff : maxDiff);
81-
}
82-
return maxDiff;
83-
73+
for(i = 0; i < len; i++) {
74+
elDiff = x[i] - y[i];
75+
maxDiff = (elDiff > maxDiff) ? elDiff : ((-elDiff > maxDiff) ? -elDiff : maxDiff);
76+
}
77+
return maxDiff;
8478
}
8579

86-
int ldl_factor_solve(QDLDL_int An,
87-
QDLDL_int* Ap,
88-
QDLDL_int* Ai,
89-
QDLDL_float* Ax,
90-
QDLDL_float* b){
91-
92-
//data for L and D factors
93-
QDLDL_int Ln = An;
94-
QDLDL_int *Lp;
95-
QDLDL_int *Li;
96-
QDLDL_float *Lx;
97-
QDLDL_float *D;
98-
QDLDL_float *Dinv;
99-
100-
//data for elim tree calculation
101-
QDLDL_int *etree;
102-
QDLDL_int *Lnz;
103-
QDLDL_int sumLnz;
104-
105-
//data for factorisation
106-
QDLDL_int *iwork;
107-
QDLDL_bool *bwork;
108-
QDLDL_float *fwork;
109-
QDLDL_int factorStatus;
110-
111-
/*--------------------------------
112-
* pre-factorisation memory allocations
113-
*---------------------------------*/
114-
115-
//These can happen *before* the etree is calculated
116-
//since the sizes are not sparsity pattern specific
117-
118-
//For the elimination tree
119-
etree = (QDLDL_int*)malloc(sizeof(QDLDL_int)*An);
120-
Lnz = (QDLDL_int*)malloc(sizeof(QDLDL_int)*An);
121-
122-
//For the L factors. Li and Lx are sparsity dependent
123-
//so must be done after the etree is constructed
124-
Lp = (QDLDL_int*)malloc(sizeof(QDLDL_int)*(An+1));
125-
D = (QDLDL_float*)malloc(sizeof(QDLDL_float)*An);
126-
Dinv = (QDLDL_float*)malloc(sizeof(QDLDL_float)*An);
127-
128-
//Working memory. Note that both the etree and factor
129-
//calls requires a working vector of QDLDL_int, with
130-
//the factor function requiring 3*An elements and the
131-
//etree only An elements. Just allocate the larger
132-
//amount here and use it in both places
133-
iwork = (QDLDL_int*)malloc(sizeof(QDLDL_int)*(3*An));
134-
bwork = (QDLDL_bool*)malloc(sizeof(QDLDL_bool)*An);
135-
fwork = (QDLDL_float*)malloc(sizeof(QDLDL_float)*An);
136-
137-
138-
/*--------------------------------
139-
* elimination tree calculation
140-
*---------------------------------*/
141-
sumLnz = QDLDL_etree(An,Ap,Ai,iwork,Lnz,etree);
142-
143-
//not perfect triu A = bomb
144-
if(sumLnz < 0){
145-
free(Lp); free(D); free(Dinv); free(etree); free(Lnz);
146-
free(iwork); free(bwork); free(fwork);
147-
return sumLnz;
148-
}
149-
150-
/*--------------------------------
151-
* LDL factorisation
152-
*---------------------------------*/
153-
154-
//First allocate memory for Li and Lx
155-
Li = (QDLDL_int*)malloc(sizeof(QDLDL_int)*sumLnz);
156-
Lx = (QDLDL_float*)malloc(sizeof(QDLDL_float)*sumLnz);
157-
158-
//now factor
159-
factorStatus = QDLDL_factor(An,Ap,Ai,Ax,Lp,Li,Lx,D,Dinv,Lnz,etree,bwork,iwork,fwork);
160-
161-
//Zero on the diagonal = bomb
162-
if(factorStatus < 0){
163-
free(Lp); free(D); free(Dinv); free(etree); free(Lnz);
164-
free(iwork); free(bwork); free(fwork); free(Li); free(Lx);
165-
return factorStatus;
166-
}
167-
168-
/*--------------------------------
169-
* solve
170-
*---------------------------------*/
171-
QDLDL_solve(Ln,Lp,Li,Lx,Dinv,b);
172-
173-
174-
/*--------------------------------
175-
* clean up
176-
*---------------------------------*/
177-
free(Lp); free(D); free(Dinv); free(etree); free(Lnz);
178-
free(iwork); free(bwork); free(fwork); free(Li); free(Lx);
179-
180-
return 0 ;
181-
80+
int ldl_factor_solve(QDLDL_int An, QDLDL_int* Ap, QDLDL_int* Ai, QDLDL_float* Ax, QDLDL_float* b) {
81+
// Data for L and D factors
82+
QDLDL_int Ln = An;
83+
QDLDL_int* Lp = 0;
84+
QDLDL_int* Li = 0;
85+
QDLDL_float* Lx;
86+
QDLDL_float* D;
87+
QDLDL_float* Dinv;
88+
89+
// Data for elim tree calculation
90+
QDLDL_int* etree;
91+
QDLDL_int* Lnz;
92+
QDLDL_int sumLnz = 0;
93+
94+
// Data for factorisation
95+
QDLDL_int* iwork;
96+
QDLDL_bool* bwork;
97+
QDLDL_float* fwork;
98+
QDLDL_int factorStatus = 0;
99+
100+
/*--------------------------------
101+
* pre-factorisation memory allocations
102+
*---------------------------------*/
103+
104+
// These can happen *before* the etree is calculated
105+
// since the sizes are not sparsity pattern specific
106+
107+
// For the elimination tree
108+
etree = (QDLDL_int*) malloc(sizeof(QDLDL_int) * An);
109+
Lnz = (QDLDL_int*) malloc(sizeof(QDLDL_int) * An);
110+
111+
// For the L factors. Li and Lx are sparsity dependent
112+
// so must be done after the etree is constructed
113+
Lp = (QDLDL_int*) malloc(sizeof(QDLDL_int) * (An + 1));
114+
D = (QDLDL_float*) malloc(sizeof(QDLDL_float) * An);
115+
Dinv = (QDLDL_float*) malloc(sizeof(QDLDL_float) * An);
116+
117+
// Working memory. Note that both the etree and factor
118+
// calls requires a working vector of QDLDL_int, with
119+
// the factor function requiring 3*An elements and the
120+
// etree only An elements. Just allocate the larger
121+
// amount here and use it in both places
122+
iwork = (QDLDL_int*) malloc(sizeof(QDLDL_int) * (3 * An));
123+
bwork = (QDLDL_bool*) malloc(sizeof(QDLDL_bool) * An);
124+
fwork = (QDLDL_float*) malloc(sizeof(QDLDL_float) * An);
125+
126+
127+
/*--------------------------------
128+
* Elimination tree calculation
129+
*---------------------------------*/
130+
sumLnz = QDLDL_etree(An, Ap, Ai, iwork, Lnz, etree);
131+
132+
// Not perfect triu A = bomb
133+
if(sumLnz < 0) {
134+
free(Lp);
135+
free(D);
136+
free(Dinv);
137+
free(etree);
138+
free(Lnz);
139+
free(iwork);
140+
free(bwork);
141+
free(fwork);
142+
return sumLnz;
143+
}
144+
145+
/*--------------------------------
146+
* LDL factorisation
147+
*---------------------------------*/
148+
149+
// First allocate memory for Li and Lx
150+
Li = (QDLDL_int*) malloc(sizeof(QDLDL_int) * sumLnz);
151+
Lx = (QDLDL_float*) malloc(sizeof(QDLDL_float) * sumLnz);
152+
153+
// Now factor
154+
factorStatus =
155+
QDLDL_factor(An, Ap, Ai, Ax, Lp, Li, Lx, D, Dinv, Lnz, etree, bwork, iwork, fwork);
156+
157+
// Zero on the diagonal = bomb
158+
if(factorStatus < 0) {
159+
free(Lp);
160+
free(D);
161+
free(Dinv);
162+
free(etree);
163+
free(Lnz);
164+
free(iwork);
165+
free(bwork);
166+
free(fwork);
167+
free(Li);
168+
free(Lx);
169+
return factorStatus;
170+
}
171+
172+
/*--------------------------------
173+
* solve
174+
*---------------------------------*/
175+
QDLDL_solve(Ln, Lp, Li, Lx, Dinv, b);
176+
177+
178+
/*--------------------------------
179+
* clean up
180+
*---------------------------------*/
181+
free(Lp);
182+
free(D);
183+
free(Dinv);
184+
free(etree);
185+
free(Lnz);
186+
free(iwork);
187+
free(bwork);
188+
free(fwork);
189+
free(Li);
190+
free(Lx);
191+
192+
return 0;
182193
}
183194

184195

185-
186-
187196
int main(void) {
188-
char *result = all_tests();
197+
char* result = all_tests();
189198

190-
if (result != 0) {
191-
printf("%s\n", result);
192-
}
193-
else {
194-
printf("ALL TESTS PASSED\n");
195-
}
196-
printf("Tests run: %d\n", tests_run);
199+
if(result != 0) {
200+
printf("%s\n", result);
201+
} else {
202+
printf("ALL TESTS PASSED\n");
203+
}
204+
printf("Tests run: %d\n", tests_run);
197205

198-
return result != 0;
206+
return result != 0;
199207
}

‎tests/test_basic.h

+17-18
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,25 @@
2121
* SPDX-License-Identifier: Apache-2.0
2222
*/
2323

24-
static char* test_basic()
25-
{
26-
//A matrix data
27-
QDLDL_int Ap[] = {0, 1, 2, 4, 5, 6, 8, 10, 12, 14, 17};
28-
QDLDL_int Ai[] = {0, 1, 1, 2, 3, 4, 1, 5, 0, 6, 3, 7, 6, 8, 1, 2, 9};
29-
QDLDL_float Ax[] = {1.0, 0.460641, -0.121189, 0.417928, 0.177828,
30-
0.1, -0.0290058, -1.0, 0.350321, -0.441092, -0.0845395,
31-
-0.316228, 0.178663, -0.299077, 0.182452, -1.56506, -0.1};
32-
QDLDL_int An = 10;
24+
static char* test_basic() {
25+
// A matrix data
26+
QDLDL_int Ap[] = { 0, 1, 2, 4, 5, 6, 8, 10, 12, 14, 17 };
27+
QDLDL_int Ai[] = { 0, 1, 1, 2, 3, 4, 1, 5, 0, 6, 3, 7, 6, 8, 1, 2, 9 };
28+
QDLDL_float Ax[] = { 1.0, 0.460641, -0.121189, 0.417928, 0.177828, 0.1,
29+
-0.0290058, -1.0, 0.350321, -0.441092, -0.0845395, -0.316228,
30+
0.178663, -0.299077, 0.182452, -1.56506, -0.1 };
31+
QDLDL_int An = 10;
3332

34-
// RHS and solution to Ax = b
35-
QDLDL_float b[] = {1,2,3,4,5,6,7,8,9,10};
36-
QDLDL_float xsol[] = {10.2171, 3.9416, -5.69096, 9.28661, 50.0, -6.11433,
37-
-26.3104, -27.7809, -45.8099, -3.74178};
33+
// RHS and solution to Ax = b
34+
QDLDL_float b[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
35+
QDLDL_float xsol[] = { 10.2171, 3.9416, -5.69096, 9.28661, 50.0,
36+
-6.11433, -26.3104, -27.7809, -45.8099, -3.74178 };
3837

39-
//x replaces b during solve
40-
int status = ldl_factor_solve(An,Ap,Ai,Ax,b);
38+
// x replaces b during solve
39+
int status = ldl_factor_solve(An, Ap, Ai, Ax, b);
4140

42-
mu_assert("Factorisation failed", status >= 0);
43-
mu_assert("Solve accuracy failed", vec_diff_norm(b,xsol,An) < QDLDL_TESTS_TOL);
41+
mu_assert("Factorisation failed", status >= 0);
42+
mu_assert("Solve accuracy failed", vec_diff_norm(b, xsol, An) < QDLDL_TESTS_TOL);
4443

45-
return 0;
44+
return 0;
4645
}

‎tests/test_identity.h

+14-15
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,22 @@
2121
* SPDX-License-Identifier: Apache-2.0
2222
*/
2323

24-
static char* test_identity()
25-
{
26-
//A matrix data
27-
QDLDL_int Ap[] = {0, 1, 2, 3, 4};
28-
QDLDL_int Ai[] = {0, 1, 2, 3};
29-
QDLDL_float Ax[] = {1.0, 1.0, 1.0, 1.0};
30-
QDLDL_int An = 4;
24+
static char* test_identity() {
25+
// A matrix data
26+
QDLDL_int Ap[] = { 0, 1, 2, 3, 4 };
27+
QDLDL_int Ai[] = { 0, 1, 2, 3 };
28+
QDLDL_float Ax[] = { 1.0, 1.0, 1.0, 1.0 };
29+
QDLDL_int An = 4;
3130

32-
// RHS and solution to Ax = b
33-
QDLDL_float b[] = {2,2,2,2};
34-
QDLDL_float xsol[] = {2,2,2,2};
31+
// RHS and solution to Ax = b
32+
QDLDL_float b[] = { 2, 2, 2, 2 };
33+
QDLDL_float xsol[] = { 2, 2, 2, 2 };
3534

36-
//x replaces b during solve
37-
int status = ldl_factor_solve(An,Ap,Ai,Ax,b);
35+
// x replaces b during solve
36+
int status = ldl_factor_solve(An, Ap, Ai, Ax, b);
3837

39-
mu_assert("Factorisation failed", status >= 0);
40-
mu_assert("Solve accuracy failed", vec_diff_norm(b,xsol,An) < QDLDL_TESTS_TOL);
38+
mu_assert("Factorisation failed", status >= 0);
39+
mu_assert("Solve accuracy failed", vec_diff_norm(b, xsol, An) < QDLDL_TESTS_TOL);
4140

42-
return 0;
41+
return 0;
4342
}

‎tests/test_osqp_kkt.h

+19-20
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,28 @@
2121
* SPDX-License-Identifier: Apache-2.0
2222
*/
2323

24-
static char* test_osqp_kkt()
25-
{
26-
// Unordered A
27-
QDLDL_int Ap[] = {0, 1, 2, 5, 6, 7, 8, 12};
28-
QDLDL_int Ai[] = {0, 1, 2, 1, 0, 3, 4, 5, 5, 6, 4, 3};
29-
QDLDL_float Ax[] = {-0.25, -0.25, 1.0, 0.513578, 0.529142, -0.25, -0.25, 1.10274, 0.15538, 1.25883, 0.13458, 0.621134};
24+
static char* test_osqp_kkt() {
25+
// Unordered A
26+
QDLDL_int Ap[] = { 0, 1, 2, 5, 6, 7, 8, 12 };
27+
QDLDL_int Ai[] = { 0, 1, 2, 1, 0, 3, 4, 5, 5, 6, 4, 3 };
28+
QDLDL_float Ax[] = { -0.25, -0.25, 1.0, 0.513578, 0.529142, -0.25,
29+
-0.25, 1.10274, 0.15538, 1.25883, 0.13458, 0.621134 };
3030

31-
// Ordered A (this works)
32-
// QDLDL_int Ap[] = {0, 1, 2, 5, 6, 7, 8, 12};
33-
// QDLDL_int Ai[] = {0, 1, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6};
34-
// QDLDL_float Ax[] = {-0.25, -0.25, 0.529142, 0.513578, 1.0, -0.25, -0.25, 1.10274, 0.621134, 0.13458, 0.15538, 1.25883};
35-
QDLDL_int An = 7;
31+
// Ordered A (this works)
32+
// QDLDL_int Ap[] = {0, 1, 2, 5, 6, 7, 8, 12};
33+
// QDLDL_int Ai[] = {0, 1, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6};
34+
// QDLDL_float Ax[] = {-0.25, -0.25, 0.529142, 0.513578, 1.0, -0.25, -0.25, 1.10274, 0.621134, 0.13458, 0.15538, 1.25883};
35+
QDLDL_int An = 7;
3636

37-
// RHS and solution to Ax = b
38-
QDLDL_float b[] = {-0.595598, -0.0193715, -0.576156, -0.168746, 0.61543, 0.419073, 1.31087};
39-
QDLDL_float xsol[] = {1.13141, -1.1367, -0.591044, 1.68867, -2.24209, 0.32254, 0.407998};
37+
// RHS and solution to Ax = b
38+
QDLDL_float b[] = { -0.595598, -0.0193715, -0.576156, -0.168746, 0.61543, 0.419073, 1.31087 };
39+
QDLDL_float xsol[] = { 1.13141, -1.1367, -0.591044, 1.68867, -2.24209, 0.32254, 0.407998 };
4040

41-
//x replaces b during solve
42-
int status = ldl_factor_solve(An,Ap,Ai,Ax,b);
41+
// x replaces b during solve
42+
int status = ldl_factor_solve(An, Ap, Ai, Ax, b);
4343

44-
mu_assert("Factorisation failed", status >= 0);
45-
mu_assert("Solve accuracy failed", vec_diff_norm(b,xsol,An) < QDLDL_TESTS_TOL);
44+
mu_assert("Factorisation failed", status >= 0);
45+
mu_assert("Solve accuracy failed", vec_diff_norm(b, xsol, An) < QDLDL_TESTS_TOL);
4646

47-
return 0;
47+
return 0;
4848
}
49-

‎tests/test_rank_deficient.h

+12-13
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,20 @@
2121
* SPDX-License-Identifier: Apache-2.0
2222
*/
2323

24-
static char* test_rank_deficient()
25-
{
26-
//A matrix data
27-
QDLDL_int Ap[] = {0, 1, 3};
28-
QDLDL_int Ai[] = {0, 0, 1};
29-
QDLDL_float Ax[] = {1.0, 1.0, 1.0};
30-
QDLDL_int An = 2;
24+
static char* test_rank_deficient() {
25+
// A matrix data
26+
QDLDL_int Ap[] = { 0, 1, 3 };
27+
QDLDL_int Ai[] = { 0, 0, 1 };
28+
QDLDL_float Ax[] = { 1.0, 1.0, 1.0 };
29+
QDLDL_int An = 2;
3130

32-
// RHS for Ax = b (should fail to solve)
33-
QDLDL_float b[] = {1,1};
31+
// RHS for Ax = b (should fail to solve)
32+
QDLDL_float b[] = { 1, 1 };
3433

35-
//x replaces b during solve
36-
int status = ldl_factor_solve(An,Ap,Ai,Ax,b);
34+
// x replaces b during solve
35+
int status = ldl_factor_solve(An, Ap, Ai, Ax, b);
3736

38-
mu_assert("Rank deficiency not detected", status < 0);
37+
mu_assert("Rank deficiency not detected", status < 0);
3938

40-
return 0;
39+
return 0;
4140
}

‎tests/test_singleton.h

+14-15
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,22 @@
2121
* SPDX-License-Identifier: Apache-2.0
2222
*/
2323

24-
static char* test_singleton()
25-
{
26-
//A matrix data
27-
QDLDL_int Ap[] = {0, 1};
28-
QDLDL_int Ai[] = {0};
29-
QDLDL_float Ax[] = {0.2};
30-
QDLDL_int An = 1;
24+
static char* test_singleton() {
25+
// A matrix data
26+
QDLDL_int Ap[] = { 0, 1 };
27+
QDLDL_int Ai[] = { 0 };
28+
QDLDL_float Ax[] = { 0.2 };
29+
QDLDL_int An = 1;
3130

32-
// RHS and solution to Ax = b
33-
QDLDL_float b[] = {2};
34-
QDLDL_float xsol[] = {10.0};
31+
// RHS and solution to Ax = b
32+
QDLDL_float b[] = { 2 };
33+
QDLDL_float xsol[] = { 10.0 };
3534

36-
//x replaces b during solve
37-
int status = ldl_factor_solve(An,Ap,Ai,Ax,b);
35+
// x replaces b during solve
36+
int status = ldl_factor_solve(An, Ap, Ai, Ax, b);
3837

39-
mu_assert("Factorisation failed", status >= 0);
40-
mu_assert("Solve accuracy failed", vec_diff_norm(b,xsol,An) < QDLDL_TESTS_TOL);
38+
mu_assert("Factorisation failed", status >= 0);
39+
mu_assert("Solve accuracy failed", vec_diff_norm(b, xsol, An) < QDLDL_TESTS_TOL);
4140

42-
return 0;
41+
return 0;
4342
}

‎tests/test_sym_structure.h

+12-13
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,20 @@
2121
* SPDX-License-Identifier: Apache-2.0
2222
*/
2323

24-
static char* test_sym_structure()
25-
{
26-
//A matrix data
27-
QDLDL_int Ap[] = {0, 2, 4};
28-
QDLDL_int Ai[] = {0, 1, 0, 1};
29-
QDLDL_float Ax[] = {5.0,1.0,1.0,5.0};
30-
QDLDL_int An = 2;
24+
static char* test_sym_structure() {
25+
// A matrix data
26+
QDLDL_int Ap[] = { 0, 2, 4 };
27+
QDLDL_int Ai[] = { 0, 1, 0, 1 };
28+
QDLDL_float Ax[] = { 5.0, 1.0, 1.0, 5.0 };
29+
QDLDL_int An = 2;
3130

32-
// RHS for Ax = b
33-
QDLDL_float b[] = {1,1};
31+
// RHS for Ax = b
32+
QDLDL_float b[] = { 1, 1 };
3433

35-
//x replaces b during solve
36-
int status = ldl_factor_solve(An,Ap,Ai,Ax,b);
34+
// x replaces b during solve
35+
int status = ldl_factor_solve(An, Ap, Ai, Ax, b);
3736

38-
mu_assert("Fully symmetric input not detected", status < 0);
37+
mu_assert("Fully symmetric input not detected", status < 0);
3938

40-
return 0;
39+
return 0;
4140
}

‎tests/test_tril_structure.h

+12-13
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,20 @@
2121
* SPDX-License-Identifier: Apache-2.0
2222
*/
2323

24-
static char* test_tril_structure()
25-
{
26-
//A matrix data
27-
QDLDL_int Ap[] = {0, 2, 3};
28-
QDLDL_int Ai[] = {0, 1, 1};
29-
QDLDL_float Ax[] = {5.0,1.0,5.0};
30-
QDLDL_int An = 2;
24+
static char* test_tril_structure() {
25+
// A matrix data
26+
QDLDL_int Ap[] = { 0, 2, 3 };
27+
QDLDL_int Ai[] = { 0, 1, 1 };
28+
QDLDL_float Ax[] = { 5.0, 1.0, 5.0 };
29+
QDLDL_int An = 2;
3130

32-
// RHS for Ax = b
33-
QDLDL_float b[] = {1,1};
31+
// RHS for Ax = b
32+
QDLDL_float b[] = { 1, 1 };
3433

35-
//x replaces b during solve
36-
int status = ldl_factor_solve(An,Ap,Ai,Ax,b);
34+
// x replaces b during solve
35+
int status = ldl_factor_solve(An, Ap, Ai, Ax, b);
3736

38-
mu_assert("Tril input not detected", status < 0);
37+
mu_assert("Tril input not detected", status < 0);
3938

40-
return 0;
39+
return 0;
4140
}

‎tests/test_two_by_two.h

+14-15
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,22 @@
2121
* SPDX-License-Identifier: Apache-2.0
2222
*/
2323

24-
static char* test_two_by_two()
25-
{
26-
//A matrix data
27-
QDLDL_int Ap[] = {0,1,3};
28-
QDLDL_int Ai[] = {0, 0, 1};
29-
QDLDL_float Ax[] = {1.0, 1.0, -1.0};
30-
QDLDL_int An = 2;
24+
static char* test_two_by_two() {
25+
// A matrix data
26+
QDLDL_int Ap[] = { 0, 1, 3 };
27+
QDLDL_int Ai[] = { 0, 0, 1 };
28+
QDLDL_float Ax[] = { 1.0, 1.0, -1.0 };
29+
QDLDL_int An = 2;
3130

32-
// RHS and solution to Ax = b
33-
QDLDL_float b[] = {2,4};
34-
QDLDL_float xsol[] = {3,-1};
31+
// RHS and solution to Ax = b
32+
QDLDL_float b[] = { 2, 4 };
33+
QDLDL_float xsol[] = { 3, -1 };
3534

36-
//x replaces b during solve
37-
int status = ldl_factor_solve(An,Ap,Ai,Ax,b);
35+
// x replaces b during solve
36+
int status = ldl_factor_solve(An, Ap, Ai, Ax, b);
3837

39-
mu_assert("Factorisation failed", status >= 0);
40-
mu_assert("Solve accuracy failed", vec_diff_norm(b,xsol,An) < QDLDL_TESTS_TOL);
38+
mu_assert("Factorisation failed", status >= 0);
39+
mu_assert("Solve accuracy failed", vec_diff_norm(b, xsol, An) < QDLDL_TESTS_TOL);
4140

42-
return 0;
41+
return 0;
4342
}

‎tests/test_zero_on_diag.h

+15-16
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,23 @@
2121
* SPDX-License-Identifier: Apache-2.0
2222
*/
2323

24-
static char* test_zero_on_diag()
25-
{
26-
//A matrix data
27-
QDLDL_int Ap[] = {0, 1, 2, 5};
28-
QDLDL_int Ai[] = {0 ,0, 0, 1, 2};
29-
QDLDL_float Ax[] = {4,1,2,1,-3};
30-
QDLDL_int An = 3;
24+
static char* test_zero_on_diag() {
25+
// A matrix data
26+
QDLDL_int Ap[] = { 0, 1, 2, 5 };
27+
QDLDL_int Ai[] = { 0, 0, 0, 1, 2 };
28+
QDLDL_float Ax[] = { 4, 1, 2, 1, -3 };
29+
QDLDL_int An = 3;
3130

32-
// RHS and solution to Ax = b
33-
QDLDL_float b[] = {6,9,12};
34-
QDLDL_float xsol[] = {17,-46,-8};
31+
// RHS and solution to Ax = b
32+
QDLDL_float b[] = { 6, 9, 12 };
33+
QDLDL_float xsol[] = { 17, -46, -8 };
3534

36-
//x replaces b during solve (should fill due to zero in middle)
37-
//NB : this system is solvable, but not by LDL
38-
int status = ldl_factor_solve(An,Ap,Ai,Ax,b);
35+
// x replaces b during solve (should fill due to zero in middle)
36+
// NB : this system is solvable, but not by LDL
37+
int status = ldl_factor_solve(An, Ap, Ai, Ax, b);
3938

40-
mu_assert("Factorisation failed", status >= 0);
41-
mu_assert("Solve accuracy failed", vec_diff_norm(b,xsol,An) < QDLDL_TESTS_TOL);
39+
mu_assert("Factorisation failed", status >= 0);
40+
mu_assert("Solve accuracy failed", vec_diff_norm(b, xsol, An) < QDLDL_TESTS_TOL);
4241

43-
return 0;
42+
return 0;
4443
}

0 commit comments

Comments
 (0)
Please sign in to comment.