Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop 1.0 #55

Open
wants to merge 40 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f508be6
Updated the Matlab interface
AmitSolomonPrinceton Aug 21, 2023
33e2f98
Debugging
AmitSolomonPrinceton Sep 8, 2023
ef80b1f
warm_start -> warm_starting
AmitSolomonPrinceton Sep 8, 2023
3283b10
Fixed a bug with time_limit
AmitSolomonPrinceton Sep 12, 2023
734eb8f
Updated unittests: basic_tests (initial time_limit) and update_matric…
AmitSolomonPrinceton Sep 12, 2023
463030b
Fixed an issue where time_limit would not update
AmitSolomonPrinceton Sep 13, 2023
a0bb370
Disabling codegen tests
AmitSolomonPrinceton Sep 27, 2023
3c48d73
Addressed Ian's comments: use the public functions and update setting…
AmitSolomonPrinceton Nov 9, 2023
3a853cd
Consolidate C sources into one folder
imciner2 Nov 15, 2023
8bb91ad
Refactor mex build system to simplify it
imciner2 Nov 15, 2023
265ab65
Fix memory management in the OSQP mex interface
imciner2 Nov 15, 2023
6ba8078
Gate debug information on GNU compilers only
imciner2 Nov 15, 2023
48fbbc4
Add linking against the ut library
imciner2 Nov 15, 2023
1ee89e8
Fix submodule
imciner2 Nov 15, 2023
03f9554
Fix building and installing on Windows
imciner2 Nov 15, 2023
756dc99
Include libut link path on macos/linux as well
imciner2 Nov 15, 2023
dd86a79
Fixed copyUpdatedSettingsToWork
AmitSolomonPrinceton Nov 16, 2023
fcc7b4b
added cg_precond to copySettingsToMxStruct
AmitSolomonPrinceton Nov 16, 2023
aaae761
rho is updated through update_rho
AmitSolomonPrinceton Nov 16, 2023
3896fa0
Merge branch 'master' into matlab-interface
imciner2 Nov 17, 2023
fd75800
Merge pull request #50 from osqp/matlab-interface
imciner2 Nov 17, 2023
4a93044
Reorganize OSQP class structure
imciner2 Nov 17, 2023
e6a2ca8
Expose rho update function over the mex interface
imciner2 Nov 17, 2023
2f5aba3
Simplify the constant generation
imciner2 Nov 17, 2023
c3d24fc
Only compile the memory management functions once then link them
imciner2 Nov 17, 2023
cc96cf2
Restructure settings handling to make it easier to maintain
imciner2 Nov 20, 2023
a6d5c70
Fix copying OSQP Settings objects and add better update tests
imciner2 Nov 20, 2023
7b7f38f
[CI] Update OSQP Mex build step
imciner2 Nov 20, 2023
5e42763
Refactor how structs are passed to allow cleaner passing of OSQPInfo
imciner2 Nov 21, 2023
8025d54
Rework how vectors are created and passed around
imciner2 Nov 21, 2023
424bccd
Cleanup unused routines and some style changes
imciner2 Nov 21, 2023
5cf4a61
Remove extraneous static string on mex call to static methods
imciner2 Nov 23, 2023
b2b3be0
Simplify check inside setup function
imciner2 Dec 4, 2023
38b984f
Simplify warm start routine
imciner2 Dec 4, 2023
391fe8f
Merge pull request #52 from osqp/im/restructure
imciner2 Dec 4, 2023
c47c8df
Added the following to osqp_mex.cpp: codegen, default_codegen_defines…
AmitSolomonPrinceton Feb 16, 2024
fcc4055
Minor changes
AmitSolomonPrinceton Feb 16, 2024
a7a5e89
Fixed a bug where osqpData->defines would be freed twice
AmitSolomonPrinceton Feb 20, 2024
6b9d2d0
Merge pull request #56 from osqp/Develop-1.0-codegen
AmitSolomonPrinceton Apr 4, 2024
f354a10
Adding SPDX-License-Identifier: Apache-2.0 to all .m, .c, .cpp, .h fi…
AmitSolomonPrinceton Apr 4, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Build OSQP interface
uses: matlab-actions/run-command@v1
with:
command: make_osqp
command: osqp.build('osqp_mex')

