├── LICENSE
├── README.md
├── data.sh
├── demoH36M.m
├── demoHG.m
├── demoMPII.m
├── dict
├── poseDict-Posing-K64.mat
├── poseDict-all-K128.mat
└── tennis_forehand.mat
├── em
├── PoseFromVideo.m
├── estimateC_fused.m
├── estimateR_fused.m
├── findWmax.m
└── rotateS.m
├── general
├── alignHuman.m
├── centralize.m
├── compareStructs.m
├── computeError2D.m
├── computeError3D.m
├── computeErrorPCK.m
├── findRotation.m
├── findWmax.m
├── generateRotation.m
├── limbLength.m
├── meanShape.m
├── normalizeS.m
├── perspAdj.m
├── proj22D.m
├── reshapeS.m
├── sampleShapes.m
├── viewStruct.m
├── vis2Dcar.m
├── vis2Dmarker.m
├── vis2Dskel.m
├── vis3Dcar.m
├── vis3Dmarker.m
└── vis3Dskel.m
├── manopt
├── CLA.txt
├── COPYING.txt
├── CREDITS.txt
├── LICENSE.txt
├── README.txt
├── checkinstall
│ └── basicexample.m
├── examples
│ ├── dominant_invariant_subspace.m
│ ├── dominant_invariant_subspace_complex.m
│ ├── essential_svd.m
│ ├── generalized_eigenvalue_computation.m
│ ├── generalized_procrustes.m
│ ├── low_rank_dist_completion.m
│ ├── low_rank_matrix_completion.m
│ ├── low_rank_tensor_completion.m
│ ├── maxcut.m
│ ├── nonlinear_eigenspace.m
│ ├── packing_on_the_sphere.m
│ ├── positive_definite_karcher_mean.m
│ ├── radio_interferometric_calibration.m
│ ├── robust_pca.m
│ ├── shapefit_smoothed.m
│ ├── sparse_pca.m
│ └── truncated_svd.m
├── importmanopt.m
├── manopt
│ ├── core
│ │ ├── StoreDB.m
│ │ ├── applyStatsfun.m
│ │ ├── canGetApproxHessian.m
│ │ ├── canGetCost.m
│ │ ├── canGetDirectionalDerivative.m
│ │ ├── canGetEuclideanGradient.m
│ │ ├── canGetGradient.m
│ │ ├── canGetHessian.m
│ │ ├── canGetLinesearch.m
│ │ ├── canGetPrecon.m
│ │ ├── canGetSqrtPrecon.m
│ │ ├── getApproxHessian.m
│ │ ├── getCost.m
│ │ ├── getCostGrad.m
│ │ ├── getDirectionalDerivative.m
│ │ ├── getEuclideanGradient.m
│ │ ├── getGlobalDefaults.m
│ │ ├── getGradient.m
│ │ ├── getHessian.m
│ │ ├── getHessianFD.m
│ │ ├── getLinesearch.m
│ │ ├── getPrecon.m
│ │ ├── getSqrtPrecon.m
│ │ ├── getStore.m
│ │ ├── handle_light.m
│ │ ├── mergeOptions.m
│ │ ├── purgeStoredb.m
│ │ ├── setStore.m
│ │ └── stoppingcriterion.m
│ ├── manifolds
│ │ ├── complexcircle
│ │ │ └── complexcirclefactory.m
│ │ ├── essential
│ │ │ ├── README_Essential.txt
│ │ │ ├── essential_costE2cost.m
│ │ │ ├── essential_egradE2egrad.m
│ │ │ ├── essential_ehessE2ehess.m
│ │ │ ├── essential_flat.m
│ │ │ ├── essential_hat3.m
│ │ │ ├── essential_sharp.m
│ │ │ ├── essentialfactory.m
│ │ │ └── privateessential
│ │ │ │ ├── essential_closestRepresentative.m
│ │ │ │ ├── essential_distMinAngle.m
│ │ │ │ ├── essential_distMinAnglePair.m
│ │ │ │ ├── essential_distMinAnglePair_base.m
│ │ │ │ ├── essential_distMinAnglePair_computeDfBreak.m
│ │ │ │ ├── essential_distMinAnglePair_dfNewton.m
│ │ │ │ ├── essential_distMinAnglePair_discontinuityDistance.m
│ │ │ │ ├── essential_distMinAnglePair_ft.m
│ │ │ │ ├── essential_distMinAnglePair_ftFromQ.m
│ │ │ │ ├── essential_distMinAnglePair_test.m
│ │ │ │ └── modAngle.m
│ │ ├── euclidean
│ │ │ ├── centeredmatrixfactory.m
│ │ │ ├── euclideancomplexfactory.m
│ │ │ ├── euclideanfactory.m
│ │ │ ├── shapefitfactory.m
│ │ │ └── symmetricfactory.m
│ │ ├── fixedrank
│ │ │ ├── fixedrankMNquotientfactory.m
│ │ │ ├── fixedrankembeddedfactory.m
│ │ │ ├── fixedrankfactory_2factors.m
│ │ │ ├── fixedrankfactory_2factors_preconditioned.m
│ │ │ ├── fixedrankfactory_2factors_subspace_projection.m
│ │ │ ├── fixedrankfactory_3factors.m
│ │ │ └── fixedrankfactory_3factors_preconditioned.m
│ │ ├── fixedranktensors
│ │ │ ├── fixedrankfactory_tucker_preconditioned.m
│ │ │ └── tucker2multiarray.m
│ │ ├── grassmann
│ │ │ ├── grassmanncomplexfactory.m
│ │ │ ├── grassmannfactory.m
│ │ │ └── grassmanngeneralizedfactory.m
│ │ ├── multinomial
│ │ │ └── multinomialfactory.m
│ │ ├── oblique
│ │ │ └── obliquefactory.m
│ │ ├── rotations
│ │ │ ├── randrot.m
│ │ │ ├── randskew.m
│ │ │ └── rotationsfactory.m
│ │ ├── specialeuclidean
│ │ │ └── specialeuclideanfactory.m
│ │ ├── sphere
│ │ │ ├── spherecomplexfactory.m
│ │ │ ├── spherefactory.m
│ │ │ └── spheresymmetricfactory.m
│ │ ├── stiefel
│ │ │ ├── stiefelcomplexfactory.m
│ │ │ ├── stiefelfactory.m
│ │ │ ├── stiefelgeneralizedfactory.m
│ │ │ └── stiefelstackedfactory.m
│ │ └── symfixedrank
│ │ │ ├── elliptopefactory.m
│ │ │ ├── spectrahedronfactory.m
│ │ │ ├── symfixedrankYYcomplexfactory.m
│ │ │ ├── symfixedrankYYfactory.m
│ │ │ └── sympositivedefinitefactory.m
│ ├── solvers
│ │ ├── conjugategradient
│ │ │ └── conjugategradient.m
│ │ ├── hessianapproximations
│ │ │ └── approxhessianFD.m
│ │ ├── linesearch
│ │ │ ├── linesearch.m
│ │ │ ├── linesearch_adaptive.m
│ │ │ ├── linesearch_decrease.m
│ │ │ └── linesearch_hint.m
│ │ ├── neldermead
│ │ │ ├── centroid.m
│ │ │ └── neldermead.m
│ │ ├── preconditioners
│ │ │ └── preconhessiansolve.m
│ │ ├── pso
│ │ │ └── pso.m
│ │ ├── steepestdescent
│ │ │ └── steepestdescent.m
│ │ └── trustregions
│ │ │ ├── license for original GenRTR code.txt
│ │ │ ├── tCG.m
│ │ │ └── trustregions.m
│ └── tools
│ │ ├── checkdiff.m
│ │ ├── checkgradient.m
│ │ ├── checkhessian.m
│ │ ├── dexpm.m
│ │ ├── dfunm.m
│ │ ├── diagsum.m
│ │ ├── dlogm.m
│ │ ├── dsqrtm.m
│ │ ├── hashmd5.m
│ │ ├── hessianextreme.m
│ │ ├── hessianspectrum.m
│ │ ├── identify_linear_piece.m
│ │ ├── manoptsolve.m
│ │ ├── matrixlincomb.m
│ │ ├── multihconj.m
│ │ ├── multiherm.m
│ │ ├── multiprod.m
│ │ ├── multiprodmultitransp_license.txt
│ │ ├── multiscale.m
│ │ ├── multiskew.m
│ │ ├── multisqnorm.m
│ │ ├── multisym.m
│ │ ├── multitrace.m
│ │ ├── multitransp.m
│ │ ├── plotprofile.m
│ │ ├── powermanifold.m
│ │ ├── productmanifold.m
│ │ ├── statsfunhelper.m
│ │ ├── surfprofile.m
│ │ ├── tangentspacefactory.m
│ │ └── tangentspherefactory.m
└── manopt_version.m
├── pose-hg-demo
├── .DS_Store
├── .gitignore
├── LICENSE
├── README.md
├── img.lua
├── model.sh
├── residual.lua
├── run-hg.lua
├── stacked-hourglass-model.lua
└── util.lua
├── ssr
├── composeShape.m
├── estimateC.m
├── estimateR_manopt.m
├── estimateR_proj.m
├── learnPoseDict.m
├── nnscDL.m
├── proj_deformable_approx.m
├── prox_2norm.m
├── ssr2D3D_alm.m
├── ssr2D3D_alt.m
├── ssr2D3D_wrapper.m
└── syncRot.m
├── startup.m
└── utils
├── getMPIIdict.m
└── transformMPII.m
/README.md:
--------------------------------------------------------------------------------
1 | This repository implements the 3D human pose estimation algorithm introduced in the following paper:
2 | > Monocap: Monocular human motion capture using a CNN coupled with a geometric prior. X. Zhou, M. Zhu, G. Pavlakos, S. Leonardos, K.G. Derpanis, K. Daniilidis. IEEE Transactions on Pattern Analysis and Machine Intelligence (T-PAMI), 2018. Accepted.
3 |
4 | ## How to use?
5 | 1. Download data by running the following script in command line:
6 | ```bash data.sh```
7 | 2. Open MATLAB and run:
8 | ```startup```
9 | 3. Run the demo scripts:
10 | - demoH36M for an example from Human3.6M dataset
11 | - demoHG for an example of how to use our algorithm combined with the "Stacked hourglass network"
12 | - demoMPII for an example of how to reconstruct 3D poses from a single image from MPII dataset
13 |
14 | ## Notes:
15 | - The code for hourglass network in pose-hg-demo is from Newell et al., https://github.com/anewell/pose-hg-demo
16 | - See the comments in demoHG.m for how to run hourglass network on your images and save heatmaps
17 | - If you want to use the hourglass network, you need to first install Torch and make it work
18 | - Generally "Hourglass network" + "poseDict-all-K128" (pose dictionary learned from Human3.6M) work well. For better 3D reconstruction, you can learn a 3D pose dictionary using your own mocap data. For more details on pose dictionary learning, please see the following project: [sparse representation for shape estimation](http://cis.upenn.edu/~xiaowz/shapeconvex.html)
19 | - The optimization could be accelerated by changing the initialization method to alternating by changing the option when calling PoseFromVideo:
20 | ```PoseFromVideo(...,'InitialMethod','altern')```
--------------------------------------------------------------------------------
/data.sh:
--------------------------------------------------------------------------------
1 | # Download demo data
2 | wget http://visiondata.cis.upenn.edu/monocap/data.zip
3 | unzip data.zip
4 | rm data.zip
--------------------------------------------------------------------------------
/demoH36M.m:
--------------------------------------------------------------------------------
1 | % This script demonstrates how to use:
2 | % the proposed EM algorithm + pose dictionary learned from Human3.6M
3 | % + the 2D joint detector described in the paper
4 | % We use a Human3.6M sequence as example
5 |
6 | clear
7 |
8 | %% load data
9 | % load data including heatmaps, images, etc ...
10 | data = load('data/h36m/S9-Posing 1.55011271.mat');
11 | % load camera parameters
12 | cam = load('data/h36m/camera/S9-Posing 1.55011271.mat');
13 | % load dictionary
14 | dict = load('dict/poseDict-Posing-K64.mat');
15 |
16 | %% pose estimation using orthographic camera model
17 | Given2DPose = false;
18 | if Given2DPose
19 | output = PoseFromVideo('W_gt',data.W_gt,'dict',dict);
20 | else
21 | output = PoseFromVideo('heatmap',data.heatmap,'dict',dict);
22 | end
23 |
24 | %% using perspective camera model if camera parameters are known
25 | output.dict = dict;
26 | output.rootID = 1; % root node in the skeleton tree
27 | output.camera = cam;
28 | output.bbox = data.bbox;
29 | output = perspAdj(output);
30 |
31 | %% visualization
32 |
33 | nPlot = 4;
34 | figure('position',[300 300 200*nPlot 200]);
35 | for i = 1:length(data.frames)
36 | clf;
37 | % heatmap
38 | subplot('position',[0/nPlot 0 1/nPlot 1]);
39 | cmap = colormap('jet');
40 | hmap = size(cmap,1)*mat2gray(sum(data.heatmap(:,:,:,i),3));
41 | imshow(hmap,cmap);
42 | % 2D optimized pose
43 | subplot('position',[1/nPlot 0 1/nPlot 1]);
44 | imshow(data.img(:,:,:,i));
45 | vis2Dskel(output.W_proj(2*i-1:2*i,:)*data.scale,dict.skel);
46 | % 3D reconstructed pose
47 | subplot('position',[2/nPlot 0 1/nPlot 1]);
48 | vis3Dskel(output.S_refine(3*i-2:3*i,:),dict.skel);
49 | % 3D reconstructed pose in novel view
50 | subplot('position',[3/nPlot 0 1/nPlot 1]);
51 | vis3Dskel(output.S_refine(3*i-2:3*i,:),dict.skel,'viewpoint',[-90 0]);
52 | camroll(5);
53 | pause(0.01);
54 | end
--------------------------------------------------------------------------------
/demoHG.m:
--------------------------------------------------------------------------------
1 | % This script demonstrates how to use:
2 | % the proposed EM algorithm + pose dictionary learned from Human3.6M
3 | % + the most recent CNN based 2D detector "Hourglass network"
4 | % (https://github.com/anewell/pose-hg-demo)
5 | % to reconstruct 3D human poses from a sequence of images
6 | % The images should have been centered at the subject and cropped
7 | % and all cropped images are saved in a folder
8 | % the heatmaps can be generated by running the HG model:
9 | % (1) go to pose-hg-demo folder
10 | % (2) run in command line
11 | % > bash model.sh
12 | % to download the pre-trained hourglass model
13 | % (3) run in command line:
14 | % > th run-hg.lua ImageFolderName ImageFileExtension
15 | % for example: th run-hg.lua ../data/tennis jpg
16 | % make sure Torch has been installed and run correctly
17 |
18 | clear
19 | startup
20 |
21 | %%
22 |
23 | datapath = 'data/tennis/';
24 |
25 | % read images
26 | filelist = dir([datapath '/*.jpg']);
27 | imagelist = {filelist.name};
28 | nImg = length(imagelist);
29 | image = [];
30 | for i = 1:nImg
31 | image = cat(4,image,imread(sprintf('%s/%s',datapath,imagelist{i})));
32 | end
33 |
34 | % read heatmaps generated by the Hourglass model
35 | % and stack the heatmaps of all frames
36 | heatmap = [];
37 | for i = 1:nImg
38 | hm = hdf5read(sprintf('%s/%s.h5',datapath,imagelist{i}(1:end-4)),'heatmap');
39 | % transpose heatmaps to make it consistent with the MATLAB x-y directions
40 | heatmap = cat(4,heatmap,permute(hm,[2,1,3]));
41 | end
42 |
43 | %% load dictionary learned from Human3.6M or CMU
44 |
45 | % dict = load('dict/poseDict-all-K128'); % a general pose dict
46 | % dictDataset = 'hm36m';
47 | dict = load('dict/tennis_forehand.mat'); % a motion-specific dict
48 | dictDataset = 'cmu';
49 |
50 | % convert dictionary format
51 | % because the joint order in MPII is different from that in Human3.6M
52 | dict = getMPIIdict(dict,dictDataset);
53 | numKp = length(dict.skel.tree);
54 |
55 | %% EM
56 | output = PoseFromVideo('heatmap',heatmap,'dict',dict);
57 | % get estimated poses coordinates for EM output
58 | % the estimated 2D joint location is w.r.t. the bounding box
59 | % need to be converted to the original image coordinates
60 | preds_2d = zeros(2,16,nImg);
61 | preds_3d = zeros(3,16,nImg);
62 | for i = 1:nImg
63 | center = [size(image,2);size(image,1)]/2;
64 | scale = size(image,1)/200;
65 | preds_2d(:,:,i) = transformMPII(output.W_final(2*i-1:2*i,:),center,scale,[size(heatmap,1) size(heatmap,2)],1);
66 | preds_3d(:,:,i) = output.S_final(3*i-2:3*i,:);
67 | end
68 |
69 | %% visualize
70 |
71 | nPlot = 4;
72 | figure('position',[300 300 200*nPlot 200]);
73 |
74 | for i = 1:nImg
75 |
76 | clf
77 |
78 | subplot(1,nPlot,1);
79 | imshow(image(:,:,:,i));
80 |
81 | subplot(1,nPlot,2);
82 | imagesc(mat2gray(sum(heatmap(:,:,:,i),3)));
83 | axis equal off
84 |
85 | subplot(1,nPlot,3);
86 | imshow(image(:,:,:,i));
87 | vis2Dskel(preds_2d(:,:,i),dict.skel);
88 |
89 | subplot(1,nPlot,4);
90 | vis3Dskel(preds_3d(:,:,i),dict.skel,'viewpoint',[-90 0]);
91 |
92 | pause(0.01)
93 |
94 | end
95 |
96 |
--------------------------------------------------------------------------------
/demoMPII.m:
--------------------------------------------------------------------------------
1 | % This script demonstrates how to use:
2 | % the proposed EM algorithm + pose dictionary learned from Human3.6M
3 | % + the most recent CNN based 2D detector "Hourglass network"
4 | % (https://github.com/anewell/pose-hg-demo)
5 | % We use the first image in the validation set of MPII as example
6 |
7 | clear
8 |
9 | datapath = 'data/mpii/';
10 |
11 | % list of validation images in MPII
12 | fileID = fopen([datapath 'annot/valid_images.txt']);
13 | imgList = textscan(fileID,'%s');
14 | fclose(fileID);
15 |
16 | % load dictionary learned from Human3.6M
17 | dict = load('dict/poseDict-all-K128');
18 | dictDataset = 'hm36m';
19 |
20 | % convert dictionary format
21 | % because the joint order in MPII is different from that in Human3.6M
22 | dict = getMPIIdict(dict,dictDataset);
23 | numKp = length(dict.skel.tree);
24 |
25 | % read MPII annotation
26 | h5File = [datapath 'annot/valid.h5'];
27 | scales = hdf5read(h5File,'scale');
28 | centers = hdf5read(h5File,'center');
29 | parts = hdf5read(h5File,'part');
30 |
31 | %% process the first image
32 | i = 1;
33 |
34 | % read heatmaps generated by the Hourglass model
35 | % see data/mpii/main-heatmaps.lua for how to run Hourglass on MPII and save heatmaps
36 | % if you are processing a seqeunce, stack the heatmaps of all frames see demoHG for example
37 | heatmap = hdf5read(sprintf('%s/test-valid/valid%d.h5',datapath,i),'heatmaps');
38 | % transpose heatmaps to make it consistent with the MATLAB x-y directions
39 | heatmap = permute(heatmap,[2,1,3]);
40 |
41 | % EM
42 | % set beta and gamma to be zero because you are processing single images
43 | output = PoseFromVideo('heatmap',heatmap,'dict',dict);
44 | % get estimated poses coordinates for EM output
45 | % the estimated 2D joint location is w.r.t. the bounding box
46 | % need to be converted to the original image coordinates
47 | preds_2d = transformMPII(output.W_final,centers(:,i),scales(i),[size(heatmap,1) size(heatmap,2)],1);
48 | preds_3d = output.S_final;
49 |
50 |
51 | %% visualize
52 |
53 | nPlot = 4;
54 | figure('position',[300 300 200*nPlot 200]);
55 |
56 | subplot(1,nPlot,1);
57 | I = imread(sprintf('%s/images/%s',datapath,imgList{1}{i}));
58 | imshow(I); hold on
59 | vis2Dmarker(parts(:,:,i));
60 | title('image+gt')
61 |
62 | subplot(1,nPlot,2);
63 | imagesc(mat2gray(sum(heatmap,3)));
64 | axis equal off
65 | title('heatmap')
66 |
67 | subplot(1,nPlot,3);
68 | imshow(I);
69 | vis2Dskel(preds_2d,dict.skel);
70 | title('2D estimates')
71 |
72 | subplot(1,nPlot,4);
73 | vis3Dskel(preds_3d(:,:,i),dict.skel,'viewpoint',[-90 0]);
74 | title('3D (novel view)')
75 |
76 |
--------------------------------------------------------------------------------
/dict/poseDict-Posing-K64.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/dict/poseDict-Posing-K64.mat
--------------------------------------------------------------------------------
/dict/poseDict-all-K128.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/dict/poseDict-all-K128.mat
--------------------------------------------------------------------------------
/dict/tennis_forehand.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/dict/tennis_forehand.mat
--------------------------------------------------------------------------------
/em/estimateC_fused.m:
--------------------------------------------------------------------------------
1 | function [C,info] = estimateC_fused(W,R,B,C,alpha,beta,tol)
2 |
3 | % assume W and B have been centralized!!!
4 |
5 | % INPUT:
6 | % W: 2F-by-P matrix
7 | % R: 2F-by-3 matrix
8 | % B: 3K-by-P matrx
9 | % C: F-by-K vector
10 |
11 | P = size(W,2);
12 | F = size(W,1)/2;
13 | K = size(B,1)/3;
14 |
15 | % reshape R
16 | Rdiag = zeros(2*F,3*F);
17 | for i = 1:F
18 | Rdiag(2*i-1:2*i,3*i-2:3*i) = R(2*i-1:2*i,:);
19 | end
20 |
21 | C0 = C; % C0: the previous estimate
22 | t = 1; % auxiliary variable for nesterov
23 | t0 = 1; % auxiliary variable for nesterov
24 | fval = inf;
25 |
26 | % next we work on the linear system yi = X(Ri)*Ci
27 | % compute gradient for each Ci
28 | ytX = zeros(F,K);
29 | XtX = zeros(K,K,F);
30 | for i = 1:F
31 | y = W(2*i-1:2*i,:);
32 | y = y(:);
33 | X = zeros(2*P,K); % each column is a rotated Bk
34 | for k = 1:K
35 | RBk = R(2*i-1:2*i,:)*B(3*k-2:3*k,:);
36 | X(:,k) = RBk(:);
37 | end
38 | ytX(i,:) = y'*X;
39 | XtX(:,:,i) = X'*X;
40 | end
41 | % for fused term
42 | A = zeros(F-1,F);
43 | A(1:F:end) = 1;
44 | A(F:F:end) = -1;
45 | AtA = A'*A;
46 |
47 | % mu should be larger than the 2-norm of the Hessian of f(C)
48 | mu = (norm(XtX(:,:,1))+beta*norm(AtA))*2;
49 |
50 | for iter = 1:500
51 |
52 | % Z is an auxiliary variable in nesterov method
53 | Z = C + (t0-1)/t*(C-C0);
54 |
55 | % gradient descent
56 | G = zeros(F,K);
57 | for i = 1:F
58 | G(i,:) = - ytX(i,:) + Z(i,:)*XtX(:,:,i);
59 | end
60 | G = G + beta*AtA*Z;
61 | Z = Z - G/mu;
62 |
63 | % nonegative thresholding
64 | % Z = Z - alpha/mu;
65 | % Z = max(Z,0);
66 |
67 | % soft thresholding
68 | Z = sign(Z).*max(abs(Z)-alpha/mu,0);
69 |
70 | % update C
71 | C0 = C;
72 | C = Z;
73 |
74 | % update t
75 | t0 = t;
76 | t = (1+sqrt(1+4*t^2))/2;
77 |
78 | % function value
79 | fval_pre = fval;
80 | S = composeShape(B,C);
81 | loss = 1/2 * norm(W-Rdiag*S,'fro')^2;
82 | penalty = alpha * sum(abs(C(:))) ...
83 | + beta/2 * norm(C(1:end-1,:)-C(2:end,:),'fro')^2;
84 | fval = loss + penalty;
85 | if fval > fval_pre
86 | t0 = 1; % APG with restart
87 | t = 1;
88 | end
89 | % fprintf('Iter %d: FunVal = %f, RelChg = %f\n',iter,fval,RelChg);
90 |
91 | % check convergence
92 | RelChg = norm(C-C0,'fro')/(norm(C0,'fro')+eps);
93 | if RelChg < tol
94 | break
95 | end
96 |
97 | end
98 |
99 | info.fval = fval;
100 | info.loss = loss;
101 | info.penalty = penalty;
102 |
103 | end
104 |
105 | function S = composeShape(B,C)
106 |
107 | f = size(C,1);
108 | p = size(B,2);
109 | k = size(B,1)/3;
110 |
111 | B = reshape(B',3*p,k);
112 | S = B*C';
113 | S = reshape(S,p,3*f)';
114 |
115 | end
--------------------------------------------------------------------------------
/em/estimateR_fused.m:
--------------------------------------------------------------------------------
1 | function [R,fval] = estimateR_fused(S,W,lambda,R0,tol)
2 |
3 | F = size(S,1)/3;
4 | P = size(S,2);
5 | S1 = zeros(3,P,F);
6 | W1 = zeros(2,P,F);
7 | R1 = zeros(3,3,F);
8 | for i = 1:F
9 | S1(:,:,i) = S(3*i-2:3*i,:);
10 | W1(:,:,i) = W(2*i-1:2*i,:);
11 | R1(:,:,i) = [R0(2*i-1:2*i,:);cross(R0(2*i-1,:),R0(2*i,:))];
12 | end
13 |
14 | [R2,fval] = updateRotations(W1,S1,lambda,R1,tol);
15 | R = zeros(size(R0));
16 | for i = 1:F
17 | R(2*i-1:2*i,:) = R2(1:2,:,i);
18 | end
19 |
20 | end
21 |
22 |
23 | function [R,fval,info] = updateRotations(W,S,lambda,R0,tol)
24 | %function R = updateRotations(W,S,lambda,R0)
25 | % minimize .5* sum_{i=1}^F ||W(:,:,i)-I_{23}*R(:,:,i)*S(:,:,i)||_F^2 +
26 | % .5*lambda * sum_{i=1}^{F-1} ||R_i-R_{i+1}||_F^2
27 | % w.r.t. R in SO(3)^F
28 | %
29 | % F : number of frames
30 | % P : number of points
31 | % W : 2xPxF
32 | % S : 3xPxF
33 | % R0: 3x3xF
34 | % R : 3x3xF
35 |
36 | warning('off','manopt:getHessian:approx');
37 | DebugMode = false;
38 | options.verbosity = 0;
39 | options.tolgradnorm = tol;
40 | options.maxiter = 50;
41 | % options.verbosity = 3;
42 |
43 | % initialization
44 | if nargin < 4
45 | X0 = repmat(eye(3),[1 1 F]);
46 | else
47 | X0 = R0;
48 | end
49 |
50 | F = size(W,3);
51 |
52 | % Create the problem structure.
53 | manifold = rotationsfactory(3, F);
54 | problem.M = manifold;
55 | problem.cost = @cost;
56 | problem.egrad = @egrad;
57 |
58 |
59 | % Cost function
60 | function totalcost = cost(X)
61 |
62 | P2 = [1 0 0; 0 1 0];
63 |
64 | totalcost = 0;
65 | for i=1:F
66 | totalcost = totalcost + .5*norm(W(:,:,i)- P2*X(:,:,i)*S(:,:,i),'fro')^2;
67 | if i < F
68 | totalcost = totalcost + .5*lambda*norm(X(:,:,i)-X(:,:,i+1),'fro')^2;
69 | end
70 | end
71 | end
72 |
73 | % Euclidean gradient of the cost function
74 | function g = egrad(X)
75 |
76 | P2 = [1 0 0; 0 1 0];
77 |
78 | g = zeros(size(X));
79 |
80 | for i=1:F
81 | g(:,:,i) =g(:,:,i) - P2'*W(:,:,i)*S(:,:,i)' + ...
82 | (P2'*P2)*X(:,:,i)*S(:,:,i)*S(:,:,i)';
83 | if i < F
84 | g(:,:,i) =g(:,:,i)-lambda*X(:,:,i+1);
85 | end
86 |
87 | if i>1
88 | g(:,:,i) = g(:,:,i)-lambda*X(:,:,i-1);
89 | end
90 | end
91 |
92 | end
93 |
94 | % Numerically check gradient consistency (optional).
95 | if DebugMode
96 | checkgradient(problem);
97 | pause(0.1)
98 | end
99 |
100 | % solve
101 | [R, fval, info] = trustregions(problem,X0,options);
102 |
103 | % Display some statistics.
104 | if DebugMode
105 | figure,
106 | semilogy([info.iter], [info.cost], '.-');
107 | xlabel('Iteration number');
108 | ylabel('Cost');
109 | end
110 |
111 | end
112 |
113 |
--------------------------------------------------------------------------------
/em/findWmax.m:
--------------------------------------------------------------------------------
1 | function [W_max,score] = findWmax(heatmap)
2 |
3 | W_max = zeros(2*size(heatmap,4),size(heatmap,3));
4 | score = zeros(size(heatmap,4),size(heatmap,3));
5 | for j = 1:size(W_max,1)/2
6 | for i = 1:size(heatmap,3)
7 | score(j,i) = max(max(heatmap(:,:,i,j)));
8 | [u,v] = find(heatmap(:,:,i,j)==score(j,i),1);
9 | W_max(2*j-1:2*j,i) = [v;u];
10 | end
11 | end
--------------------------------------------------------------------------------
/em/rotateS.m:
--------------------------------------------------------------------------------
1 | function S = rotateS(S,R)
2 |
3 | nFrame = size(S,1)/3;
4 | T = mean(S,2);
5 | S = bsxfun(@minus,S,T);
6 |
7 | for i = 1:nFrame
8 | Ri = [R(2*i-1:2*i,:);cross(R(2*i-1,:),R(2*i,:))];
9 | S(3*i-2:3*i,:) = Ri * S(3*i-2:3*i,:);
10 | end
11 |
12 | S = bsxfun(@plus,S,T);
13 |
--------------------------------------------------------------------------------
/general/alignHuman.m:
--------------------------------------------------------------------------------
1 | function S = alignHuman(S,torso)
2 |
3 | F = size(S,1)/3;
4 | S = bsxfun(@minus,S,mean(S,2));
5 |
6 | St = S(:,torso);
7 | for i = 2:F
8 | % Procrust Alignment of Torso
9 | Y = findRotation(St(1:3,:),St(3*i-2:3*i,:));
10 | S(3*i-2:3*i,:) = Y*S(3*i-2:3*i,:);
11 | end
12 |
--------------------------------------------------------------------------------
/general/centralize.m:
--------------------------------------------------------------------------------
1 | function S = centralize(S)
2 |
3 | S = bsxfun(@minus,S,mean(S,2));
4 |
--------------------------------------------------------------------------------
/general/compareStructs.m:
--------------------------------------------------------------------------------
1 | function [dist,S2] = compareStructs(S1,S2,rot)
2 |
3 | if nargin < 3
4 | rot = 0;
5 | end
6 |
7 | % compare two structures and align S2 to S1 with similarity transformation
8 |
9 | T1 = mean(S1,2);
10 | S1 = bsxfun(@minus,S1,T1);
11 | S2 = bsxfun(@minus,S2,mean(S2,2));
12 |
13 | [f,p] = size(S1);
14 | f = f/3;
15 | dist = zeros(f,p);
16 |
17 | if rot == 0
18 | Y = eye(3);
19 | else
20 | Y = findRotation(S1,S2);
21 | end
22 |
23 | for i = 1:f
24 | A = S1(3*i-2:3*i,:);
25 | B = S2(3*i-2:3*i,:);
26 | if rot == 1
27 | Y = findRotation(A,B);
28 | end
29 | % rotate B
30 | B = Y*B;
31 | % scale B
32 | w = trace(A'*B)/(trace(B'*B)+eps);
33 | B = w*B;
34 | % output
35 | dist(i,:) = sqrt(sum((A-B).^2,1)); % average distance
36 | S2(3*i-2:3*i,:) = B;
37 | end
38 |
39 | S2 = bsxfun(@plus,S2,T1);
40 |
41 | end
42 |
43 | function R = findRotation(S1,S2)
44 | [F,P] = size(S1);
45 | F = F/3;
46 | S1 = reshape(S1,3,F*P);
47 | S2 = reshape(S2,3,F*P);
48 | R = S1*S2';
49 | [U,~,V] = svd(R);
50 | R = U*V';
51 | % R = U*diag([1 1 det(R)])*V';
52 | end
53 |
--------------------------------------------------------------------------------
/general/computeError2D.m:
--------------------------------------------------------------------------------
1 | function dist = computeError2D(W1,W2)
2 |
3 | dist = zeros(size(W1,1)/2,size(W1,2));
4 | for i = 1:size(W1,1)/2
5 | dist(i,:) = sqrt(sum((W1(2*i-1:2*i,:)-W2(2*i-1:2*i,:)).^2,1));
6 | end
--------------------------------------------------------------------------------
/general/computeError3D.m:
--------------------------------------------------------------------------------
1 | function dist = computeError3D(S1,S2)
2 |
3 | dist = zeros(size(S1,1)/3,size(S1,2));
4 | for i = 1:size(S1,1)/3
5 | dist(i,:) = sqrt(sum((S1(3*i-2:3*i,:)-S2(3*i-2:3*i,:)).^2,1));
6 | end
--------------------------------------------------------------------------------
/general/computeErrorPCK.m:
--------------------------------------------------------------------------------
1 | function label = computeErrorPCK(W1,W2,th)
2 |
3 | dist = zeros(size(W1,1)/2,size(W1,2));
4 | for i = 1:size(W1,1)/2
5 | dist(i,:) = sqrt(sum((W1(2*i-1:2*i,:)-W2(2*i-1:2*i,:)).^2,1));
6 | end
7 |
8 | label = dist
44 |
--------------------------------------------------------------------------------
/manopt/CREDITS.txt:
--------------------------------------------------------------------------------
1 | The core developers of Manopt are
2 |
3 | * Nicolas Boumal
4 | * Bamdev Mishra
5 |
6 | Through the RANSO group, Manopt is supported by
7 |
8 | * Pierre-Antoine Absil
9 | * Yurii Nesterov
10 | * Rodolphe Sepulchre
11 |
12 | We are grateful for the excellent contributions of
13 |
14 | * Pierre Borckmans
15 | * Bart Vandereycken
16 | * Hiroyuki Sato
17 | * Roberto Tron
18 | * Sarod Yatawatta
19 | * Hiroyuki Kasai
20 |
21 | Furthermore, code written by the following people can be found in Manopt:
22 |
23 | * Chris Baker
24 | * Pierre-Antoine Absil
25 | * Kyle Gallivan
26 | * Paolo de Leva
27 | * Wynton Moore
28 | * Michael Kleder
29 |
30 | Each person's contribution is marked by their name in the relevant files.
31 | See http://www.manopt.org/about.html for a more precise breakdown.
32 |
--------------------------------------------------------------------------------
/manopt/LICENSE.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/LICENSE.txt
--------------------------------------------------------------------------------
/manopt/README.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/README.txt
--------------------------------------------------------------------------------
/manopt/checkinstall/basicexample.m:
--------------------------------------------------------------------------------
1 | function basicexample()
2 |
3 | % Verify that Manopt was indeed added to the Matlab path.
4 | if isempty(which('spherefactory'))
5 | error(['You should first add Manopt to the Matlab path.\n' ...
6 | 'Please run importmanopt first.']);
7 | end
8 |
9 | % Generate the problem data.
10 | n = 1000;
11 | A = randn(n);
12 | A = .5*(A+A');
13 |
14 | % Create the problem structure.
15 | manifold = spherefactory(n);
16 | problem.M = manifold;
17 |
18 | % Define the problem cost function and its gradient.
19 | problem.cost = @(x) -x'*(A*x);
20 | problem.egrad = @(x) -2*A*x;
21 | problem.ehess = @(x, xdot) -2*A*xdot;
22 |
23 | % Numerically check gradient and Hessian consistency.
24 | figure;
25 | checkgradient(problem);
26 | figure;
27 | checkhessian(problem);
28 |
29 | % Solve.
30 | [x, xcost, info] = trustregions(problem); %#ok
31 |
32 | % Display some statistics.
33 | figure;
34 | semilogy([info.iter], [info.gradnorm], '.-');
35 | xlabel('Iteration #');
36 | ylabel('Gradient norm');
37 | title('Convergence of the trust-regions algorithm on the sphere');
38 |
39 | end
40 |
--------------------------------------------------------------------------------
/manopt/examples/dominant_invariant_subspace_complex.m:
--------------------------------------------------------------------------------
1 | function [X, info] = dominant_invariant_subspace_complex(A, p)
2 | % Returns a unitary basis of the dominant invariant p-subspace of A.
3 | %
4 | % function X = dominant_invariant_subspace(A, p)
5 | %
6 | % Input: A complex, Hermitian matrix A of size nxn and an integer p < n.
7 | % Output: A complex, unitary matrix X of size nxp such that trace(X'*A*X)
8 | % is maximized. That is, the columns of X form a unitary basis
9 | % of a dominant subspace of dimension p of A.
10 | %
11 | % The optimization is performed on the complex Grassmann manifold, since
12 | % only the space spanned by the columns of X matters.
13 | %
14 | % See dominant_invariant_subspace for more details in the real case.
15 | %
16 | % See also: dominant_invariant_subspace grassmanncomplexfactory
17 |
18 | % This file is part of Manopt and is copyrighted. See the license file.
19 | %
20 | % Main author: Nicolas Boumal, June 30, 2015
21 | % Contributors:
22 | %
23 | % Change log:
24 |
25 | % Generate some random data to test the function
26 | if ~exist('A', 'var') || isempty(A)
27 | A = randn(128) + 1i*randn(128);
28 | A = (A+A')/2;
29 | end
30 | if ~exist('p', 'var') || isempty(p)
31 | p = 3;
32 | end
33 |
34 | % Make sure the input matrix is Hermitian
35 | n = size(A, 1);
36 | assert(size(A, 2) == n, 'A must be square.');
37 | assert(norm(A-A', 'fro') < n*eps, 'A must be Hermitian.');
38 | assert(p<=n, 'p must be smaller than n.');
39 |
40 | % Define the cost and its derivatives on the complex Grassmann manifold
41 | Gr = grassmanncomplexfactory(n, p);
42 | problem.M = Gr;
43 | problem.cost = @(X) -real(trace(X'*A*X));
44 | problem.egrad = @(X) -2*A*X;
45 | problem.ehess = @(X, H) -2*A*H;
46 |
47 | % Execute some checks on the derivatives for early debugging.
48 | % These can be commented out.
49 | % checkgradient(problem);
50 | % pause;
51 | % checkhessian(problem);
52 | % pause;
53 |
54 | % Issue a call to a solver. A random initial guess will be chosen and
55 | % default options are selected except for the ones we specify here.
56 | options.Delta_bar = 8*sqrt(p);
57 | [X, costX, info, options] = trustregions(problem, [], options); %#ok
58 |
59 | fprintf('Options used:\n');
60 | disp(options);
61 |
62 | % For our information, Manopt can also compute the spectrum of the
63 | % Riemannian Hessian on the tangent space at (any) X. Computing the
64 | % spectrum at the solution gives us some idea of the conditioning of
65 | % the problem. If we were to implement a preconditioner for the
66 | % Hessian, this would also inform us on its performance.
67 | %
68 | % Notice that (typically) all eigenvalues of the Hessian at the
69 | % solution are positive, i.e., we find an isolated minimizer. If we
70 | % replace the Grassmann manifold by the Stiefel manifold, hence still
71 | % optimizing over orthonormal matrices but ignoring the invariance
72 | % cost(XQ) = cost(X) for all Q orthogonal, then we see
73 | % dim O(p) = p(p-1)/2 zero eigenvalues in the Hessian spectrum, making
74 | % the optimizer not isolated anymore.
75 | if Gr.dim() < 512
76 | evs = hessianspectrum(problem, X);
77 | stairs(sort(evs));
78 | title(['Eigenvalues of the Hessian of the cost function ' ...
79 | 'at the solution']);
80 | xlabel('Eigenvalue number (sorted)');
81 | ylabel('Value of the eigenvalue');
82 | end
83 |
84 | end
85 |
--------------------------------------------------------------------------------
/manopt/examples/essential_svd.m:
--------------------------------------------------------------------------------
1 | function essential_svd
2 | % Sample solution of an optimization problem on the essential manifold.
3 | %
4 | % Solves the problem \sum_{i=1}^N ||E_i-A_i||^2, where E_i are essential
5 | % matrices. Essential matrices are used in computer vision to represent the
6 | % epipolar constraint between projected points in two perspective views.
7 | %
8 | % Note: the essentialfactory file uses a quotient R1/R2 representation to
9 | % work with essential matrices. On the other hand, from a user point of
10 | % view, it is convenient to use the E representation (a matrix of size
11 | % 3-by-3) to give cost, gradient, and Hessian information. To this end, we
12 | % provide auxiliary files essential_costE2cost, essential_egradE2egrad, and
13 | % essential_ehessE2ehess that convert these ingredients to their R1/R2
14 | % counterparts.
15 | %
16 | % See also: essentialfactory essential_costE2cost essential_egradE2egrad
17 | % essential_ehessE2ehess
18 |
19 | % This file is part of Manopt: www.manopt.org.
20 | % Original author: Roberto Tron, Aug. 8, 2014
21 | % Contributors: Bamdev Mishra, May 15, 2015.
22 |
23 |
24 | % Make data for the test
25 | N = 2; % Number of matrices to process in parallel.
26 | A = multiprod(multiprod(randrot(3, N), essential_hat3([0; 0; 1])), randrot(3, N));
27 |
28 | % The essential manifold
29 | M = essentialfactory(N);
30 | problem.M = M;
31 |
32 | % Function handles of the essential matrix E and Euclidean gradient and Hessian
33 | costE = @(E) 0.5*sum(multisqnorm(E-A));
34 | egradE = @(E) E - A;
35 | ehessE = @(E, U) U;
36 |
37 |
38 | % Manopt descriptions
39 | problem.cost = @cost;
40 | function val = cost(X)
41 | val = essential_costE2cost(X, costE); % Cost
42 | end
43 |
44 | problem.egrad = @egrad;
45 | function g = egrad(X)
46 | g = essential_egradE2egrad(X, egradE); % Converts gradient in E to X.
47 | end
48 |
49 | problem.ehess = @ehess;
50 | function gdot = ehess(X, S)
51 | gdot = essential_ehessE2ehess(X, egradE, ehessE, S); % Converts Hessian in E to X.
52 | end
53 |
54 |
55 | % Numerically check the differentials.
56 | % checkgradient(problem); pause;
57 | % checkhessian(problem); pause;
58 |
59 | %Solve the problem
60 | Xsol = trustregions(problem);
61 |
62 | % Distance between original matrices and decompositions
63 | val = essential_costE2cost(Xsol, costE);
64 | fprintf('Distance between original matrices and decompositions is %e \n', val);
65 |
66 | end
67 |
--------------------------------------------------------------------------------
/manopt/examples/generalized_eigenvalue_computation.m:
--------------------------------------------------------------------------------
1 | function [Xsol, Ssol] = generalized_eigenvalue_computation(A, B, p)
2 | % Returns orthonormal basis of the dominant invariant p-subspace of B^-1 A.
3 | %
4 | % function [Xsol, Ssol] = generalized_eigenvalue_computation(A, B, p)
5 | %
6 | % Input: A is a real, symmetric matrix of size nxn,
7 | % B is a symmetric positive definite matrix, same size as A, and
8 | % an integer p < n.
9 | % Output: Xsol: a real, orthonormal matrix X of size nxp such that
10 | % trace(X'*A*X) is maximized, subject to X'*B*X being identity.
11 | % That is, the columns of X form an orthonormal basis of a dominant
12 | % subspace of dimension p of B^(-1)*A. These are thus eigenvectors
13 | % associated with the largest eigenvalues of B^(-1)*A (in no
14 | % particular order). Sign is important: 2 is deemed a larger
15 | % eigenvalue than -5.
16 | % Ssol: the eigenvalues associated with the eigenvectors Xsol.
17 | %
18 | % We intend to solve the homogeneous system A*X = B*X*S,
19 | % where S is a diagonal matrix of dominant eigenvalues of B^-1 A.
20 | %
21 | %
22 | % The optimization is performed on the generalized Grassmann manifold,
23 | % since only the space spanned by the columns of X matters.
24 | %
25 | % The optimization problem that we are solving here is
26 | % maximize trace(X'*A*X) subject to X'*B*X = eye(p).
27 | % Consequently, the solutions remain invariant to transformation
28 | % X --> XO, where O is a p-by-p orthogonal matrix. The search space, in
29 | % essence, is set of equivalence classes
30 | % [X] = {XO : X'*B*X = I and O is orthogonal matrix}. This space is called
31 | % the generalized Grassmann manifold.
32 | %
33 | % See also dominant_invariant_subspace nonlinear_eigenspace
34 |
35 |
36 | % This file is part of Manopt and is copyrighted. See the license file.
37 | %
38 | % Main author: Bamdev Mishra, June 30, 2015.
39 | % Contributors:
40 | % Change log:
41 |
42 | % Generate some random data to test the function
43 | if ~exist('A', 'var') || isempty(A)
44 | n = 128;
45 | A = randn(n);
46 | A = (A+A')/2;
47 | end
48 | if ~exist('B', 'var') || isempty(B)
49 | n = size(A, 1);
50 | e = ones(n, 1);
51 | B = spdiags([-e 2*e -e], -1:1, n, n); % Symmetric positive definite
52 | end
53 |
54 | if ~exist('p', 'var') || isempty(p)
55 | p = 3;
56 | end
57 |
58 | % Make sure the input matrix is square and symmetric
59 | n = size(A, 1);
60 | assert(isreal(A), 'A must be real.')
61 | assert(size(A, 2) == n, 'A must be square.');
62 | assert(norm(A-A', 'fro') < n*eps, 'A must be symmetric.');
63 | assert(p <= n, 'p must be smaller than n.');
64 |
65 | % Define the cost and its derivatives on the generalized
66 | % Grassmann manifold, i.e., the column space of all X such that
67 | % X'*B*X is identity.
68 | gGr = grassmanngeneralizedfactory(n, p, B);
69 |
70 | problem.M = gGr;
71 | problem.cost = @(X) -trace(X'*A*X);
72 | problem.egrad = @(X) -2*(A*X); % Only Euclidean gradient needed.
73 | problem.ehess = @(X, H) -2*(A*H); % Only Euclidean Hessian needed.
74 |
75 | % Execute some checks on the derivatives for early debugging.
76 | % These things can be commented out of course.
77 | % checkgradient(problem);
78 | % pause;
79 | % checkhessian(problem);
80 | % pause;
81 |
82 | % Issue a call to a solver. A random initial guess will be chosen and
83 | % default options are selected except for the ones we specify here.
84 | options.Delta_bar = 8*sqrt(p);
85 | [Xsol, costXsol, info] = trustregions(problem, [], options); %#ok
86 |
87 | % To extract the eigenvalues, solve the small p-by-p symmetric
88 | % eigenvalue problem.
89 | Ssol = eig(Xsol'*(A*Xsol));
90 |
91 | end
92 |
--------------------------------------------------------------------------------
/manopt/examples/nonlinear_eigenspace.m:
--------------------------------------------------------------------------------
1 | function Xsol = nonlinear_eigenspace(L, k, alpha)
2 | % Example of nonlinear eigenvalue problem: total energy minimization.
3 | %
4 | % function Xsol = nonlinear_eigenspace(L, k, alpha)
5 | %
6 | % L is a discrete Laplacian operator,
7 | % alpha is a given constant, and
8 | % k corresponds to the dimension of the least eigenspace sought.
9 | %
10 | % This example demonstrates how to use the Grassmann geometry factory
11 | % to solve the nonlinear eigenvalue problem as the optimization problem:
12 | %
13 | % minimize 0.5*trace(X'*L*X) + (alpha/4)*(rho(X)*L\(rho(X)))
14 | % over X such that X'*X = Identity,
15 | %
16 | % where L is of size n-by-n,
17 | % X is an n-by-k matrix, and
18 | % rho(X) is the diagonal part of X*X'.
19 | %
20 | % This example is motivated in the paper
21 | % "A Riemannian Newton Algorithm for Nonlinear Eigenvalue Problems",
22 | % Zhi Zhao, Zheng-Jian Bai, and Xiao-Qing Jin,
23 | % SIAM Journal on Matrix Analysis and Applications, 36(2), 752-774, 2015.
24 | %
25 |
26 |
27 | % This file is part of Manopt and is copyrighted. See the license file.
28 | %
29 | % Main author: Bamdev Mishra, June 19, 2015.
30 | % Contributors:
31 | %
32 | % Change log:
33 |
34 |
35 | % If no inputs are provided, generate a discrete Laplacian operator.
36 | % This is for illustration purposes only.
37 | % The default example corresponds to Case (c) of Example 6.2 of the
38 | % above referenced paper.
39 |
40 | if ~exist('L', 'var') || isempty(L)
41 | n = 100;
42 | L = gallery('tridiag', n, -1, 2, -1);
43 | end
44 |
45 | n = size(L, 1);
46 | assert(size(L, 2) == n, 'L must be square.');
47 |
48 | if ~exist('k', 'var') || isempty(k) || k > n
49 | k = 10;
50 | end
51 |
52 | if ~exist('alpha', 'var') || isempty(alpha)
53 | alpha = 1;
54 | end
55 |
56 |
57 | % Grassmann manifold description
58 | Gr = grassmannfactory(n, k);
59 | problem.M = Gr;
60 |
61 | % Cost function evaluation
62 | problem.cost = @cost;
63 | function val = cost(X)
64 | rhoX = sum(X.^2, 2); % diag(X*X');
65 | val = 0.5*trace(X'*(L*X)) + (alpha/4)*(rhoX'*(L\rhoX));
66 | end
67 |
68 | % Euclidean gradient evaluation
69 | % Note: Manopt automatically converts it to the Riemannian counterpart.
70 | problem.egrad = @egrad;
71 | function g = egrad(X)
72 | rhoX = sum(X.^2, 2); % diag(X*X');
73 | g = L*X + alpha*diag(L\rhoX)*X;
74 | end
75 |
76 | % Euclidean Hessian evaluation
77 | % Note: Manopt automatically converts it to the Riemannian counterpart.
78 | problem.ehess = @ehess;
79 | function h = ehess(X, U)
80 | rhoX = sum(X.^2, 2); %diag(X*X');
81 | rhoXdot = 2*sum(X.*U, 2);
82 | h = L*U + alpha*diag(L\rhoXdot)*X + alpha*diag(L\rhoX)*U;
83 | end
84 |
85 |
86 | % Check whether gradient and Hessian computations are correct.
87 | % checkgradient(problem);
88 | % pause;
89 | % checkhessian(problem);
90 | % pause;
91 |
92 |
93 | % Initialization as suggested in above referenced paper.
94 | X = randn(n, k);
95 | [U, S, V] = svd(X, 0); %#ok
96 | X = U*V';
97 | [U0, S0, V0] = eigs(L + alpha*diag(L\(sum(X.^2, 2))), k,'sm'); %#ok
98 | X0 = U0;
99 |
100 | % Call manoptsolve to automatically call an appropriate solver.
101 | % Note: it calls the trust regions solver as we have all the required
102 | % ingredients, namely, gradient and Hessian, information.
103 | Xsol = manoptsolve(problem, X0);
104 |
105 | end
106 |
--------------------------------------------------------------------------------
/manopt/importmanopt.m:
--------------------------------------------------------------------------------
1 | % Add Manopt to the path to make all manopt components available.
2 |
3 | % This file is part of Manopt: www.manopt.org.
4 | % Original author: Nicolas Boumal, Jan. 3, 2013.
5 | % Contributors:
6 | % Change log:
7 | % Aug. 7, 2013 (NB): Changed to work without the import command
8 | % (new structure of the toolbox).
9 | % Aug. 8, 2013 (NB): Changed to use addpath_recursive, home brewed.
10 | % Aug. 22, 2013 (NB): Using genpath instead of home cooked
11 | % addpath_recursive.
12 |
13 | addpath(pwd);
14 |
15 | % Recursively add Manopt directories to the Matlab path.
16 | cd manopt;
17 | addpath(genpath(pwd));
18 | cd ..;
19 |
--------------------------------------------------------------------------------
/manopt/manopt/core/applyStatsfun.m:
--------------------------------------------------------------------------------
1 | function stats = applyStatsfun(problem, x, storedb, key, options, stats)
2 | % Apply the statsfun function to a stats structure (for solvers).
3 | %
4 | % function stats = applyStatsfun(problem, x, storedb, key, options, stats)
5 | %
6 | % Applies the options.statsfun user supplied function (if it was provided)
7 | % to the stats structure, and returns the (possibly) modified stats
8 | % structure.
9 | %
10 | % storedb is a StoreDB object, key is the StoreDB key to point x.
11 | %
12 | % Note: if statsfun accepts a store structure as input, this structure can
13 | % be read but not modified (modifications will be lost) ; the store
14 | % structure will contain the store.shared field.
15 | %
16 | % See also:
17 |
18 | % This file is part of Manopt: www.manopt.org.
19 | % Original author: Nicolas Boumal, April 3, 2013.
20 | % Contributors:
21 | % Change log:
22 | %
23 | % April 3, 2015 (NB):
24 | % Works with the new StoreDB class system.
25 |
26 | if isfield(options, 'statsfun')
27 |
28 | switch nargin(options.statsfun)
29 | case 3
30 | stats = options.statsfun(problem, x, stats);
31 | case 4
32 | % Obtain, pass along, and save the store for x.
33 | % get/setWithShared must come in pairs.
34 | store = storedb.getWithShared(key);
35 | stats = options.statsfun(problem, x, stats, store);
36 | storedb.setWithShared(store, key);
37 | otherwise
38 | warning('manopt:statsfun', ...
39 | 'statsfun unused: wrong number of inputs');
40 | end
41 | end
42 |
43 | end
44 |
--------------------------------------------------------------------------------
/manopt/manopt/core/canGetApproxHessian.m:
--------------------------------------------------------------------------------
1 | function candoit = canGetApproxHessian(problem)
2 | % Checks whether an approximate Hessian can be computed for this problem.
3 | %
4 | % function candoit = canGetApproxHessian(problem)
5 | %
6 | % Returns true if an approximate Hessian of the cost function is provided
7 | % in the given problem description, false otherwise.
8 | % If a Hessian is defined but no approximate Hessian is defined explicitly,
9 | % returns false.
10 | %
11 | % Even if this returns false, calls to getApproxHessian may succeed, as
12 | % they will be redirected to getHessianFD. The latter simply requires
13 | % availability of gradients in problem, and vector transports in problem.M.
14 | %
15 | % See also: canGetHessian getHessianFD
16 |
17 | % This file is part of Manopt: www.manopt.org.
18 | % Original author: Nicolas Boumal, April 8, 2015.
19 | % Contributors:
20 | % Change log:
21 |
22 | candoit = isfield(problem, 'approxhess');
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/manopt/manopt/core/canGetCost.m:
--------------------------------------------------------------------------------
1 | function candoit = canGetCost(problem)
2 | % Checks whether the cost function can be computed for a problem structure.
3 | %
4 | % function candoit = canGetCost(problem)
5 | %
6 | % Returns true if the cost function can be computed given the problem
7 | % description, false otherwise.
8 | %
9 | % See also: getCost canGetDirectionalDerivative canGetGradient canGetHessian
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, Dec. 30, 2012.
13 | % Contributors:
14 | % Change log:
15 |
16 |
17 | candoit = isfield(problem, 'cost') || isfield(problem, 'costgrad');
18 |
19 | end
20 |
--------------------------------------------------------------------------------
/manopt/manopt/core/canGetDirectionalDerivative.m:
--------------------------------------------------------------------------------
1 | function candoit = canGetDirectionalDerivative(problem)
2 | % Checks whether dir. derivatives can be computed for a problem structure.
3 | %
4 | % function candoit = canGetDirectionalDerivative(problem)
5 | %
6 | % Returns true if the directional derivatives of the cost function can be
7 | % computed given the problem description, false otherwise.
8 | %
9 | % See also: canGetCost canGetGradient canGetHessian
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, Dec. 30, 2012.
13 | % Contributors:
14 | % Change log:
15 |
16 | candoit = isfield(problem, 'diff') || canGetGradient(problem);
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/manopt/manopt/core/canGetEuclideanGradient.m:
--------------------------------------------------------------------------------
1 | function candoit = canGetEuclideanGradient(problem)
2 | % Checks whether the Euclidean gradient can be computed for a problem.
3 | %
4 | % function candoit = canGetEuclideanGradient(problem)
5 | %
6 | % Returns true if the Euclidean gradient can be computed given the problem
7 | % description, false otherwise.
8 | %
9 | % See also: canGetGradient getEuclideanGradient
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, Dec. 30, 2012.
13 | % Contributors:
14 | % Change log:
15 |
16 |
17 | candoit = isfield(problem, 'egrad');
18 |
19 | end
20 |
--------------------------------------------------------------------------------
/manopt/manopt/core/canGetGradient.m:
--------------------------------------------------------------------------------
1 | function candoit = canGetGradient(problem)
2 | % Checks whether the gradient can be computed for a problem structure.
3 | %
4 | % function candoit = canGetGradient(problem)
5 | %
6 | % Returns true if the gradient of the cost function can be computed given
7 | % the problem description, false otherwise.
8 | %
9 | % See also: canGetCost canGetDirectionalDerivative canGetHessian
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, Dec. 30, 2012.
13 | % Contributors:
14 | % Change log:
15 |
16 | candoit = isfield(problem, 'grad') || isfield(problem, 'costgrad') || ...
17 | canGetEuclideanGradient(problem);
18 |
19 | end
20 |
--------------------------------------------------------------------------------
/manopt/manopt/core/canGetHessian.m:
--------------------------------------------------------------------------------
1 | function candoit = canGetHessian(problem)
2 | % Checks whether the Hessian can be computed for a problem structure.
3 | %
4 | % function candoit = canGetHessian(problem)
5 | %
6 | % Returns true if the Hessian of the cost function can be computed given
7 | % the problem description, false otherwise.
8 | %
9 | % See also: canGetCost canGetDirectionalDerivative canGetGradient
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, Dec. 30, 2012.
13 | % Contributors:
14 | % Change log:
15 |
16 | candoit = isfield(problem, 'hess') || ...
17 | (isfield(problem, 'ehess') && canGetEuclideanGradient(problem));
18 |
19 | if ~candoit && ...
20 | (isfield(problem, 'ehess') && ~canGetEuclideanGradient(problem))
21 | warning('manopt:canGetHessian', ...
22 | ['If the Hessian is supplied as a Euclidean Hessian (ehess), ' ...
23 | 'then the Euclidean gradient must also be supplied (egrad).']);
24 | end
25 |
26 | end
27 |
--------------------------------------------------------------------------------
/manopt/manopt/core/canGetLinesearch.m:
--------------------------------------------------------------------------------
1 | function candoit = canGetLinesearch(problem)
2 | % Checks whether the problem structure can give a line-search a hint.
3 | %
4 | % function candoit = canGetLinesearch(problem)
5 | %
6 | % Returns true if the the problem description includes a mechanism to give
7 | % line-search algorithms a hint as to "how far to look", false otherwise.
8 | %
9 | % See also: getLinesearch
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, July 17, 2014.
13 | % Contributors:
14 | % Change log:
15 |
16 |
17 | candoit = isfield(problem, 'linesearch');
18 |
19 | end
20 |
--------------------------------------------------------------------------------
/manopt/manopt/core/canGetPrecon.m:
--------------------------------------------------------------------------------
1 | function candoit = canGetPrecon(problem)
2 | % Checks whether a preconditioner was specified in the problem description.
3 | %
4 | % function candoit = canGetPrecon(problem)
5 | %
6 | % Returns true if a preconditioner was specified, false otherwise. Notice
7 | % that even if this function returns false, it is still possible to call
8 | % getPrecon, as the default preconditioner is simply the identity operator.
9 | % This check function is mostly useful to tell whether that default
10 | % preconditioner will be in use or not.
11 | %
12 | % See also: getPrecon getSqrtPrecon canGetSqrtPrecon getHessian
13 |
14 | % This file is part of Manopt: www.manopt.org.
15 | % Original author: Nicolas Boumal, July 3, 2013.
16 | % Contributors:
17 | % Change log:
18 |
19 | candoit = isfield(problem, 'precon') || canGetSqrtPrecon(problem);
20 |
21 | end
22 |
--------------------------------------------------------------------------------
/manopt/manopt/core/canGetSqrtPrecon.m:
--------------------------------------------------------------------------------
1 | function candoit = canGetSqrtPrecon(problem)
2 | % Checks whether a square root of preconditioner was specified in problem.
3 | %
4 | % function candoit = canGetSqrtPrecon(problem)
5 | %
6 | % Returns true if the problem structure allows for applying the square root
7 | % of a preconditioner to tangent vectors at a given point. The square root
8 | % of the preconditioner at x must be a symmetric, positive definite
9 | % operator Q such that applying Q twice (Q o Q) amounts to applying the
10 | % preconditioner once. If both a preconditioner and a square root of
11 | % preconditioner are provided, it is the user's responsibility to ensure
12 | % their compatibility.
13 | %
14 | % Similarly to getPrecon, if the present function returns false, calls to
15 | % getSqrtPrecon will still work: they will act as the identity. Note that
16 | % this may be incompatible with the preconditioner if it is given. Thus,
17 | % always check by calling canGetSqrtPrecon first.
18 | %
19 | % See also: canGetPrecon getSqrtPrecon getPrecon
20 |
21 | % This file is part of Manopt: www.manopt.org.
22 | % Original author: Nicolas Boumal, April 3, 2015.
23 | % Contributors:
24 | % Change log:
25 |
26 | candoit = isfield(problem, 'sqrtprecon');
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getApproxHessian.m:
--------------------------------------------------------------------------------
1 | function approxhess = getApproxHessian(problem, x, d, storedb, key)
2 | % Computes an approximation of the Hessian of the cost fun. at x along d.
3 | %
4 | % function approxhess = getApproxHessian(problem, x, d)
5 | % function approxhess = getApproxHessian(problem, x, d, storedb)
6 | % function approxhess = getApproxHessian(problem, x, d, storedb, key)
7 | %
8 | % Returns an approximation of the Hessian at x along d of the cost function
9 | % described in the problem structure.
10 | %
11 | % storedb is a StoreDB object, key is the StoreDB key to point x.
12 | %
13 | % If no approximate Hessian was provided, this call is redirected to
14 | % getHessianFD.
15 | %
16 | % See also: getHessianFD canGetApproxHessian
17 |
18 | % This file is part of Manopt: www.manopt.org.
19 | % Original author: Nicolas Boumal, Dec. 30, 2012.
20 | % Contributors:
21 | % Change log:
22 | %
23 | % April 3, 2015 (NB):
24 | % Works with the new StoreDB class system.
25 |
26 | % Allow omission of the key, and even of storedb.
27 | if ~exist('key', 'var')
28 | if ~exist('storedb', 'var')
29 | storedb = StoreDB();
30 | end
31 | key = storedb.getNewKey();
32 | end
33 |
34 |
35 | if isfield(problem, 'approxhess')
36 | %% Compute the approximate Hessian using approxhess.
37 |
38 | % Check whether this function wants to deal with storedb or not.
39 | switch nargin(problem.approxhess);
40 | case 2
41 | approxhess = problem.approxhess(x, d);
42 | case 3
43 | % Obtain, pass along, and save the store for x.
44 | store = storedb.getWithShared(key);
45 | [approxhess, store] = problem.approxhess(x, d, store);
46 | storedb.setWithShared(store, key);
47 | case 4
48 | % Pass along the whole storedb (by reference), with key.
49 | approxhess = problem.approxhess(x, d, storedb, key);
50 | otherwise
51 | up = MException('manopt:getApproxHessian:badapproxhess', ...
52 | 'approxhess should accept 2, 3 or 4 inputs.');
53 | throw(up);
54 | end
55 |
56 | else
57 | %% Try to fall back to a standard FD approximation.
58 |
59 | approxhess = getHessianFD(problem, x, d, storedb, key);
60 |
61 | end
62 |
63 | end
64 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getCost.m:
--------------------------------------------------------------------------------
1 | function cost = getCost(problem, x, storedb, key)
2 | % Computes the cost function at x.
3 | %
4 | % function cost = getCost(problem, x)
5 | % function cost = getCost(problem, x, storedb)
6 | % function cost = getCost(problem, x, storedb, key)
7 | %
8 | % Returns the value at x of the cost function described in the problem
9 | % structure.
10 | %
11 | % storedb is a StoreDB object, key is the StoreDB key to point x.
12 | %
13 | % See also: canGetCost
14 |
15 | % This file is part of Manopt: www.manopt.org.
16 | % Original author: Nicolas Boumal, Dec. 30, 2012.
17 | % Contributors:
18 | % Change log:
19 | %
20 | % April 3, 2015 (NB):
21 | % Works with the new StoreDB class system.
22 |
23 | % Allow omission of the key, and even of storedb.
24 | if ~exist('key', 'var')
25 | if ~exist('storedb', 'var')
26 | storedb = StoreDB();
27 | end
28 | key = storedb.getNewKey();
29 | end
30 |
31 |
32 | if isfield(problem, 'cost')
33 | %% Compute the cost function using cost.
34 |
35 | % Check whether this function wants to deal with storedb or not.
36 | switch nargin(problem.cost)
37 | case 1
38 | cost = problem.cost(x);
39 | case 2
40 | % Obtain, pass along, and save the store for x.
41 | store = storedb.getWithShared(key);
42 | [cost, store] = problem.cost(x, store);
43 | storedb.setWithShared(store, key);
44 | case 3
45 | % Pass along the whole storedb (by reference), with key.
46 | cost = problem.cost(x, storedb, key);
47 | otherwise
48 | up = MException('manopt:getCost:badcost', ...
49 | 'cost should accept 1, 2 or 3 inputs.');
50 | throw(up);
51 | end
52 |
53 | elseif isfield(problem, 'costgrad')
54 | %% Compute the cost function using costgrad.
55 |
56 | % Check whether this function wants to deal with storedb or not.
57 | switch nargin(problem.costgrad)
58 | case 1
59 | cost = problem.costgrad(x);
60 | case 2
61 | % Obtain, pass along, and save the store for x.
62 | store = storedb.getWithShared(key);
63 | [cost, grad, store] = problem.costgrad(x, store); %#ok
64 | storedb.setWithShared(store, key);
65 | case 3
66 | % Pass along the whole storedb (by reference), with key.
67 | cost = problem.costgrad(x, storedb, key);
68 | otherwise
69 | up = MException('manopt:getCost:badcostgrad', ...
70 | 'costgrad should accept 1, 2 or 3 inputs.');
71 | throw(up);
72 | end
73 |
74 | else
75 | %% Abandon computing the cost function.
76 |
77 | up = MException('manopt:getCost:fail', ...
78 | ['The problem description is not explicit enough to ' ...
79 | 'compute the cost.']);
80 | throw(up);
81 |
82 | end
83 |
84 | end
85 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getCostGrad.m:
--------------------------------------------------------------------------------
1 | function [cost, grad] = getCostGrad(problem, x, storedb, key)
2 | % Computes the cost function and the gradient at x in one call if possible.
3 | %
4 | % function [cost, grad] = getCostGrad(problem, x)
5 | % function [cost, grad] = getCostGrad(problem, x, storedb)
6 | % function [cost, grad] = getCostGrad(problem, x, storedb, key)
7 | %
8 | % Returns the value at x of the cost function described in the problem
9 | % structure, as well as the gradient at x.
10 | %
11 | % storedb is a StoreDB object, key is the StoreDB key to point x.
12 | %
13 | % See also: canGetCost canGetGradient getCost getGradient
14 |
15 | % This file is part of Manopt: www.manopt.org.
16 | % Original author: Nicolas Boumal, Dec. 30, 2012.
17 | % Contributors:
18 | % Change log:
19 | %
20 | % April 3, 2015 (NB):
21 | % Works with the new StoreDB class system.
22 |
23 | % Allow omission of the key, and even of storedb.
24 | if ~exist('key', 'var')
25 | if ~exist('storedb', 'var')
26 | storedb = StoreDB();
27 | end
28 | key = storedb.getNewKey();
29 | end
30 |
31 |
32 | if isfield(problem, 'costgrad')
33 | %% Compute the cost/grad pair using costgrad.
34 |
35 | % Check whether this function wants to deal with storedb or not.
36 | switch nargin(problem.costgrad)
37 | case 1
38 | [cost, grad] = problem.costgrad(x);
39 | case 2
40 | % Obtain, pass along, and save the store for x.
41 | store = storedb.getWithShared(key);
42 | [cost, grad, store] = problem.costgrad(x, store);
43 | storedb.setWithShared(store, key);
44 | case 3
45 | % Pass along the whole storedb (by reference), with key.
46 | [cost, grad] = problem.costgrad(x, storedb, key);
47 | otherwise
48 | up = MException('manopt:getCostGrad:badcostgrad', ...
49 | 'costgrad should accept 1, 2 or 3 inputs.');
50 | throw(up);
51 | end
52 |
53 | else
54 | %% Revert to calling getCost and getGradient separately
55 |
56 | cost = getCost(problem, x, storedb, key);
57 | grad = getGradient(problem, x, storedb, key);
58 |
59 | end
60 |
61 | end
62 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getDirectionalDerivative.m:
--------------------------------------------------------------------------------
1 | function diff = getDirectionalDerivative(problem, x, d, storedb, key)
2 | % Computes the directional derivative of the cost function at x along d.
3 | %
4 | % function diff = getDirectionalDerivative(problem, x, d)
5 | % function diff = getDirectionalDerivative(problem, x, d, storedb)
6 | % function diff = getDirectionalDerivative(problem, x, d, storedb, key)
7 | %
8 | % Returns the derivative at x along d of the cost function described in the
9 | % problem structure.
10 | %
11 | % storedb is a StoreDB object, key is the StoreDB key to point x.
12 | %
13 | % See also: getGradient canGetDirectionalDerivative
14 |
15 | % This file is part of Manopt: www.manopt.org.
16 | % Original author: Nicolas Boumal, Dec. 30, 2012.
17 | % Contributors:
18 | % Change log:
19 | %
20 | % April 3, 2015 (NB):
21 | % Works with the new StoreDB class system.
22 |
23 | % Allow omission of the key, and even of storedb.
24 | if ~exist('key', 'var')
25 | if ~exist('storedb', 'var')
26 | storedb = StoreDB();
27 | end
28 | key = storedb.getNewKey();
29 | end
30 |
31 |
32 | if isfield(problem, 'diff')
33 | %% Compute the directional derivative using diff.
34 |
35 | % Check whether this function wants to deal with storedb or not.
36 | switch nargin(problem.diff)
37 | case 2
38 | diff = problem.diff(x, d);
39 | case 3
40 | % Obtain, pass along, and save the store for x.
41 | store = storedb.getWithShared(key);
42 | [diff, store] = problem.diff(x, d, store);
43 | storedb.setWithShared(store, key);
44 | case 4
45 | % Pass along the whole storedb (by reference), with key.
46 | diff = problem.diff(x, d, storedb, key);
47 | otherwise
48 | up = MException('manopt:getDirectionalDerivative:baddiff', ...
49 | 'diff should accept 2, 3 or 4 inputs.');
50 | throw(up);
51 | end
52 |
53 | elseif canGetGradient(problem)
54 | %% Compute the directional derivative using the gradient.
55 |
56 | % Compute the gradient at x, then compute its inner product with d.
57 | grad = getGradient(problem, x, storedb, key);
58 | diff = problem.M.inner(x, grad, d);
59 |
60 | else
61 | %% Abandon computing the directional derivative.
62 |
63 | up = MException('manopt:getDirectionalDerivative:fail', ...
64 | ['The problem description is not explicit enough to ' ...
65 | 'compute the directional derivatives of f.']);
66 | throw(up);
67 |
68 | end
69 |
70 | end
71 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getEuclideanGradient.m:
--------------------------------------------------------------------------------
1 | function egrad = getEuclideanGradient(problem, x, storedb, key)
2 | % Computes the Euclidean gradient of the cost function at x.
3 | %
4 | % function egrad = getEuclideanGradient(problem, x)
5 | % function egrad = getEuclideanGradient(problem, x, storedb)
6 | % function egrad = getEuclideanGradient(problem, x, storedb, key)
7 | %
8 | % Returns the Euclidean gradient at x of the cost function described in the
9 | % problem structure.
10 | %
11 | % storedb is a StoreDB object, key is the StoreDB key to point x.
12 | %
13 | % Because computing the Hessian based on the Euclidean Hessian will require
14 | % the Euclidean gradient every time, to avoid overly redundant
15 | % computations, if the egrad function does not use the store caching
16 | % capabilites, this implements an automatic caching functionality. Writing
17 | % egrad to accept the optional store or storedb parameter will disable
18 | % automatic caching, but allow user controlled caching.
19 | %
20 | % See also: getGradient canGetGradient canGetEuclideanGradient
21 |
22 | % This file is part of Manopt: www.manopt.org.
23 | % Original author: Nicolas Boumal, July 9, 2013.
24 | % Contributors:
25 | % Change log:
26 | %
27 | % April 3, 2015 (NB):
28 | % Works with the new StoreDB class system.
29 |
30 | % Allow omission of the key, and even of storedb.
31 | if ~exist('key', 'var')
32 | if ~exist('storedb', 'var')
33 | storedb = StoreDB();
34 | end
35 | key = storedb.getNewKey();
36 | end
37 |
38 |
39 | if isfield(problem, 'egrad')
40 | %% Compute the Euclidean gradient using egrad.
41 |
42 | % Check whether this function wants to deal with storedb or not.
43 | switch nargin(problem.egrad)
44 | case 1
45 | % If it does not want to deal with the store structure,
46 | % then we do some caching of our own. There is a small
47 | % performance hit for this is some cases, but we expect
48 | % that this is most often the preferred choice.
49 | store = storedb.get(key);
50 | if ~isfield(store, 'egrad__')
51 | store.egrad__ = problem.egrad(x);
52 | storedb.set(store, key);
53 | end
54 | egrad = store.egrad__;
55 | case 2
56 | % Obtain, pass along, and save the store for x.
57 | % If the user deals with the store structure, then we don't
58 | % do any automatic caching: the user is in control.
59 | store = storedb.getWithShared(key);
60 | [egrad, store] = problem.egrad(x, store);
61 | storedb.setWithShared(store, key);
62 | case 3
63 | % Pass along the whole storedb (by reference), with key.
64 | % Same here: no automatic caching.
65 | egrad = problem.egrad(x, storedb, key);
66 | otherwise
67 | up = MException('manopt:getEuclideanGradient:badegrad', ...
68 | 'egrad should accept 1, 2 or 3 inputs.');
69 | throw(up);
70 | end
71 |
72 | else
73 | %% Abandon computing the Euclidean gradient
74 |
75 | up = MException('manopt:getEuclideanGradient:fail', ...
76 | ['The problem description is not explicit enough to ' ...
77 | 'compute the Euclidean gradient of the cost.']);
78 | throw(up);
79 |
80 | end
81 |
82 | end
83 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getGlobalDefaults.m:
--------------------------------------------------------------------------------
1 | function opts = getGlobalDefaults()
2 | % Returns a structure with default option values for Manopt.
3 | %
4 | % function opts = getGlobalDefaults()
5 | %
6 | % Returns a structure opts containing the global default options such as
7 | % verbosity level etc. Typically, global defaults are overwritten by solver
8 | % defaults, which are in turn overwritten by user-specified options.
9 | % See the online Manopt documentation for details on options.
10 | %
11 | % See also: mergeOptions
12 |
13 | % This file is part of Manopt: www.manopt.org.
14 | % Original author: Nicolas Boumal, Dec. 30, 2012.
15 | % Contributors:
16 | % Change log:
17 |
18 |
19 | % There should be no reason to modify this file.
20 | % For better compatibility with future Manopt versions,
21 | % use the options structure of solvers.
22 | %
23 | % Really: don't modify it.
24 |
25 |
26 | % Verbosity level: 0 is no output at all. The higher the verbosity, the
27 | % more info is printed / displayed during solver execution.
28 | opts.verbosity = 3;
29 |
30 | % If debug is set to true, additional computations may be performed and
31 | % debugging information is outputed during solver execution.
32 | opts.debug = false;
33 |
34 | % Maximum number of store structures to store. If set to 0, caching
35 | % capabilities are not disabled, but the cache will be emptied at each
36 | % iteration of iterative solvers (more specifically: every time the
37 | % solver calls to purge the storedb).
38 | opts.storedepth = 20;
39 |
40 | % Maximum amount of time a solver may execute, in seconds.
41 | opts.maxtime = inf;
42 |
43 | end
44 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getGradient.m:
--------------------------------------------------------------------------------
1 | function grad = getGradient(problem, x, storedb, key)
2 | % Computes the gradient of the cost function at x.
3 | %
4 | % function grad = getGradient(problem, x)
5 | % function grad = getGradient(problem, x, storedb)
6 | % function grad = getGradient(problem, x, storedb, key)
7 | %
8 | % Returns the gradient at x of the cost function described in the problem
9 | % structure.
10 | %
11 | % storedb is a StoreDB object, key is the StoreDB key to point x.
12 | %
13 | % See also: getDirectionalDerivative canGetGradient
14 |
15 | % This file is part of Manopt: www.manopt.org.
16 | % Original author: Nicolas Boumal, Dec. 30, 2012.
17 | % Contributors:
18 | % Change log:
19 | %
20 | % April 3, 2015 (NB):
21 | % Works with the new StoreDB class system.
22 |
23 | % Allow omission of the key, and even of storedb.
24 | if ~exist('key', 'var')
25 | if ~exist('storedb', 'var')
26 | storedb = StoreDB();
27 | end
28 | key = storedb.getNewKey();
29 | end
30 |
31 |
32 | if isfield(problem, 'grad')
33 | %% Compute the gradient using grad.
34 |
35 | % Check whether this function wants to deal with storedb or not.
36 | switch nargin(problem.cost)
37 | case 1
38 | grad = problem.grad(x);
39 | case 2
40 | % Obtain, pass along, and save the store for x.
41 | store = storedb.getWithShared(key);
42 | [grad, store] = problem.grad(x, store);
43 | storedb.setWithShared(store, key);
44 | case 3
45 | % Pass along the whole storedb (by reference), with key.
46 | grad = problem.grad(x, storedb, key);
47 | otherwise
48 | up = MException('manopt:getGradient:badgrad', ...
49 | 'grad should accept 1, 2 or 3 inputs.');
50 | throw(up);
51 | end
52 |
53 | elseif isfield(problem, 'costgrad')
54 | %% Compute the gradient using costgrad.
55 |
56 | % Check whether this function wants to deal with storedb or not.
57 | switch nargin(problem.costgrad)
58 | case 1
59 | [unused, grad] = problem.costgrad(x); %#ok
60 | case 2
61 | % Obtain, pass along, and save the store for x.
62 | store = storedb.getWithShared(key);
63 | [unused, grad, store] = problem.costgrad(x, store); %#ok
64 | storedb.setWithShared(store, key);
65 | case 3
66 | % Pass along the whole storedb (by reference), with key.
67 | [unused, grad] = problem.costgrad(x, storedb, key); %#ok
68 | otherwise
69 | up = MException('manopt:getGradient:badcostgrad', ...
70 | 'costgrad should accept 1, 2 or 3 inputs.');
71 | throw(up);
72 | end
73 |
74 | elseif canGetEuclideanGradient(problem)
75 | %% Compute the gradient using the Euclidean gradient.
76 |
77 | egrad = getEuclideanGradient(problem, x, storedb, key);
78 | grad = problem.M.egrad2rgrad(x, egrad);
79 |
80 | else
81 | %% Abandon computing the gradient.
82 |
83 | up = MException('manopt:getGradient:fail', ...
84 | ['The problem description is not explicit enough to ' ...
85 | 'compute the gradient of the cost.']);
86 | throw(up);
87 |
88 | end
89 |
90 | end
91 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getHessian.m:
--------------------------------------------------------------------------------
1 | function hess = getHessian(problem, x, d, storedb, key)
2 | % Computes the Hessian of the cost function at x along d.
3 | %
4 | % function hess = getHessian(problem, x, d)
5 | % function hess = getHessian(problem, x, d, storedb)
6 | % function hess = getHessian(problem, x, d, storedb, key)
7 | %
8 | % Returns the Hessian at x along d of the cost function described in the
9 | % problem structure.
10 | %
11 | % storedb is a StoreDB object, key is the StoreDB key to point x.
12 | %
13 | % If an exact Hessian is not provided, an approximate Hessian is returned
14 | % if possible, without warning. If not possible, an exception will be
15 | % thrown. To check whether an exact Hessian is available or not (typically
16 | % to issue a warning if not), use canGetHessian.
17 | %
18 | % See also: getPrecon getApproxHessian canGetHessian
19 |
20 | % This file is part of Manopt: www.manopt.org.
21 | % Original author: Nicolas Boumal, Dec. 30, 2012.
22 | % Contributors:
23 | % Change log:
24 | %
25 | % April 3, 2015 (NB):
26 | % Works with the new StoreDB class system.
27 |
28 | % Allow omission of the key, and even of storedb.
29 | if ~exist('key', 'var')
30 | if ~exist('storedb', 'var')
31 | storedb = StoreDB();
32 | end
33 | key = storedb.getNewKey();
34 | end
35 |
36 |
37 | if isfield(problem, 'hess')
38 | %% Compute the Hessian using hess.
39 |
40 | % Check whether this function wants to deal with storedb or not.
41 | switch nargin(problem.hess)
42 | case 2
43 | hess = problem.hess(x, d);
44 | case 3
45 | % Obtain, pass along, and save the store for x.
46 | store = storedb.getWithShared(key);
47 | [hess, store] = problem.hess(x, d, store);
48 | storedb.setWithShared(store, key);
49 | case 4
50 | % Pass along the whole storedb (by reference), with key.
51 | hess = problem.hess(x, d, storedb, key);
52 | otherwise
53 | up = MException('manopt:getHessian:badhess', ...
54 | 'hess should accept 2, 3 or 4 inputs.');
55 | throw(up);
56 | end
57 |
58 | elseif isfield(problem, 'ehess') && canGetEuclideanGradient(problem)
59 | %% Compute the Hessian using ehess.
60 |
61 | % We will need the Euclidean gradient for the conversion from the
62 | % Euclidean Hessian to the Riemannian Hessian.
63 | egrad = getEuclideanGradient(problem, x, storedb, key);
64 |
65 | % Check whether this function wants to deal with storedb or not.
66 | switch nargin(problem.ehess)
67 | case 2
68 | ehess = problem.ehess(x, d);
69 | case 3
70 | % Obtain, pass along, and save the store for x.
71 | store = storedb.getWithShared(key);
72 | [ehess, store] = problem.ehess(x, d, store);
73 | storedb.setWithShared(store, key);
74 | case 4
75 | % Pass along the whole storedb (by reference), with key.
76 | ehess = problem.ehess(x, d, storedb, key);
77 | otherwise
78 | up = MException('manopt:getHessian:badehess', ...
79 | 'ehess should accept 2, 3 or 4 inputs.');
80 | throw(up);
81 | end
82 |
83 | % Convert to the Riemannian Hessian
84 | hess = problem.M.ehess2rhess(x, egrad, ehess, d);
85 |
86 | else
87 | %% Attempt the computation of an approximation of the Hessian.
88 |
89 | hess = getApproxHessian(problem, x, d, storedb, key);
90 |
91 | end
92 |
93 | end
94 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getHessianFD.m:
--------------------------------------------------------------------------------
1 | function hessfd = getHessianFD(problem, x, d, storedb, key)
2 | % Computes an approx. of the Hessian w/ finite differences of the gradient.
3 | %
4 | % function hessfd = getHessianFD(problem, x, d)
5 | % function hessfd = getHessianFD(problem, x, d, storedb)
6 | % function hessfd = getHessianFD(problem, x, d, storedb, key)
7 | %
8 | % Returns a finite difference approximation of the Hessian at x along d of
9 | % the cost function described in the problem structure. The finite
10 | % difference is based on computations of the gradient.
11 | %
12 | % storedb is a StoreDB object, key is the StoreDB key to point x.
13 | %
14 | % If the gradient cannot be computed, an exception is thrown.
15 | %
16 | % See also: approxhessianFD
17 |
18 | % This file is part of Manopt: www.manopt.org.
19 | % Original author: Nicolas Boumal, Dec. 30, 2012.
20 | % Contributors:
21 | % Change log:
22 | %
23 | % Feb. 19, 2015 (NB):
24 | % It is sufficient to ensure positive radial linearity to guarantee
25 | % (together with other assumptions) that this approximation of the
26 | % Hessian will confer global convergence to the trust-regions method.
27 | % Formerly, in-code comments referred to the necessity of having
28 | % complete radial linearity, and that this was harder to achieve.
29 | % This appears not to be necessary after all, which simplifies the
30 | % code.
31 | %
32 | % April 3, 2015 (NB):
33 | % Works with the new StoreDB class system.
34 |
35 | % Allow omission of the key, and even of storedb.
36 | if ~exist('key', 'var')
37 | if ~exist('storedb', 'var')
38 | storedb = StoreDB();
39 | end
40 | key = storedb.getNewKey();
41 | end
42 |
43 |
44 | if ~canGetGradient(problem)
45 | up = MException('manopt:getHessianFD:nogradient', ...
46 | 'getHessianFD requires the gradient to be computable.');
47 | throw(up);
48 | end
49 |
50 | % Step size
51 | norm_d = problem.M.norm(x, d);
52 |
53 | % First, check whether the step d is not too small
54 | if norm_d < eps
55 | hessfd = problem.M.zerovec(x);
56 | return;
57 | end
58 |
59 | % Parameter: how far do we look?
60 | % (Use approxhessianFD explicitly to gain access to this parameter.)
61 | epsilon = 1e-4;
62 |
63 | c = epsilon/norm_d;
64 |
65 | % Compute the gradient at the current point.
66 | grad = getGradient(problem, x, storedb, key);
67 |
68 | % Compute a point a little further along d and the gradient there.
69 | % Since this is a new point, we need a new key for it, for the storedb.
70 | x1 = problem.M.retr(x, d, c);
71 | key1 = storedb.getNewKey();
72 | grad1 = getGradient(problem, x1, storedb, key1);
73 |
74 | % Transport grad1 back from x1 to x.
75 | grad1 = problem.M.transp(x1, x, grad1);
76 |
77 | % Return the finite difference of them.
78 | hessfd = problem.M.lincomb(x, 1/c, grad1, -1/c, grad);
79 |
80 | end
81 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getLinesearch.m:
--------------------------------------------------------------------------------
1 | function t = getLinesearch(problem, x, d, storedb, key)
2 | % Returns a hint for line-search algorithms.
3 | %
4 | % function t = getLinesearch(problem, x, d)
5 | % function t = getLinesearch(problem, x, d, storedb)
6 | % function t = getLinesearch(problem, x, d, storedb, key)
7 | %
8 | % For a line-search problem at x along the tangent direction d, computes
9 | % and returns t such that retracting t*d at x yields a good point around
10 | % where to look for a line-search solution. That is: t is a hint as to
11 | % "how far to look" along the line.
12 | %
13 | % storedb is a StoreDB object, key is the StoreDB key to point x.
14 | %
15 | % See also: canGetLinesearch
16 |
17 | % This file is part of Manopt: www.manopt.org.
18 | % Original author: Nicolas Boumal, July 17, 2014.
19 | % Contributors:
20 | % Change log:
21 | %
22 | % April 3, 2015 (NB):
23 | % Works with the new StoreDB class system.
24 |
25 | % Allow omission of the key, and even of storedb.
26 | if ~exist('key', 'var')
27 | if ~exist('storedb', 'var')
28 | storedb = StoreDB();
29 | end
30 | key = storedb.getNewKey();
31 | end
32 |
33 |
34 | if isfield(problem, 'linesearch')
35 | %% Compute the line-search hint function using linesearch.
36 |
37 | % Check whether this function wants to deal with storedb or not.
38 | switch nargin(problem.linesearch)
39 | case 2
40 | t = problem.linesearch(x, d);
41 | case 3
42 | % Obtain, pass along, and save the store for x.
43 | store = storedb.getWithShared(key);
44 | [t, store] = problem.linesearch(x, d, store);
45 | storedb.setWithShared(store, key);
46 | case 4
47 | % Pass along the whole storedb (by reference), with key.
48 | t = problem.linesearch(x, d, storedb, key);
49 | otherwise
50 | up = MException('manopt:getLinesearch:badfun', ...
51 | 'linesearch should accept 2, 3 or 4 inputs.');
52 | throw(up);
53 | end
54 |
55 | else
56 | %% Abandon computing the line-search function.
57 |
58 | up = MException('manopt:getLinesearch:fail', ...
59 | ['The problem description is not explicit enough to ' ...
60 | 'compute a line-search hint.']);
61 | throw(up);
62 |
63 | end
64 |
65 | end
66 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getPrecon.m:
--------------------------------------------------------------------------------
1 | function Pd = getPrecon(problem, x, d, storedb, key)
2 | % Applies the preconditioner for the Hessian of the cost at x along d.
3 | %
4 | % function Pd = getPrecon(problem, x, d)
5 | % function Pd = getPrecon(problem, x, d, storedb)
6 | % function Pd = getPrecon(problem, x, d, storedb, key)
7 | %
8 | % Returns as Pd the result of applying the Hessian preconditioner to the
9 | % tangent vector d at point x. The preconditioner is supposed to be a
10 | % symmetric, positive definite approximation of the inverse of the Hessian.
11 | %
12 | % If no preconditioner is available, Pd = d (identity).
13 | %
14 | % storedb is a StoreDB object, key is the StoreDB key to point x.
15 | %
16 | % See also: getHessian
17 |
18 | % This file is part of Manopt: www.manopt.org.
19 | % Original author: Nicolas Boumal, Dec. 30, 2012.
20 | % Contributors:
21 | % Change log:
22 | %
23 | % April 3, 2015 (NB):
24 | % Works with the new StoreDB class system.
25 |
26 | % Allow omission of the key, and even of storedb.
27 | if ~exist('key', 'var')
28 | if ~exist('storedb', 'var')
29 | storedb = StoreDB();
30 | end
31 | key = storedb.getNewKey();
32 | end
33 |
34 |
35 | if isfield(problem, 'precon')
36 | %% Precondition using precon.
37 |
38 | % Check whether this function wants to deal with storedb or not.
39 | switch nargin(problem.precon)
40 | case 2
41 | Pd = problem.precon(x, d);
42 | case 3
43 | % Obtain, pass along, and save the store for x.
44 | store = storedb.getWithShared(key);
45 | [Pd, store] = problem.precon(x, d, store);
46 | storedb.setWithShared(store, key);
47 | case 4
48 | % Pass along the whole storedb (by reference), with key.
49 | Pd = problem.precon(x, d, storedb, key);
50 | otherwise
51 | up = MException('manopt:getPrecon:badprecon', ...
52 | 'precon should accept 2, 3 or 4 inputs.');
53 | throw(up);
54 | end
55 |
56 | elseif canGetSqrtPrecon(problem)
57 | %% Precondition by applying the square root of the preconditioner twice.
58 |
59 | sqrtPd = getSqrtPrecon(problem, x, d, storedb, key);
60 | Pd = getSqrtPrecon(problem, x, sqrtPd, storedb, key);
61 |
62 | else
63 | %% No preconditioner provided, so just use the identity.
64 |
65 | Pd = d;
66 |
67 | end
68 |
69 | end
70 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getSqrtPrecon.m:
--------------------------------------------------------------------------------
1 | function sqrtPd = getSqrtPrecon(problem, x, d, storedb, key)
2 | % Applies the square root of the Hessian preconditioner at x along d.
3 | %
4 | % function sqrtPd = getSqrtPrecon(problem, x, d)
5 | % function sqrtPd = getSqrtPrecon(problem, x, d, storedb)
6 | % function sqrtPd = getSqrtPrecon(problem, x, d, storedb, key)
7 | %
8 | % Returns as sqrtPd the result of applying the square root of the Hessian
9 | % preconditioner to the tangent vector d at point x. The preconditioner is
10 | % supposed to be a symmetric, positive definite approximation of the
11 | % inverse of the Hessian. Its square root must thus be symmetric and
12 | % positive definite itself.
13 | %
14 | % If no square root of preconditioner is available, sqrtPd = d (identity).
15 | % Note that this may be incompatible with the preconditioner, if that one
16 | % is supplied in the problem description. Always check with canGetPrecon
17 | % and canGetSqrtPrecon.
18 | %
19 | % storedb is a StoreDB object, key is the StoreDB key to point x.
20 | %
21 | % See also: getPrecon canGetPrecon canGetSqrtPrecon getHessian
22 |
23 | % This file is part of Manopt: www.manopt.org.
24 | % Original author: Nicolas Boumal, April 3, 2015.
25 | % Contributors:
26 | % Change log:
27 |
28 | % Allow omission of the key, and even of storedb.
29 | if ~exist('key', 'var')
30 | if ~exist('storedb', 'var')
31 | storedb = StoreDB();
32 | end
33 | key = storedb.getNewKey();
34 | end
35 |
36 |
37 | if isfield(problem, 'sqrtprecon')
38 | %% Apply sqrtprecon for the square root of the preconditioner
39 |
40 | % Check whether this function wants to deal with storedb or not.
41 | switch nargin(problem.sqrtprecon)
42 | case 2
43 | sqrtPd = problem.sqrtprecon(x, d);
44 | case 3
45 | % Obtain, pass along, and save the store for x.
46 | store = storedb.getWithShared(key);
47 | [sqrtPd, store] = problem.sqrtprecon(x, d, store);
48 | storedb.setWithShared(store, key);
49 | case 4
50 | % Pass along the whole storedb (by reference), with key.
51 | sqrtPd = problem.sqrtprecon(x, d, storedb, key);
52 | otherwise
53 | up = MException('manopt:getSqrtPrecon:badsqrtprecon', ...
54 | 'sqrtprecon should accept 2, 3 or 4 inputs.');
55 | throw(up);
56 | end
57 |
58 | else
59 | %% No preconditioner square root provided, so just use the identity.
60 |
61 | sqrtPd = d;
62 |
63 | end
64 |
65 | end
66 |
--------------------------------------------------------------------------------
/manopt/manopt/core/getStore.m:
--------------------------------------------------------------------------------
1 | function store = getStore(problem, x, storedb) %#ok
2 |
3 | error('This file was removed from Manopt. Please use the StoreDB class.');
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/manopt/manopt/core/handle_light.m:
--------------------------------------------------------------------------------
1 | classdef handle_light < handle
2 | % Trick class to hide methods inherited from the handle class
3 | % when calling methods(myclass).
4 | %
5 | % Source:
6 | % http://stackoverflow.com/questions/6621850/is-it-possible-to-hide-the-methods-inherited-from-the-handle-class-in-matlab
7 | % Posted by sclarke81 on StackOverflow on Oct. 24, 2012.
8 |
9 | % This file is part of Manopt: www.manopt.org.
10 | % Original author: sclarke81, added April 3, 2013.
11 | % Contributors:
12 | % Change log:
13 |
14 | methods(Hidden)
15 | function lh = addlistener(varargin)
16 | lh = addlistener@handle(varargin{:});
17 | end
18 | function notify(varargin)
19 | notify@handle(varargin{:});
20 | end
21 | function delete(varargin)
22 | delete@handle(varargin{:});
23 | end
24 | function Hmatch = findobj(varargin)
25 | Hmatch = findobj@handle(varargin{:});
26 | end
27 | function p = findprop(varargin)
28 | p = findprop@handle(varargin{:});
29 | end
30 | function TF = eq(varargin)
31 | TF = eq@handle(varargin{:});
32 | end
33 | function TF = ne(varargin)
34 | TF = ne@handle(varargin{:});
35 | end
36 | function TF = lt(varargin)
37 | TF = lt@handle(varargin{:});
38 | end
39 | function TF = le(varargin)
40 | TF = le@handle(varargin{:});
41 | end
42 | function TF = gt(varargin)
43 | TF = gt@handle(varargin{:});
44 | end
45 | function TF = ge(varargin)
46 | TF = ge@handle(varargin{:});
47 | end
48 | end
49 |
50 | end
51 |
--------------------------------------------------------------------------------
/manopt/manopt/core/mergeOptions.m:
--------------------------------------------------------------------------------
1 | function opts = mergeOptions(opts1, opts2)
2 | % Merges two options structures with one having precedence over the other.
3 | %
4 | % function opts = mergeOptions(opts1, opts2)
5 | %
6 | % input: opts1 and opts2 are two structures.
7 | % output: opts is a structure containing all fields of opts1 and opts2.
8 | % Whenever a field is present in both opts1 and opts2, it is the value in
9 | % opts2 that is kept.
10 | %
11 | % The typical usage is to have opts1 contain default options and opts2
12 | % contain user-specified options that overwrite the defaults.
13 | %
14 | % See also: getGlobalDefaults
15 |
16 | % This file is part of Manopt: www.manopt.org.
17 | % Original author: Nicolas Boumal, Dec. 30, 2012.
18 | % Contributors:
19 | % Change log:
20 |
21 |
22 | if isempty(opts1)
23 | opts1 = struct();
24 | end
25 | if isempty(opts2)
26 | opts2 = struct();
27 | end
28 |
29 | opts = opts1;
30 | fields = fieldnames(opts2);
31 | for i = 1 : length(fields)
32 | opts.(fields{i}) = opts2.(fields{i});
33 | end
34 |
35 | end
36 |
--------------------------------------------------------------------------------
/manopt/manopt/core/purgeStoredb.m:
--------------------------------------------------------------------------------
1 | function storedb = purgeStoredb(storedb, storedepth) %#ok
2 |
3 | error('This file was removed from Manopt. Please use the StoreDB class.');
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/manopt/manopt/core/setStore.m:
--------------------------------------------------------------------------------
1 | function storedb = setStore(problem, x, storedb, store) %#ok
2 |
3 | error('This file was removed from Manopt. Please use the StoreDB class.');
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/manopt/manopt/core/stoppingcriterion.m:
--------------------------------------------------------------------------------
1 | function [stop, reason] = stoppingcriterion(problem, x, options, info, last)
2 | % Checks for standard stopping criteria, as a helper to solvers.
3 | %
4 | % function [stop, reason] = stoppingcriterion(problem, x, options, info, last)
5 | %
6 | % Executes standard stopping criterion checks, based on what is defined in
7 | % the info(last) stats structure and in the options structure.
8 | %
9 | % The returned number 'stop' is 0 if none of the stopping criteria
10 | % triggered, and a (strictly) positive integer otherwise. The integer
11 | % identifies which criterion triggered:
12 | % 0 : Nothing triggered;
13 | % 1 : Cost tolerance reached;
14 | % 2 : Gradient norm tolerance reached;
15 | % 3 : Max time exceeded;
16 | % 4 : Max iteration count reached;
17 | % 5 : Maximum number of cost evaluations reached;
18 | % 6 : User defined stopfun criterion triggered.
19 | %
20 | % The output 'reason' is a string describing the triggered event.
21 |
22 | % This file is part of Manopt: www.manopt.org.
23 | % Original author: Nicolas Boumal, Dec. 30, 2012.
24 | % Contributors:
25 | % Change log:
26 | %
27 | % April 2, 2015 (NB):
28 | % 'reason' now contains the option (name and value) that triggered.
29 |
30 |
31 | stop = 0;
32 | reason = '';
33 |
34 | stats = info(last);
35 |
36 | % Target cost attained
37 | if isfield(stats, 'cost') && isfield(options, 'tolcost') && ...
38 | stats.cost <= options.tolcost
39 | reason = sprintf('Cost tolerance reached; options.tolcost = %g.', options.tolcost);
40 | stop = 1;
41 | return;
42 | end
43 |
44 | % Target gradient norm attained
45 | if isfield(stats, 'gradnorm') && isfield(options, 'tolgradnorm') && ...
46 | stats.gradnorm < options.tolgradnorm
47 | reason = sprintf('Gradient norm tolerance reached; options.tolgradnorm = %g.', options.tolgradnorm);
48 | stop = 2;
49 | return;
50 | end
51 |
52 | % Allotted time exceeded
53 | if isfield(stats, 'time') && isfield(options, 'maxtime') && ...
54 | stats.time >= options.maxtime
55 | reason = sprintf('Max time exceeded; options.maxtime = %g.', options.maxtime);
56 | stop = 3;
57 | return;
58 | end
59 |
60 | % Allotted iteration count exceeded
61 | if isfield(stats, 'iter') && isfield(options, 'maxiter') && ...
62 | stats.iter >= options.maxiter
63 | reason = sprintf('Max iteration count reached; options.maxiter = %g.', options.maxiter);
64 | stop = 4;
65 | return;
66 | end
67 |
68 | % Allotted function evaluation count exceeded
69 | if isfield(stats, 'costevals') && isfield(options, 'maxcostevals') && ...
70 | stats.costevals >= options.maxcostevals
71 | reason = sprintf('Maximum number of cost evaluations reached; options.maxcostevals = %g.', options.maxcostevals);
72 | stop = 5;
73 | end
74 |
75 | % Check whether the possibly user defined stopping criterion
76 | % triggers or not.
77 | if isfield(options, 'stopfun')
78 | userstop = options.stopfun(problem, x, info, last);
79 | if userstop
80 | reason = 'User defined stopfun criterion triggered; see options.stopfun.';
81 | stop = 6;
82 | return;
83 | end
84 | end
85 |
86 | end
87 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/essential_costE2cost.m:
--------------------------------------------------------------------------------
1 | function val = essential_costE2cost(X, costE)
2 | % Cost evaluation at X given function handle in the Essential matrix E.
3 | %
4 | % function val = essential_costE2cost(X, costE)
5 | %
6 | % costE is the function handle for the cost function in E.
7 | %
8 | % See also: essential_egradE2egrad essential_ehessE2ehess
9 |
10 | % This file is part of Manopt: www.manopt.org.
11 | % Original author: Roberto Tron, Aug. 8, 2014
12 | % Contributors: Bamdev Mishra, May 22, 2015.
13 |
14 | e3hat = [0 -1 0; 1 0 0; 0 0 0];
15 |
16 | RA = X(:,1:3,:);
17 | RB = X(:,4:6,:);
18 | E = multiprod(multiprod(multitransp(RA), e3hat), RB);
19 |
20 | val = costE(E);
21 | end
22 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/essential_egradE2egrad.m:
--------------------------------------------------------------------------------
1 | function egrad = essential_egradE2egrad(X, egradE)
2 | % Converts the gradient in essential matrix E to the gradient in X.
3 | %
4 | % function egrad = essential_egradE2egrad(X, egradE)
5 | %
6 | % egradE is the function handle for the gradient in E.
7 | %
8 | % The output is a matrix in the space of X.
9 | %
10 | % See also: essential_costE2cost essential_ehessE2ehess
11 |
12 |
13 | % This file is part of Manopt: www.manopt.org.
14 | % Original author: Roberto Tron, Aug. 8, 2014
15 | % Contributors: Bamdev Mishra, May 22, 2015.
16 |
17 | e3hat = [0 -1 0; 1 0 0; 0 0 0];
18 | RA = X(:,1:3,:);
19 | RB = X(:,4:6,:);
20 | E = multiprod(multiprod(multitransp(RA), e3hat), RB);
21 | G = egradE(E);
22 |
23 | %The following is the vectorized version of egrad = e3hat*[RB*G' -RA*G];
24 | egrad = multiprod(e3hat, cat(2,...
25 | multiprod(RB, multitransp(G)),...
26 | -multiprod(RA, G)));
27 | end
28 |
29 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/essential_ehessE2ehess.m:
--------------------------------------------------------------------------------
1 | function ehess = essential_ehessE2ehess(X, egradE, ehessE, S)
2 | % Converts the Hessian in essential matrix E to the Hessian in X.
3 | %
4 | % function ehess = essential_ehessE2ehess(X, egradE, ehessE, S)
5 | %
6 | % egradE is the function handle for the gradient in E.
7 | % ehessE is the function handle for the Hessian in E.
8 | % S is the search direction in the space of X.
9 | %
10 | % The output is a matrix in the space of X.
11 | %
12 | % See also: essential_costE2cost essential_egradE2egrad
13 |
14 |
15 | % This file is part of Manopt: www.manopt.org.
16 | % Original author: Roberto Tron, Aug. 8, 2014
17 | % Contributors: Bamdev Mishra, May 22, 2015.
18 |
19 | e3hat = [0 -1 0; 1 0 0; 0 0 0];
20 |
21 | RA = X(:,1:3,:);
22 | RB = X(:,4:6,:);
23 | E = multiprod(multiprod(multitransp(RA), e3hat), RB); % M.E(X);
24 | G = egradE(E);
25 |
26 | V = essential_sharp(multiprod(essential_flat(X), essential_flat(S)));
27 | VA = V(:,1:3,:);
28 | VB = V(:,4:6,:);
29 |
30 | dE = multiprod(multiprod(multitransp(RA), e3hat), VB)...
31 | + multiprod(multiprod(multitransp(VA), e3hat), RB);
32 | dG = ehessE(E, dE);
33 |
34 | %The following is the vectorized version of ehess = e3hat*[(VB*G'+RB*H') -(VA*G+RA*H)]
35 | ehess = multiprod(e3hat,cat(2,...
36 | multiprod(VB, multitransp(G)) + multiprod(RB, multitransp(dG)),...
37 | -multiprod(VA, G) - multiprod(RA, dG)));
38 |
39 | end
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/essential_flat.m:
--------------------------------------------------------------------------------
1 | function Hp = essential_flat(H)
2 | %Reshape a [3x6xk] matrix to a [3x3x2k] matrix
3 | Hp = reshape(H,3,3,[]);
4 | end
5 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/essential_hat3.m:
--------------------------------------------------------------------------------
1 | %Compute the matrix representation of the cross product
2 | %function [V,vShift] = essential_hat3(v)
3 | %V is a [3x3xN] array of skew-symmetric matrices where each [3x3] block is
4 | %the matrix representation of the cross product of one of the columns of v
5 | %vShift is equal to permute(v,[1 3 2]).
6 | function [V, vShift] = essential_hat3(v)
7 | N = size(v,2);
8 | V = zeros(3,3,N);
9 | vShift = permute(v,[1 3 2]);
10 | V(1,2,:) = -vShift(3,:,:);
11 | V(2,1,:) = vShift(3,:,:);
12 | V(1,3,:) = vShift(2,:,:);
13 | V(3,1,:) = -vShift(2,:,:);
14 | V(2,3,:) = -vShift(1,:,:);
15 | V(3,2,:) = vShift(1,:,:);
16 | end
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/essential_sharp.m:
--------------------------------------------------------------------------------
1 | function H = essential_sharp(Hp)
2 | %Reshape a [3x3x2k] matrix to a [3x6xk] matrix
3 | H = reshape(Hp,3,6,[]);
4 | end
5 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/privateessential/essential_closestRepresentative.m:
--------------------------------------------------------------------------------
1 | function Q2r=essential_closestRepresentative(Q1,Q2,varargin)
2 | [tMin,~,Q2]=essential_distMinAngle(Q1,Q2,varargin{:});
3 | NQ1=size(Q1,3);
4 | NQ2=size(Q2,3);
5 |
6 | if NQ1>1 && NQ2==1
7 | Q2=repmat(Q2,[1 1 NQ1]);
8 | end
9 | NQ=max(NQ1,NQ2);
10 |
11 | Q2r=zeros(size(Q2));
12 | for iQ=1:NQ
13 | t=tMin(iQ);
14 | Rz=[cos(t) -sin(t) 0; sin(t) cos(t) 0; 0 0 1];
15 | Q2r(1:3,1:3,iQ)=Rz*Q2(1:3,1:3,iQ);
16 | Q2r(4:6,1:3,iQ)=Rz*Q2(4:6,1:3,iQ);
17 | end
18 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/privateessential/essential_distMinAngle.m:
--------------------------------------------------------------------------------
1 | function [tMin,fMin,Q2Flip,output]=essential_distMinAngle(Q1,Q2,varargin)
2 | NQ1=size(Q1,3);
3 | NQ2=size(Q2,3);
4 |
5 | if NQ1==1 && NQ2>1
6 | Q1=repmat(Q1,[1 1 NQ2]);
7 | NQ1=NQ2;
8 | end
9 | if NQ1>1 && NQ2==1
10 | Q2=repmat(Q2,[1 1 NQ1]);
11 | end
12 |
13 | if NQ1>1
14 | tMin=zeros(NQ1,1);
15 | fMin=zeros(NQ1,1);
16 | Q2Flip=zeros(6,3,NQ1);
17 | if nargout>3
18 | output=repmat(struct('tMin',[],'fMin',[],'tBreak1',[],'tBreak2',[]),NQ1,1);
19 | end
20 | for iQ=1:NQ1
21 | if nargout>3
22 | [tMin(iQ),fMin(iQ),Q2Flip(:,:,iQ),output(iQ)]=...
23 | essential_distMinAngle(Q1(:,:,iQ),Q2(:,:,iQ),varargin{:});
24 | else
25 | [tMin(iQ),fMin(iQ),Q2Flip(:,:,iQ)]=...
26 | essential_distMinAngle(Q1(:,:,iQ),Q2(:,:,iQ),varargin{:});
27 | end
28 | end
29 | else
30 | flagModTMin=false;
31 | flagSigned=false;
32 |
33 | %optional parameters
34 | ivarargin=1;
35 | while(ivarargin<=length(varargin))
36 | switch(lower(varargin{ivarargin}))
37 | case 'flagmodtmin'
38 | ivarargin=ivarargin+1;
39 | flagModTMin=varargin{ivarargin};
40 | case 'signed'
41 | flagSigned=true;
42 | case 'flagsigned'
43 | ivarargin=ivarargin+1;
44 | flagSigned=varargin{ivarargin};
45 | otherwise
46 | error(['Argument ' varargin{ivarargin} ' not valid!'])
47 | end
48 | ivarargin=ivarargin+1;
49 | end
50 |
51 | tMin=zeros(4,1);
52 | fMin=zeros(4,1);
53 | tBreak1=zeros(4,1);
54 | tBreak2=zeros(4,1);
55 | Q2Flip=zeros(6,3,4);
56 | if ~flagSigned
57 | for k=1:4
58 | [tMin(k),fMin(k),tBreak1(k),tBreak2(k),Q2Flip(:,:,k)]=...
59 | essential_distMinAnglePair(Q1,Q2,k);
60 | end
61 | else
62 | [tMin,fMin,tBreak1,tBreak2,Q2Flip]=...
63 | essential_distMinAnglePair(Q1,Q2,1);
64 | end
65 |
66 | if flagModTMin
67 | tMin=modAngle(tMin);
68 | end
69 |
70 | if nargout>3
71 | output.tMin=tMin;
72 | output.fMin=fMin;
73 | output.tBreak1=tBreak1;
74 | output.tBreak2=tBreak2;
75 | end
76 |
77 | if ~flagSigned
78 | [fMin,idxMin]=min(fMin);
79 | fMin=max(fMin,0);
80 | tMin=tMin(idxMin);
81 | Q2Flip=Q2Flip(:,:,idxMin);
82 | if nargout>3
83 | output.idxMin=idxMin;
84 | end
85 | end
86 | end
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/privateessential/essential_distMinAnglePair.m:
--------------------------------------------------------------------------------
1 | function [tMin,fMin,tBreak1,tBreak2,Q2,tMinAll]=essential_distMinAnglePair(Q1,Q2,kFlip)
2 |
3 | switch kFlip
4 | case 1
5 | %nothing to do
6 | case 2
7 | Q2([2 3 4 6],:)=-Q2([2 3 4 6],:);
8 | case 3
9 | Q2([4 5],:)=-Q2([4 5],:);
10 | case 4
11 | Q2([2 3 5 6],:)=-Q2([2 3 5 6],:);
12 | otherwise
13 | error('Value of kFlip invalid')
14 | end
15 |
16 | Q11=Q1(1:3,:);
17 | Q12=Q1(4:6,:);
18 | Q21=Q2(1:3,:);
19 | Q22=Q2(4:6,:);
20 |
21 | Q211=Q21*Q11';
22 | Q212=Q22*Q12';
23 | [tMin,fMin,tBreak1,tBreak2,tMinAll]=essential_distMinAnglePair_base(Q211,Q212);
24 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/privateessential/essential_distMinAnglePair_computeDfBreak.m:
--------------------------------------------------------------------------------
1 | function dfBreak=essential_distMinAnglePair_computeDfBreak(tBreak,Q21)
2 | c=cos(tBreak);
3 | s=sin(tBreak);
4 |
5 | % The code below is an optimization exploiting the structure of RBreak to
6 | % substitute the following code
7 | % RBreak=Q1'*[c -s 0; s c 0; 0 0 1]*Q2;
8 | %
9 | % %compute v0 such that RBreak=rot(pi*v0)
10 | % [U,~,~]=svd(RBreak+eye(3));
11 | % v0=U(:,1);
12 | %
13 | % dfBreak=pi*abs(Q1(3,:)*v0);
14 |
15 | Q1RBreakQ1=[c -s 0; s c 0; 0 0 1]*Q21;
16 | [U,~,~]=svd(Q1RBreakQ1+eye(3));
17 | dfBreak=pi*abs(U(3,1));
18 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/essential/privateessential/essential_distMinAnglePair_dfNewton.m:
--------------------------------------------------------------------------------
1 | %Support function for essential_distMinAnglePair implementing Newton's search
2 | function [tMin,fMin]=essential_distMinAnglePair_dfNewton(m1,p1,c1,m2,p2,c2,tMin,tLow,tHigh)
3 | tolDist=1e-8;
4 | for i=1:100
5 | % d=dfi(m1,p1,c1,tMin)+dfi(m2,p2,c2,tMin);
6 | % dd=ddfi(m1,p1,c1,tMin)+ddfi(m2,p2,c2,tMin);
7 | %The code below unrolls the following calls
8 | % f1=fi(m1,p1,c1,tMin);
9 | % f2=fi(m2,p2,c2,tMin);
10 | % d=dfi2(m1,p1,f1,tMin)+dfi2(m2,p2,f2,tMin);
11 | % dd=ddfi2(m1,p1,f1,tMin)+ddfi2(m2,p2,f2,tMin);
12 | mc1=m1*cos(tMin+p1);
13 | mc2=m2*cos(tMin+p2);
14 | f1=acos(clip((m1*sin(tMin+p1)+c1-1)/2));
15 | f2=acos(clip((m2*sin(tMin+p2)+c2-1)/2));
16 | sf1=2*sin(f1);
17 | sf2=2*sin(f2);
18 | d1=-f1*mc1/sf1;
19 | d2=-f2*mc2/sf2;
20 | d=d1+d2;
21 | eztuSq1=(mc1/sf1)^2;
22 | dd1=eztuSq1+f1/2*cot(f1/2)*(1-eztuSq1);
23 | eztuSq2=(mc2/sf2)^2;
24 | dd2=eztuSq2+f2/2*cot(f2/2)*(1-eztuSq2);
25 | dd=dd1+dd2;
26 |
27 |
28 | tOld=tMin;
29 | tMin=max(tLow+tolDist,min(tHigh-tolDist,tOld-d/dd));
30 | if abs(tMin-tOld)
66 | u = randn(m, n) + 1i*randn(m, n);
67 | u = u / norm(u, 'fro');
68 | end
69 |
70 | M.lincomb = @matrixlincomb;
71 |
72 | M.zerovec = @(x) zeros(m, n);
73 |
74 | M.transp = @(x1, x2, d) d;
75 |
76 | M.pairmean = @(x1, x2) .5*(x1+x2);
77 |
78 | mn = m*n;
79 | M.vec = @(x, u_mat) [real(u_mat(:)) ; imag(u_mat(:))];
80 | M.mat = @(x, u_vec) reshape(u_vec(1:mn), [m, n]) + 1i*reshape(u_vec((mn+1):end), [m, n]);
81 | M.vecmatareisometries = @() true;
82 |
83 | end
84 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/euclidean/euclideanfactory.m:
--------------------------------------------------------------------------------
1 | function M = euclideanfactory(m, n)
2 | % Returns a manifold struct to optimize over m-by-n matrices.
3 | %
4 | % function M = euclideanfactory(m, n)
5 | %
6 | % Returns M, a structure describing the Euclidean space of m-by-n matrices,
7 | % equipped with the standard Frobenius distance and associated trace inner
8 | % product, as a manifold for Manopt.
9 | %
10 | % m and n in general can be vectors to handle multidimensional arrays.
11 | % If either of m or n is a vector, they are concatenated as [m, n].
12 | %
13 | % Using this simple linear manifold, Manopt can be used to solve standard
14 | % unconstrained optimization problems, for example in replacement of
15 | % Matlab's fminunc.
16 | %
17 | % See also: euclideancomplexfactory
18 |
19 | % This file is part of Manopt: www.manopt.org.
20 | % Original author: Nicolas Boumal, Dec. 30, 2012.
21 | % Contributors: Bamdev Mishra, May 4, 2015.
22 | % Change log:
23 | %
24 | % July 5, 2013 (NB):
25 | % Added egred2rgrad, ehess2rhess, mat, vec, tangent.
26 | % May 4, 2015 (BM):
27 | % Added functionality to handle multidimensional arrays.
28 |
29 |
30 | % The size can be defined using both m and n, or simply with m.
31 | % If m is a scalar, then n is implicitly 1.
32 | % This mimicks the use of built-in Matlab functions such as zeros(...).
33 | if ~exist('n', 'var') || isempty(n)
34 | if numel(m) == 1
35 | n = 1;
36 | else
37 | n = [];
38 | end
39 | end
40 |
41 | dimensions_vec = [m(:)', n(:)']; % We have a row vector.
42 |
43 |
44 | M.name = @() sprintf('Euclidean space R^(%s)', num2str(dimensions_vec)); % BM: okay.
45 |
46 | M.dim = @() prod(dimensions_vec);% BM: replacing m*n;
47 |
48 | M.inner = @(x, d1, d2) d1(:).'*d2(:); % BM: okay.
49 |
50 | M.norm = @(x, d) norm(d(:), 'fro');% BM: replacing norm(d, 'fro');
51 |
52 | M.dist = @(x, y) norm(x(:) - y(:), 'fro');% BM: replacing norm(x-y, 'fro');
53 |
54 | M.typicaldist = @() sqrt(prod(dimensions_vec));% BM: replacing sqrt(m*n);
55 |
56 | M.proj = @(x, d) d; % BM: okay.
57 |
58 | M.egrad2rgrad = @(x, g) g; % BM: okay.
59 |
60 | M.ehess2rhess = @(x, eg, eh, d) eh; % BM: okay.
61 |
62 | M.tangent = M.proj;
63 |
64 | M.exp = @exp;
65 | function y = exp(x, d, t)
66 | if nargin == 3
67 | y = x + t*d; % BM: okay.
68 | else
69 | y = x + d; % BM: okay.
70 | end
71 | end
72 |
73 | M.retr = M.exp;
74 |
75 | M.log = @(x, y) y-x; % BM: okay.
76 |
77 | M.hash = @(x) ['z' hashmd5(x(:))]; % BM: okay.
78 |
79 | M.rand = @() randn(dimensions_vec);% BM: replacing randn(m, n);
80 |
81 | M.randvec = @randvec;
82 | function u = randvec(x) %#ok
83 | u = randn(dimensions_vec);% BM: replacing randn(m, n);
84 | u = u / norm(u(:), 'fro');% BM: replacing u / norm(u, 'fro');
85 | end
86 |
87 | M.lincomb = @matrixlincomb;
88 |
89 | M.zerovec = @(x) zeros(dimensions_vec);% BM: replacing zeros(m, n);
90 |
91 | M.transp = @(x1, x2, d) d;
92 |
93 | M.pairmean = @(x1, x2) .5*(x1+x2); % BM: okay.
94 |
95 | M.vec = @(x, u_mat) u_mat(:); % BM: okay.
96 | M.mat = @(x, u_vec) reshape(u_vec, dimensions_vec);% BM: replacing reshape(u_vec, [m, n]);
97 | M.vecmatareisometries = @() true;
98 |
99 | end
100 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/euclidean/shapefitfactory.m:
--------------------------------------------------------------------------------
1 | function M = shapefitfactory(VJt)
2 | % Linear manifold structure for optimization over the ShapeFit search space
3 | %
4 | % function M = shapefitfactory(VJt)
5 | %
6 | % Input: VJt is a matrix of size dxn, such that VJt * ones(n, 1) = 0.
7 | %
8 | % Returns M, a structure describing the Euclidean space of d-by-n matrices
9 | % equipped with the standard Frobenius distance and associated trace inner
10 | % product, as a manifold for Manopt. Matrices on M, denoted by T, have size
11 | % dxn and obey T*ones(n, 1) = 0 (centered columns) and = 1, where
12 | % = Trace(A' * B).
13 | %
14 | % See this paper: http://arxiv.org/abs/1506.01437
15 | % ShapeFit: Exact location recovery from corrupted pairwise directions, 2015
16 | % Paul Hand, Choongbum Lee, Vladislav Voroninski
17 | %
18 | % See also: shapefit_smoothed
19 |
20 | % This file is part of Manopt: www.manopt.org.
21 | % Original author: Nicolas Boumal, June 18, 2015.
22 | % Contributors:
23 | % Change log:
24 |
25 | [d, n] = size(VJt);
26 |
27 | M.name = @() sprintf('ShapeFit space of size %d x %d', d, n);
28 |
29 | M.dim = @() d*n - d - 1;
30 |
31 | M.inner = @(x, d1, d2) d1(:).'*d2(:);
32 |
33 | M.norm = @(x, d) norm(d, 'fro');
34 |
35 | M.dist = @(x, y) norm(x-y, 'fro');
36 |
37 | M.typicaldist = @() sqrt(d*n);
38 |
39 | M.proj = @(T, U) projection(U);
40 | VJt_normed = VJt / norm(VJt, 'fro');
41 | function PU = projection(U)
42 | % Center the columns
43 | PU = bsxfun(@minus, U, mean(U, 2));
44 | % Remove component along VJt
45 | % Note: these two actions can be executed separately, without
46 | % interference, owing to VJt having centered columns itself.
47 | PU = PU - (VJt_normed(:)'*U(:))*VJt_normed;
48 | end
49 |
50 | M.egrad2rgrad = M.proj;
51 |
52 | M.ehess2rhess = @(x, eg, eh, d) projection(eh);
53 |
54 | M.tangent = @(x, d) d;
55 |
56 | M.exp = @exp;
57 | function y = exp(x, d, t)
58 | if nargin == 3
59 | y = x + t*d;
60 | else
61 | y = x + d;
62 | end
63 | end
64 |
65 | M.retr = M.exp;
66 |
67 | M.log = @(x, y) y-x;
68 |
69 | M.hash = @(x) ['z' hashmd5(x(:))];
70 |
71 | M.randvec = @(x) randvec();
72 | function u = randvec()
73 | u = projection(randn(d, n));
74 | u = u / norm(u, 'fro');
75 | end
76 |
77 | % We exploit the fact that VJt_normed belongs to the manifold
78 | M.rand = @() VJt_normed + randn(1) * randvec();
79 |
80 | M.lincomb = @matrixlincomb;
81 |
82 | M.zerovec = @(x) zeros(d, n);
83 |
84 | M.transp = @(x1, x2, d) d;
85 |
86 | M.pairmean = @(x1, x2) .5*(x1+x2);
87 |
88 | M.vec = @(x, u_mat) u_mat(:);
89 | M.mat = @(x, u_vec) reshape(u_vec, [d, n]);
90 | M.vecmatareisometries = @() true;
91 |
92 | end
93 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/fixedranktensors/tucker2multiarray.m:
--------------------------------------------------------------------------------
1 | function Xtensor = tucker2multiarray(X)
2 | % Converts a 3d Tucker form tensor to a multiarray.
3 | %
4 | % function Xtensor = tucker2multiarray(X)
5 | %
6 | % X has fields U1, U2, U3, and G.
7 | %
8 | % The matrices U1 (n1-by-r1), U2 (n2-by-r2) and U3 (n3-by-r3) are
9 | % orthogonal matrices.
10 | % G (r1-by-r2-by-r3) is a multidimensional array.
11 | %
12 | % See also: fixedrankfactory_tucker_preconditioned
13 |
14 | % This file is part of Manopt: www.manopt.org.
15 | % Original authors: Hiroyuki Kasai and Bamdev Mishra, June 05, 2015.
16 | % Contributors:
17 | % Change log:
18 |
19 | U1 = X.U1;
20 | U2 = X.U2;
21 | U3 = X.U3;
22 | G = X.G;
23 |
24 | % Tensor size
25 | n1 = size(U1, 1);
26 | n2 = size(U2, 1);
27 | n3 = size(U3, 1);
28 |
29 | % Core size
30 | [r1, r2, r3] = size(G);
31 |
32 | % Multplication by U1
33 | G1 = reshape(G, r1, r2*r3);
34 | GU1 = reshape(U1*G1, n1, r2, r3);
35 |
36 | % Further multplication by U2
37 | G2 = reshape(permute(GU1, [2 1 3]), r2, n1*r3);
38 | GU1U2 = permute(reshape(U2*G2, n2, n1, r3), [2 1 3]);
39 |
40 | % Further multplication by U3
41 | G3 = reshape(permute(GU1U2, [3 1 2]), r3, n1*n2);
42 | GU1U2U3 = permute(reshape(U3*G3, n3, n1, n2), [2 3 1]);
43 |
44 | Xtensor = GU1U2U3;% Full tensor
45 |
46 | end
47 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/rotations/randrot.m:
--------------------------------------------------------------------------------
1 | function R = randrot(n, N)
2 | % Generates uniformly random rotation matrices.
3 | %
4 | % function R = randrot(n, N)
5 | %
6 | % R is a n-by-n-by-N matrix such that each slice R(:, :, i) is an
7 | % orthogonal matrix of size n of determinant +1 (i.e., a matrix in SO(n)).
8 | % By default, N = 1.
9 | % Complexity: N times O(n^3).
10 | % Theory in Diaconis and Shahshahani 1987 for the uniformity on O(n);
11 | % With details in Mezzadri 2007,
12 | % "How to generate random matrices from the classical compact groups."
13 | % To ensure matrices in SO(n), we permute the two first columns when
14 | % the determinant is -1.
15 | %
16 | % See also: randskew
17 |
18 | % This file is part of Manopt: www.manopt.org.
19 | % Original author: Nicolas Boumal, Sept. 25, 2012.
20 | % Contributors:
21 | % Change log:
22 |
23 | if nargin < 2
24 | N = 1;
25 | end
26 |
27 | if n == 1
28 | R = ones(1, 1, N);
29 | return;
30 | end
31 |
32 | R = zeros(n, n, N);
33 |
34 | for i = 1 : N
35 |
36 | % Generated as such, Q is uniformly distributed over O(n), the set
37 | % of orthogonal matrices.
38 | A = randn(n);
39 | [Q, RR] = qr(A);
40 | Q = Q * diag(sign(diag(RR))); %% Mezzadri 2007
41 |
42 | % If Q is in O(n) but not in SO(n), we permute the two first
43 | % columns of Q such that det(new Q) = -det(Q), hence the new Q will
44 | % be in SO(n), uniformly distributed.
45 | if det(Q) < 0
46 | Q(:, [1 2]) = Q(:, [2 1]);
47 | end
48 |
49 | R(:, :, i) = Q;
50 |
51 | end
52 |
53 | end
54 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/rotations/randskew.m:
--------------------------------------------------------------------------------
1 | function S = randskew(n, N)
2 | % Generates random skew symmetric matrices with normal entries.
3 | %
4 | % function S = randskew(n, N)
5 | %
6 | % S is an n-by-n-by-N matrix where each slice S(:, :, i) for i = 1..N is a
7 | % random skew-symmetric matrix with upper triangular entries distributed
8 | % independently following a normal distribution (Gaussian, zero mean, unit
9 | % variance).
10 | %
11 | % See also: randrot
12 |
13 | % This file is part of Manopt: www.manopt.org.
14 | % Original author: Nicolas Boumal, Sept. 25, 2012.
15 | % Contributors:
16 | % Change log:
17 |
18 |
19 | if nargin < 2
20 | N = 1;
21 | end
22 |
23 | % Subindices of the (strictly) upper triangular entries of an n-by-n
24 | % matrix
25 | [I J] = find(triu(ones(n), 1));
26 |
27 | K = repmat(1:N, n*(n-1)/2, 1);
28 |
29 | % Indices of the strictly upper triangular entries of all N slices of
30 | % an n-by-n-by-N matrix
31 | L = sub2ind([n n N], repmat(I, N, 1), repmat(J, N, 1), K(:));
32 |
33 | % Allocate memory for N random skew matrices of size n-by-n and
34 | % populate each upper triangular entry with a random number following a
35 | % normal distribution and copy them with opposite sign on the
36 | % corresponding lower triangular side.
37 | S = zeros(n, n, N);
38 | S(L) = randn(size(L));
39 | S = S-multitransp(S);
40 |
41 | end
42 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/specialeuclidean/specialeuclideanfactory.m:
--------------------------------------------------------------------------------
1 | function M = specialeuclideanfactory(n, k)
2 | % Returns a manifold structure to optimize over the special Euclidean group
3 | %
4 | % function M = specialeuclideanfactory(n)
5 | % function M = specialeuclideanfactory(n, k)
6 | %
7 | % The special Euclidean group (the manifold of rigid transformations):
8 | % This is a product manifold of the rotations group SO(n) and the
9 | % translation group R^n, copied k times.
10 | %
11 | % Points on the manifold are represented as structures X with two fields.
12 | % X.R is a 3D array of size nxnxk such that each slice X.R(:, :, i)
13 | % corresponds to a rotation matrix (orthogonal with determinant 1).
14 | % X.t is a matrix of size nxk such that each column X.t(:, i) corresponds
15 | % to a translation vector.
16 | %
17 | % Tangent vectors are represented as structures with the same fields. Note
18 | % that rotational components of the tangent vectors are represented in the
19 | % Lie algebra, i.e., each slice Xdot.R(:, :, i) is a skew-symmetric matrix.
20 | % Use M.tangent2ambient(X, Xdot) to obtain a representation in the ambient
21 | % space.
22 | %
23 | % This is a description of SE(n)^k with the induced metric from the
24 | % embedding space (R^nxn)^k x (R^n)^k, i.e., this manifold is a Riemannian
25 | % submanifold of the embedding Euclidean space with the usual inner
26 | % product.
27 | %
28 | % By default, k = 1.
29 | %
30 | % This is a test geometry: it may not be the "appropriate" geometry to give
31 | % to SE(n).
32 | %
33 | % See rotationsfactory and euclideanfactory for details.
34 | %
35 | % See also: rotationsfactory euclideanfactory
36 |
37 | % This file is part of Manopt: www.manopt.org.
38 | % Original author: Nicolas Boumal, Sep. 23, 2014.
39 | % Contributors:
40 | % Change log:
41 |
42 |
43 | if ~exist('k', 'var') || isempty(k)
44 | k = 1;
45 | end
46 |
47 | elements = struct();
48 | elements.R = rotationsfactory(n, k);
49 | elements.t = euclideanfactory(n, k);
50 |
51 | M = productmanifold(elements);
52 |
53 | end
54 |
--------------------------------------------------------------------------------
/manopt/manopt/manifolds/sphere/spherefactory.m:
--------------------------------------------------------------------------------
1 | function M = spherefactory(n, m)
2 | % Returns a manifold struct to optimize over unit-norm vectors or matrices.
3 | %
4 | % function M = spherefactory(n)
5 | % function M = spherefactory(n, m)
6 | %
7 | % Manifold of n-by-m real matrices of unit Frobenius norm.
8 | % By default, m = 1, which corresponds to the unit sphere in R^n. The
9 | % metric is such that the sphere is a Riemannian submanifold of the space
10 | % of nxm matrices with the usual trace inner product, i.e., the usual
11 | % metric.
12 | %
13 | % See also: obliquefactory spherecomplexfactory
14 |
15 | % This file is part of Manopt: www.manopt.org.
16 | % Original author: Nicolas Boumal, Dec. 30, 2012.
17 | % Contributors:
18 | % Change log:
19 |
20 |
21 | if ~exist('m', 'var')
22 | m = 1;
23 | end
24 |
25 | if m == 1
26 | M.name = @() sprintf('Sphere S^%d', n-1);
27 | else
28 | M.name = @() sprintf('Unit F-norm %dx%d matrices', n, m);
29 | end
30 |
31 | M.dim = @() n*m-1;
32 |
33 | M.inner = @(x, d1, d2) d1(:).'*d2(:);
34 |
35 | M.norm = @(x, d) norm(d, 'fro');
36 |
37 | M.dist = @(x, y) real(acos(x(:).'*y(:)));
38 |
39 | M.typicaldist = @() pi;
40 |
41 | M.proj = @(x, d) d - x*(x(:).'*d(:));
42 |
43 | M.tangent = M.proj;
44 |
45 | % For Riemannian submanifolds, converting a Euclidean gradient into a
46 | % Riemannian gradient amounts to an orthogonal projection.
47 | M.egrad2rgrad = M.proj;
48 |
49 | M.ehess2rhess = @ehess2rhess;
50 | function rhess = ehess2rhess(x, egrad, ehess, u)
51 | rhess = M.proj(x, ehess) - (x(:)'*egrad(:))*u;
52 | end
53 |
54 | M.exp = @exponential;
55 |
56 | M.retr = @retraction;
57 |
58 | M.log = @logarithm;
59 | function v = logarithm(x1, x2)
60 | v = M.proj(x1, x2 - x1);
61 | di = M.dist(x1, x2);
62 | % If the two points are "far apart", correct the norm.
63 | if di > 1e-6
64 | nv = norm(v, 'fro');
65 | v = v * (di / nv);
66 | end
67 | end
68 |
69 | M.hash = @(x) ['z' hashmd5(x(:))];
70 |
71 | M.rand = @() random(n, m);
72 |
73 | M.randvec = @(x) randomvec(n, m, x);
74 |
75 | M.lincomb = @matrixlincomb;
76 |
77 | M.zerovec = @(x) zeros(n, m);
78 |
79 | M.transp = @(x1, x2, d) M.proj(x2, d);
80 |
81 | M.pairmean = @pairmean;
82 | function y = pairmean(x1, x2)
83 | y = x1+x2;
84 | y = y / norm(y, 'fro');
85 | end
86 |
87 | M.vec = @(x, u_mat) u_mat(:);
88 | M.mat = @(x, u_vec) reshape(u_vec, [n, m]);
89 | M.vecmatareisometries = @() true;
90 |
91 | end
92 |
93 | % Exponential on the sphere
94 | function y = exponential(x, d, t)
95 |
96 | if nargin == 2
97 | t = 1;
98 | end
99 |
100 | td = t*d;
101 |
102 | nrm_td = norm(td, 'fro');
103 |
104 | if nrm_td > 4.5e-8
105 | y = x*cos(nrm_td) + td*(sin(nrm_td)/nrm_td);
106 | else
107 | % If the step is too small to accurately evaluate sin(x)/x,
108 | % then sin(x)/x is almost indistinguishable from 1.
109 | y = x + td;
110 | y = y / norm(y, 'fro');
111 | end
112 |
113 | end
114 |
115 | % Retraction on the sphere
116 | function y = retraction(x, d, t)
117 |
118 | if nargin == 2
119 | t = 1;
120 | end
121 |
122 | y = x + t*d;
123 | y = y / norm(y, 'fro');
124 |
125 | end
126 |
127 | % Uniform random sampling on the sphere.
128 | function x = random(n, m)
129 |
130 | x = randn(n, m);
131 | x = x/norm(x, 'fro');
132 |
133 | end
134 |
135 | % Random normalized tangent vector at x.
136 | function d = randomvec(n, m, x)
137 |
138 | d = randn(n, m);
139 | d = d - x*(x(:).'*d(:));
140 | d = d / norm(d, 'fro');
141 |
142 | end
143 |
--------------------------------------------------------------------------------
/manopt/manopt/solvers/neldermead/centroid.m:
--------------------------------------------------------------------------------
1 | function y = centroid(M, x)
2 | % Attempts the computation of a centroid of a set of points on a manifold.
3 | %
4 | % function y = centroid(M, x)
5 | %
6 | % M is a structure representing a manifold.
7 | % x is a cell of points on that manifold.
8 |
9 | % This file is part of Manopt: www.manopt.org.
10 | % Original author: Nicolas Boumal, Dec. 30, 2012.
11 | % Contributors:
12 | % Change log:
13 |
14 |
15 | % For now, just apply a few steps of gradient descent for Karcher means
16 |
17 | n = numel(x);
18 |
19 | problem.M = M;
20 |
21 | problem.cost = @cost;
22 | function val = cost(y)
23 | val = 0;
24 | for i = 1 : n
25 | val = val + M.dist(y, x{i})^2;
26 | end
27 | val = val/2;
28 | end
29 |
30 | problem.grad = @grad;
31 | function g = grad(y)
32 | g = M.zerovec(y);
33 | for i = 1 : n
34 | g = M.lincomb(y, 1, g, -1, M.log(y, x{i}));
35 | end
36 | end
37 |
38 | % This line can be uncommented to check that the gradient is indeed
39 | % correct. This should always be the case if the dist and the log
40 | % functions in the manifold are correct.
41 | % checkgradient(problem); pause;
42 |
43 | query = warning('query', 'manopt:getHessian:approx');
44 | warning('off', 'manopt:getHessian:approx');
45 | options.verbosity = 0;
46 | options.maxiter = 15;
47 | y = trustregions(problem, x{randi(n)}, options);
48 | warning(query.state, 'manopt:getHessian:approx');
49 |
50 | end
51 |
--------------------------------------------------------------------------------
/manopt/manopt/solvers/trustregions/license for original GenRTR code.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2007,2012 Christopher G. Baker, Pierre-Antoine Absil, Kyle A. Gallivan
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * Neither the names of the contributors nor of their affiliated
12 | institutions may be used to endorse or promote products
13 | derived from this software without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
26 | For questions, please contact Chris Baker (chris@cgbaker.net)
27 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/checkdiff.m:
--------------------------------------------------------------------------------
1 | function checkdiff(problem, x, d)
2 | % Checks the consistency of the cost function and directional derivatives.
3 | %
4 | % function checkdiff(problem)
5 | % function checkdiff(problem, x)
6 | % function checkdiff(problem, x, d)
7 | %
8 | % checkdiff performs a numerical test to check that the directional
9 | % derivatives defined in the problem structure agree up to first order with
10 | % the cost function at some point x, along some direction d. The test is
11 | % based on a truncated Taylor series (see online Manopt documentation).
12 | %
13 | % Both x and d are optional and will be sampled at random if omitted.
14 | %
15 | % See also: checkgradient checkhessian
16 |
17 | % This file is part of Manopt: www.manopt.org.
18 | % Original author: Nicolas Boumal, Dec. 30, 2012.
19 | % Contributors:
20 | % Change log:
21 | %
22 | % April 3, 2015 (NB):
23 | % Works with the new StoreDB class system.
24 |
25 |
26 | % Verify that the problem description is sufficient.
27 | if ~canGetCost(problem)
28 | error('It seems no cost was provided.');
29 | end
30 | if ~canGetDirectionalDerivative(problem)
31 | error('It seems no directional derivatives were provided.');
32 | end
33 |
34 | x_isprovided = exist('x', 'var') && ~isempty(x);
35 | d_isprovided = exist('d', 'var') && ~isempty(d);
36 |
37 | if ~x_isprovided && d_isprovided
38 | error('If d is provided, x must be too, since d is tangent at x.');
39 | end
40 |
41 | % If x and / or d are not specified, pick them at random.
42 | if ~x_isprovided
43 | x = problem.M.rand();
44 | end
45 | if ~d_isprovided
46 | d = problem.M.randvec(x);
47 | end
48 |
49 | % Compute the value f0 at f and directional derivative at x along d.
50 | storedb = StoreDB();
51 | xkey = storedb.getNewKey();
52 | f0 = getCost(problem, x, storedb, xkey);
53 | df0 = getDirectionalDerivative(problem, x, d, storedb, xkey);
54 |
55 | % Compute the value of f at points on the geodesic (or approximation
56 | % of it) originating from x, along direction d, for stepsizes in a
57 | % large range given by h.
58 | h = logspace(-8, 0, 51);
59 | value = zeros(size(h));
60 | for i = 1 : length(h)
61 | y = problem.M.exp(x, d, h(i));
62 | ykey = storedb.getNewKey();
63 | value(i) = getCost(problem, y, storedb, ykey);
64 | end
65 |
66 | % Compute the linear approximation of the cost function using f0 and
67 | % df0 at the same points.
68 | model = polyval([df0 f0], h);
69 |
70 | % Compute the approximation error
71 | err = abs(model - value);
72 |
73 | % And plot it.
74 | loglog(h, err);
75 | title(sprintf(['Directional derivative check.\nThe slope of the '...
76 | 'continuous line should match that of the dashed '...
77 | '(reference) line\nover at least a few orders of '...
78 | 'magnitude for h.']));
79 | xlabel('h');
80 | ylabel('Approximation error');
81 |
82 | line('xdata', [1e-8 1e0], 'ydata', [1e-8 1e8], ...
83 | 'color', 'k', 'LineStyle', '--', ...
84 | 'YLimInclude', 'off', 'XLimInclude', 'off');
85 |
86 |
87 | % In a numerically reasonable neighborhood, the error should decrease
88 | % as the square of the stepsize, i.e., in loglog scale, the error
89 | % should have a slope of 2.
90 | window_len = 10;
91 | [range, poly] = identify_linear_piece(log10(h), log10(err), window_len);
92 | hold on;
93 | loglog(h(range), 10.^polyval(poly, log10(h(range))), ...
94 | 'r-', 'LineWidth', 3);
95 | hold off;
96 |
97 | fprintf('The slope should be 2. It appears to be: %g.\n', poly(1));
98 | fprintf(['If it is far from 2, then directional derivatives ' ...
99 | 'might be erroneous.\n']);
100 |
101 | end
102 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/checkgradient.m:
--------------------------------------------------------------------------------
1 | function checkgradient(problem, x, d)
2 | % Checks the consistency of the cost function and the gradient.
3 | %
4 | % function checkgradient(problem)
5 | % function checkgradient(problem, x)
6 | % function checkgradient(problem, x, d)
7 | %
8 | % checkgradient performs a numerical test to check that the gradient
9 | % defined in the problem structure agrees up to first order with the cost
10 | % function at some point x, along some direction d. The test is based on a
11 | % truncated Taylor series (see online Manopt documentation).
12 | %
13 | % It is also tested that the gradient is indeed a tangent vector.
14 | %
15 | % Both x and d are optional and will be sampled at random if omitted.
16 | %
17 | % See also: checkdiff checkhessian
18 |
19 | % This file is part of Manopt: www.manopt.org.
20 | % Original author: Nicolas Boumal, Dec. 30, 2012.
21 | % Contributors:
22 | % Change log:
23 | %
24 | % April 3, 2015 (NB):
25 | % Works with the new StoreDB class system.
26 |
27 |
28 | % Verify that the problem description is sufficient.
29 | if ~canGetCost(problem)
30 | error('It seems no cost was provided.');
31 | end
32 | if ~canGetGradient(problem)
33 | error('It seems no gradient provided.');
34 | end
35 |
36 | x_isprovided = exist('x', 'var') && ~isempty(x);
37 | d_isprovided = exist('d', 'var') && ~isempty(d);
38 |
39 | if ~x_isprovided && d_isprovided
40 | error('If d is provided, x must be too, since d is tangent at x.');
41 | end
42 |
43 | % If x and / or d are not specified, pick them at random.
44 | if ~x_isprovided
45 | x = problem.M.rand();
46 | end
47 | if ~d_isprovided
48 | d = problem.M.randvec(x);
49 | end
50 |
51 | %% Check that the gradient yields a first order model of the cost.
52 |
53 | % By removing the 'directional derivative' function, it should be so
54 | % (?) that the checkdiff function will use the gradient to compute
55 | % directional derivatives.
56 | if isfield(problem, 'diff')
57 | problem = rmfield(problem, 'diff');
58 | end
59 | checkdiff(problem, x, d);
60 | title(sprintf(['Gradient check.\nThe slope of the continuous line ' ...
61 | 'should match that of the dashed (reference) line\n' ...
62 | 'over at least a few orders of magnitude for h.']));
63 | xlabel('h');
64 | ylabel('Approximation error');
65 |
66 | %% Try to check that the gradient is a tangent vector.
67 | if isfield(problem.M, 'tangent')
68 | storedb = StoreDB();
69 | key = storedb.getNewKey();
70 | grad = getGradient(problem, x, storedb, key);
71 | pgrad = problem.M.tangent(x, grad);
72 | residual = problem.M.lincomb(x, 1, grad, -1, pgrad);
73 | err = problem.M.norm(x, residual);
74 | fprintf('The residual should be 0, or very close. Residual: %g.\n', err);
75 | fprintf('If it is far from 0, then the gradient is not in the tangent space.\n');
76 | else
77 | fprintf(['Unfortunately, Manopt was unable to verify that the '...
78 | 'gradient is indeed a tangent vector.\nPlease verify ' ...
79 | 'this manually or implement the ''tangent'' function ' ...
80 | 'in your manifold structure.']);
81 | end
82 |
83 | end
84 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/dexpm.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/dexpm.m
--------------------------------------------------------------------------------
/manopt/manopt/tools/dfunm.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/dfunm.m
--------------------------------------------------------------------------------
/manopt/manopt/tools/diagsum.m:
--------------------------------------------------------------------------------
1 | function [tracedtensor] = diagsum(tensor1, d1, d2)
2 | % C = DIAGSUM(A, d1, d2) Performs the trace
3 | % C(i[1],...,i[d1-1],i[d1+1],...,i[d2-1],i[d2+1],...i[n]) =
4 | % A(i[1],...,i[d1-1],k,i[d1+1],...,i[d2-1],k,i[d2+1],...,i[n])
5 | % (Sum on k).
6 | %
7 | % C = DIAGSUM(A, d1, d2) traces A along the diagonal formed by dimensions d1
8 | % and d2. If the lengths of these dimensions are not equal, DIAGSUM traces
9 | % until the end of the shortest of dimensions d1 and d2 is reached. This is
10 | % an analogue of the built in TRACE function.
11 | %
12 | % Wynton Moore, January 2006
13 |
14 |
15 | dim1=size(tensor1);
16 | numdims=length(dim1);
17 |
18 |
19 | %check inputs
20 | if d1==d2
21 | tracedtensor=squeeze(sum(tensor1,d1));
22 | elseif numdims==2
23 | tracedtensor=trace(tensor1);
24 | elseif dim1(d1)==1 && dim1(d2)==1
25 | tracedtensor=squeeze(tensor1);
26 | else
27 |
28 |
29 | %determine correct permutation
30 | swapd1=d1;swapd2=d2;
31 |
32 | if d1~=numdims-1 && d1~=numdims && d2~=numdims-1
33 | swapd1=numdims-1;
34 | elseif d1~=numdims-1 && d1~=numdims && d2~=numdims
35 | swapd1=numdims;
36 | end
37 | if d2~=numdims-1 && d2~=numdims && swapd1~=numdims-1
38 | swapd2=numdims-1;
39 | elseif d2~=numdims-1 && d2~=numdims && swapd1~=numdims
40 | swapd2=numdims;
41 | end
42 |
43 |
44 | %prepare for construction of selector tensor
45 | temp1=eye(numdims);
46 | permmatrix=temp1;
47 | permmatrix(:,d1)=temp1(:,swapd1);
48 | permmatrix(:,swapd1)=temp1(:,d1);
49 | permmatrix(:,d2)=temp1(:,swapd2);
50 | permmatrix(:,swapd2)=temp1(:,d2);
51 |
52 | selectordim=dim1*permmatrix;
53 | permvector=(1:numdims)*permmatrix;
54 |
55 |
56 | %construct selector tensor
57 | if numdims>3
58 | selector = ipermute(outer(ones(selectordim(1:numdims-2)), ...
59 | eye(selectordim(numdims-1), ...
60 | selectordim(numdims)), ...
61 | 0), ...
62 | permvector);
63 | else
64 | %when numdims=3, the above line gives ndims(selector)=4. This
65 | %routine avoids that error. When used with GMDMP, numdims will be
66 | %at least 4, so this routine will be unnecessary.
67 | selector2=eye(selectordim(numdims-1), selectordim(numdims));
68 | selector=zeros(selectordim);
69 | for j=1:selectordim(1)
70 | selector(j, :, :)=selector2;
71 | end
72 | selector=ipermute(selector, permvector);
73 | end
74 |
75 |
76 | %perform trace, discard resulting singleton dimensions
77 | tracedtensor=sum(sum(tensor1.*selector, d1), d2);
78 | tracedtensor=squeeze(tracedtensor);
79 |
80 |
81 | end
82 |
83 |
84 | %correction for abberation in squeeze function:
85 | %size(squeeze(rand(1,1,2)))=[2 1]
86 | nontracedimensions=dim1;
87 | nontracedimensions(d1)=[];
88 | if d2>d1
89 | nontracedimensions(d2-1)=[];
90 | else
91 | nontracedimensions(d2)=[];
92 | end
93 | tracedsize=size(tracedtensor);
94 | % Next line modified, Nicolas Boumal, April 30, 2012, such that
95 | % diagsum(A, 1, 2) would compute the trace of A, a 2D matrix.
96 | if length(tracedsize)==2 && tracedsize(2)==1 && ...
97 | (isempty(nontracedimensions) || tracedsize(1)~=nontracedimensions(1))
98 |
99 | tracedtensor=tracedtensor.';
100 |
101 | end
102 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/dlogm.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/dlogm.m
--------------------------------------------------------------------------------
/manopt/manopt/tools/dsqrtm.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/dsqrtm.m
--------------------------------------------------------------------------------
/manopt/manopt/tools/hashmd5.m:
--------------------------------------------------------------------------------
1 | function h = hashmd5(inp)
2 | % Computes the MD5 hash of input data.
3 | %
4 | % function h = hashmd5(inp)
5 | %
6 | % Returns a string containing the MD5 hash of the input variable. The input
7 | % variable may be of any class that can be typecast to uint8 format, which
8 | % is fairly non-restrictive.
9 |
10 | % This file is part of Manopt: www.manopt.org.
11 | % This code is a stripped version of more general hashing code by
12 | % Michael Kleder, Nov 2005.
13 | % Change log:
14 | %
15 | % Aug. 8, 2013 (NB):
16 | % Made x a static (persistent) variable, in the hope it will speed
17 | % it up. Furthermore, the function is now Octave compatible.
18 |
19 | is_octave = exist('OCTAVE_VERSION', 'builtin');
20 |
21 | persistent x;
22 | if isempty(x) && ~is_octave
23 | x = java.security.MessageDigest.getInstance('MD5');
24 | end
25 |
26 | inp=inp(:);
27 | % Convert strings and logicals into uint8 format
28 | if ischar(inp) || islogical(inp)
29 | inp=uint8(inp);
30 | else % Convert everything else into uint8 format without loss of data
31 | inp=typecast(inp,'uint8');
32 | end
33 |
34 | % Create hash
35 | if ~is_octave
36 | x.update(inp);
37 | h = typecast(x.digest, 'uint8');
38 | h = dec2hex(h)';
39 | % Remote possibility: all hash bytes < 128, so pad:
40 | if(size(h,1))==1
41 | h = [repmat('0',[1 size(h,2)]);h];
42 | end
43 | h = lower(h(:)');
44 | else
45 | h = md5sum(char(inp'), true);
46 | end
47 |
48 | end
49 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/identify_linear_piece.m:
--------------------------------------------------------------------------------
1 | function [range, poly] = identify_linear_piece(x, y, window_length)
2 | % Identify a segment of the curve (x, y) that appears to be linear.
3 | %
4 | % function [range poly] = identify_linear_piece(x, y, window_length)
5 | %
6 | % This function attempts to identify a contiguous segment of the curve
7 | % defined by the vectors x and y that appears to be linear. A line is fit
8 | % through the data over all windows of length window_length and the best
9 | % fit is retained. The output specifies the range of indices such that
10 | % x(range) is the portion over which (x, y) is the most linear and the
11 | % output poly specifies a first order polynomial that best fits (x, y) over
12 | % that range, following the usual matlab convention for polynomials
13 | % (highest degree coefficients first).
14 | %
15 | % See also: checkdiff checkgradient checkhessian
16 |
17 | % This file is part of Manopt: www.manopt.org.
18 | % Original author: Nicolas Boumal, July 8, 2013.
19 | % Contributors:
20 | % Change log:
21 |
22 | residues = zeros(length(x)-window_length, 1);
23 | polys = zeros(2, length(residues));
24 | for i = 1 : length(residues)
25 | range = i:(i+window_length);
26 | [poly, meta] = polyfit(x(range), y(range), 1);
27 | residues(i) = meta.normr;
28 | polys(:, i) = poly';
29 | end
30 | [unused, best] = min(residues); %#ok
31 | range = best:(best+window_length);
32 | poly = polys(:, best)';
33 |
34 | end
35 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/manoptsolve.m:
--------------------------------------------------------------------------------
1 | function [x, cost, info, options] = manoptsolve(problem, x0, options)
2 | % Gateway helper function to call a Manopt solver, chosen in the options.
3 | %
4 | % function [x, cost, info, options] = manoptsolve(problem)
5 | % function [x, cost, info, options] = manoptsolve(problem, x0)
6 | % function [x, cost, info, options] = manoptsolve(problem, x0, options)
7 | % function [x, cost, info, options] = manoptsolve(problem, [], options)
8 | %
9 | % Depending on what is available in the Manopt problem structure, one of
10 | % the Manopt solvers will be called and the outputs passed along. It is
11 | % also possible to force the choice of a solver by specifying it in the
12 | % options structure. For example:
13 | %
14 | % options.solver = @trustregions;
15 | %
16 | % Simply specify a function handle to a Manopt solver.
17 | %
18 | % See also: trustregions conjugategradient steepestdescent
19 |
20 | % This file is part of Manopt: www.manopt.org.
21 | % Original author: Nicolas Boumal, Aug. 13, 2014.
22 | % Contributors:
23 | % Change log:
24 |
25 | % At the very least, we need a cost function.
26 | if ~canGetCost(problem)
27 | error('The problem structure must specify a cost function.');
28 | end
29 |
30 | % Depending on the number of differentials available, pick a different
31 | % default solver.
32 | if ~canGetGradient(problem)
33 | localdefaults.solver = @neldermead;
34 | elseif ~canGetHessian(problem)
35 | localdefaults.solver = @conjugategradient;
36 | else
37 | localdefaults.solver = @trustregions;
38 | end
39 |
40 | % Merge local defaults with user options, if any.
41 | if ~exist('options', 'var') || isempty(options)
42 | options = struct();
43 | end
44 | options = mergeOptions(localdefaults, options);
45 |
46 | % If no initial guess was specified, prepare the empty one.
47 | if ~exist('x0', 'var')
48 | x0 = [];
49 | end
50 |
51 | % Issue the actual call.
52 | [x, cost, info, options] = options.solver(problem, x0, options);
53 |
54 | end
55 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/matrixlincomb.m:
--------------------------------------------------------------------------------
1 | function v = matrixlincomb(x, a1, d1, a2, d2) %#ok
2 | % Linear combination function for tangent vectors represented as matrices.
3 | %
4 | % function v = lincomb(x, a1, d1)
5 | % function v = lincomb(x, a1, d1, a2, d2)
6 | %
7 | % Given a point x, two tangent vectors d1 and d2 at x, and two real
8 | % coefficients a1 and a2, returns a tangent vector at x representing
9 | % a1*d1 + a2*d2, if d1 and d2 are represented as matrices (or more
10 | % generally as arrays in Matlab).
11 | %
12 | % If a2 and d2 are omitted, the returned tangent vector is a1*d1.
13 | %
14 | % The input x is actually unused.
15 | %
16 | % This function is a helper to define manifolds in Manopt.
17 |
18 | % This file is part of Manopt: www.manopt.org.
19 | % Original author: Nicolas Boumal, July 2, 2015.
20 | % Contributors:
21 | % Change log:
22 |
23 | if nargin == 3
24 | v = a1*d1;
25 | elseif nargin == 5
26 | v = a1*d1 + a2*d2;
27 | else
28 | error('matrixlincomb takes either 3 or 5 inputs.');
29 | end
30 |
31 | end
32 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/multihconj.m:
--------------------------------------------------------------------------------
1 | function b = multihconj(a, dim)
2 | %MULTIHCONJ Hermitian conjugating arrays of matrices.
3 | % B = MULTIHCONJ(A) is equivalent to B = MULTIHCONJ(A, DIM), where
4 | % DIM = 1.
5 | %
6 | % B = MULTIHCONJ(A, DIM) is equivalent to
7 | % B = PERMUTE(A, [1:DIM-1, DIM+1, DIM, DIM+2:NDIMS(A)]), where A is an
8 | % array containing N P-by-Q matrices along its dimensions DIM and DIM+1,
9 | % and B is an array containing the Q-by-P Hermitian conjugate (') of
10 | % those N matrices along the same dimensions. N = NUMEL(A) / (P*Q), i.e.
11 | % N is equal to the number of elements in A divided by the number of
12 | % elements in each matrix.
13 | %
14 | %
15 | % Example:
16 | % A 5-by-9-by-3-by-2 array may be considered to be a block array
17 | % containing ten 9-by-3 matrices along dimensions 2 and 3. In this
18 | % case, its size is so indicated: 5-by-(9-by-3)-by-2 or 5x(9x3)x2.
19 | % If A is ................ a 5x(9x3)x2 array of 9x3 matrices,
20 | % C = MULTIHCONJ(A, 2) is a 5x(3x9)x2 array of 3x9 matrices.
21 | %
22 | % See also MULTITRANSP MULTIHERM.
23 |
24 | % This file is part of Manopt: www.manopt.org.
25 | % Original author: Hiroyuki Sato, April 27, 2015.
26 | % Contributors:
27 | % Change log:
28 |
29 | % Setting DIM if not supplied.
30 | if nargin == 1, dim = 1; end
31 |
32 | % Transposing
33 | b = multitransp(a, dim);
34 |
35 | %Conjugating
36 | b = conj(b);
37 |
38 | end
39 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/multiherm.m:
--------------------------------------------------------------------------------
1 | function Y = multiherm(X)
2 | % Returns the Hermitian parts of the matrices in the 3D matrix X
3 | %
4 | % function Y = multiherm(X)
5 | %
6 | % Y is a 3D matrix the same size as X. Each slice Y(:, :, i) is the
7 | % Hermitian part of the slice X(:, :, i).
8 | %
9 | % See also: multiprod multitransp multihconj multiscale multiskew
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Hiroyuki Sato, April 27, 2015.
13 | % Contributors:
14 | % Change log:
15 |
16 | Y = .5*(X + multihconj(X));
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/multiprod.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/multiprod.m
--------------------------------------------------------------------------------
/manopt/manopt/tools/multiprodmultitransp_license.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009, Paolo de Leva
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are
6 | met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 | * Redistributions in binary form must reproduce the above copyright
11 | notice, this list of conditions and the following disclaimer in
12 | the documentation and/or other materials provided with the distribution
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 | POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/multiscale.m:
--------------------------------------------------------------------------------
1 | function A = multiscale(scale, A)
2 | % Multiplies the 2D slices in a 3D matrix by individual scalars.
3 | %
4 | % function A = multiscale(scale, A)
5 | %
6 | % Given a vector scale of length N and a 3-dimensional matrix A of size
7 | % n-by-m-by-N, returns a matrix A of same size such that
8 | % A(:, :, k) := scale(k) * A(:, :, k);
9 | %
10 | % See also: multiprod multitransp multitrace
11 |
12 | % This file is part of Manopt: www.manopt.org.
13 | % Original author: Nicolas Boumal, Dec. 30, 2012.
14 | % Contributors:
15 | % Change log:
16 |
17 |
18 | assert(ndims(A) <= 3, ...
19 | ['multiscale is only well defined for matrix arrays of 3 ' ...
20 | 'or less dimensions.']);
21 | [n, m, N] = size(A);
22 | assert(numel(scale) == N, ...
23 | ['scale must be a vector whose length equals the third ' ...
24 | 'dimension of A, that is, the number of 2D matrix slices ' ...
25 | 'in the 3D matrix A.']);
26 |
27 | scale = scale(:);
28 | A = reshape(bsxfun(@times, reshape(A, n*m, N), scale'), n, m, N);
29 |
30 | end
31 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/multiskew.m:
--------------------------------------------------------------------------------
1 | function Y = multiskew(X)
2 | % Returns the skew-symmetric parts of the matrices in the 3D matrix X.
3 | %
4 | % function Y = multiskew(X)
5 | %
6 | % Y is a 3D matrix the same size as X. Each slice Y(:, :, i) is the
7 | % skew-symmetric part of the slice X(:, :, i).
8 | %
9 | % See also: multiprod multitransp multiscale multisym
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, Jan. 31, 2013.
13 | % Contributors:
14 | % Change log:
15 |
16 | Y = .5*(X - multitransp(X));
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/multisqnorm.m:
--------------------------------------------------------------------------------
1 | function sqnorm = multisqnorm(A)
2 | % Returns the squared Frobenius norms of the slices of a 3D matrix.
3 | %
4 | % function sqnorm = multisqnorm(A)
5 | %
6 | % Given a 3-dimensional matrix A of size n-by-m-by-N, returns a column
7 | % vector of length N such that sqnorm(i) = norm(A(:, :, i), 'fro')^2.
8 | %
9 | % See also: multiprod multitransp multitrace norms
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, June 17, 2015.
13 | % Contributors:
14 | % Change log:
15 |
16 |
17 | assert(ndims(A) <= 3, ...
18 | ['multisqnorm is only well defined for matrix arrays of 3 ' ...
19 | 'or less dimensions.']);
20 | [n, m, N] = size(A);
21 |
22 | % This is equivalent to squeeze(sum(norms(A, 2, 1).^2)), but faster.
23 | sqnorm = sum(reshape(A, n*m, N).^2, 1)';
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/multisym.m:
--------------------------------------------------------------------------------
1 | function Y = multisym(X)
2 | % Returns the symmetric parts of the matrices in the 3D matrix X
3 | %
4 | % function Y = multisym(X)
5 | %
6 | % Y is a 3D matrix the same size as X. Each slice Y(:, :, i) is the
7 | % symmetric part of the slice X(:, :, i).
8 | %
9 | % See also: multiprod multitransp multiscale multiskew
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, Jan. 31, 2013.
13 | % Contributors:
14 | % Change log:
15 |
16 | Y = .5*(X + multitransp(X));
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/multitrace.m:
--------------------------------------------------------------------------------
1 | function tr = multitrace(A)
2 | % Computes the traces of the 2D slices in a 3D matrix.
3 | %
4 | % function tr = multitrace(A)
5 | %
6 | % For a 3-dimensional matrix A of size n-by-n-by-N, returns a column vector
7 | % tr of length N such that tr(k) = trace(A(:, :, k));
8 | %
9 | % See also: multiprod multitransp multiscale
10 |
11 | % This file is part of Manopt: www.manopt.org.
12 | % Original author: Nicolas Boumal, Dec. 30, 2012.
13 | % Contributors:
14 | % Change log:
15 |
16 |
17 | assert(ndims(A) <= 3, ...
18 | ['multitrace is only well defined for matrix arrays of 3 ' ...
19 | 'or less dimensions.']);
20 |
21 | tr = diagsum(A, 1, 2);
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/multitransp.m:
--------------------------------------------------------------------------------
1 | function b = multitransp(a, dim)
2 | % Transposing arrays of matrices.
3 | %
4 | % B = MULTITRANSP(A) is equivalent to B = MULTITRANSP(A, DIM), where
5 | % DIM = 1.
6 | %
7 | % B = MULTITRANSP(A, DIM) is equivalent to
8 | % B = PERMUTE(A, [1:DIM-1, DIM+1, DIM, DIM+2:NDIMS(A)]), where A is an
9 | % array containing N P-by-Q matrices along its dimensions DIM and DIM+1,
10 | % and B is an array containing the Q-by-P transpose (.') of those N
11 | % matrices along the same dimensions. N = NUMEL(A) / (P*Q), i.e. N is
12 | % equal to the number of elements in A divided by the number of elements
13 | % in each matrix.
14 | %
15 | % MULTITRANSP, PERMUTE and IPERMUTE are a generalization of TRANSPOSE
16 | % (.') for N-D arrays.
17 | %
18 | % Example:
19 | % A 5-by-9-by-3-by-2 array may be considered to be a block array
20 | % containing ten 9-by-3 matrices along dimensions 2 and 3. In this
21 | % case, its size is so indicated: 5-by-(9-by-3)-by-2 or 5x(9x3)x2.
22 | % If A is ................ a 5x(9x3)x2 array of 9x3 matrices,
23 | % C = MULTITRANSP(A, 2) is a 5x(3x9)x2 array of 3x9 matrices.
24 | %
25 | % See also PERMUTE, IPERMUTE, MULTIPROD, MULTITRACE, MULTISCALE.
26 |
27 | % $ Version: 1.0 $
28 | % CODE by: Paolo de Leva (IUSM, Rome, IT) 2005 Sep 9
29 | % COMMENTS by: Code author 2006 Nov 21
30 | % OUTPUT tested by: Code author 2005 Sep 13
31 | % -------------------------------------------------------------------------
32 |
33 | % Setting DIM if not supplied.
34 | if nargin == 1, dim = 1; end
35 |
36 | % Transposing
37 | order = [1:dim-1, dim+1, dim, dim+2:ndims(a)];
38 | b = permute(a, order);
39 |
40 | end
41 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/plotprofile.m:
--------------------------------------------------------------------------------
1 | function cost = plotprofile(problem, x, d, t)
2 | % Plot the cost function along a geodesic or a retraction path.
3 | %
4 | % function plotprofile(problem, x, d, t)
5 | % function costs = plotprofile(problem, x, d, t)
6 | %
7 | % Plot profile evaluates the cost function along a geodesic gamma(t) such
8 | % that gamma(0) = x and the derivative of gamma at 0 is the direction d.
9 | % The input t is a vector specifying for which values of t we must evaluate
10 | % f(gamma(t)) (it may include negative values).
11 | %
12 | % If the function is called with an output, the plot is not drawn and the
13 | % values of the cost are returned for the instants t.
14 |
15 | % This file is part of Manopt: www.manopt.org.
16 | % Original author: Nicolas Boumal, Jan. 9, 2013.
17 | % Contributors:
18 | % Change log:
19 | %
20 | % April 3, 2015 (NB):
21 | % Works with the new StoreDB class system.
22 |
23 | % Verify that the problem description is sufficient.
24 | if ~canGetCost(problem)
25 | error('It seems no cost was provided.');
26 | end
27 |
28 | if isfield(problem.M, 'exp')
29 | expo = problem.M.exp;
30 | str = 'Exp';
31 | else
32 | expo = problem.M.retr;
33 | str = 'Retr';
34 | end
35 |
36 | storedb = StoreDB();
37 | linesearch_fun = @(t) getCost(problem, expo(x, d, t), storedb);
38 |
39 | cost = zeros(size(t));
40 | for i = 1 : numel(t)
41 | cost(i) = linesearch_fun(t(i));
42 | end
43 |
44 | if nargout == 0
45 | plot(t, cost);
46 | xlabel('t');
47 | ylabel(['f(' str '_x(t*d))']);
48 | end
49 |
50 | end
51 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/statsfunhelper.m:
--------------------------------------------------------------------------------
1 | function statsfun = statsfunhelper(inp1, inp2)
2 | % Helper tool to create a statsfun for the options structure of solvers.
3 | %
4 | % function statsfun = statsfunhelper(name, fun)
5 | % function statsfun = statsfunhelper(S)
6 | %
7 | % Usage with (name, fun):
8 | %
9 | % Input 1: name is a string which is a valid field name (no spaces, starts
10 | % with a letter or an underscore, only alphanumeric characters and
11 | % underscores).
12 | %
13 | % Input2: fun is a function handle with one output and 1 to 4 inputs, as
14 | % follows (your choice):
15 | %
16 | % fun(x) or fun(problem, x) or
17 | % fun(problem, x, stats) or fun(problem, x, stats, store)
18 | %
19 | % where the inputs are the ones that would be given to options.statsfun, as
20 | % described in the help of the solver used. Typically, x is the point on
21 | % the manifold at the current iterate, problem is the Manopt problem
22 | % structure, stats is all the current statistics recorded for that iterate
23 | % and store is the cache structure at the current iterate.
24 | %
25 | % When calling a Manopt solver with the options structure, such as for
26 | % example with:
27 | %
28 | % [x, xcost, info] = steepestdescent(problem, [], options);
29 | %
30 | % you may set a field of the options structure as follows:
31 | %
32 | % options.statsfun = statsfunhelper('nameofthefield', fun);
33 | %
34 | % As a result, at each iteration, the stats structure will contain a field
35 | % stats.nameofthefield with the value returned by the call to fun at that
36 | % iterate. The stats structures are stored in the struct-array info.
37 | % As an example, if the value returned by fun is a scalar, then
38 | % [info.nameofthefield] is a vector containing all returned values.
39 | %
40 | %
41 | % Usage with S:
42 | %
43 | % The input S is a structure. For each field of S, say S.field, the stats
44 | % structure will be augmented with stats.field = fun(..), where fun is the
45 | % function handle stored in S.field, and with the same conventions as
46 | % above. This version allows to record more than one bit of information at
47 | % each iteration. Example:
48 | %
49 | % metrics.nameofthefield = fun;
50 | % metrics.othername = otherfun;
51 | % options.statsfun = statsfunhelper(metrics);
52 | %
53 | % The different function handles (here, fun and otherfun) can take 1 to 4
54 | % inputs too, and they do not have to take the same number of inputs.
55 |
56 | % This file is part of Manopt: www.manopt.org.
57 | % Original author: Nicolas Boumal, Dec. 17, 2014.
58 | % Contributors:
59 | % Change log:
60 |
61 | if (nargin == 1) && isstruct(inp1)
62 | S = inp1;
63 | elseif (nargin == 2)
64 | S = struct(inp1, inp2);
65 | else
66 | error('statsfunhelper takes 1 or 2 inputs. If 1 input, it must be a structure.');
67 | end
68 |
69 |
70 | function stats = thestatsfun(problem, x, stats, store)
71 | names = fieldnames(S);
72 | for it = 1 : length(names)
73 | name = names{it};
74 | fun = S.(name);
75 | switch nargin(fun)
76 | case 1
77 | stats.(name) = fun(x);
78 | case 2
79 | stats.(name) = fun(problem, x);
80 | case 3
81 | stats.(name) = fun(problem, x, stats);
82 | case 4
83 | stats.(name) = fun(problem, x, stats, store);
84 | otherwise
85 | error('The functions passed to statsfunhelper must take 1 to 4 inputs.');
86 | end
87 | end
88 | end
89 |
90 | statsfun = @thestatsfun;
91 |
92 | end
93 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/surfprofile.m:
--------------------------------------------------------------------------------
1 | function costs = surfprofile(problem, x, d1, d2, t1, t2)
2 | % Plot the cost function as a surface over a 2-dimensional subspace.
3 | %
4 | % function surfprofile(problem, x, d1, d2, t1, t2)
5 | % function costs = surfprofile(problem, x, d1, d2, t1, t2)
6 | %
7 | % Evaluates the cost function at points
8 | %
9 | % gamma(t1, t2) = exponential_x(t1*d1 + t2*d2)
10 | %
11 | % where the exponential map at x is specified by problem.M.exp (retr is
12 | % used instead if needed). d1 and d2 are two tangent vectors to problem.M
13 | % at the point x. The values assigned to t1 and t2 are as specified in the
14 | % two input vectors t1 and t2.
15 | %
16 | % If the function is called with an output, the plot is not drawn and the
17 | % values of the cost are returned in a matrix of size
18 | % length(t1)*length(t2). To plot a surf, call surf(t1, t2, costs.') (notice
19 | % the transpose).
20 |
21 | % This file is part of Manopt: www.manopt.org.
22 | % Original author: Nicolas Boumal, Sep. 1, 2014.
23 | % Contributors:
24 | % Change log:
25 | %
26 | % April 3, 2015 (NB):
27 | % Works with the new StoreDB class system.
28 |
29 | % Verify that the problem description is sufficient.
30 | if ~canGetCost(problem)
31 | error('It seems no cost was provided.');
32 | end
33 |
34 | if isfield(problem.M, 'exp')
35 | expo = problem.M.exp;
36 | str = 'Exp';
37 | else
38 | expo = problem.M.retr;
39 | str = 'Retr';
40 | end
41 |
42 | storedb = StoreDB();
43 | linesearch_fun = @(ta, tb) getCost(problem, ...
44 | expo(x, problem.M.lincomb(x, ta, d1, tb, d2)), ...
45 | storedb);
46 |
47 | costs = zeros(length(t1), length(t2));
48 | for i = 1 : length(t1)
49 | for j = 1 : length(t2)
50 | costs(i, j) = linesearch_fun(t1(i), t2(j));
51 | end
52 | end
53 |
54 | if nargout == 0
55 | surf(t1, t2, costs.');
56 | xlabel('t1');
57 | ylabel('t2');
58 | zlabel(['f(' str '_x(t1*d1+t2*d2))']);
59 | end
60 |
61 | end
62 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/tangentspacefactory.m:
--------------------------------------------------------------------------------
1 | function N = tangentspacefactory(M, x)
2 | % Returns a manifold structure representing the tangent space to M at x.
3 | %
4 | % N = tangentspacefactory(M, x)
5 | %
6 | % N defines a (linear) manifold that is the tangent space to M at x. Points
7 | % are represented as tangent vectors to M at x. Tangent vectors are also
8 | % represented as tangent vectors to M at x.
9 | %
10 | % This is chiefly useful to solve optimization problems involving tangent
11 | % vectors to M at x, which notably comes up when solving linear systems
12 | % involving, for example, the Hessian of the cost on M at x. The Riemannian
13 | % (actually, Euclidean) structure on N is that of the tangent space to M,
14 | % that is, the inner product is inherited.
15 | %
16 | % See also: preconhessiansolve
17 |
18 | % This file is part of Manopt: www.manopt.org.
19 | % Original author: Nicolas Boumal, April 9, 2015.
20 | % Contributors:
21 | % Change log:
22 |
23 | % N is the manifold we build. y will be a point on N, thus also a
24 | % tangent vector to M at x. This is a typical Euclidean space, hence it
25 | % will be easy to describe in terms of the tools available for M.
26 | N = struct();
27 |
28 | % u, u1 and u2 will be tangent vectors to N at y. The tangent space to
29 | % N at y is the tangent space to M at x, thus u, u1 and u2 are also
30 | % tangent vectors to M at x.
31 |
32 | N.dim = @() M.dim();
33 | N.inner = @(y, u1, u2) M.inner(x, u1, u2);
34 | N.norm = @(y, u) M.norm(x, u);
35 | N.proj = M.proj;
36 | N.typicaldist = @() N.dim();
37 | N.tangent = @(y, u) u;
38 | N.egrad2rgrad = @(x, g) g;
39 | N.ehess2rhess = @(x, eg, eh, d) eh;
40 | N.exp = @exponential;
41 | N.retr = @exponential;
42 | N.log = @(y1, y2) M.lincomb(x, 1, y2, -1, y1);
43 | N.pairmean = @(y1, y2) M.lincomb(x, 0.5, y1, 0.5, y2);
44 | N.rand = @() M.randvec(x);
45 | N.randvec = @(y) M.randvec(x);
46 | N.zerovec = M.zerovec;
47 | N.lincomb = M.lincomb;
48 | N.transp = @(y1, y2, u) u;
49 | N.hash = @(y) ['z' hashmd5(M.vec(x, y))];
50 |
51 | % In a Euclidean space, the exponential is merely the sum: y + tu.
52 | function yy = exponential(y, u, t)
53 | if nargin == 2
54 | t = 1;
55 | end
56 | yy = M.lincomb(x, 1, y, t, u);
57 | end
58 |
59 | end
60 |
--------------------------------------------------------------------------------
/manopt/manopt/tools/tangentspherefactory.m:
--------------------------------------------------------------------------------
1 | function N = tangentspherefactory(M, x)
2 | % Returns a manifold struct. for the sphere on the tangent space to M at x.
3 | %
4 | % N = tangentspherefactory(M, x)
5 | %
6 | % N defines a manifold that is the unit sphere on the tangent space to M
7 | % at x. Points are represented as tangent vectors of unit norm. Tangent
8 | % vectors are represented as tangent vectors orthogonal to the root point,
9 | % with respect to the Riemannian metric on the tangent space.
10 | %
11 | % This is chiefly useful to solve optimization problems involving unit norm
12 | % tangent vectors to M at x, which notably comes up when looking for
13 | % extreme eigenvectors of the Hessian of a cost function on M at x, for
14 | % example. The Riemannian structure on this sphere is that of a Riemannian
15 | % submanifold of the (Euclidean) tangent space, equipped with the
16 | % Riemannian metric of M at that point.
17 | %
18 | % See also: hessianextreme
19 |
20 | % This file is part of Manopt: www.manopt.org.
21 | % Original author: Nicolas Boumal, March 16, 2015.
22 | % Contributors:
23 | % Change log:
24 |
25 | % N is the manifold we build. y will be a point on N, thus also a
26 | % tangent vector to M at x. This is a typical Riemannian submanifold of
27 | % a Euclidean space, hence it will be easy to describe in terms of the
28 | % tools available for M.
29 | N = struct();
30 |
31 | % u, u1 and u2 will be tangent vectors to N at y. The tangent space to
32 | % N at y is a subspace of the tangent space to M at x, thus u, u1 and
33 | % u2 are also tangent vectors to M at x.
34 |
35 | N.dim = @() M.dim() - 1;
36 | N.inner = @(y, u1, u2) M.inner(x, u1, u2);
37 | N.norm = @(y, u) M.norm(x, u);
38 | N.proj = @(y, v) M.lincomb(x, 1, v, -M.inner(x, v, y), y);
39 | N.typicaldist = @() 1;
40 | N.tangent = N.proj;
41 | N.egrad2rgrad = N.proj;
42 | N.retr = @retraction;
43 | N.exp = N.retr;
44 | function yy = retraction(y, u, t)
45 | if nargin == 2
46 | t = 1;
47 | end
48 | y_plus_tu = M.lincomb(x, 1, y, t, u);
49 | nrm = M.norm(x, y_plus_tu);
50 | yy = M.lincomb(x, 1/nrm, y_plus_tu);
51 | end
52 | N.rand = @random;
53 | function y = random()
54 | y = M.randvec(x);
55 | nrm = M.norm(x, y);
56 | y = M.lincomb(x, 1/nrm, y);
57 | end
58 | N.randvec = @randvec;
59 | function u = randvec(y)
60 | u = N.proj(y, N.rand());
61 | nrm = N.norm(y, u);
62 | u = M.lincomb(x, 1/nrm, u);
63 | end
64 | N.zerovec = M.zerovec;
65 | N.lincomb = M.lincomb;
66 | N.transp = @(y1, y2, u) N.proj(y2, u);
67 | N.hash = @(y) ['z' hashmd5(M.vec(x, y))];
68 |
69 | end
70 |
--------------------------------------------------------------------------------
/manopt/manopt_version.m:
--------------------------------------------------------------------------------
1 | function [version, released] = manopt_version()
2 | % Returns the version of the Manopt package you are running, as a vector.
3 | %
4 | % function [version, released] = manopt_version()
5 | %
6 | % version(1) is the primary version number.
7 | % released is the date this version was released, in the same format as the
8 | % date() function in Matlab.
9 |
10 | version = [2, 0, 0];
11 | released = '06-Jul-2015';
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/pose-hg-demo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/pose-hg-demo/.DS_Store
--------------------------------------------------------------------------------
/pose-hg-demo/.gitignore:
--------------------------------------------------------------------------------
1 | *.t7
2 |
--------------------------------------------------------------------------------
/pose-hg-demo/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, University of Michigan
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5 |
6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 |
8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 |
10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11 |
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/pose-hg-demo/README.md:
--------------------------------------------------------------------------------
1 | # Stacked Hourglass Networks for Human Pose Estimation (Demo Code)
2 |
3 | This repository includes Torch code for evaluation and visualization of the network presented in:
4 |
5 | Alejandro Newell, Kaiyu Yang, and Jia Deng,
6 | **Stacked Hourglass Networks for Human Pose Estimation**,
7 | [arXiv:1603.06937](http://arxiv.org/abs/1603.06937), 2016.
8 |
9 | A pretrained model is available on the [project site](http://www-personal.umich.edu/~alnewell/pose). Include the model in the main directory of this repository to run the demo code.
10 |
11 | **Check out the training and experimentation code now available at: [https://github.com/anewell/pose-hg-train](https://github.com/anewell/pose-hg-train)**
12 |
13 | In addition, if you download the full [MPII Human Pose dataset](http://human-pose.mpi-inf.mpg.de) and replace this repository's `images` directory you can generate full predictions on the validation and test sets.
14 |
15 | To run this code, the following must be installed:
16 |
17 | - [Torch7](https://github.com/torch/torch7)
18 | - hdf5 (and the [torch-hdf5](https://github.com/deepmind/torch-hdf5/) package)
19 | - cudnn
20 | - qlua (for displaying results)
21 |
22 | For displaying the demo images:
23 | `qlua main.lua demo`
24 |
25 | For generating predictions:
26 | `th main.lua predict-[valid or test]`
27 |
28 | For evaluation on a set of validation predictions:
29 | `th main.lua eval`
30 |
31 | ## Testing your own images
32 |
33 | To use the network off-the-shelf, it is critical that the target person is centered in the input image. There is some robustness to scale, but for best performance the person should be sized such that their full height is roughly three-quarters of the input height. Play around with different scale settings to see the impact it has on the network output. We offer a convenient function for generating an input image:
34 |
35 | `inputImg = crop(img, center, scale, rot, res)`
36 |
37 | `res` should be set to 256 for our network. `rot` is offered if you wish to rotate the image (in degrees). You can run the input image through the network, and get the (x,y) coordinates with:
38 |
39 | `outputHm = m:forward(inputImg:view(1,3,256,256):cuda())`
40 |
41 | `predsHm,predsImg = getPreds(outputHm, center, scale)`
42 |
43 | The two outputs of `getPreds` are coordinates with respect to either the heatmap or the original image (using center and scale to apply the appropriate transformation back to the image space).
44 |
45 | The MPII images come with center and scale annotations already. An important detail with regards to the annotations: we have modified their format slightly for ease of use with our code. In addition, we adjusted the original center and scale annotations uniformly across all images so as to reduce the chances of our function cropping out feet from the bottom of the image. This mostly involved moving the center down a fraction.
46 |
47 |
--------------------------------------------------------------------------------
/pose-hg-demo/model.sh:
--------------------------------------------------------------------------------
1 | # Download Stacked Hourglass model
2 | wget http://www-personal.umich.edu/~alnewell/pose/umich-stacked-hourglass.zip
3 | unzip umich-stacked-hourglass.zip
4 | mv umich-stacked-hourglass/umich-stacked-hourglass.t7 ./
5 | rm umich-stacked-hourglass.zip
6 | rm -r umich-stacked-hourglass
--------------------------------------------------------------------------------
/pose-hg-demo/residual.lua:
--------------------------------------------------------------------------------
1 | local conv = nnlib.SpatialConvolution
2 | local batchnorm = nn.SpatialBatchNormalization
3 | local relu = nnlib.ReLU
4 |
5 | -- Main convolutional block
6 | local function convBlock(numIn,numOut)
7 | return nn.Sequential()
8 | :add(conv(numIn,numOut/2,1,1))
9 | :add(batchnorm(numOut/2))
10 | :add(relu(true))
11 | :add(conv(numOut/2,numOut/2,3,3,1,1,1,1))
12 | :add(batchnorm(numOut/2))
13 | :add(relu(true))
14 | :add(conv(numOut/2,numOut,1,1))
15 | :add(batchnorm(numOut))
16 | end
17 |
18 | -- Skip layer
19 | local function skipLayer(numIn,numOut)
20 | if numIn == numOut then
21 | return nn.Identity()
22 | else
23 | return nn.Sequential()
24 | :add(conv(numIn,numOut,1,1))
25 | :add(batchnorm(numOut))
26 | end
27 | end
28 |
29 | -- Residual block
30 | function Residual(numIn,numOut)
31 | return nn.Sequential()
32 | :add(nn.ConcatTable()
33 | :add(convBlock(numIn,numOut))
34 | :add(skipLayer(numIn,numOut)))
35 | :add(nn.CAddTable(true))
36 | end
37 |
--------------------------------------------------------------------------------
/pose-hg-demo/run-hg.lua:
--------------------------------------------------------------------------------
1 | -- Generate heatmaps for all images in a folder
2 | -- The heatmaps are saved as hdf5 files in the same folder
3 | -- routine: th run-hg.lua FolderName ImageFilenameExtension
4 | -- example: th run-hg.lua ../data/tennis jpg
5 |
6 | require 'paths'
7 | paths.dofile('util.lua')
8 | paths.dofile('img.lua')
9 |
10 | local imgdir = arg[1]
11 | local ext = arg[2]
12 |
13 | model = torch.load('umich-stacked-hourglass.t7') -- Load pre-trained model
14 |
15 | for file in paths.files(imgdir) do
16 | if file:find(ext .. '$') then
17 | local name = paths.concat(imgdir,file)
18 | local img = image.load(name)
19 | local center = torch.Tensor(2)
20 | center[1] = img:size(3)/2
21 | center[2] = img:size(2)/2
22 | local scale = img:size(2) / 200
23 | local savefile = name:gsub(ext,'h5')
24 |
25 | local inp = crop(img,center,scale,0,256)
26 | local out = model:forward(inp:view(1,3,256,256):cuda())
27 | local hm = out[2][1]:float()
28 | hm[hm:lt(0)] = 0
29 |
30 | local predFile = hdf5.open(savefile,'w')
31 | predFile:write('heatmap',hm)
32 | predFile:close()
33 |
34 | print(savefile)
35 |
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/pose-hg-demo/stacked-hourglass-model.lua:
--------------------------------------------------------------------------------
1 | paths.dofile('residual.lua')
2 |
3 | local function hourglass(n, numIn, numOut, inp)
4 | -- Upper branch
5 | local up1 = Residual(numIn,256)(inp)
6 | local up2 = Residual(256,256)(up1)
7 | local up4 = Residual(256,numOut)(up2)
8 |
9 | -- Lower branch
10 | local pool = nnlib.SpatialMaxPooling(2,2,2,2)(inp)
11 | local low1 = Residual(numIn,256)(pool)
12 | local low2 = Residual(256,256)(low1)
13 | local low5 = Residual(256,256)(low2)
14 | local low6
15 | if n > 1 then
16 | low6 = hourglass(n-1,256,numOut,low5)
17 | else
18 | low6 = Residual(256,numOut)(low5)
19 | end
20 | local low7 = Residual(numOut,numOut)(low6)
21 | local up5 = nn.SpatialUpSamplingNearest(2)(low7)
22 |
23 | -- Bring two branches together
24 | return nn.CAddTable()({up4,up5})
25 | end
26 |
27 | local function lin(numIn,numOut,inp)
28 | -- Apply 1x1 convolution, no stride, no padding
29 | local l_ = nnlib.SpatialConvolution(numIn,numOut,1,1,1,1,0,0)(inp)
30 | return nnlib.ReLU(true)(nn.SpatialBatchNormalization(numOut)(l_))
31 | end
32 |
33 | function createModel()
34 |
35 | local inp = nn.Identity()()
36 |
37 | -- Initial processing of the image
38 | local cnv1_ = nnlib.SpatialConvolution(3,64,7,7,2,2,3,3)(inp) -- 128
39 | local cnv1 = nnlib.ReLU(true)(nn.SpatialBatchNormalization(64)(cnv1_))
40 | local r1 = Residual(64,128)(cnv1)
41 | local pool = nnlib.SpatialMaxPooling(2,2,2,2)(r1) -- 64
42 | local r4 = Residual(128,128)(pool)
43 | local r5 = Residual(128,128)(r4)
44 | local r6 = Residual(128,256)(r5)
45 |
46 | -- First hourglass
47 | local hg1 = hourglass(4,256,512,r6)
48 |
49 | -- Linear layers to produce first set of predictions
50 | local l1 = lin(512,512,hg1)
51 | local l2 = lin(512,256,l1)
52 |
53 | -- First predicted heatmaps
54 | local out1 = nnlib.SpatialConvolution(256,outputDim[1][1],1,1,1,1,0,0)(l2)
55 | local out1_ = nnlib.SpatialConvolution(outputDim[1][1],256+128,1,1,1,1,0,0)(out1)
56 |
57 | -- Concatenate with previous linear features
58 | local cat1 = nn.JoinTable(2)({l2,pool})
59 | local cat1_ = nnlib.SpatialConvolution(256+128,256+128,1,1,1,1,0,0)(cat1)
60 | local int1 = nn.CAddTable()({cat1_,out1_})
61 |
62 | -- Second hourglass
63 | local hg2 = hourglass(4,256+128,512,int1)
64 |
65 | -- Linear layers to produce predictions again
66 | local l3 = lin(512,512,hg2)
67 | local l4 = lin(512,512,l3)
68 |
69 | -- Output heatmaps
70 | local out2 = nnlib.SpatialConvolution(512,outputDim[2][1],1,1,1,1,0,0)(l4)
71 |
72 | -- Final model
73 | local model = nn.gModule({inp}, {out1,out2})
74 |
75 | return model
76 |
77 | end
78 |
--------------------------------------------------------------------------------
/ssr/composeShape.m:
--------------------------------------------------------------------------------
1 | function S = composeShape(B,C)
2 |
3 | if size(C,2) ~= size(B,1)/3
4 | C = C';
5 | end
6 |
7 | f = size(C,1);
8 | p = size(B,2);
9 | k = size(B,1)/3;
10 |
11 | B = reshape(B',3*p,k);
12 | S = B*C';
13 | S = reshape(S,p,3*f)';
--------------------------------------------------------------------------------
/ssr/estimateC.m:
--------------------------------------------------------------------------------
1 | function C = estimateC(W,R,B,C,lam,tol)
2 |
3 | % INPUT:
4 | % W: 2-by-P matrix
5 | % R: 2-by-3 matrix
6 | % B: 3K-by-P matrx
7 | % C: 1-by-K vector
8 |
9 | % This function estimates c by minimizing
10 | % f(C) + lam*r(C), where
11 | % f(C) = 0.5 * norm(W-R*S,'fro')^2 where S = \sum_i C_i*B_i
12 | % r(C) = \|C\|_1
13 | % It implements proximal gradient + nesterov
14 |
15 | P = size(W,2);
16 | K = size(B,1)/3;
17 |
18 | C = C'; % transpose to be a column vector
19 | C0 = C; % C0: the previous estimate
20 | t = 1; % auxiliary variable for nesterov
21 | t0 = 1; % auxiliary variable for nesterov
22 | fvalue = inf;
23 |
24 | % next we work on the linear system y = X*C
25 | y = W(:); % vectorized W
26 | X = zeros(2*P,K); % each column is a rotated Bk
27 | for k = 1:K
28 | RBk = R*B(3*k-2:3*k,:);
29 | X(:,k) = RBk(:);
30 | end
31 |
32 | if lam == 0
33 | C = X\y;
34 | C = C';
35 | return
36 | end
37 |
38 | % mu is set as the 2-norm of the Hessian of f(C)
39 | mu = norm(X'*X);
40 |
41 | for iter = 1:1000
42 |
43 | % Z is an auxiliary variable in nesterov method
44 | Z = C + (t0-1)/t*(C-C0);
45 |
46 | % gradient descent
47 | Z = Z + X'*(y-X*Z)/mu;
48 |
49 | % nonegative thresholding
50 | % Z = Z - lam/mu;
51 | % Z = max(Z,0);
52 |
53 | % soft thresholding
54 | Z = sign(Z).*max(abs(Z)-lam/mu,0);
55 |
56 | % update C
57 | C0 = C;
58 | C = Z;
59 |
60 | % update t
61 | t0 = t;
62 | t = (1+sqrt(1+4*t^2))/2;
63 |
64 | % function value
65 | fvalue0 = fvalue;
66 | fvalue = 0.5 * norm(y-X*C,'fro')^2 + lam*sum(abs(C));
67 | if fvalue > fvalue0
68 | t0 = 1; % APG with restart
69 | t = 1;
70 | end
71 |
72 | % check convergence
73 | RelChg = norm(C-C0,'fro')/(norm(C0,'fro')+eps) ;
74 | % fprintf('Iter %d: FunVal = %f, RelChg = %f\n',iter,fvalue,RelChg);
75 | if RelChg < tol
76 | break
77 | end
78 |
79 | end
80 |
81 | C = C'; % transpose back to be a row vector
82 |
--------------------------------------------------------------------------------
/ssr/estimateR_manopt.m:
--------------------------------------------------------------------------------
1 | function R = estimateR_manopt(S,W,R0)
2 |
3 | A = S';
4 | B = W';
5 | X0 = R0(1:2,:)';
6 |
7 | warning('off', 'manopt:getHessian:approx');
8 |
9 | [m,n,N] = size(A);
10 | p = size(B,2);
11 |
12 | At = zeros([n,m,N]);
13 | for i=1:N
14 | At(:,:,i) = A(:,:,i)';
15 | end
16 |
17 |
18 | manifold = stiefelfactory(n,p, N);
19 | problem.M = manifold;
20 |
21 | function [f, store] = cost(X, store)
22 | if ~isfield(store, 'E')
23 | store.E = multiprod(A,X) - B;
24 | end
25 | E = store.E;
26 | f = (E(:)'*E(:))/(2*N);
27 | end
28 |
29 | % Riemannian gradient of the cost function.
30 | function [g, store] = grad(X, store)
31 |
32 | if ~isfield(store, 'E')
33 | [~, store] = cost(X, store);
34 | end
35 | E = store.E;
36 | % Compute the Euclidean gradient of the cost wrt the rotations R
37 | % and wrt the cloud A,
38 | egrad = multiprod(At/N,E);
39 | % then transform this Euclidean gradient into the Riemannian
40 | % gradient.
41 | g = manifold.egrad2rgrad(X, egrad);
42 | store.egrad = egrad;
43 | end
44 |
45 |
46 | % Setup the problem structure with manifold M and cost+grad functions.
47 |
48 | problem.cost = @cost;
49 | problem.grad = @grad;
50 |
51 | options.verbosity = 0;
52 | options.tolgradnorm = 1e-3;
53 | options.maxiter = 100;
54 | X = trustregions(problem,X0,options);
55 |
56 | R = X';
57 |
58 | end
--------------------------------------------------------------------------------
/ssr/estimateR_proj.m:
--------------------------------------------------------------------------------
1 | function R = estimateR_proj(S,W)
2 |
3 | R = W/S;
4 | [U,~,V] = svd(R,'econ');
5 | R = U*V';
6 |
7 |
--------------------------------------------------------------------------------
/ssr/learnPoseDict.m:
--------------------------------------------------------------------------------
1 | function [B,mu,ERR,SP] = learnPoseDict(S_train,skel,K,lam)
2 |
3 | % Input:
4 | % K: size of dictionary
5 | % lam: regularization weight
6 |
7 | %% normalization and alignment
8 | S_train = normalizeS(S_train);
9 | S_train = alignHuman(S_train,skel.torso);
10 | [F,P] = size(S_train);
11 | F = F/3;
12 |
13 | %% run dictionary learning
14 | Y = reshape(S_train',3*P,F);
15 | [D,X] = nnscDL(Y,K,lam);
16 |
17 | %% calculate reconstruction error
18 | S_rec = reshape(D*X,P,3*F)';
19 | for i=1:F
20 | x = lsqnonneg(D(:,X(:,i)>0),Y(:,i));
21 | S_rec(3*i-2:3*i,:) = reshape(D(:,X(:,i)>0)*x,P,3)';
22 | err(i) = sum(sqrt(sum((S_train(3*i-2:3*i,:)-S_rec(3*i-2:3*i,:)).^2)))/P;
23 | sp(i) = sum(x>0);
24 | end
25 | ERR = mean(err); % reconstruction error
26 | SP = mean(sp); % average sparsity (tune lam to change sparsity, sp < 10 is recommended)
27 |
28 | %% output dictionary
29 | B = reshape(D,P,3*size(D,2))';
30 | mu = meanShape(S_train);
31 |
32 | fprintf('Dictionary learning is done, \n reconstr. err. = %f, average sparsity = %f \n',ERR,SP);
--------------------------------------------------------------------------------
/ssr/nnscDL.m:
--------------------------------------------------------------------------------
1 | function [D,X] = nnscDL(Y,K,lam)
2 |
3 | % This function implements dictionary learning with nonnegative sparse
4 | % coding:
5 | % min_{D,X} 1/2||Y-DX||^2 + lam ||X||_1, X > 0
6 |
7 | % INPUT:
8 | % Y: training data (each column vector is a sample)
9 | % K: dictionary size
10 | % lam: regularization parameter
11 |
12 | % OUTPUT:
13 | % D: dictionary
14 | % X: sparse codes for training data
15 |
16 | N = size(Y,2);
17 |
18 | % Initializing D by uniformly sampling
19 | % Other initialization scheme could be used
20 | D = Y(:,round(linspace(1,N,K)));
21 | nrm0 = mean(sqrt(sum(D.^2)));
22 |
23 | % Initializing X
24 | X = pinv(D)*Y;
25 | X(X(:)<0) = 0;
26 | Xp = X;
27 |
28 |
29 | for iter = 1:10000
30 |
31 | % Update X by proximal gradient
32 | mu = norm(D'*D);
33 | for i = 1:500
34 | dX = D'*(Y-D*X);
35 | X = X + 1/mu*(dX-lam);
36 | X(X(:)<0) = 0;
37 | if norm(X-Xp,'fro')/norm(Xp,'fro') < 1e-3
38 | break
39 | end
40 | Xp = X;
41 | end
42 |
43 | % Update D
44 | D = D + 1/norm(X*X')*(Y-D*X)*X';
45 | % D = Y*pinv(X);
46 | for i = 1:size(D,2)
47 | nrm = sqrt(sum(D(:,i).^2));
48 | if nrm > nrm0
49 | D(:,i) = D(:,i)*nrm0/nrm;
50 | end
51 | end
52 |
53 | % Calculate and print objective
54 | obj(iter) = (0.5*sum(sum((Y-D*X).^2)) + lam*sum(sum(X)));
55 | fprintf('Iter %d, obj %.3f\n', iter, obj(end));
56 | if iter > 1 && (obj(end-1)-obj(end))/obj(end-1) < 1e-6
57 | break
58 | end
59 |
60 | end
61 |
62 |
63 |
--------------------------------------------------------------------------------
/ssr/proj_deformable_approx.m:
--------------------------------------------------------------------------------
1 | % Ref: A. Del Bue, J. Xavier, L. Agapito, and M. Paladini, "Bilinear
2 | % Factorization via Augmented Lagrange Multipliers (BALM)" ECCV 2010.
3 | %
4 | % This program is free software; you can redistribute it and/or
5 | % modify it under the terms of the GNU General Public License
6 | % as published by the Free Software Foundation; version 2, June 1991
7 | %
8 | % USAGE: Y = proj_deformable_approx(X)
9 | %
10 | % This function projects a generic matrix X of size 3*K x 2 where K is the
11 | % number of basis shapes into the matrix Y that satisfy the manifold
12 | % constraints. This projection is an approximation of the projector
13 | % introduced in: M. Paladini, A. Del Bue, S. M. s, M. Dodig, J. Xavier, and
14 | % L. Agapito, "Factorization for Non-Rigid and Articulated Structure using
15 | % Metric Projections" CVPR 2009. Check the BALM paper, Sec 5.1.
16 | %
17 | % INPUT
18 | %
19 | % X: the 3*K x 2 affine matrix
20 | %
21 | % OUTPUT
22 | %
23 | % Y: the 3*K x 2 with manifold constraints
24 |
25 | function [Y,L,Q] = proj_deformable_approx(X)
26 |
27 | if nargin < 1
28 |
29 | Y = 2; % this says on how many columns of M the projection must be done
30 | return
31 | end
32 |
33 | r = size(X,1);
34 | d = r/3;
35 |
36 | A = zeros(3,3);
37 | for i = 1:d
38 | Ai = X((i-1)*3+1:i*3,:);
39 | A = A + Ai*Ai';
40 | end;
41 |
42 | [U,S,V] = svd(A);
43 |
44 | Q = U(:,1:2);
45 |
46 | G = zeros(2,2);
47 | for i = 1:d
48 | Ai = X((i-1)*3+1:i*3,:);
49 | Ti = Q'*Ai;
50 | gi = [ trace(Ti) ; Ti(2,1)-Ti(1,2) ];
51 | G = G + gi*gi';
52 | end;
53 |
54 | [U1,S1,V1] = svd(G);
55 |
56 | G = zeros(2,2);
57 | for i = 1:d
58 | Ai = X((i-1)*3+1:i*3,:);
59 | Ti = Q'*Ai;
60 | gi = [ Ti(1,1)-Ti(2,2) ; Ti(1,2)+Ti(2,1) ];
61 | G = G + gi*gi';
62 | end;
63 |
64 | [U2,S2,V2] = svd(G);
65 |
66 | if S1(1,1) > S2(1,1)
67 | u = U1(:,1);
68 | R = [ u(1) -u(2) ; u(2) u(1) ];
69 | else
70 | u = U2(:,1);
71 | R = [ u(1) u(2) ; u(2) -u(1) ];
72 | end;
73 |
74 | Q = Q*R;
75 |
76 | Y = [];
77 | L = [];
78 | for i = 1:d
79 | Ai = X((i-1)*3+1:i*3,:);
80 | ti = 0.5*trace(Q'*Ai);
81 | % if i == 1 && ti < 0
82 | % ti = -ti;
83 | % Q = -Q;
84 | % end
85 | L = [ L ; ti];
86 | Y = [ Y ; ti*Q ];
87 | end;
--------------------------------------------------------------------------------
/ssr/prox_2norm.m:
--------------------------------------------------------------------------------
1 | function [X,normX] = prox_2norm(Z,lam)
2 |
3 | [U,W,V] = svd(Z,'econ');
4 | w = diag(W);
5 | w = prox_inf(w,lam);
6 | X = U*diag(w)*V';
7 | normX = w(1);
8 |
9 | end
--------------------------------------------------------------------------------
/ssr/ssr2D3D_alm.m:
--------------------------------------------------------------------------------
1 | function [S,info] = ssr2D3D_alm(W,B,lam,beta,varargin)
2 |
3 | tol = 1e-3;
4 | refine = false;
5 | verb = true;
6 | if nargin < 4
7 | beta = inf;
8 | end
9 |
10 | ivargin = 1;
11 | while ivargin <= length(varargin)
12 | switch lower(varargin{ivargin})
13 | case 'tol'
14 | ivargin = ivargin + 1;
15 | tol = varargin{ivargin};
16 | case 'refine'
17 | ivargin = ivargin + 1;
18 | refine = varargin{ivargin};
19 | case 'verb'
20 | ivargin = ivargin + 1;
21 | verb = varargin{ivargin};
22 | otherwise
23 | fprintf('Unknown option ''%s'' is ignored !\n',varargin{ivargin});
24 | end
25 | ivargin = ivargin + 1;
26 | end
27 |
28 | % centralize basis
29 | B = bsxfun(@minus,B,mean(B,2));
30 |
31 | % data size
32 | [k,p] = size(B);
33 | k = k/3;
34 |
35 | % initialization
36 | M = zeros(2,3*k);
37 | C = zeros(1,k); % norm of each Xi
38 | E = zeros(size(W));
39 | T = mean(W,2);
40 | % auxiliary variables for ADMM
41 | Z = M;
42 | Y = M;
43 | mu = 1/mean(abs(W(:)));
44 | % pre-computing
45 | BBt = B*B';
46 |
47 | % flagOD detection?
48 | if beta > max(abs(W(:))) % too large
49 | flagOD = false;
50 | else
51 | flagOD = true;
52 | end
53 |
54 | t0 = tic;
55 |
56 | for iter = 1:1000
57 |
58 | % update motion matrix Z
59 | Z0 = Z;
60 | Z = ((W-E-T*ones(1,p))*B'+mu*M+Y)/(BBt+mu*eye(3*k));
61 |
62 | % update motion matrix M
63 | Q = Z - Y/mu;
64 | for i = 1:k
65 | [M(:,3*i-2:3*i),C(i)] = prox_2norm(Q(:,3*i-2:3*i),lam/mu);
66 | end
67 |
68 | if flagOD
69 |
70 | % update flagOD term
71 | E = W - Z*B - T*ones(1,p);
72 | E = sign(E).*max(abs(E)-beta,0);
73 |
74 | % update translation
75 | T = mean(W-Z*B-E,2);
76 |
77 | end
78 |
79 | % update dual variable
80 | Y = Y + mu*(M-Z);
81 |
82 | PrimRes = norm(M-Z,'fro')/norm(Z0,'fro');
83 | DualRes = mu*norm(Z-Z0,'fro')/norm(Z0,'fro');
84 |
85 | % show info
86 | if verb && mod(iter,10) == 0
87 | fprintf('Iter %d: PrimRes = %f, DualRes = %f, mu = %f\n',...
88 | iter,PrimRes,DualRes,mu);
89 | end
90 |
91 | % Convergent?
92 | if PrimRes < tol && DualRes < tol
93 | break
94 | else
95 | if PrimRes>10*DualRes
96 | mu = 2*mu;
97 | elseif DualRes>10*PrimRes
98 | mu = mu/2;
99 | else
100 | end
101 | end
102 |
103 | end
104 |
105 | info.time = toc(t0);
106 |
107 | if refine
108 | [R,C] = syncRot(M);
109 | S = R*composeShape(B,C);
110 | [S,info1] = ssr2D3D_alt(W,B,lam,beta,'S0',R'*S,'R0',R,'E0',E,...
111 | 'method','manopt','verb',verb);
112 | info.M = M;
113 | info.R = info1.R;
114 | info.C = info1.C;
115 | info.T = info1.T;
116 | info.E = info1.E;
117 | info.fval = info1.fval;
118 | info.timeAlt = info1.time;
119 | else
120 | R = zeros(3,3*k);
121 | C(C<1e-6) = 0;
122 | for i = find(C>0)
123 | R(1:2,3*i-2:3*i) = M(:,3*i-2:3*i)/C(i);
124 | R(3,3*i-2:3*i) = cross(R(1,3*i-2:3*i),R(2,3*i-2:3*i));
125 | end
126 | S = R*kron(diag(C),eye(3))*B;
127 | info.M = M;
128 | info.R = R;
129 | info.C = C;
130 | info.T = T;
131 | info.E = E;
132 | info.fval = 0;
133 | end
134 |
135 | end
136 |
137 | function [X,normX] = prox_2norm(Z,lam)
138 | % X is a 3-by-2 matrix
139 | [U,W,V] = svd(Z,'econ');
140 | w = diag(W);
141 | if sum(w) <= lam
142 | w = [0,0];
143 | elseif w(1)-w(2) <= lam
144 | w(1) = (sum(w)-lam)/2;
145 | w(2) = w(1);
146 | else
147 | w(1) = w(1) - lam;
148 | w(2) = w(2);
149 | end
150 | X = U*diag(w)*V';
151 | normX = w(1);
152 | end
--------------------------------------------------------------------------------
/ssr/ssr2D3D_alt.m:
--------------------------------------------------------------------------------
1 | function [S,info] = ssr2D3D_alt(W,B,lam,beta,varargin)
2 |
3 | if nargin < 4
4 | beta = inf;
5 | end
6 |
7 | % centralize data
8 | B = bsxfun(@minus,B,mean(B,2));
9 |
10 | % data size
11 | k = size(B,1)/3;
12 | p = size(B,2);
13 |
14 | % initialize
15 | C = zeros(1,k);
16 | S = meanShape(B);
17 | R = eye(3);
18 | E = zeros(size(W));
19 | T = mean(W,2);
20 | tol = 1e-4;
21 | method = 'manopt';
22 | verb = true;
23 |
24 | ivargin = 1;
25 | while ivargin <= length(varargin)
26 | switch lower(varargin{ivargin})
27 | case 'tol'
28 | ivargin = ivargin + 1;
29 | tol = varargin{ivargin};
30 | case 's0'
31 | ivargin = ivargin + 1;
32 | S = varargin{ivargin};
33 | case 'r0'
34 | ivargin = ivargin + 1;
35 | R = varargin{ivargin};
36 | case 'e0'
37 | ivargin = ivargin + 1;
38 | E = varargin{ivargin};
39 | case 'method'
40 | ivargin = ivargin + 1;
41 | method = varargin{ivargin};
42 | case 'verb'
43 | ivargin = ivargin + 1;
44 | verb = varargin{ivargin};
45 | otherwise
46 | fprintf('Unknown option ''%s'' is ignored !\n',varargin{ivargin});
47 | end
48 | ivargin = ivargin + 1;
49 | end
50 |
51 | % outlier detection?
52 | if beta > max(abs(W(:))) % too large
53 | flagOD = false;
54 | else
55 | flagOD = true;
56 | end
57 |
58 | R = R(1:2,:);
59 |
60 | fval = inf;
61 | t0 = tic;
62 | for iter = 1:1000
63 |
64 | % update rotation
65 | W2fit = W - E - T*ones(1,p);
66 | switch method
67 | case 'proj' % greedy projection
68 | R = estimateR_proj(S,W2fit);
69 | case 'manopt' % manifold optimizaiton
70 | R = estimateR_manopt(S,W2fit,R);
71 | otherwise
72 | error('Invalid input for option:method!');
73 | end
74 |
75 | % update shape
76 | C = estimateC(W2fit,R,B,C,lam,1e-4);
77 | S = kron(C,eye(3))*B;
78 |
79 | if flagOD
80 |
81 | % update outlier
82 | E = W - R*S - T*ones(1,p);
83 | E = sign(E).*max(abs(E)-beta,0);
84 |
85 | % update translation
86 | T = mean(W-R*S-E,2);
87 |
88 | % evaluate obj. func.
89 | fvaltm1 = fval;
90 | fval = 0.5*norm(W-R*S-E-T*ones(1,p),'fro')^2 + lam*sum(abs(C(:))) + beta*sum(abs(E(:)));
91 |
92 | else
93 |
94 | fvaltm1 = fval;
95 | fval = 0.5*norm(W-R*S-E-T*ones(1,p),'fro')^2 + lam*sum(abs(C(:)));
96 |
97 | end
98 |
99 | % show info
100 | if verb
101 | fprintf('Iter: %d, fval = %f\n',iter,fval);
102 | end
103 |
104 | % check convergence
105 | if abs(fval-fvaltm1)/fvaltm1 < tol
106 | break
107 | end
108 |
109 | end
110 |
111 | R(3,:) = cross(R(1,:),R(2,:));
112 |
113 | % output
114 | S = R*S;
115 | info.R = R;
116 | info.C = C;
117 | info.T = T;
118 | info.E = E;
119 | info.fval = fval;
120 | info.time = toc(t0);
121 |
--------------------------------------------------------------------------------
/ssr/ssr2D3D_wrapper.m:
--------------------------------------------------------------------------------
1 | function [S,info] = ssr2D3D_wrapper(W,B,method,varargin)
2 |
3 | lam = 1;
4 | beta = 1;
5 | verb = false;
6 |
7 | ivargin = 1;
8 | while ivargin <= length(varargin)
9 | switch lower(varargin{ivargin})
10 | case 'lam'
11 | ivargin = ivargin + 1;
12 | lam = varargin{ivargin};
13 | case 'beta'
14 | ivargin = ivargin + 1;
15 | beta = varargin{ivargin};
16 | case 'verb'
17 | ivargin = ivargin + 1;
18 | verb = varargin{ivargin};
19 | otherwise
20 | fprintf('Unknown option ''%s'' is ignored !\n',varargin{ivargin});
21 | end
22 | ivargin = ivargin + 1;
23 | end
24 |
25 | % run solvers
26 | switch lower(method)
27 | case 'convex'
28 | [S,info] = ssr2D3D_alm(W,B,lam,inf,'verb',verb);
29 | case 'convex+refine'
30 | [S,info] = ssr2D3D_alm(W,B,lam,inf,'refine',true,'verb',verb);
31 | case 'convex+robust'
32 | [S,info] = ssr2D3D_alm(W,B,lam,beta,'verb',verb);
33 | case 'convex+robust+refine'
34 | [S,info] = ssr2D3D_alm(W,B,lam,beta,'refine',true,'verb',verb);
35 | case 'altern'
36 | [S,info] = ssr2D3D_alt(W,B,lam,inf,'method','proj','verb',verb);
37 | case 'altern+robust'
38 | [S,info] = ssr2D3D_alt(W,B,lam,beta,'method','proj','verb',verb);
39 | otherwise
40 | error('Undefined method!');
41 | end
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/ssr/syncRot.m:
--------------------------------------------------------------------------------
1 | function [R,C] = syncRot(T)
2 |
3 | [~,L,Q] = proj_deformable_approx(T');
4 | s = sign(L(find(abs(L)==max(abs(L)),1)));
5 | C = s*L';
6 | R = s*Q';
7 | R(3,:) = cross(R(1,:),R(2,:));
8 |
9 | % [R,C] = projectNonrigid(T);
10 | % R(3,:) = cross(R(1,:),R(2,:));
11 |
--------------------------------------------------------------------------------
/startup.m:
--------------------------------------------------------------------------------
1 | addpath em
2 | addpath general
3 | addpath ssr
4 | addpath utils
5 | addpath(genpath('manopt'));
--------------------------------------------------------------------------------
/utils/getMPIIdict.m:
--------------------------------------------------------------------------------
1 | function mpiidict = getMPIIdict(dict,source)
2 |
3 | % create dictionary for mpii human pose dataset from other 3D datasets
4 |
5 | switch lower(source)
6 | case 'hm36m'
7 | ind_new = 1:16;
8 | ind_old = [7,6,5,2,3,4,1,9,10,11,17,16,15,12,13,14];
9 | mpiidict.B(:,ind_new) = dict.B(:,ind_old);
10 | mpiidict.mu(:,ind_new) = dict.mu(:,ind_old);
11 | case 'cmu'
12 | ind_new = [1:8,10:16];
13 | ind_old = [7,6,5,2,3,4,1,8,9,15,14,13,10,11,12];
14 | mpiidict.B(:,ind_new) = dict.B(:,ind_old);
15 | mpiidict.mu(:,ind_new) = dict.mu(:,ind_old);
16 | % interpolate the location of neck = 1/3*head + 2/3*thorax
17 | mpiidict.B(:,9) = mpiidict.B(:,8)*2/3 + mpiidict.B(:,10)*1/3;
18 | mpiidict.mu(:,9) = mpiidict.mu(:,8)*2/3 + mpiidict.mu(:,10)*1/3;
19 | otherwise
20 | error('Unknown source of 3D data!');
21 | end
22 |
23 | mpiidict.skel.tree(1).name = ['RAnk'];
24 | mpiidict.skel.tree(2).name = ['RKne'];
25 | mpiidict.skel.tree(3).name = ['RHip'];
26 | mpiidict.skel.tree(4).name = ['LHip'];
27 | mpiidict.skel.tree(5).name = ['LKne'];
28 | mpiidict.skel.tree(6).name = ['LAnk'];
29 | mpiidict.skel.tree(7).name = ['Pelv'];
30 | mpiidict.skel.tree(8).name = ['Thrx'];
31 | mpiidict.skel.tree(9).name = ['Neck'];
32 | mpiidict.skel.tree(10).name = ['Head'];
33 | mpiidict.skel.tree(11).name = ['RWri'];
34 | mpiidict.skel.tree(12).name = ['RElb'];
35 | mpiidict.skel.tree(13).name = ['RSho'];
36 | mpiidict.skel.tree(14).name = ['LSho'];
37 | mpiidict.skel.tree(15).name = ['LElb'];
38 | mpiidict.skel.tree(16).name = ['LWri'];
39 |
40 | mpiidict.skel.tree(1).children = [];
41 | mpiidict.skel.tree(2).children = [1];
42 | mpiidict.skel.tree(3).children = [2];
43 | mpiidict.skel.tree(4).children = [5];
44 | mpiidict.skel.tree(5).children = [6];
45 | mpiidict.skel.tree(6).children = [];
46 | mpiidict.skel.tree(7).children = [3,4,8];
47 | mpiidict.skel.tree(8).children = [9,13,14];
48 | mpiidict.skel.tree(9).children = [10];
49 | mpiidict.skel.tree(10).children = [];
50 | mpiidict.skel.tree(11).children = [];
51 | mpiidict.skel.tree(12).children = [11];
52 | mpiidict.skel.tree(13).children = [12];
53 | mpiidict.skel.tree(14).children = [15];
54 | mpiidict.skel.tree(15).children = [16];
55 | mpiidict.skel.tree(16).children = [];
56 |
57 | mpiidict.skel.tree(1).color = ['g'];
58 | mpiidict.skel.tree(2).color = ['g'];
59 | mpiidict.skel.tree(3).color = ['g'];
60 | mpiidict.skel.tree(4).color = ['r'];
61 | mpiidict.skel.tree(5).color = ['r'];
62 | mpiidict.skel.tree(6).color = ['r'];
63 | mpiidict.skel.tree(7).color = ['b'];
64 | mpiidict.skel.tree(8).color = ['b'];
65 | mpiidict.skel.tree(9).color = ['b'];
66 | mpiidict.skel.tree(10).color = ['b'];
67 | mpiidict.skel.tree(11).color = ['g'];
68 | mpiidict.skel.tree(12).color = ['g'];
69 | mpiidict.skel.tree(13).color = ['g'];
70 | mpiidict.skel.tree(14).color = ['r'];
71 | mpiidict.skel.tree(15).color = ['r'];
72 | mpiidict.skel.tree(16).color = ['r'];
73 |
74 | mpiidict.skel.torso = [3,4,7,8,13,14];
75 |
--------------------------------------------------------------------------------
/utils/transformMPII.m:
--------------------------------------------------------------------------------
1 | function new_pt = transformMPII(pt,center,scale,res,invert)
2 |
3 | t = get_transform(center,scale,res);
4 | if invert
5 | t = inv(t);
6 | end
7 |
8 | new_pt = [pt(1,:);pt(2,:)-0.5;ones(1,size(pt,2))];
9 | new_pt = t*new_pt;
10 | new_pt = new_pt(1:2,:);
11 |
12 | end
13 |
14 | function t = get_transform(center,scale,res)
15 | h = 200*scale;
16 | t = eye(3,3);
17 | t(1,1) = res(2)/h;
18 | t(2,2) = res(1)/h;
19 | t(1,3) = res(2)*(-center(1)/h + 0.5);
20 | t(2,3) = res(1)*(-center(2)/h + 0.5);
21 | t(3,3) = 1;
22 | end
23 |
24 |
--------------------------------------------------------------------------------
|