Last active
June 24, 2023 19:15
-
-
Save gramian/6027733 to your computer and use it in GitHub Desktop.
Octave and Matlab Snippets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% Math %% | |
si = @(x) sin(x) ./ (x + (x==0)); % cardinal sine without pi multiplied argument | |
hsin = @(x) 0.5 * (1.0 - cos(x)); % haversed sine | |
hcos = @(x) 0.5 * (1.0 + cos(x)); % haversed cosine | |
sigm = @(x,k) 0.5 * tanh(0.5 * k * x) + 0.5; % sigmoid function to (exp(-kx)+1)^-1 | |
midr = @(x,d) 0.5 * (max(x,[],d) + min(x,[],d)); % midrange along dimension d | |
arcl = @(x,y) sum(sqrt(diff(x).^2 + diff(y).^2)); % simple arc length approximation from coordinate vectors | |
eoc = @(y,y1,y2,h1,h2) log(norm(y1 - y,'fro')/norm(y2 - y,'fro')) / log(h1 / h2); % experimental order of convergence | |
coh = @(x,y) sum(x(:))*sum(y(:)) / sum(x(:).*y(:)); % coherence | |
tau = 2.0 * pi; % define tau constant | |
%% Matrix %% | |
A(1:N+1:end) = 1.0; % set square N-dim matrix diagonal to one | |
a = A(A > 0); % get all elements greater than zero | |
dinv = @(D) diag(1.0 ./ (diag(D))); % invert diagonal matrix | |
ainv = @(m) ((m - diag(diag(m))) .* (-1.0./diag(m))) .* (1.0./diag(m)') + diag(1.0./diag(m)); % rough approximate inverse | |
[r,c] = find(A == max(A(:))); % get row and column index of maximum element in matrix | |
erand = @(k,l,m) -log(rand(k,l))./m; % exponential distribution | |
sperand = @(k,l,m) (-log(rand(k,l))./m) .* (sprand(k,l,d) > 0); % sparse exponential distribution | |
lrandn = @(k,l,m,v) exp(m + v * randn(k,l)); % log-normal distribution | |
splrandn = @(k,l,m,v,d) exp(m + v * randn(k,l)) .* (sprand(k,l,d) > 0); % sparse log-normal distribution | |
randab = @(k,l,a,b) a* ( (b/a).^rand(k,l) ); % distribution between [a,b] uniformly over orders of magnitude | |
yey = @(n) fliplr(eye(n)); % anti-diagonal "identity"-matrix | |
adiag = @(A,k) diag(flipud(A),k); % get anti-diagonal entries | |
spdiag = @(d) spdiags(d,0,numel(d),numel(d)); % sparse diagonal matrix | |
LINSPACE = @(a,b,n) a + (b - a).*linspace(0,1.0,n); % linspace variant for vector-valued arguments a,b | |
gramian = @(m) m * m'; % compute gramian matrix | |
isnormal = @(m) all(all(abs((m * m') - (m' * m)) < 1e-15)); % test if (small) matrix is normal | |
pad = @(m,r,c) [m,zeros(size(m,1),max(c-size(m,2),0));zeros(max(r-size(m,1),0),max(c,size(m,2)))]; % pad matrix with zeros | |
saxpy = @(a,x,y) a * x + y; % scalar a times x plus y | |
symtridiag = @(n,a,b) toeplitz([a,b,zeros(1,n-2)]); % symmetric tri-diagonal matrix | |
valmat = @(r,c,v) repmat(v,r,c); % create matrix with r rows and c columns filled with value v (also NaN) | |
%% Linear Algebra %% | |
[U,D,V] = svd(A,'econ'); % faster singular value decomposition for non square matrices | |
[U,d,v] = svds(X,1); % principal POD mode (in U) | |
msvds = @(A,r) sqrt(eigs((A'*A),r)); % memory-economical sparse svd | |
trnorm = @(m) sum(svd(m)); % Trace norm (aka nuclear norm) of a matrix | |
L = chol(A + norm(A,1)) - norm(A,1); % approximate cholesky decomposition for non positive definite matrices | |
logdet = @(m) 2.0 * sum(log(diag(chol(m)))); % faster log(det(A)) | |
prodtrace = @(a,b) sum(sum(a .* b')); % Faster than trace(a*b) | |
sympart = @(m) 0.5 * (m + m'); % symmetric part of matrix | |
symnorm = @(m) norm(m - m',1); % check how un-symmetric a matrix is | |
nornorm = @(m) norm(m*m' - m'*m,'fro'); % check how non-normal a matrix is | |
unit = @(n,N) (1:N==n)'; % generate n-th N-dim unit vector | |
units = @(n,N) sparse(n,1,1,N,1); % generate sparse n-th N-dim unit vector | |
specrad = @(A) abs(abs(eigs(A,1,'lm'))); % spectral radius | |
gmean = @(A,d) prod(A,d).^(1/size(A,d)); % geometric mean | |
%% ODE Solver %% | |
deeval = @(t,x,k) interp1(t,x,k(:))'; % Interpolate ODE solution [t,x] at vector k time points | |
%% Plotting %% | |
imshow(full(A)); % display dense or sparse matrix | |
imwrite(full(A),[filename,'.png']); % save dense or sparse matrix to a png | |
imshow(dicomread('filename'),[]); % display DICOM image with automatic range | |
gplot(sprand(N,N,d),[cos(2*pi/N:2*pi/N:2*pi)',sin(2*pi/N:2*pi/N:2*pi)']); % visualize networks adjacency matrix | |
n = 2.0^nextpow2(N); Z = fft(Y',n)/N; loglog(2*abs(Z(1:n/2+1))); % Bode-plot for a (outputs x steps) matrix timeseries | |
c = hsv(N); % get N colors from the hsv color map | |
set([gca; findall(gca,'Type','text')],'FontSize',16); % scale all fonts in a plot | |
ylim([10^floor(log10(min([y(:)]))-1),1]); % set lower log y limit based on data y | |
ytickformat = @(f) set(gca,'yticklabel',arrayfun(@(x) sprintf(f,x),get(gca,'ytick'),'UniformOutput',false)); % tick formatting | |
figure('Name',mfilename,'NumberTitle','off'); % set figure title bar content | |
print('-dsvg',[mfilename,'.svg']); % save current figure as svg with running m-file as base name | |
clim = @(a,b) set(gca,'CLim',[a,b]); % set colorbar limits | |
set(gcf,'renderer','Painters'); % Forces vectorization of instead of rasterization for complex figures when printing eps | |
%% System %% | |
exist('OCTAVE_VERSION','builtin') % test if gnu octave is used | |
verLessThan('matlab','9.1') % test if mathworks matlab version is less than 2016b | |
warning off all; % supress all warnings | |
rand('seed',s); % set seed s of uniform random number generator | |
randn('seed',s); % set seed s of normal random number generator | |
wfk = @() eval('fprintf(''Any Key!\n''); pause;'); % wait for key | |
fuse = onCleanup(@() clear myvar); % global destructor triggered by destruction of fuse | |
chars = @(n,c) arrayfun(@() c,blanks(n)); % create n-dim vector of characters c | |
%% Functional %% | |
vec = @(m) m(:); % useful function octave has but matlab has not | |
getelem = @(m,r,c) m(r,c); % get matrix element | |
setelem = @(m,r,c,v) m + sparse(r,c,-m(r,c)+v,size(m,1),size(m,2)); % set matrix element | |
cmov = @(c,varargin) varargin{2 - c}(); % conditional set: if c then varargin{1} else varargin{2} | |
foreach = @arrayfun; % note that Matlab's version of for-each is arrayfun (or cellfun) | |
head = @(m) m(1); % return first element of matrix | |
tail = @(m) m(end); % return last element of matrix | |
%% Utils %% | |
fprint('Hello World'); % disp without line-end | |
delchar = @() fprintf('\b'); % Delete last printed character | |
say = @(m) fprintf([m,'\n']); % emit text line | |
if(nargin<1 || isempty(a)), x = 0; end % default argument value for argument a | |
system(['notify-send "',mfilename,':\ I am done!"']); % local notification | |
system('mutt -s "I am done!" me@host.tld -a result.svg < nohup.out'); % remote notification | |
varsize = @(m) whos(m).bytes/(1024*1024*1024); % memory footprint of variable (name as string) in GB | |
caller = @() (dbstack).name; % get current running function name | |
addpath(genpath('mypath')); % Add search path recursively for subfolders | |
picked = @(list,name) any(strcmp(list,name)); % Check if string exists inside cell array | |
bool2str = @(b) cmov(b,{'true','false'}); % Convert scalar logical value to string | |
%% Misc %% | |
[Amin,Amax] = bounds(A,d); % minimum and maximum of matrix A along dimension d | |
maxabs = @(m) max(abs(m(:))); % Maximum absolute value in matrix | |
nanmax = @(a,b) max(a,b) + (a - a) + (b - b); % NaN propagating maximum | |
nanmin = @(a,b) min(a,b) + (a - a) + (b - b); % NaN propagating minimum | |
expand = @(a) [zeros(isempty(a)),a]; % expand argument to zero if it empty else return argument | |
[r,n] = max(abs(diff(log(V)))); % find the largest change in consecutive elements of a vector | |
n = 10.0.^round(log10(a)); % round to next order of magnitude | |
almost_eq = @(a,b,tol) std([a,b]) < sqrt(2) * tol; % Compare scalars within tolerance | |
A(A == 0) = NaN; % change zero entries to NaN; useful for log plots | |
ascii = @() [num2str((32:127)'),repmat(' ',[96,1]),char(32:127)']; % ASCII Table | |
%% System Theory %% | |
l0norm = @(y) sum(prod(abs(y),1).^(1/size(y,1)),2); % L0-norm of time series y (states x time-steps) | |
l1norm = @(y,h) h * norm(y(:),1); % L1-norm of time series y (states x time-steps (h)) | |
l2norm = @(y,h) sqrt(h)*norm(y(:),2); % L2-norm of time series y (states x time-steps (h)) | |
l8norm = @(y) norm(y(:),Inf); % Linfinity-norm of time series y (states x time-steps) | |
wc = @(A,B) sylvester(A,A',-B*B'); % algebraic controllability gramian | |
wo = @(A,C) sylvester(A',A,-C'*C); % algebraic observability gramian | |
wx = @(A,B,C) sylvester(A,A,-B*C); % algebraic cross gramian | |
%% Readability %% | |
% use "if" and "for" without parenthesis | |
% use not() instead of ~() inside if-conditions | |
% use isequal() instead of == inside if-conditions | |
% use end%if, end%for, etc for Matlab compatible specific ends in Octave | |
%% Notes %% | |
% Every .m file should have a header with: project, version, authors, licence, summary | |
% Numerical arrays are stored in continous memory, cell arrays are not. | |
%% MATLAB %% | |
version('-blas') % display BLAS identifier and version | |
version('-lapack') % display LAPACK identifier and version | |
profile -memory on; % activate memory usage profiling | |
matlabpool(feature('numCores')); % allocate maximum local workers | |
## Octave ## | |
page_screen_output(0); # octave command to disable paged output | |
page_output_immediately(1); # octave command to enable immediate output | |
history_control("ignoredups"); # do not record duplicate entries in command history | |
graphics_toolkit("gnuplot"); # set render backend to gnuplot | |
setenv GNUTERM dumb; # force ASCII plots via gnuplot | |
svd_driver("gesvd"); # set safe LAPACK SVD backend | |
#!/usr/bin/octave-cli # command-line octave shebang | |
## Remote ## | |
nohup matlab -nodisplay -r "progname(args); exit(0);" < /dev/null > my.log & # remote matlab execution | |
nohup octave-cli --eval "progname(args)" > my.log & # remote octave execution | |
## Parallel ## | |
taskset -c 0,2,4,6 octave-cli # set CPU affinity to every second core (for SMT machines) | |
numactl -N 0 -m 0 octave-cli # pin to first node and its memory (for NUMA machines) | |
lstopo # print CPU topology (part of hwloc) | |
matlab2020b -nodisplay -singleCompThread # (use only single thread in terminal) | |
## Profiling ## | |
/usr/bin/time -f "%M KB" octave # record peak memory usage | |
mlint('mycode.m','-cyc') % static code analysis and cyclomatic complexity in MATLAB | |
flamegraph(profdata) # use flame graph visualization for Octave profiler data ( https://git.io/flamegraph ) | |
## Custom Backends ## | |
LD_PRELOAD='/path/to/my/blas.so /path/to/lapack.so' # change BLAS and LAPACK backends for Octave | |
BLAS_VERSION='/path/to/my/blas.so' # change MATLAB BLAS backend | |
LAPACK_VERSION ='/path/to/my/lapack.so' # change MATLAB LAPACK backend | |
# use FlexiBLAS ( https://www.mpi-magdeburg.mpg.de/projects/flexiblas ) | |
## Postprocessing ## | |
pdfcrop figure.pdf cropped.pdf # remove white-space framing plots | |
## Develop ## | |
http://wiki.octave.org/Nano # syntax highlighting for the nano editor | |
% by: https://gramian.de |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very Nice! Thanks.