- name: Run tests
uses: matlab-actions/run-tests@v1
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# -------------------------------------------------------------------
# Out folder
out/
c_sources/build/

# Prerequisites
*.d
Expand Down
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "osqp_sources"]
path = osqp_sources
path = c_sources/osqp_sources
url = https://github.com/osqp/osqp
164 changes: 164 additions & 0 deletions @osqp/build.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
function build(varargin)
% Matlab MEX makefile for OSQP.
%
% MAKE_OSQP(VARARGIN) is a make file for OSQP solver. It
% builds OSQP and its components from source.
%
% WHAT is the last element of VARARGIN and cell array of strings,
% with the following options:
%
% {}, '' (empty string) or 'all': build all components and link.
%
% 'osqp_mex': builds the OSQP mex interface and the OSQP library
%
% Additional commands:
%
% 'clean': Delete all compiled files
% 'purge': Delete all compiled files and copied code generation files

if( nargin == 0 )
what = {'all'};
verbose = false;
elseif ( nargin == 1 && ismember('-verbose', varargin) )
what = {'all'};
verbose = true;
else
what = varargin{nargin};
if(isempty(strfind(what, 'all')) && ...
isempty(strfind(what, 'osqp_mex')) && ...
isempty(strfind(what, 'clean')) && ...
isempty(strfind(what, 'purge')))
fprintf('No rule to make target "%s", exiting.\n', what);
end

verbose = ismember('-verbose', varargin);
end

%% Determine where the various files are all located
% Various parts of the build system
[osqp_classpath,~,~] = fileparts( mfilename( 'fullpath' ) );
osqp_mex_src_dir = fullfile( osqp_classpath, '..', 'c_sources' );
osqp_mex_build_dir = fullfile( osqp_mex_src_dir, 'build' );
osqp_cg_src_dir = fullfile( osqp_mex_build_dir, 'codegen_src' );
osqp_cg_dest_dir = fullfile( osqp_classpath, '..', 'codegen', 'sources' );

% Determine where CMake should look for MATLAB
Matlab_ROOT = strrep( matlabroot, '\', '/' );

%% Try to unlock any pre-existing version of osqp_mex
% this prevents compile errors if a user builds, runs osqp
% and then tries to recompile
if(mislocked('osqp_mex'))
munlock('osqp_mex');
end

%% Configure, build and install the OSQP mex interface
if( any(strcmpi(what,'osqp_mex')) || any(strcmpi(what,'all')) )
fprintf('Compiling OSQP solver mex interface...\n');

% Create build for the mex file and go inside
if exist( osqp_mex_build_dir, 'dir' )
rmdir( osqp_mex_build_dir, 's' );
end
mkdir( osqp_mex_build_dir );
% cd( osqp_mex_build_dir );

% Extend path for CMake mac (via Homebrew)
PATH = getenv('PATH');
if( (ismac) && (isempty(strfind(PATH, '/usr/local/bin'))) )
setenv('PATH', [PATH ':/usr/local/bin']);
end



%% Configure CMake for the mex interface
fprintf(' Configuring...' )
[status, output] = system( sprintf( 'cmake -B %s -S %s -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMatlab_ROOT_DIR=\"%s\"', osqp_mex_build_dir, osqp_mex_src_dir, Matlab_ROOT ), 'LD_LIBRARY_PATH', '' );
if( status )
fprintf( '\n' );
disp( output );
error( 'Error configuring CMake environment' );
elseif( verbose )
fprintf( '\n' );
disp( output );
else
fprintf( '\t\t\t\t\t[done]\n' );
end

%% Build the mex interface
fprintf( ' Building...')
[status, output] = system( sprintf( 'cmake --build %s --config Release', osqp_mex_build_dir ), 'LD_LIBRARY_PATH', '' );
if( status )
fprintf( '\n' );
disp( output );
error( 'Error compiling OSQP mex interface' );
elseif( verbose )
fprintf( '\n' );
disp( output );
else
fprintf( '\t\t\t\t\t\t[done]\n' );
end


%% Install various files
fprintf( ' Installing...' )

% Copy mex file to root directory for use
if( ispc )
[err, errmsg, ~] = copyfile( [osqp_mex_build_dir, filesep, 'Release', filesep, 'osqp_mex.mex*'], [osqp_classpath, filesep, 'private'] );
else
[err, errmsg, ~] = copyfile( [osqp_mex_build_dir, filesep, 'osqp_mex.mex*'], [osqp_classpath, filesep, 'private'] );
end
if( ~err )
fprintf( '\n' )
disp( errmsg )
error( ' Error copying mex file' )
end

% Copy the code generation source files
% Create build for the mex file and go inside
if exist( osqp_cg_dest_dir, 'dir' )
rmdir( osqp_cg_dest_dir, 's' );
end
mkdir( osqp_cg_dest_dir );

[err, errmsg, ~] = copyfile( [osqp_cg_src_dir, filesep, '*'], osqp_cg_dest_dir );
if( ~err )
fprintf( '\n' )
disp( errmsg )
error( ' Error copying code generation source files' )
end

fprintf( '\t\t\t\t\t\t[done]\n' );
end

%% Clean and purge
if( any(strcmpi(what,'clean')) || any(strcmpi(what,'purge')) )
fprintf('Cleaning OSQP mex files and build directory...');

% Delete mex file
mexfiles = dir(['*.', mexext]);
for i = 1 : length(mexfiles)
delete(mexfiles(i).name);
end

% Delete OSQP build directory
if exist(osqp_mex_build_dir, 'dir')
rmdir(osqp_mex_build_dir, 's');
end

fprintf('\t\t[done]\n');

%% Purge only
if( any(strcmpi(what,'purge')) )
fprintf('Cleaning OSQP codegen directories...');

% Delete codegen files
if exist(osqp_cg_dest_dir, 'dir')
rmdir(osqp_cg_dest_dir, 's');
end

fprintf('\t\t\t[done]\n');
end
end
end
148 changes: 148 additions & 0 deletions @osqp/codegen.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
%%
function codegen(this, out, varargin)
% CODEGEN generate C code for the parametric problem
%
% codegen(target_dir,options)

% Parse input arguments
p = inputParser;
defaultPrefix = 'prob1_'; % Prefix for filenames and C variables; useful if generating multiple problems
defaultForceRewrite = true; % Force rewrite if output folder exists?
defaultParameters = 'vectors'; % What do we wish to update in the generated code?
% One of 'vectors' (allowing update of q/l/u through prob.update_data_vec)
% or 'matrices' (allowing update of P/A/q/l/u
% through prob.update_data_vec or prob.update_data_mat)
defaultUseFloat = false; % Use single precision in generated code?
defaultPrintingEnable = false; % Enable solver printing?
defaultProfilingEnable = false; % Enable solver profiling?
defaultInterruptEnable = false; % Enable user interrupt (Ctrl-C)?
defaultEnableDerivatives = false; % Enable derivatives?

addRequired(p, 'out', @isstr);
addOptional(p, 'prefix', defaultPrefix, @isstr);
addParameter(p, 'force_rewrite', defaultForceRewrite, @isboolean);
addParameter(p, 'parameters', defaultParameters, @isstr);
addParameter(p, 'float_type', defaultUseFloat, @isboolean);
addParameter(p, 'printing_enable', defaultPrintingEnable, @isboolean);
addParameter(p, 'profiling_enable', defaultProfilingEnable, @isboolean);
addParameter(p, 'interrupt_enable', defaultInterruptEnable, @isboolean);
addParameter(p, 'derivatives_enable', defaultEnableDerivatives, @isboolean);

parse(p, out, varargin{:});

% Set internal variables
if strcmp(p.Results.parameters, 'vectors')
embedded = 1;
else
embedded = 2;
end


% Check whether the specified directory already exists
if exist(out, 'dir')
while(1)
prompt = sprintf('Directory "%s" already exists. Do you want to replace it? y/n [y]: ', out);
str = input(prompt, 's');

if any(strcmpi(str, {'','y'}))
rmdir(out, 's');
break;
elseif strcmpi(str, 'n')
return;
end
end
end

% Import OSQP path
[osqp_path,~,~] = fileparts(which('osqp.m'));

% Add codegen directory to path
addpath(fullfile(osqp_path, 'codegen'));

% Path of osqp module
cg_dir = fullfile(osqp_path, '..', 'codegen');
files_to_generate_path = fullfile(cg_dir, 'files_to_generate');

% Make target directory
fprintf('Creating target directories...\t\t\t\t\t');
target_configure_dir = fullfile(out, 'configure');
target_include_dir = fullfile(out, 'include');
target_src_dir = fullfile(out, 'src');

if ~exist(out, 'dir')
mkdir(out);
end
if ~exist(target_configure_dir, 'dir')
mkdir(target_configure_dir);
end
if ~exist(target_include_dir, 'dir')
mkdir(target_include_dir);
end
if ~exist(target_src_dir, 'dir')
mkdir(fullfile(target_src_dir, 'osqp'));
end
fprintf('[done]\n');

%TODO: Fix the copying stuff
% % Copy source files to target directory
% fprintf('Copying OSQP source files...\t\t\t\t\t');
% cdir = fullfile(cg_dir, 'sources', 'src');
% cfiles = dir(fullfile(cdir, '*.c'));
% for i = 1 : length(cfiles)
% if embedded == 1
% % Do not copy kkt.c if embedded is 1
% if ~strcmp(cfiles(i).name, 'kkt.c')
% copyfile(fullfile(cdir, cfiles(i).name), ...
% fullfile(target_src_dir, 'osqp', cfiles(i).name));
% end
% else
% copyfile(fullfile(cdir, cfiles(i).name), ...
% fullfile(target_src_dir, 'osqp', cfiles(i).name));
% end
% end
% configure_dir = fullfile(cg_dir, 'sources', 'configure');
% configure_files = dir(fullfile(configure_dir, '*.h.in'));
% for i = 1 : length(configure_files)
% copyfile(fullfile(configure_dir, configure_files(i).name), ...
% fullfile(target_configure_dir, configure_files(i).name));
% end
% hdir = fullfile(cg_dir, 'sources', 'inc');
% hfiles = dir(fullfile(hdir, '*.h'));
% for i = 1 : length(hfiles)
% if embedded == 1
% % Do not copy kkt.h if embedded is 1
% if ~strcmp(hfiles(i).name, 'kkt.h')
% copyfile(fullfile(hdir, hfiles(i).name), ...
% fullfile(target_include_dir, hfiles(i).name));
% end
% else
% copyfile(fullfile(hdir, hfiles(i).name), ...
% fullfile(target_include_dir, hfiles(i).name));
% end
% end
%
% % Copy cmake files
% copyfile(fullfile(cdir, 'CMakeLists.txt'), ...
% fullfile(target_src_dir, 'osqp', 'CMakeLists.txt'));
% copyfile(fullfile(hdir, 'CMakeLists.txt'), ...
% fullfile(target_include_dir, 'CMakeLists.txt'));
% fprintf('[done]\n');
%
% % Copy example.c
% copyfile(fullfile(files_to_generate_path, 'example.c'), target_src_dir);

% Update codegen defines
update_codegen_defines(this, 'embedded_mode', embedded, 'float_type', p.Results.float_type, 'printing_enable', p.Results.printing_enable, 'profiling_enable', p.Results.profiling_enable, 'interrupt_enable', p.Results.interrupt_enable, 'derivatives_enable', p.Results.derivatives_enable);
% Call codegen
osqp_mex('codegen', this.objectHandle, out, p.Results.prefix);

% TODO: Do we want to keep this?
% % Make mex interface to the generated code
% mex_cfile = fullfile(files_to_generate_path, 'emosqp_mex.c');
% make_emosqp(out, mex_cfile, embedded, float_flag, long_flag);
%
% % Rename the mex file
% old_mexfile = ['emosqp_mex.', mexext];
% new_mexfile = [p.Results.mexname, '.', mexext];
% movefile(old_mexfile, new_mexfile);
end
Loading
Loading